C

CAFEBABE

Software Engineer.

Standard Notes v/s Day One


Summary:

    • Day One: all the note-taking features of SN; offers social media integration; and, offers some features not available on SN.
    • Standard Notes: has all the note-taking features of D1; has some features not available on D1; but, is way better for privacy.
    • Day One: lacks in Privacy and Security compared to SN.
    • Standard Notes: all the same note-taking features but lacks some UI features and social media integration option offered by Day One. 


    Legend: 

    • ❌ feature unavailable  ☠ 
    • ✅ Feature Available ◎
    • ✔ Feature Available But Comparatively Not As Convenient As The Other App ⚛


    Evaluation CategorySubcategoryFunctionDay OneStandard NotesNote
    SafetyNotes PrivacyNotes End-to-End Encryption✅ ✔❌

    Day One:

    1. ✔notes content is encrypted when sent from your device to Day One Servers,
    2. ✅Notes are encrypted on Day One Servers; BUT
    3. ❌notes are NOT ENCRYPTED ON YOUR DEVICE.
    4. ❌notes metadata is NOT ENCRYPTED on servers.

    SN: standard notes encrypts data on your device, over the network, and on its server.

    1. You need to use App Passcode for SN to encrypt data on your device.
    2. Without app passcode, app data is stored in plaintext on the device.


    SafetyNotes PrivacyEncrypted Note Metadata

    Day One tracks following Note Metadata which is NOT ENCRYPTED ❌:

    1. Note Create Datetime ❌
    2. Note Edit Datetime ❌
    3. Names of Journals ❌
    4. Total Number of Journals ❌
    5. Total Number of Notes ❌
    6. Total Number of Images ❌
    7. Attachment Image Type & Size ❌
    8. Device Info ❌

    Source: https://dayoneapp.com/blog/end-to-end-encryption-for-day-one-sync


    SN does NOT ENCRYPT the following Note metadata:

    1. Note Create Datetime❌
    2. Note Modified Datetime ❌
    3. Note Type (Note or Tag/Folder) ❌
    4. Browser ❌
    SafetyUser PrivacySafe Personal Info

    Day One collects and shares Name, Address, IP Address, Location, Device ID.


    SN: collects no user information.

    SafetyUser PrivacyNo Tracking

    Day One Tracks Location, Time, Day to add to note.

    SN: collects no user information.

    Safety
    User PrivacySafe Behavior Info

    Day One uses Google Analytics to track and analyze your behavior.

    SN: does not run any analytics software, BUT

    1. To avoid spamming, SN Servers Firewall stores IP Address for 5 Minutes, but the IP addresses are not logged in long-term storage.
    SafetyApp SecurityApp Password 


    Safety
    App SecurityBiometrics Password


    DevicesApp UsabilityUnlimited Number of Devices


    FeaturesIntegration
    Integrate with SM

    Day One integrates Instagram
    SN offers no integration.
    FeaturesNotes-StorageUnlimited Notes


    FeaturesNotes-StorageUnlimited Cloud Backup


    Features
    Notes-StorageSync


    Features
    Notes-StorageExport Backup


    Features
    Notes-StorageExport Encrypted Backup


    Features
    Notes-CreationRich Formatting Editors

    Features
    Notes-CreationPublish Note To Blog


    Features
    Notes-CreationOffline Notes


    Features
    Note-CreationReminders


    Features
    Note-CreationNote Templates

    Day One; provides note templates like "Meal logging note".
    Features
    Note-CreationSpreadsheet?

    SN; has a built-in Spreadsheet editor which allows you to create notes in in-app spreadsheets.

    • Spreadsheet in one note is limited to 70 rows, but allows multiple sheets/tabs within a single note.

    Day One: Needs to be checked.


    Note-InfoNote Statistics

    Word and character counts for a note.
    Features
    Notes-BrowsingSearch By Note Content


    Features
    Notes BrowsingSearch By Tag

    Day One: Search Function allows searching by tags out-of-the-box.

    Standard Notes: has Smart Tags which allows you to create "Views" to "View All Notes With This Tag" in a single place.

    Features
    Notes Browsing
    Activity Feed

    Day One: has an in-built UI for activity wall.

    SN: has Smart Tags instead of UI elements that allow you to create any sort of "Views"  view your activity like "All Notes Created/Updated On-This-Day/Days/Years/Weeks/Days Ago" in a single place.
    Features
    Notes-BrowsingCalendar View

    Day One: has an in-built Calendar view which shows the days on which notes were taken.

    SN: no in-built Calendar View, but allows you to create "Views" using smart tags/folders to View Activity like "All Notes Created/Updated On This Day A Years/Weeks/Days Ago" in a single place.

    Features
    Notes-BrowsingMap View

    Day One: Show locations of notes.

    SN: does not track location data.

    Features
    AttachmentsUnlimited Images Attachment

    Standard Notes has a file size limit of 50 MB on attachments.

    Day One: Needs to be checked.

    Features
    Attachments

    Encrypted Images Attachment




    Features
    AttachmentsUnlimited Audio/Video Attachment

    SN: Attachment file-size limit of 50MB
    Features
    AttachmentsUnlimited File Attachment


    FeaturesToolsIn-built 2FA App

    SN: has a built-in 2FA editor which can be used to generate 2FA OTP for other apps/websites/accounts.
    Features
    ToolsScan-To-PDF


    Features
    ToolsBrowser Extensions


    Features
    ToolsSiri Shortcuts


    Features
    ToolsHealthKit

    Day One: allows integration with Apple Health App to track the time spent on the app as "mindful time".
    Features
    Tools


    Day One: allows you to import data from YouTube, Facebook, Spotify, Twitter, Fitbit etc.
    Customer Support
    Regular Support


    Customer Support
    Ephemeral Support

    SN: allows you to send support requests which get deleted after a time (set by you) by using the ProtonMail Disappearing Mail functionality: they offer a SN ProtonMail email support account.
    AvailabilityAccount & Data Lifespan


    Day One:

    1. will sell your data in case of merger or take over. 
    2. no information available about what happens to your data if the company shuts down.

    SN:

    1. does not analyze or share data.
    2. provides tool to retain and keep using the app in case the company shuts down.
      1. provides a self-hosting option.

    Books: Notes From PowerSexSuicide By Nick Lane

    Mitochondria and Egg Cells: Why (mostly) uniparental inheritence?

    • The Mitochondria in a cell is almost always, but not always, inherited from the mother to eliminate the cytoplasmic competition between two different cytoplasmic components (from different gametes).
      • Mitochondrial DNA gets recombined, when needed, with the damaged genes getting replaced with copies from other chromosomes.
      • Yeasts, Rats, and Bats can recombine mitchondrial DNA
      • There's a recorded case of a human having heart cells containing mitochondria from the father.
    • In a fertilized egg, the mitochondria from the male is either eliminated or selectively silenced, almost always.
    • The zygote (the fertilized egg cell) contains 100,000 mitochondria 99.99% coming from the mother.
    • The zygote divides a number of times within first two weeks to form the embryo: every time the zygote divides the 100,000 mitochondria are distributed among the new cells.
    • Until mitochondria themselves start dividing (asexual reproduction), no new mitochondria are formed during this (first two weeks') period, and the new embryo cells must utilise whatever mitochondria are available to them for their development: any embryo cells that cannot do this die.
    • If the embryo is a female embryo, the egg cells start forming after two/three weeks, and contain around 10 mitochondria, each containing just a single copy of the chromosomes: there's variation in the mitochondrial sequences within these oocytes, and more than 50% contain errors in the DNA sequence.
      • The mitochondrial DNA is verified for a match against the nuclear DNA
    • The number of egg cells formed in a female embryo is around 100 after the first three weeks --> seven million after five months --> two million after birth --> 300,000 by menstruation --> 25,000 by age 40: only 200 of which ovulate during female's reproductive life.


    Mitochondria and Ageing: Anti-oxidants do not increase lifespan

    • Denham Harman proposed relation between free-radicals and ageing in 1972: theorized that higher metabolism rate leads to higher free-radicals which cause higher cell damage leading to cell death and, consequently, ageing.
    • Richard Cutler, in 1980's, showed -- erroneously -- that long-lived animals have a higher levels on anti-oxidants in their cells, and conversely, short-lived animals have lower anti-oxidant levels: the data was flawed since he divided the number of anti-oxidants by the metabolic rate in the respective organism, which has the following problems:
      • Opposite is true: a short-lived rat with higher metabolic rate (7 times human metabolic rate) also has a higher anti-oxidant concentration.
      • Several independent studies have confirmed a negative correlation between the antioxidant level and lifespan i.e. the lifespan decreases with the increase in antioxidants: a correlation not causation, since the lifespan is independent of antioxidant concentration.
      • The levels of antioxidant is maintained wrt the metabolic rate: low-for-low/high-for-high to maintain a flexible redox state within the cell.

    Java: Serialization

    Notes and Format

    • What: Convert an object into a stream of bytes by storing the state of the object.
    • What gets stored in the byte stream:
      • The member variables/fields
      • function signature (but NOT the function's code) impacts the bytes created for the object
    • How: "The default serialization mechanism for an object writes the class of the
      object, the class signature, and the values of all non-transient and
      non-static fields. References to other objects (except in transient or
      static fields) cause those objects to be written also. Multiple references
      to a single object are encoded using a reference sharing mechanism so that
      graphs of objects can be restored to the same shape as when the original was
      written."
    • How: "The default deserialization mechanism for objects restores the contents
      of each field to the value and type it had when it was written. Fields
      declared as transient or static are ignored by the deserialization process.
      References to other objects cause those objects to be read from the stream
      as necessary. Graphs of objects are restored correctly using a reference
      sharing mechanism. New objects are always allocated when deserializing,
      which prevents existing objects from being overwritten."

      "Reading an object is analogous to running the constructors of a new
      object. Memory is allocated for the object and initialized to zero (NULL).
      No-arg constructors are invoked for the non-serializable classes and then
      the fields of the serializable classes are restored from the stream starting
      with the serializable class closest to java.lang.object and finishing with
      the object's most specific class. "  

    • Important: With respect to byte streams, notes on closing the streams:
      • For an output stream, calling close() ensures that the data gets written to its destination (file or whathaveyou); not closing the stream will result in the data being in the buffer without being written to its destination.
      • For an input stream, a file descriptor is associated with the stream, and is stored in the file descriptor table; consequently, the file descriptor table can run out of space if there is a lot of unclosed file streams, and may stop the program from opening new files -- which can be problematic. Close your input file streams.
    • Important: it introduces vulnreability in the code since the serialized byte stream can be easily edited to change bytes such that some invariant of the serialized object is broken.
    • source https://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html#10258

    Stream Format:

    • Stream Format For Classes

      Magic NumberVersion UIDclassNameserialVersionUIDhandleclassDescFlags bytefield1TypeCode field1NamefieldNTypeCode fieldNName <classNameForFieldOfObjectType>
      fieldBytes
      nullReferenceprevObjectReference

    • Stream Format For Objects        

    Magic NumberVersion UIDclassNameserialVersionUIDhandleclassDescFlags bytefield1TypeCode field1NamefieldNTypeCode fieldNName <classNameForFieldOfObjectType>
    fieldBytes

    nullReference
    prevObjectReference
    classData[]: fieldsInClass, bytesForPrimitives

    stream:
    magic version contents



    contents:
    content contents content



    content:
    object: classes, outputStream Objects, Enums

    blockdata: primitive dataTypes


    • "All of the write methods for primitive types encode their values using a DataOutputStream to put them in the standard stream format. The bytes are buffered into block data records so they can be distinguished from the encoding of objects. This buffering allows primitive data to be skipped if necessary for class versioning. It also allows the stream to be parsed without invoking class-specific methods."


    Codes used in the serialized data:

    primtypecode:

    B = byte

    C = char

    D = double

    F = float

    I = integer

    J =long

    S = short

    Z = boolean


    objtypecode:

    [ = array

    L = object


    final static short STREAMMAGIC = (short)0xaced;
        final static short STREAMVERSION = 5;
        final static byte TCNULL = (byte)0x70;
        final static byte TCREFERENCE = (byte)0x71;
        final static byte TCCLASSDESC = (byte)0x72;
        final static byte TCOBJECT = (byte)0x73;
        final static byte TCSTRING = (byte)0x74;
        final static byte TCARRAY = (byte)0x75;
        final static byte TCCLASS = (byte)0x76;
        final static byte TCBLOCKDATA = (byte)0x77;
        final static byte TCENDBLOCKDATA = (byte)0x78;
        final static byte TCRESET = (byte)0x79;
        final static byte TCBLOCKDATALONG = (byte)0x7A;
        final static byte TCEXCEPTION = (byte)0x7B;
        final static byte TCLONGSTRING = (byte) 0x7C;
        final static byte TCPROXYCLASSDESC = (byte) 0x7D;
        final static byte TC_ENUM = (byte) 0x7E;
        final static  int   baseWireHandle = 0x7E0000;



    Serialization Vulnerability Demonstration Code:
    <add after lunch>

    Java: Volatile and Synchronized

    Gist: a volatile variable isn't enough synchronization.


    In Java, a "volatile" field is often presented as a weaker form of synchronization: a field that's specifically indicated to the compiler and runtime as "not-to-be-reordered", which, consequently, doesn't get cached; it is guaranteed to return the most recent write on the field to any threads accessing that field.

    Because "most recent write" doesn't always imply "every write", using volatile as a form of synchronization could become problematic.

    Consider the code below where the starting balance (represented by volatile member variable balance) is 0; two threads (the main thread, and another created (thread) change the balance to add 100 and 51000 respectively. After execution, one'd expect the final balance to be 51100 (100+51000) for a synchronized operation; however, that isn't what happens: on my machine, the final balance takes values like 51100, 51099, 51000 etc. See the output following the code.

    import java.lang.Thread;
    /* Over several executions of the program,
     a write to the  volatile variable "balance" 
     either by the main thread or by the created thread 
     is lost i.e. overwritten*/
    public class ThreadTest
    {
    volatile int balance = 0;
    public void deposit(int val)
    {
    balance = balance+val;
    }

    public void credit(int val)
    {
    if(balance>0)
    balance = balance-val;
    }
    public void debit(int val) 
    {
    try
    {
    Thread internalThread = new Thread(new Runnable(){
    @Override
    public void run()
    {
    try
    {
    System.out.println("pre-change balance in second thread is: "+Integer.toString(balance));

    deposit(val);
    System.out.println("post-change balance in second thread is: "+Integer.toString(balance));
    }
    catch(Exception ioe)
    {
    System.out.println("error in debit thread run.");
    }
    }
    });

    internalThread.start();
    }
    catch(Exception ioe)
    {
    System.out.println("error in debit().");
    }

    }
    public static void main(String[] args)  throws InterruptedException
    {
    System.out.println("Main Thread started");
    ThreadTest tt = new ThreadTest();


    System.out.println("Main Thread starting balance is: "+Integer.toString(tt.balance));

    // alter balance from a new thread
    tt.debit(100);

    // alter balance from the main thread
    for(int i = 1;i<=51000; i++)
    {
    tt.deposit(1);
    }

    System.out.println("Main Thread changed balance is: "+Integer.toString(tt.balance));
    }
    }


    [my-pc java]$ java ThreadTest  
    Main Thread started
    Main Thread starting balance is: 0
    pre-change balance in second thread is: 1420
    post-change balance in second thread is: 2837
    Main Thread changed balance is: 51000
    [my-pc java]$ java ThreadTest        
    Main Thread started
    Main Thread starting balance is: 0
    pre-change balance in second thread is: 935
    post-change balance in second thread is: 1619
    Main Thread changed balance is: 51100


    In the same code, simply marking the method "deposit()" as synchronized ensures that the final balance is always 51100. Of course, the choice of using a synchronized method or a synchronized block is situational.