Esempio n. 1
0
        /// <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()
        {
            SettingsModel settings = _settingsService.LoadSettingsOrDefault();
            SerializeableCloudStorageCredentials credentials = settings.Credentials;

            if (!settings.HasCloudStorageClient || !settings.HasTransferCode)
            {
                _feedbackService.ShowToast(_languageService["pushpull_error_need_sync_first"]);
                return;
            }

            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;
                    }
                }

                if (stopBecauseNewOAuthLoginIsRequired)
                {
                    _feedbackService.ShowToast(_languageService["sync_error_oauth_refresh"]);
                }
                else
                {
                    bool repositoryExists = await cloudStorageClient.ExistsFileAsync(Config.RepositoryFileName, credentials);

                    if (repositoryExists)
                    {
                        await StoryBoard.ContinueWith(PullPushStoryStepId.DownloadCloudRepository);
                    }
                    else
                    {
                        _feedbackService.ShowToast(_languageService["pushpull_error_need_sync_first"]);
                    }
                }
            }
            catch (Exception ex)
            {
                // Keep the current page open and show the error message
                ShowExceptionMessage(ex, _feedbackService, _languageService);
            }
        }
        /// <summary>
        /// Creates an <see cref="ICloudStorageClientFactory"/> mock from a given
        /// <paramref name="cloudStorageClient"/>.
        /// </summary>
        /// <param name="cloudStorageClient">Cloud storage client which should be returned.</param>
        /// <returns>Mock for a cloud storage client factory.</returns>
        public static ICloudStorageClientFactory CloudStorageClientFactory(ICloudStorageClient cloudStorageClient)
        {
            Mock <ICloudStorageClientFactory> result = new Mock <ICloudStorageClientFactory>();

            result.
            Setup(m => m.GetOrCreate(It.IsAny <string>())).
            Returns(cloudStorageClient);
            return(result.Object);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="EmailHandlerManager"/> class.
 /// </summary>
 /// <param name="configuration">An instance of <see cref="IConfiguration"/>.</param>
 /// <param name="mSGraphSetting">Graph settings  <see cref="MSGraphSetting"/>.</param>
 /// <param name="cloudStorageClient">An instance of <see cref="ICloudStorageClient"/>.</param>
 /// <param name="logger">An instance of <see cref="ILogger"/>.</param>
 /// <param name="emailManager">An instance of <see cref="IEmailManager"/>.</param>
 public EmailHandlerManager(
     IConfiguration configuration,
     IOptions <MSGraphSetting> mSGraphSetting,
     ICloudStorageClient cloudStorageClient,
     ILogger logger,
     IEmailManager emailManager)
 {
     this.configuration      = configuration;
     this.mSGraphSetting     = mSGraphSetting?.Value;
     this.cloudStorageClient = cloudStorageClient;
     this.logger             = logger;
     this.emailManager       = emailManager;
 }
        public override async Task Run()
        {
            try
            {
                if (!StoryBoard.TryLoadFromSession(SynchronizationStorySessionKey.CloudStorageCredentials, out SerializeableCloudStorageCredentials credentials))
                {
                    throw new ArgumentNullException(nameof(credentials));
                }
                if (!StoryBoard.TryLoadFromSession(SynchronizationStorySessionKey.OauthState, out string oauthState))
                {
                    throw new ArgumentNullException(nameof(oauthState));
                }
                if (!StoryBoard.TryLoadFromSession(SynchronizationStorySessionKey.OauthCodeVerifier, out string oauthCodeVerifier))
                {
                    throw new ArgumentNullException(nameof(oauthState));
                }
                if (!StoryBoard.TryLoadFromSession(SynchronizationStorySessionKey.OauthRedirectUrl, out string redirectUrl))
                {
                    throw new ArgumentNullException(nameof(redirectUrl));
                }

                StoryBoard.RemoveFromSession(SynchronizationStorySessionKey.OauthState);
                StoryBoard.RemoveFromSession(SynchronizationStorySessionKey.OauthCodeVerifier);
                StoryBoard.RemoveFromSession(SynchronizationStorySessionKey.OauthRedirectUrl);

                ICloudStorageClient cloudStorageClient = _cloudStorageClientFactory.GetOrCreate(credentials.CloudStorageId);
                if (cloudStorageClient is IOAuth2CloudStorageClient oauthStorageClient)
                {
                    CloudStorageToken token = await oauthStorageClient.FetchTokenAsync(redirectUrl, oauthState, oauthCodeVerifier);

                    if (token != null)
                    {
                        // User has granted access.
                        credentials.Token = token;
                        await StoryBoard.ContinueWith(SynchronizationStoryStepId.ExistsCloudRepository);
                    }
                    else
                    {
                        // User has rejected access.
                        _feedbackService.ShowToast(_languageService.LoadText("sync_reject"));
                        await StoryBoard.ContinueWith(SynchronizationStoryStepId.StopAndShowRepository);
                    }
                }
            }
            catch (Exception ex)
            {
                // Keep the current page open and show the error message
                ShowExceptionMessage(ex, _feedbackService, _languageService);
            }
        }
Esempio n. 7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="EmailHandlerManager"/> class.
 /// </summary>
 /// <param name="configuration">An instance of <see cref="IConfiguration"/>.</param>
 /// <param name="mSGraphSetting">Graph settings  <see cref="MSGraphSetting"/>.</param>
 /// <param name="cloudStorageClient">An instance of <see cref="ICloudStorageClient"/>.</param>
 /// <param name="logger">An instance of <see cref="ILogger"/>.</param>
 /// <param name="emailManager">An instance of <see cref="IEmailManager"/>.</param>
 public EmailHandlerManager(
     IConfiguration configuration,
     IOptions <MSGraphSetting> mSGraphSetting,
     ICloudStorageClient cloudStorageClient,
     ILogger logger,
     IEmailManager emailManager)
 {
     this.configuration      = configuration;
     this.mSGraphSetting     = mSGraphSetting?.Value;
     this.cloudStorageClient = cloudStorageClient;
     this.logger             = logger;
     this.emailManager       = emailManager;
     this.notificationQueue  = this.configuration?[$"{ConfigConstants.StorageAccountConfigSectionKey}:{ConfigConstants.StorageAccNotificationQueueName}"];
 }
        private async Task <bool> TryDeleteCloudNoteRepository()
        {
            var credentials = Model.Credentials;
            ICloudStorageClient cloudStorageClient = _cloudStorageClientFactory.GetOrCreate(credentials.CloudStorageId);

            try
            {
                await cloudStorageClient.DeleteFileAsync(Config.RepositoryFileName, credentials);

                return(true);
            }
            catch (Exception)
            {
                return(false);
            }
        }
        /// <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);
            }
        }
Esempio n. 10
0
        /// <inheritdoc/>
        public override async Task Run()
        {
            SerializeableCloudStorageCredentials credentials = _settingsService.LoadSettingsOrDefault().Credentials;
            ICloudStorageClient cloudStorageClient           = _cloudStorageClientFactory.GetOrCreate(credentials.CloudStorageId);

            try
            {
                // The repository can be cached for this story, download the repository only once.
                byte[] binaryCloudRepository = await cloudStorageClient.DownloadFileAsync(Config.RepositoryFileName, credentials);

                StoryBoard.StoreToSession(PullPushStorySessionKey.BinaryCloudRepository, binaryCloudRepository);
                await StoryBoard.ContinueWith(PullPushStoryStepId.DecryptCloudRepository);
            }
            catch (Exception ex)
            {
                // Keep the current page open and show the error message
                ShowExceptionMessage(ex, _feedbackService, _languageService);
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="EmailServiceManager"/> class.
        /// </summary>
        /// <param name="configuration">An instance of <see cref="IConfiguration"/>.</param>
        /// <param name="repositoryFactory">An instance of <see cref="IRepositoryFactory"/>.</param>
        /// <param name="cloudStorageClient">An instance of <see cref="ICloudStorageClient"/>.</param>
        /// <param name="logger">Instance of Logger.</param>
        /// <param name="notificationProviderFactory">An instance of <see cref="INotificationProviderFactory"/>.</param>
        /// <param name="emailManager">An instance of <see cref="IEmailManager"/>.</param>
        public EmailServiceManager(
            IConfiguration configuration,
            IRepositoryFactory repositoryFactory,
            ICloudStorageClient cloudStorageClient,
            ILogger logger,
            INotificationProviderFactory notificationProviderFactory,
            IEmailManager emailManager)
        {
            this.repositoryFactory           = repositoryFactory;
            this.configuration               = configuration;
            this.emailNotificationRepository = repositoryFactory.GetRepository(Enum.TryParse <StorageType>(this.configuration?[Constants.StorageType], out this.repo) ? this.repo : throw new Exception());
            this.cloudStorageClient          = cloudStorageClient;
            this.logger = logger;
            this.notificationProvider = notificationProviderFactory.GetNotificationProvider(Enum.TryParse <NotificationProviderType>(this.configuration?[Constants.NotificationProviderType], out this.provider) ? this.provider : throw new Exception());
            if (this.configuration?["MailSettings"] != null)
            {
                this.mailSettings = JsonConvert.DeserializeObject <List <MailSettings> >(this.configuration?["MailSettings"]);
            }

            this.emailManager = emailManager;
        }
Esempio n. 12
0
        /// <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);
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="MailTemplateRepository"/> class.
        /// </summary>
        /// <param name="logger">logger.</param>
        /// <param name="cloudStorageClient">cloud storage client for blob storage.</param>
        /// <param name="tableStorageClient">cloud storage client for table storage.</param>
        /// <param name="storageAccountSetting">primary key of storage account.</param>
        public MailTemplateRepository(
            ILogger logger,
            ICloudStorageClient cloudStorageClient,
            ITableStorageClient tableStorageClient,
            IOptions <StorageAccountSetting> storageAccountSetting)
        {
            this.logger             = logger ?? throw new ArgumentNullException(nameof(logger));
            this.cloudStorageClient = cloudStorageClient ?? throw new ArgumentNullException(nameof(cloudStorageClient));
            this.tableStorageClient = tableStorageClient ?? throw new ArgumentNullException(nameof(tableStorageClient));

            if (storageAccountSetting is null)
            {
                throw new ArgumentNullException(nameof(storageAccountSetting));
            }

            if (string.IsNullOrWhiteSpace(storageAccountSetting?.Value?.MailTemplateTableName))
            {
                this.logger.WriteException(new ArgumentException("MailTemplateTableName"));
                throw new ArgumentException("MailTemplateTableName");
            }

            this.cloudTable = this.tableStorageClient.GetCloudTable(storageAccountSetting.Value.MailTemplateTableName);
        }
        /// <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);
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="MailAttachmentRepository"/> class.
 /// </summary>
 /// <param name="logger">The Logger instance.</param>
 /// <param name="cloudStorageClient">The Cloud Storage Client instance.</param>
 /// <param name="encryptionService">The IEncryptionService instance.</param>
 public MailAttachmentRepository(ILogger logger, ICloudStorageClient cloudStorageClient, IEncryptionService encryptionService)
 {
     this.logger             = logger;
     this.cloudStorageClient = cloudStorageClient;
     this.encryptionService  = encryptionService;
 }
Esempio n. 16
0
 protected ICloudStorageClientTests(ICloudStorageClient client, string testFolder)
 {
     this._client    = client;
     this.TestFolder = testFolder;
 }
 protected ICloudStorageThumbnailProviderTests(ICloudStorageClient client, string testFolder)
     : base(client, testFolder)
 {
 }
        /// <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);
            }
        }
Esempio n. 19
0
        private static async Task Test(ICloudStorageClient client)
        {
            TokenManager tokenManager = new TokenManager(client.GetType().Name);

            client.SaveAccessTokenDelegate  = tokenManager.SaveAccessToken;
            client.SaveRefreshTokenDelegate = tokenManager.SaveRefreshToken;
            client.LoadAccessTokenDelegate  = tokenManager.LoadAccessToken;
            client.LoadRefreshTokenDelegate = tokenManager.LoadRefresToken;

            var result = await client.InitAsync();

            if (result.Status != Status.Success)
            {
                Console.WriteLine("Initial failed, status=" + result.Status + ", reason=" + result.Message);
            }

            CloudStorageAccountInfo accountInfo;

            if (result.Status == Status.NeedAuthenticate)
            {
                (result, accountInfo) = await client.LoginAsync();

                client.StopListen();
            }
            else
            {
                (result, accountInfo) = await client.GetAccountInfoAsync();
            }

            if (result.Status != Status.Success)
            {
                Console.WriteLine("Login failed, reason=" + result.Message);
                return;
            }

            Console.WriteLine("Login success, account=" + accountInfo.userEmail + ", username="******"Account space: {0:fs} / {1:fs}", accountInfo.usedSpace, accountInfo.totalSpace));

            string rootId = await client.GetRootFolderIdAsync();

            string folderId, folderName = "test";

            (result, folderId) = await client.CreateFolderAsync(rootId, folderName);

            if (result.Status != Status.Success)
            {
                Console.WriteLine("Create folder failed, reason=" + result.Message);
                return;
            }
            Console.WriteLine($"Created folder {folderName}, id={folderId}");

            string localFile = "test.txt";

            File.WriteAllText(localFile, "I am a test file.");
            CancellationTokenSource cts = new CancellationTokenSource();
            CloudStorageFile        cloudFile;

            (result, cloudFile) = await client.UploadFileToFolderByIdAsync(localFile, folderId, cts.Token);

            if (result.Status != Status.Success)
            {
                Console.WriteLine("Upload file failed, reason=" + result.Message);
                return;
            }
            Console.WriteLine($"Uploaded file {localFile}");
            File.Delete(localFile);

            result = await client.DownloadFileByIdAsync(cloudFile.Id, localFile, cts.Token);

            if (result.Status != Status.Success)
            {
                Console.WriteLine("Download file failed, reason=" + result.Message);
                return;
            }
            Console.WriteLine($"Downloaded file {localFile}");

            result = await client.DeleteFileByIdAsync(cloudFile.Id);

            if (result.Status != Status.Success)
            {
                Console.WriteLine("Delete file failed, reason=" + result.Message);
                return;
            }
            Console.WriteLine($"Deleted file '{cloudFile.Name}'");

            // test a larger file
            const string testPic = @"D:\Test Dir\CloudStorages\surprised pikachu.png";

            (result, cloudFile) = await client.UploadFileToFolderByIdAsync(testPic, folderId, cts.Token);

            if (result.Status != Status.Success)
            {
                Console.WriteLine("Upload large file failed, reason=" + result.Message);
                return;
            }
            Console.WriteLine($"Uploaded large file '{testPic}'");

            const string testPic2 = @"D:\Test Dir\CloudStorages\surprised pikachu 2.png";

            result = await client.DownloadFileByIdAsync(cloudFile.Id, testPic2, cts.Token);

            if (result.Status != Status.Success)
            {
                Console.WriteLine("Download large file failed, reason=" + result.Message);
                return;
            }
            Console.WriteLine($"Downloaded large file '{testPic2}'");

            result = await client.DeleteFileByIdAsync(cloudFile.Id);

            if (result.Status != Status.Success)
            {
                Console.WriteLine("Delete file failed, reason=" + result.Message);
                return;
            }
            Console.WriteLine($"Deleted file '{cloudFile.Name}'");
            File.Delete(testPic2);
        }