Example #1
0
        public static SyncResult Sync(ISimpleJsonRest web, StandardNoteConnection conn, APIResultAuthorize authToken, StandardNoteConfig cfg, StandardNoteData dat, List <StandardFileNote> allNotes, List <StandardFileNote> notesUpload, List <StandardFileNote> notesDelete, List <StandardFileTag> tagsDelete)
        {
            APIBodySync d = new APIBodySync();

            d.cursor_token = null;
            d.sync_token   = string.IsNullOrWhiteSpace(dat.SyncToken) ? null : dat.SyncToken;
            d.limit        = 150;
            d.items        = new List <APIBodyItem>();

            var items_raw = new List <APIRawBodyItem>();

            var allTags = dat.Tags.ToList();

            // Upload new notes
            foreach (var mvNote in notesUpload)
            {
                PrepareNoteForUpload(web, d, ref items_raw, mvNote, allTags, authToken, cfg, false);
            }

            // Delete deleted notes
            foreach (var rmNote in notesDelete)
            {
                PrepareNoteForUpload(web, d, ref items_raw, rmNote, allTags, authToken, cfg, true);
            }

            // Update references on tags (from changed notes)
            foreach (var upTag in GetTagsInNeedOfUpdate(dat.Tags, notesUpload, notesDelete))
            {
                PrepareTagForUpload(web, d, ref items_raw, upTag, authToken, false);
            }

            // Remove unused tags
            if (cfg.RemEmptyTags)
            {
                foreach (var rmTag in tagsDelete)
                {
                    PrepareTagForUpload(web, d, ref items_raw, rmTag, authToken, true);
                }
            }

            Logger.Debug(
                StandardNotePlugin.Name,
                $"Perform sync request ({items_raw.Count} items send)",
                "Sent Items (unencrypted):\n\n" + string.Join("\n", items_raw.Select(i => $"{{\n  content_type = {i.content_type}\n  uuid         = {i.uuid}\n  created_at   = {i.created_at}\n  deleted      = {i.deleted}\n  content      =\n{CompactJsonFormatter.FormatJSON(i.content, 2, 1)}\n}}")));

            var result = GetCursorResult(web, dat, d);

            var syncresult = new SyncResult();

            syncresult.retrieved_tags = result
                                        .retrieved_items
                                        .Where(p => p.content_type.ToLower() == "tag")
                                        .Where(p => !p.deleted)
                                        .Select(n => CreateTag(web, n, authToken))
                                        .ToList();

            syncresult.deleted_tags = result
                                      .retrieved_items
                                      .Where(p => p.content_type.ToLower() == "tag")
                                      .Where(p => p.deleted)
                                      .Select(n => CreateTag(web, n, authToken))
                                      .ToList();

            syncresult.saved_tags = result
                                    .saved_items
                                    .Where(p => p.content_type.ToLower() == "tag")
                                    .Select(n => CreateTag(web, n, authToken))
                                    .ToList();

            syncresult.unsaved_tags = result
                                      .unsaved
                                      .Where(p => p.item.content_type.ToLower() == "tag")
                                      .Select(n => CreateTag(web, n.item, authToken))
                                      .ToList();

            dat.UpdateTags(syncresult.retrieved_tags, syncresult.saved_tags, syncresult.unsaved_tags, syncresult.deleted_tags);

            syncresult.retrieved_notes = result
                                         .retrieved_items
                                         .Where(p => p.content_type.ToLower() == "note")
                                         .Where(p => !p.deleted)
                                         .Select(n => CreateNote(web, conn, n, authToken, cfg, dat))
                                         .ToList();

            syncresult.deleted_notes = result
                                       .retrieved_items
                                       .Where(p => p.content_type.ToLower() == "note")
                                       .Where(p => p.deleted)
                                       .Select(n => CreateNote(web, conn, n, authToken, cfg, dat))
                                       .ToList();

            syncresult.saved_notes = result
                                     .saved_items
                                     .Where(p => p.content_type.ToLower() == "note")
                                     .Select(n => CreateNote(web, conn, n, authToken, cfg, dat))
                                     .ToList();

            syncresult.conflict_notes = result
                                        .unsaved
                                        .Where(p => p.item.content_type.ToLower() == "note")
                                        .Where(p => p.error.tag == "sync_conflict")
                                        .Select(n => CreateNote(web, conn, n.item, authToken, cfg, dat))
                                        .ToList();

            syncresult.error_notes = result
                                     .unsaved
                                     .Where(p => p.item.content_type.ToLower() == "note")
                                     .Where(p => p.error.tag != "sync_conflict")
                                     .Select(n => CreateNote(web, conn, n.item, authToken, cfg, dat))
                                     .ToList();

            syncresult.retrieved_notes.AddRange(GetMissingNoteUpdates(syncresult.retrieved_tags.Concat(syncresult.saved_tags), dat.Tags, allNotes, syncresult.retrieved_notes));

            return(syncresult);
        }
Example #2
0
        private static APIResultAuthorize Authenticate001(ISimpleJsonRest web, APIAuthParams apiparams, string mail, string uip, AlephLogger logger)
        {
            try
            {
                logger.Debug(StandardNotePlugin.Name, $"AuthParams[version:1, pw_func:{apiparams.pw_func}, pw_alg:{apiparams.pw_alg}, pw_cost:{apiparams.pw_cost}, pw_key_size:{apiparams.pw_key_size}]");

                if (apiparams.pw_func != PasswordFunc.pbkdf2)
                {
                    throw new Exception("Unsupported pw_func: " + apiparams.pw_func);
                }

                byte[] bytes;

                if (apiparams.pw_alg == PasswordAlg.sha512)
                {
                    bytes = PBKDF2.GenerateDerivedKey(apiparams.pw_key_size / 8, Encoding.UTF8.GetBytes(uip), Encoding.UTF8.GetBytes(apiparams.pw_salt), apiparams.pw_cost, PBKDF2.HMACType.SHA512);
                }
                else if (apiparams.pw_alg == PasswordAlg.sha512)
                {
                    bytes = PBKDF2.GenerateDerivedKey(apiparams.pw_key_size / 8, Encoding.UTF8.GetBytes(uip), Encoding.UTF8.GetBytes(apiparams.pw_salt), apiparams.pw_cost, PBKDF2.HMACType.SHA512);
                }
                else
                {
                    throw new Exception("Unknown pw_alg: " + apiparams.pw_alg);
                }

                var pw = bytes.Take(bytes.Length / 2).ToArray();
                var mk = bytes.Skip(bytes.Length / 2).ToArray();

                var reqpw = EncodingConverter.ByteToHexBitFiddleUppercase(pw).ToLower();

                APIResultAuthorize tok;
                try
                {
                    tok = web.PostDownload <APIResultAuthorize>("auth/sign_in", "email=" + WebUtility.UrlEncode(mail), "password="******"Server returned status {e1.StatusCode}.\nMessage: '{req.error.message}'", e1);
                        }
                    }

                    throw;
                }

                tok.masterkey = mk;
                tok.version   = "001";
                return(tok);
            }
            catch (StandardNoteAPIException)
            {
                throw;
            }
            catch (RestException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new StandardNoteAPIException("Authentification with StandardNoteAPI failed.", e);
            }
        }
Example #3
0
        private static StandardFileNote CreateNote(ISimpleJsonRest web, StandardNoteConnection conn, APIResultItem encNote, APIResultAuthorize authToken, StandardNoteConfig cfg, StandardNoteData dat)
        {
            if (encNote.deleted)
            {
                var nd = new StandardFileNote(encNote.uuid, cfg, conn.HConfig)
                {
                    CreationDate   = encNote.created_at,
                    Text           = "",
                    InternalTitle  = "",
                    AuthHash       = encNote.auth_hash,
                    ContentVersion = StandardNoteCrypt.GetSchemaVersion(encNote.content),
                };
                nd.ModificationDate = encNote.updated_at;
                return(nd);
            }

            ContentNote content;

            try
            {
                var contentJson = StandardNoteCrypt.DecryptContent(encNote.content, encNote.enc_item_key, encNote.auth_hash, authToken.masterkey, authToken.masterauthkey);

                Logger.Debug(
                    StandardNotePlugin.Name,
                    $"DecryptContent of note {encNote.uuid:B}",
                    $"[content]:\r\n{encNote.content}\r\n" +
                    $"[enc_item_key]:\r\n{encNote.enc_item_key}\r\n" +
                    $"[auth_hash]:\r\n{encNote.auth_hash}\r\n" +
                    $"\r\n\r\n" +
                    $"[contentJson]:\r\n{contentJson}\r\n");

                content = web.ParseJsonWithoutConverter <ContentNote>(contentJson);
            }
            catch (RestException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new StandardNoteAPIException("Cannot decrypt note with local masterkey", e);
            }

            var n = new StandardFileNote(encNote.uuid, cfg, conn.HConfig)
            {
                Text           = content.text,
                InternalTitle  = content.title,
                AuthHash       = encNote.auth_hash,
                ContentVersion = StandardNoteCrypt.GetSchemaVersion(encNote.content),
                IsPinned       = GetAppDataBool(content.appData, "org.standardnotes.sn", "pinned", false),
            };

            var refTags = new List <StandardFileTag>();

            foreach (var cref in content.references)
            {
                if (cref.content_type == "Note")
                {
                    // ignore
                }
                else if (dat.Tags.Any(t => t.UUID == cref.uuid))
                {
                    refTags.Add(new StandardFileTag(cref.uuid, dat.Tags.First(t => t.UUID == cref.uuid).Title));
                }
                else if (cref.content_type == "Tag")
                {
                    Logger.Warn(StandardNotePlugin.Name, $"Reference to missing tag {cref.uuid} in note {encNote.uuid}");
                }
                else
                {
                    Logger.Error(StandardNotePlugin.Name, $"Downloaded note contains an unknown reference :{cref.uuid} ({cref.content_type}) in note {encNote.uuid}");
                }
            }

            n.SetTags(refTags);
            n.SetReferences(content.references);
            n.CreationDate     = encNote.created_at;
            n.ModificationDate = encNote.updated_at;

            return(n);
        }
Example #4
0
        public static SyncResult Sync(ISimpleJsonRest web, StandardNoteConnection conn, APIResultAuthorize authToken, StandardNoteConfig cfg, StandardNoteData dat, List <StandardFileNote> allNotes, List <StandardFileNote> notesUpload, List <StandardFileNote> notesDelete, List <StandardFileTag> tagsDelete)
        {
            APIBodySync d = new APIBodySync();

            d.cursor_token = null;
            d.sync_token   = string.IsNullOrWhiteSpace(dat.SyncToken) ? null : dat.SyncToken;
            d.limit        = 150;
            d.items        = new List <APIBodyItem>();

            var allTags = dat.Tags.ToList();

            // Upload new notes
            foreach (var mvNote in notesUpload)
            {
                PrepareForUpload(web, d, mvNote, allTags, authToken, cfg, false);
            }

            // Delete deleted notes
            foreach (var rmNote in notesDelete)
            {
                PrepareForUpload(web, d, rmNote, allTags, authToken, cfg, true);
            }

            // Update references on tags (from changed notes)
            foreach (var upTag in notesUpload.SelectMany(n => n.InternalTags).Concat(notesDelete.SelectMany(n => n.InternalTags)).Except(tagsDelete))
            {
                PrepareForUpload(web, d, upTag, allNotes, authToken, cfg, false);
            }

            // Remove unused tags
            if (cfg.RemEmptyTags)
            {
                foreach (var rmTag in tagsDelete)
                {
                    PrepareForUpload(web, d, rmTag, allNotes, authToken, cfg, true);
                }
            }

            var result = GetCursorResult(web, dat, d);

            var syncresult = new SyncResult();

            syncresult.retrieved_tags = result
                                        .retrieved_items
                                        .Where(p => p.content_type.ToLower() == "tag")
                                        .Where(p => !p.deleted)
                                        .Select(n => CreateTag(web, n, authToken))
                                        .ToList();

            syncresult.deleted_tags = result
                                      .retrieved_items
                                      .Where(p => p.content_type.ToLower() == "tag")
                                      .Where(p => p.deleted)
                                      .Select(n => CreateTag(web, n, authToken))
                                      .ToList();

            syncresult.saved_tags = result
                                    .saved_items
                                    .Where(p => p.content_type.ToLower() == "tag")
                                    .Select(n => CreateTag(web, n, authToken))
                                    .ToList();

            syncresult.unsaved_tags = result
                                      .unsaved
                                      .Where(p => p.item.content_type.ToLower() == "tag")
                                      .Select(n => CreateTag(web, n.item, authToken))
                                      .ToList();

            dat.UpdateTags(syncresult.retrieved_tags, syncresult.saved_tags, syncresult.unsaved_tags, syncresult.deleted_tags);

            syncresult.retrieved_notes = result
                                         .retrieved_items
                                         .Where(p => p.content_type.ToLower() == "note")
                                         .Where(p => !p.deleted)
                                         .Select(n => CreateNote(web, conn, n, authToken, cfg, dat))
                                         .ToList();

            syncresult.deleted_notes = result
                                       .retrieved_items
                                       .Where(p => p.content_type.ToLower() == "note")
                                       .Where(p => p.deleted)
                                       .Select(n => CreateNote(web, conn, n, authToken, cfg, dat))
                                       .ToList();

            syncresult.saved_notes = result
                                     .saved_items
                                     .Where(p => p.content_type.ToLower() == "note")
                                     .Select(n => CreateNote(web, conn, n, authToken, cfg, dat))
                                     .ToList();

            syncresult.conflict_notes = result
                                        .unsaved
                                        .Where(p => p.item.content_type.ToLower() == "note")
                                        .Where(p => p.error.tag == "sync_conflict")
                                        .Select(n => CreateNote(web, conn, n.item, authToken, cfg, dat))
                                        .ToList();

            syncresult.error_notes = result
                                     .unsaved
                                     .Where(p => p.item.content_type.ToLower() == "note")
                                     .Where(p => p.error.tag != "sync_conflict")
                                     .Select(n => CreateNote(web, conn, n.item, authToken, cfg, dat))
                                     .ToList();

            return(syncresult);
        }
Example #5
0
 public static void DeleteNote(ISimpleJsonRest web, NextcloudNote note)
 {
     web.DeleteEmpty("notes/" + note.RemoteID);
 }
Example #6
0
// ReSharper restore All
#pragma warning restore 0649

        public static List <NoteRef> ListNotes(ISimpleJsonRest web)
        {
            return(web.Get <List <NoteRef> >("notes", "exclude=title,category,content,favorite"));
        }