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); } }
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); } }
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)); }
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)); } }
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); } }
public void Release() { _logger.Debug("RepoLock", "Lock released", $"File := {_lockfile}"); _stream.Close(); File.Delete(_lockfile); }