private void RefreshToken()
        {
            try
            {
                if (_token == null)
                {
                    using (var web = CreateJsonRestClient(_proxy, _config.Server))
                    {
                        _logger.Debug(StandardNotePlugin.Name, "Requesting token from StandardNoteServer");

                        _token = StandardNoteAPI.Authenticate(web, _config.Email, _config.Password, _logger);

                        _logger.Debug(StandardNotePlugin.Name, "StandardNoteServer returned token for user " + _token.user.uuid);
                    }
                }
            }
            catch (StandardNoteAPIException)
            {
                throw;
            }
            catch (RestException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new StandardNoteAPIException("Could not authenticate with StandardNoteServer : " + e.Message, e);
            }
        }
Exemple #2
0
        private void RefreshToken()
        {
            try
            {
                if (_token == null)
                {
                    using (var web = CreateJsonRestClient(_proxy, HOST_AUTH))
                    {
                        web.AddHeader("X-Simperium-API-Key", API_KEY);
                        web.SetEscapeAllNonASCIICharacters(true);

                        _logger.Debug(SimpleNotePlugin.Name, "Requesting token from Simplenote server");
                        _token = SimpleNoteAPI.Authenticate(web, _config.Username, _config.Password);
                        _logger.Debug(SimpleNotePlugin.Name, "Simplenote server returned token for user " + _token.userid);
                    }
                }
            }
            catch (RestException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new Exception("Could not authenticate with SimpleNote server : " + e.Message, e);
            }
        }
Exemple #3
0
        public override void StartSync(IRemoteStorageSyncPersistance data, List <INote> localnotes, List <INote> localdeletednotes)
        {
            _syncScan = FileSystemUtil
                        .EnumerateFilesDeep(_config.Folder, _config.SearchDepth)
                        .Where(p => (Path.GetExtension(p) ?? "").ToLower() == "." + _config.Extension.ToLower())
                        .ToList();

            _logger.Debug(FilesystemPlugin.Name, string.Format("Found {0} note files in directory scan", _syncScan.Count));
        }
Exemple #4
0
        public static RepoLock Lock(AlephLogger logger, string pathLocalFolder)
        {
            var filename = Path.Combine(pathLocalFolder, ".lock");

            var content =
                $"[[AlephNote::RepoLock::Lockfile]]\n" +
                $"{{\n" +
                $"    ProcessID     := {Process.GetCurrentProcess().Id}\n" +
                $"    ProcessHandle := {Process.GetCurrentProcess().Handle.ToInt64()}\n" +
                $"    StartTime     := {Process.GetCurrentProcess().StartTime:u}\n" +
                $"    FileName      := {Path.GetFileName(Process.GetCurrentProcess().MainModule?.FileName)}\n" +
                $"    FilePath      := {Process.GetCurrentProcess().MainModule?.FileName}\n" +
                $"    ModuleName    := {Process.GetCurrentProcess().MainModule?.ModuleName}\n" +
                $"    ProcessName   := {Process.GetCurrentProcess().ProcessName}\n" +
                $"}}\n";

            try
            {
                if (File.Exists(filename))
                {
                    try
                    {
                        var oldcontent = File.ReadAllText(filename);
                        logger.Warn("RepoLock", "Old Lockfile found", $"File := {filename}\n\nContent:\n{oldcontent}");
                    }
                    catch (Exception)
                    {
                        logger.Warn("RepoLock", "Old Lockfile found (but could not read)", $"File := {filename}");
                    }
                }

                logger.Debug("RepoLock", "Trying to acquire lock", $"File := {filename}\n\nContent:\n{content}");
                var fs    = File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
                var bytes = Encoding.UTF8.GetBytes(content);
                fs.SetLength(0);
                fs.Write(bytes, 0, bytes.Length);
                fs.Flush();
                logger.Debug("RepoLock", "Lock acquired successfully", $"File := {filename}\n\nContent:\n{content}");
                return(new RepoLock(logger, filename, fs));
            }
            catch (Exception e1)
            {
                logger.Error("RepoLock", "Acquiring lock failed", $"File := {filename}\n\nException:\n{e1}");

                try
                {
                    var oldcontent = File.ReadAllText(filename);
                    logger.Info("RepoLock", "Old lock file read", $"File := Content:\n{oldcontent}");
                }
                catch (Exception e2)
                {
                    logger.Error("RepoLock", "Cannot read existing lockfile", e2.ToString());
                }

                throw new RepoLockedException($"Could not open Repository '{pathLocalFolder}'.\nThe repository is currently locked by a different process.", e1);
            }
        }
        private static APIResultAuthorize Authenticate003(ISimpleJsonRest web, APIAuthParams apiparams, string mail, string uip, AlephLogger logger)
        {
            try
            {
                logger.Debug(StandardNotePlugin.Name, $"AutParams[version:{apiparams.version}, pw_cost:{apiparams.pw_cost}, pw_nonce:{apiparams.pw_nonce}]");

                if (apiparams.pw_cost < 100000)
                {
                    throw new StandardNoteAPIException($"Account pw_cost is too small ({apiparams.pw_cost})");
                }

                var    salt  = StandardNoteCrypt.SHA256(string.Join(":", mail, "SF", "003", apiparams.pw_cost.ToString(), apiparams.pw_nonce));
                byte[] bytes = PBKDF2.GenerateDerivedKey(768 / 8, Encoding.UTF8.GetBytes(uip), Encoding.UTF8.GetBytes(salt), apiparams.pw_cost, PBKDF2.HMACType.SHA512);

                var pw = bytes.Skip(0 * (bytes.Length / 3)).Take(bytes.Length / 3).ToArray();
                var mk = bytes.Skip(1 * (bytes.Length / 3)).Take(bytes.Length / 3).ToArray();
                var ak = bytes.Skip(2 * (bytes.Length / 3)).Take(bytes.Length / 3).ToArray();

                var reqpw = EncodingConverter.ByteToHexBitFiddleUppercase(pw).ToLower();
                APIResultAuthorize tok;
                try
                {
                    tok = web.PostTwoWay <APIResultAuthorize>(new APIRequestUser {
                        email = mail, password = reqpw
                    }, "auth/sign_in");
                }
                catch (RestStatuscodeException e1)
                {
                    if (e1.StatusCode / 100 == 4 && !string.IsNullOrWhiteSpace(e1.HTTPContent))
                    {
                        var req = web.ParseJsonOrNull <APIBadRequest>(e1.HTTPContent);
                        if (req != null)
                        {
                            throw new StandardNoteAPIException($"Server returned status {e1.StatusCode}.\nMessage: '{req.error.message}'", e1);
                        }
                    }

                    throw;
                }

                tok.masterkey     = mk;
                tok.masterauthkey = ak;
                tok.version       = "003";
                return(tok);
            }
            catch (RestException)
            {
                throw;
            }
            catch (StandardNoteAPIException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new StandardNoteAPIException("Authentification with StandardNoteAPI failed.", e);
            }
        }
        public override void StartSync(IRemoteStorageSyncPersistance data, List <INote> localnotes, List <INote> localdeletednotes)
        {
            _data = (NextcloudData)data;

            using (var web = CreateAuthenticatedClient())
            {
                remoteNotes = NextcloudAPI.ListNotes(web);

                _logger.Debug(NextcloudPlugin.Name, string.Format("NextcloudAPI.ListNotes returned {0} elements", remoteNotes.Count));
            }
        }
Exemple #7
0
        public override void StartSync(IRemoteStorageSyncPersistance data, List <INote> localnotes, List <INote> localdeletednotes)
        {
            _data = (EvernoteData)data;

            RefreshToken();

            TTransport noteStoreTransport = new THttpClient(new Uri(@"https://sandbox.evernote.com/shard/s1/notestore"));            //TODO use url from OAuth
            TProtocol  noteStoreProtocol  = new TBinaryProtocol(noteStoreTransport);

            nsClient = new NoteStore.Client(noteStoreProtocol);

            var state = nsClient.getSyncState(_token);

            if (_data.SyncStateUpdateCount != state.UpdateCount)
            {
                _logger.Debug(EvernotePlugin.Name, string.Format("Remote has changed SyncState: {0} -> '{1}'", _data.SyncStateUpdateCount, state.UpdateCount));

                NoteFilter filter = new NoteFilter();
                filter.Order = (int)NoteSortOrder.UPDATED;

                NotesMetadataResultSpec spec = new NotesMetadataResultSpec();
                spec.IncludeUpdateSequenceNum = true;

                bucket = nsClient.findNotesMetadata(_token, filter, 0, 9999, spec);

                _data.SyncStateUpdateCount = state.UpdateCount;
            }
            else
            {
                _logger.Debug(EvernotePlugin.Name, "Remote has not changed - no need for download - SyncState := " + state.UpdateCount);

                bucket = null;
            }

            remoteDirty = false;
        }
        public static void DeleteDirectoryWithRetry(AlephLogger logger, string path)
        {
            for (int i = 0; i < 5; i++)
            {
                try
                {
                    Directory.Delete(path);
                    return;
                }
                catch (IOException e)
                {
                    logger.Debug("DeleteDirectoryWithRetry", "Retry Directory delete", "Retry directory delete, exception thrown:\r\n" + e);
                    Thread.Sleep(5);
                }
            }

            Directory.Delete(path);             // Do it again and throw Exception if it fails
        }
        public static void DeleteFolderIfEmpty(string logsrc, AlephLogger log, string baseFolder, string folder)
        {
            var p1 = Path.GetFullPath(baseFolder).TrimEnd(Path.DirectorySeparatorChar).ToLower();
            var p2 = Path.GetFullPath(folder).TrimEnd(Path.DirectorySeparatorChar).ToLower();

            if (p1 == p2)
            {
                return;
            }
            if (p1.Count(c => c == Path.DirectorySeparatorChar) >= p2.Count(c => c == Path.DirectorySeparatorChar))
            {
                return;
            }

            if (Directory.EnumerateFileSystemEntries(folder).Any())
            {
                return;
            }

            log.Debug(logsrc, $"Cleanup empty folder '{p2}' (base = '{p1}')");
            Directory.Delete(folder);
        }
        private void RefreshToken(StandardNoteData dat)
        {
            try
            {
                if (dat.SessionData == null || dat.SessionData.AccessExpiration <= DateTime.Now)
                {
                    dat.SessionData = null;
                }

                if (dat.SessionData != null)
                {
                    if (dat.SessionData.AccessExpiration != null)
                    {
                        _logger.Debug(StandardNotePlugin.Name, $"Reusing existing token (until {dat.SessionData.AccessExpiration:yyyy-MM-dd HH:mm})", dat.SessionData.Token);
                    }
                    else
                    {
                        _logger.Debug(StandardNotePlugin.Name, $"Reusing existing token (no expiration)", dat.SessionData.Token);
                    }

                    return;
                }

                using (var web = CreateJsonRestClient(_proxy, _config.Server))
                {
                    _logger.Debug(StandardNotePlugin.Name, "Requesting token from StandardNoteServer");

                    dat.SessionData = StandardNoteAPI.Authenticate(web, _config.Email, _config.Password, _logger);

                    _logger.Debug(StandardNotePlugin.Name, $"StandardNoteServer returned token \"{dat.SessionData.Token}\" (until {dat.SessionData.AccessExpiration:yyyy-MM-dd HH:mm:ss})");
                }
            }
            catch (StandardNoteAPIException)
            {
                throw;
            }
            catch (RestException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new StandardNoteAPIException("Could not authenticate with StandardNoteServer : " + e.Message, e);
            }
        }
        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);
        }
        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=" + 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);
            }
        }
Exemple #13
0
 public void Release()
 {
     _logger.Debug("RepoLock", "Lock released", $"File := {_lockfile}");
     _stream.Close();
     File.Delete(_lockfile);
 }