/// <inheritdoc/> public override async Task Run() { SerializeableCloudStorageCredentials credentials = StoryBoard.LoadFromSession <SerializeableCloudStorageCredentials>(SynchronizationStorySessionKey.CloudStorageCredentials.ToInt()); ICloudStorageClient cloudStorageClient = _cloudStorageClientFactory.GetOrCreate(credentials.CloudStorageId); try { bool stopBecauseNewOAuthLoginIsRequired = false; if ((cloudStorageClient is OAuth2CloudStorageClient oauthStorageClient) && credentials.Token.NeedsRefresh()) { try { // Get a new access token by using the refresh token credentials.Token = await oauthStorageClient.RefreshTokenAsync(credentials.Token); SaveCredentialsToSettings(credentials); } catch (RefreshTokenExpiredException) { // Refresh-token cannot be used to get new access-tokens anymore, a new // authorization by the user is required. stopBecauseNewOAuthLoginIsRequired = true; switch (StoryBoard.Mode) { case StoryBoardMode.GuiAndToasts: await StoryBoard.ContinueWith(SynchronizationStoryStepId.ShowCloudStorageAccount.ToInt()); break; case StoryBoardMode.ToastsOnly: _feedbackService.ShowToast(_languageService["sync_error_generic"]); break; } } } if (!stopBecauseNewOAuthLoginIsRequired) { bool repositoryExists = await cloudStorageClient.ExistsFileAsync(Config.RepositoryFileName, credentials); // If no error occured the credentials are ok and we can safe them SaveCredentialsToSettings(credentials); if (repositoryExists) { await StoryBoard.ContinueWith(SynchronizationStoryStepId.DownloadCloudRepository.ToInt()); } else { await StoryBoard.ContinueWith(SynchronizationStoryStepId.StoreLocalRepositoryToCloudAndQuit.ToInt()); } } } catch (Exception ex) { // Keep the current page open and show the error message ShowExceptionMessage(ex, _feedbackService, _languageService); } }
/// <inheritdoc/> public override Task Run() { if (StoryBoard.Mode.ShouldUseGui()) { SerializeableCloudStorageCredentials credentials = StoryBoard.LoadFromSession <SerializeableCloudStorageCredentials>(SynchronizationStorySessionKey.CloudStorageCredentials.ToInt()); ICloudStorageClient cloudStorageClient = _cloudStorageClientFactory.GetOrCreate(credentials.CloudStorageId); if (cloudStorageClient is IOAuth2CloudStorageClient oauthStorageClient) { // Show waiting page _navigationService.Navigate(ControllerNames.CloudStorageOauthWaiting); // Open OAuth2 login page in external browser string oauthState = CryptoUtils.GenerateRandomBase62String(16, _randomSource); string oauthCodeVerifier = CryptoUtils.GenerateRandomBase62String(64, _randomSource); StoryBoard.StoreToSession(SynchronizationStorySessionKey.OauthState.ToInt(), oauthState); StoryBoard.StoreToSession(SynchronizationStorySessionKey.OauthCodeVerifier.ToInt(), oauthCodeVerifier); string url = oauthStorageClient.BuildAuthorizationRequestUrl(oauthState, oauthCodeVerifier); _nativeBrowserService.OpenWebsiteInApp(url); } else { _navigationService.Navigate(ControllerNames.CloudStorageAccount); } } return(Task.CompletedTask); }
/// <inheritdoc/> public override async Task Run() { _repositoryStorageService.LoadRepositoryOrDefault(out NoteRepositoryModel localRepository); NoteRepositoryModel cloudRepository = StoryBoard.LoadFromSession <NoteRepositoryModel>(PullPushStorySessionKey.CloudRepository); if (localRepository.Id == cloudRepository.Id) { await StoryBoard.ContinueWith(PullPushStoryStepId.StoreMergedRepositoryAndQuit); } else { _feedbackService.ShowToast(_languageService["pushpull_error_need_sync_first"]); } }
/// <inheritdoc/> public override async Task Run() { _repositoryStorageService.LoadRepositoryOrDefault(out NoteRepositoryModel localRepository); NoteRepositoryModel cloudRepository = StoryBoard.LoadFromSession <NoteRepositoryModel>(SynchronizationStorySessionKey.CloudRepository); if (localRepository.Id == cloudRepository.Id) { await StoryBoard.ContinueWith(SynchronizationStoryStepId.StoreMergedRepositoryAndQuit); } else { await StoryBoard.ContinueWith(SynchronizationStoryStepId.ShowMergeChoice); } }
/// <inheritdoc/> public override async Task Run() { try { SettingsModel settings = _settingsService.LoadSettingsOrDefault(); byte[] binaryCloudRepository = StoryBoard.LoadFromSession <byte[]>(SynchronizationStorySessionKey.BinaryCloudRepository); // Try to decode with all possible transfer codes bool successfullyDecryptedRepository = TryDecryptWithAllTransferCodes( settings, binaryCloudRepository, out byte[] decryptedRepository); if (successfullyDecryptedRepository) { // Deserialize and update repository XDocument cloudRepositoryXml = XmlUtils.LoadFromXmlBytes(decryptedRepository); if (_noteRepositoryUpdater.IsTooNewForThisApp(cloudRepositoryXml)) { throw new SynchronizationStoryBoard.UnsuportedRepositoryRevisionException(); } _noteRepositoryUpdater.Update(cloudRepositoryXml); NoteRepositoryModel cloudRepository = XmlUtils.DeserializeFromXmlDocument <NoteRepositoryModel>(cloudRepositoryXml); // Continue with next step StoryBoard.StoreToSession(SynchronizationStorySessionKey.CloudRepository, cloudRepository); await StoryBoard.ContinueWith(SynchronizationStoryStepId.IsSameRepository); } else { bool existsUserEnteredTransferCode = StoryBoard.TryLoadFromSession <string>(SynchronizationStorySessionKey.UserEnteredTransferCode, out _); if (existsUserEnteredTransferCode) { // Keep transfercode page open and show message _feedbackService.ShowToast(_languageService["sync_error_transfercode"]); } else { // Open transfercode page await StoryBoard.ContinueWith(SynchronizationStoryStepId.ShowTransferCode); } } } catch (Exception ex) { // Keep the current page open and show the error message ShowExceptionMessage(ex, _feedbackService, _languageService); } }
/// <inheritdoc/> public override async Task Run() { try { NoteRepositoryModel cloudRepository = StoryBoard.LoadFromSession <NoteRepositoryModel>(SynchronizationStorySessionKey.CloudRepository); _repositoryStorageService.TrySaveRepository(cloudRepository); await StoryBoard.ContinueWith(SynchronizationStoryStepId.StopAndShowRepository); _feedbackService.ShowToast(_languageService["sync_success"]); } catch (Exception ex) { // Keep the current page open and show the error message ShowExceptionMessage(ex, _feedbackService, _languageService); } }
/// <inheritdoc/> public override async Task Run() { try { SerializeableCloudStorageCredentials credentials = StoryBoard.LoadFromSession <SerializeableCloudStorageCredentials>(SynchronizationStorySessionKey.CloudStorageCredentials); _repositoryStorageService.LoadRepositoryOrDefault(out NoteRepositoryModel localRepository); SettingsModel settings = _settingsService.LoadSettingsOrDefault(); string transferCode = settings.TransferCode; bool needsNewTransferCode = !TransferCode.IsCodeSet(transferCode); if (needsNewTransferCode) { transferCode = TransferCode.GenerateCode(_cryptoRandomService); } byte[] encryptedRepository = EncryptRepository( localRepository, transferCode, _cryptoRandomService, settings.SelectedEncryptionAlgorithm); ICloudStorageClient cloudStorageClient = _cloudStorageClientFactory.GetOrCreate(credentials.CloudStorageId); await cloudStorageClient.UploadFileAsync(Config.RepositoryFileName, encryptedRepository, credentials); // All went well, time to save the transfer code, if a new one was created if (needsNewTransferCode) { settings.TransferCode = transferCode; _settingsService.TrySaveSettingsToLocalDevice(settings); string formattedTransferCode = TransferCode.FormatTransferCodeForDisplay(transferCode).Replace(' ', '-'); string messageNewCreated = _languageService.LoadTextFmt("transfer_code_created", formattedTransferCode); string messageWriteDown = _languageService.LoadText("transfer_code_writedown"); if (StoryBoard.Mode.ShouldUseGui()) { await _feedbackService.ShowMessageAsync(messageNewCreated + Environment.NewLine + messageWriteDown, null, MessageBoxButtons.Ok, false); } } await StoryBoard.ContinueWith(SynchronizationStoryStepId.StopAndShowRepository); _feedbackService.ShowToast(_languageService["sync_success"]); } catch (Exception ex) { // Keep the current page open and show the error message ShowExceptionMessage(ex, _feedbackService, _languageService); } }
/// <inheritdoc/> public override async Task Run() { try { NoteRepositoryModel cloudRepository = StoryBoard.LoadFromSession <NoteRepositoryModel>(SynchronizationStorySessionKey.CloudRepository.ToInt()); SerializeableCloudStorageCredentials credentials = StoryBoard.LoadFromSession <SerializeableCloudStorageCredentials>(SynchronizationStorySessionKey.CloudStorageCredentials.ToInt()); _repositoryStorageService.LoadRepositoryOrDefault(out NoteRepositoryModel localRepository); SettingsModel settings = _settingsService.LoadSettingsOrDefault(); // Merge repositories NoteRepositoryMerger merger = new NoteRepositoryMerger(); NoteRepositoryModel mergedRepository = merger.Merge(localRepository, cloudRepository); // Store merged repository locally when different if (!RepositoriesAreEqual(mergedRepository, localRepository)) { _repositoryStorageService.TrySaveRepository(mergedRepository); } // Store merged repository to the cloud when different, otherwise spare the slow upload if (!RepositoriesAreEqual(mergedRepository, cloudRepository)) { byte[] encryptedRepository = EncryptRepository( mergedRepository, settings.TransferCode, _cryptoRandomService, settings.SelectedEncryptionAlgorithm); ICloudStorageClient cloudStorageClient = _cloudStorageClientFactory.GetOrCreate(credentials.CloudStorageId); await cloudStorageClient.UploadFileAsync(Config.RepositoryFileName, encryptedRepository, credentials); } await StoryBoard.ContinueWith(SynchronizationStoryStepId.StopAndShowRepository.ToInt()); _feedbackService.ShowToast(_languageService["sync_success"]); } catch (Exception ex) { // Keep the current page open and show the error message ShowExceptionMessage(ex, _feedbackService, _languageService); } }
/// <inheritdoc/> public override async Task Run() { SerializeableCloudStorageCredentials credentials = StoryBoard.LoadFromSession <SerializeableCloudStorageCredentials>(SynchronizationStorySessionKey.CloudStorageCredentials.ToInt()); ICloudStorageClient cloudStorageClient = _cloudStorageClientFactory.GetOrCreate(credentials.CloudStorageId); try { // The repository can be cached for this story, download the repository only once. byte[] binaryCloudRepository; if (!StoryBoard.TryLoadFromSession(SynchronizationStorySessionKey.BinaryCloudRepository.ToInt(), out binaryCloudRepository)) { binaryCloudRepository = await cloudStorageClient.DownloadFileAsync(Config.RepositoryFileName, credentials); StoryBoard.StoreToSession(SynchronizationStorySessionKey.BinaryCloudRepository.ToInt(), binaryCloudRepository); } await StoryBoard.ContinueWith(SynchronizationStoryStepId.ExistsTransferCode.ToInt()); } catch (Exception ex) { // Keep the current page open and show the error message ShowExceptionMessage(ex, _feedbackService, _languageService); } }
/// <inheritdoc/> public override async Task Run() { try { NoteRepositoryModel cloudRepository = StoryBoard.LoadFromSession <NoteRepositoryModel>(PullPushStorySessionKey.CloudRepository); _repositoryStorageService.LoadRepositoryOrDefault(out NoteRepositoryModel localRepository); SettingsModel settings = _settingsService.LoadSettingsOrDefault(); SerializeableCloudStorageCredentials credentials = settings.Credentials; NoteModel cloudNote = cloudRepository.Notes.FindById(_noteId); NoteModel localNote = localRepository.Notes.FindById(_noteId); if (localNote == null) { throw new Exception("PullPushStory is triggered on the note dialog, so the note must exist."); } if (cloudNote == null) { // Note does not yet exist in the cloud, or it was deleted permanently. Both // cases should be rejected. _feedbackService.ShowToast(_languageService["pushpull_error_no_cloud_note"]); return; } if (cloudNote.ModifiedAt == localNote.ModifiedAt) { // Notes are equal, nothing to sync _feedbackService.ShowToast(_languageService["pushpull_success"]); return; } // Merge repositories if (_direction == PullPushDirection.PullFromServer) { cloudNote.CloneTo(localNote); // this can possibly move the note to the recycling bin or reverse AddSafeToOtherRepositoryIfMissing(cloudRepository, localRepository, cloudNote.SafeId); _repositoryStorageService.TrySaveRepository(localRepository); } else { // Uploading explicitely can be seen as a confirmation that this version is the // most current one. So we make sure that the uploaded version is not overwritten // by other devices afterwards. localNote.RefreshModifiedAt(); _repositoryStorageService.TrySaveRepository(localRepository); localNote.CloneTo(cloudNote); // this can possibly move the note to the recycling bin or reverse AddSafeToOtherRepositoryIfMissing(localRepository, cloudRepository, localNote.SafeId); byte[] encryptedRepository = EncryptRepository( cloudRepository, settings.TransferCode, _cryptoRandomService, settings.SelectedEncryptionAlgorithm); ICloudStorageClient cloudStorageClient = _cloudStorageClientFactory.GetOrCreate(credentials.CloudStorageId); await cloudStorageClient.UploadFileAsync(Config.RepositoryFileName, encryptedRepository, credentials); } _feedbackService.ShowToast(_languageService["pushpull_success"]); } catch (Exception ex) { // Keep the current page open and show the error message ShowExceptionMessage(ex, _feedbackService, _languageService); } }
/// <inheritdoc/> public override async Task Run() { try { SettingsModel settings = _settingsService.LoadSettingsOrDefault(); byte[] binaryCloudRepository = StoryBoard.LoadFromSession <byte[]>(SynchronizationStorySessionKey.BinaryCloudRepository.ToInt()); List <string> transferCodesToTry = ListTransferCodesToTry(settings); // Try to decode with all possible transfer codes EncryptorDecryptor encryptor = new EncryptorDecryptor("SilentNotes"); byte[] decryptedRepository = null; bool successfullyDecryptedRepository = false; int index = 0; while (!successfullyDecryptedRepository && index < transferCodesToTry.Count) { string transferCodeCandidate = transferCodesToTry[index]; successfullyDecryptedRepository = TryDecryptRepositoryWithTransfercode(encryptor, binaryCloudRepository, transferCodeCandidate, out decryptedRepository); if (successfullyDecryptedRepository) { // Store transfercode and encryption mode if necessary if (AdoptTransferCode(settings, transferCodeCandidate) || AdoptEncryptionMode(settings, encryptor, binaryCloudRepository)) { _settingsService.TrySaveSettingsToLocalDevice(settings); } } index++; } if (successfullyDecryptedRepository) { // Deserialize and update repository XDocument cloudRepositoryXml = XmlUtils.LoadFromXmlBytes(decryptedRepository); if (_noteRepositoryUpdater.IsTooNewForThisApp(cloudRepositoryXml)) { throw new SynchronizationStoryBoard.UnsuportedRepositoryRevisionException(); } _noteRepositoryUpdater.Update(cloudRepositoryXml); NoteRepositoryModel cloudRepository = XmlUtils.DeserializeFromXmlDocument <NoteRepositoryModel>(cloudRepositoryXml); // Continue with next step StoryBoard.StoreToSession(SynchronizationStorySessionKey.CloudRepository.ToInt(), cloudRepository); await StoryBoard.ContinueWith(SynchronizationStoryStepId.IsSameRepository.ToInt()); } else { bool existsUserEnteredTransferCode = StoryBoard.TryLoadFromSession <string>(SynchronizationStorySessionKey.UserEnteredTransferCode.ToInt(), out _); if (existsUserEnteredTransferCode) { // Keep transfercode page open and show message _feedbackService.ShowToast(_languageService["sync_error_transfercode"]); } else { // Open transfercode page await StoryBoard.ContinueWith(SynchronizationStoryStepId.ShowTransferCode.ToInt()); } } } catch (Exception ex) { // Keep the current page open and show the error message ShowExceptionMessage(ex, _feedbackService, _languageService); } }