public async Task TestCallMoveDriveItemAsync()
        {
            OneDriveApi oneDriveApi = new OneDriveApi(graphClient);
            bool        result      = await oneDriveApi.CallMoveDriveItemAsync();

            Assert.IsTrue(result);
        }
        public async Task TestCallCreateFolderAsync()
        {
            OneDriveApi oneDriveApi = new OneDriveApi(graphClient);
            bool        result      = await oneDriveApi.CallCreateFolderAsync();

            Assert.IsTrue(result);
        }
        public OneDriveGraphDeviceLoginForm(OneDriveApi oneDriveApi)
        {
            InitializeComponent();

            // Cast the OneDrive instance to a Graph API instance so it can be used in this form
            OneDriveApi = (OneDriveGraphApi)oneDriveApi;

            // When the form is being closed, ensure the Timer processes are being stopped to avoid exceptions
            FormClosing += OneDriveGraphDeviceLoginForm_FormClosing;

            // Set the defaults of the components on the form
            StatusLabel.Text                    = "Communicating with the Microsoft Graph API...";
            DeviceAuthLinkLabel.Visible         = false;
            DeviceIdTextBox.Visible             = false;
            OpenBrowserButton.Enabled           = false;
            CopyDeviceIdButton.Enabled          = false;
            AuthenticationCheckTimer.Enabled    = false;
            AuthenticationCompleteTimer.Enabled = false;

            // Set the Microsoft logo on the form
            MicrosoftLogoPictureBox.BackgroundImage = Resources.MicrosoftLogo;

            // Set up a HttpClient obeying the possible proxy settings to communicate with the Microsoft Graph API
            _httpClient = CreateHttpClient();

            // Enable a timer to initiate the communication with Microsoft Graph so the UI thread doesn't block
            StartSessionTimer.Enabled = true;
        }
Esempio n. 4
0
        /// <summary>
        /// Applies the correct web proxy settings to the provided OneDriveApi instance based on KeePass proxy configuration
        /// </summary>
        /// <param name="oneDriveApi">OneDriveApi instance to apply the proper proxy settings to</param>
        public static void ApplyProxySettings(OneDriveApi oneDriveApi)
        {
            // Set the WebProxy to use
            oneDriveApi.ProxyConfiguration = GetProxySettings();

            // Configure the credentials to use for the proxy
            oneDriveApi.ProxyCredential = GetProxyCredentials();
        }
        public OneDriveAuthenticateForm(string oneDriveClientId, string oneDriveClientSecret)
        {
            InitializeComponent();

            OneDriveApi = new OneDriveApi(oneDriveClientId, oneDriveClientSecret);

            SignOut();
        }
        public OneDriveAuthenticateForm(string oneDriveClientId, string oneDriveClientSecret)
        {
            InitializeComponent();

            OneDriveApi = new OneDriveApi(oneDriveClientId, oneDriveClientSecret);

            SignOut();
        }
Esempio n. 7
0
        public OneDriveAuthenticateForm(string oneDriveClientId, string oneDriveClientSecret)
        {
            InitializeComponent();

            OneDriveApi = new OneDriveApi(oneDriveClientId, oneDriveClientSecret);
            Utilities.ApplyProxySettings(OneDriveApi);

            SignOut();
        }
        public OneDriveAuthenticateForm(string oneDriveClientId, string oneDriveClientSecret)
        {
            InitializeComponent();

            OneDriveApi = new OneDriveApi(oneDriveClientId, oneDriveClientSecret);
            Utilities.ApplyProxySettings(OneDriveApi);

            SignOut();
        }
        public OneDriveAuthenticateForm(OneDriveApi oneDriveApi)
        {
            InitializeComponent();

            OneDriveApi = oneDriveApi;
            Utilities.ApplyProxySettings(OneDriveApi);

            SignOut();
        }
Esempio n. 10
0
        public OneDriveAuthenticateForm(OneDriveApi oneDriveApi)
        {
            InitializeComponent();

            OneDriveApi = oneDriveApi;
            Utilities.ApplyProxySettings(OneDriveApi);

            SignOut();
        }
Esempio n. 11
0
        private void Step1Button_Click(object sender, EventArgs e)
        {
            // Create a new instance of the OneDriveApi framework
            OneDriveApi = new OneDriveApi(ClientId, ClientSecret);

            // First sign the current user out to make sure he/she needs to authenticate again
            var signoutUri = OneDriveApi.GetSignOutUri();

            AuthenticationBrowser.Navigate(signoutUri);
        }
Esempio n. 12
0
 public PluginForm(string name, string description, string fileName, string content)
 {
     InitializeComponent();
     Text = name;
     labelDescription.Text = description;
     labelInfo.Text        = "Connecting to OneDrive...";
     _api                  = new OneDriveApi("files.readwrite", ClientId, ClientWebsite);
     _fileName             = fileName;
     _content              = content;
     comboBoxFileName.Text = Path.GetFileName(_fileName);
 }
Esempio n. 13
0
        public OneDriveFilePickerDialog(OneDriveApi oneDriveApi)
        {
            InitializeComponent();

            _oneDriveApi = oneDriveApi;

            var sharedWithMeDisabled = (oneDriveApi is OneDriveForBusinessO365Api);

            SharedWithMePicker.Visible            = !sharedWithMeDisabled;
            SharedWithMeUpButton.Visible          = !sharedWithMeDisabled;
            SharedWithMeNotAvailableLabel.Visible = sharedWithMeDisabled;
        }
Esempio n. 14
0
        private void Form1_Load(object sender, EventArgs e)
        {
            OneDriveTypeCombo.SelectedIndex = OneDriveTypeCombo.Items.Count - 1;
            var teste = GetAuthCode();

            AccessTokenTextBox.Text = teste.Result;
            InitiateOneDriveApi();

            // First sign the current user out to make sure he/she needs to authenticate again
            var signoutUri = OneDriveApi.GetSignOutUri();

            AuthenticationBrowser.Navigate(signoutUri);
        }
Esempio n. 15
0
        private async void RefreshTokenButton_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(RefreshTokenTextBox.Text))
            {
                MessageBox.Show("You need to enter a refresh token first in the refresh token field in order to be able to retrieve a new access token based on a refresh token.", "OneDrive API", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            // Get a new access token based on the refresh token entered in the textbox
            OneDriveApi = await OneDriveApi.GetOneDriveApiFromRefreshToken(ClientId, ClientSecret, RefreshTokenTextBox.Text);

            if (OneDriveApi.AccessToken != null)
            {
                // Display the information of the new access token in the textboxes
                AccessTokenTextBox.Text      = OneDriveApi.AccessToken.AccessToken;
                RefreshTokenTextBox.Text     = OneDriveApi.AccessToken.RefreshToken;
                AccessTokenValidTextBox.Text = OneDriveApi.AccessTokenValidUntil.HasValue ? OneDriveApi.AccessTokenValidUntil.Value.ToString("dd-MM-yyyy HH:mm:ss") : "Not valid";
            }
        }
Esempio n. 16
0
        /// <summary>
        /// Returns an active OneDriveApi instance. If a RefreshToken is available, it will set up an instance based on that, otherwise it will show the login dialog
        /// </summary>
        /// <param name="databaseConfig">Configuration of the KeePass database</param>
        /// <param name="oneDriveClientId">ClientID to get access to OneDrive</param>
        /// <param name="oneDriveClientSecret">ClientSecret to get access to OneDrive</param>
        /// <returns>Active OneDrive instance or NULL if unable to get an authenticated instance</returns>
        public static async Task <OneDriveApi> GetOneDriveApi(Configuration databaseConfig, string oneDriveClientId, string oneDriveClientSecret)
        {
            if (string.IsNullOrEmpty(databaseConfig.RefreshToken))
            {
                var oneDriveAuthenticateForm = new OneDriveAuthenticateForm(oneDriveClientId, oneDriveClientSecret);
                var result = oneDriveAuthenticateForm.ShowDialog();

                if (result != System.Windows.Forms.DialogResult.OK)
                {
                    return(null);
                }

                // Check if we already know where to store the Refresh Token for this database
                if (!databaseConfig.RefreshTokenStorage.HasValue)
                {
                    // We don't know yet where the Refresh Token for this database should be stored, ask the user to choose
                    var oneDriveRefreshTokenStorageForm = new OneDriveRefreshTokenStorageDialog(databaseConfig);
                    oneDriveRefreshTokenStorageForm.ShowDialog();
                }

                // Save the configuration so we keep the Refresh Token
                var oneDriveApi = oneDriveAuthenticateForm.OneDriveApi;
                databaseConfig.RefreshToken = oneDriveApi.AccessToken.RefreshToken;

                Configuration.Save();

                return(oneDriveApi);
            }

            try
            {
                var oneDriveApi = new OneDriveApi(oneDriveClientId, oneDriveClientSecret);
                ApplyProxySettings(oneDriveApi);
                await oneDriveApi.AuthenticateUsingRefreshToken(databaseConfig.RefreshToken);

                return(oneDriveApi);
            }
            catch (WebException)
            {
                // Occurs if no connection can be made with the OneDrive service. It will be handled properly in the calling code.
                return(null);
            }
        }
Esempio n. 17
0
        /// <summary>
        /// Returns an active OneDriveApi instance. If a RefreshToken is available, it will set up an instance based on that, otherwise it will show the login dialog
        /// </summary>
        /// <param name="databaseConfig">Configuration of the KeePass database</param>
        /// <param name="oneDriveClientId">ClientID to get access to OneDrive</param>
        /// <param name="oneDriveClientSecret">ClientSecret to get access to OneDrive</param>
        /// <returns>Active OneDrive instance or NULL if unable to get an authenticated instance</returns>
        public static async Task<OneDriveApi> GetOneDriveApi(Configuration databaseConfig, string oneDriveClientId, string oneDriveClientSecret)
        {
            if (string.IsNullOrEmpty(databaseConfig.RefreshToken))
            {
                var oneDriveAuthenticateForm = new OneDriveAuthenticateForm(oneDriveClientId, oneDriveClientSecret);
                var result = oneDriveAuthenticateForm.ShowDialog();

                if (result != System.Windows.Forms.DialogResult.OK)
                {
                    return null;
                }

                // Check if we already know where to store the Refresh Token for this database
                if (!databaseConfig.RefreshTokenStorage.HasValue)
                {
                    // We don't know yet where the Refresh Token for this database should be stored, ask the user to choose
                    var oneDriveRefreshTokenStorageForm = new OneDriveRefreshTokenStorageDialog(databaseConfig);
                    oneDriveRefreshTokenStorageForm.ShowDialog();
                }

                // Save the configuration so we keep the Refresh Token
                var oneDriveApi = oneDriveAuthenticateForm.OneDriveApi;
                databaseConfig.RefreshToken = oneDriveApi.AccessToken.RefreshToken;

                Configuration.Save();

                return oneDriveApi;
            }

            try
            {
                var oneDriveApi = new OneDriveApi(oneDriveClientId, oneDriveClientSecret);
                ApplyProxySettings(oneDriveApi);
                await oneDriveApi.AuthenticateUsingRefreshToken(databaseConfig.RefreshToken);
                return oneDriveApi;
            }
            catch (WebException)
            {
                // Occurs if no connection can be made with the OneDrive service. It will be handled properly in the calling code.
                return null;
            }
        }
Esempio n. 18
0
        /// <summary>
        /// Applies the correct web proxy settings to the provided OneDriveApi instance based on KeePass proxy configuration
        /// </summary>
        /// <param name="oneDriveApi">OneDriveApi instance to apply the proper proxy settings to</param>
        public static void ApplyProxySettings(OneDriveApi oneDriveApi)
        {
            // Configure thr proxy to use
            switch (KeePass.Program.Config.Integration.ProxyType)
            {
            case ProxyServerType.None:
                oneDriveApi.ProxyConfiguration = null;
                return;

            case ProxyServerType.Manual:
                oneDriveApi.ProxyConfiguration = new WebProxy(string.Concat(KeePass.Program.Config.Integration.ProxyAddress, ":", KeePass.Program.Config.Integration.ProxyPort));
                break;

            case ProxyServerType.System:
                oneDriveApi.ProxyConfiguration = WebRequest.DefaultWebProxy;
                break;
            }

            // Configure the credentials to use for the proxy
            oneDriveApi.ProxyCredential = KeePass.Program.Config.Integration.ProxyAuthType == ProxyAuthType.Manual ? new NetworkCredential(KeePass.Program.Config.Integration.ProxyUserName, KeePass.Program.Config.Integration.ProxyPassword) : null;
        }
Esempio n. 19
0
        /// <summary>
        /// Applies the correct web proxy settings to the provided OneDriveApi instance based on KeePass proxy configuration
        /// </summary>
        /// <param name="oneDriveApi">OneDriveApi instance to apply the proper proxy settings to</param>
        public static void ApplyProxySettings(OneDriveApi oneDriveApi)
        {
            switch (KeePass.Program.Config.Integration.ProxyType)
            {
            case ProxyServerType.None:
                oneDriveApi.UseProxy = false;
                return;

            case ProxyServerType.Manual:
                oneDriveApi.UseProxy           = true;
                oneDriveApi.ProxyConfiguration = new WebProxy(string.Concat(KeePass.Program.Config.Integration.ProxyAddress, ":", KeePass.Program.Config.Integration.ProxyPort));
                oneDriveApi.ProxyConfiguration.UseDefaultCredentials = KeePass.Program.Config.Integration.ProxyAuthType == ProxyAuthType.Auto || KeePass.Program.Config.Integration.ProxyAuthType == ProxyAuthType.Default;

                if (KeePass.Program.Config.Integration.ProxyAuthType == ProxyAuthType.Manual)
                {
                    oneDriveApi.ProxyConfiguration.Credentials = new NetworkCredential(KeePass.Program.Config.Integration.ProxyUserName, KeePass.Program.Config.Integration.ProxyPassword);
                }
                break;

            case ProxyServerType.System:
                oneDriveApi.UseProxy = true;
                break;
            }
        }
Esempio n. 20
0
        /// <summary>
        /// Creates a new instance of the OneDrive API
        /// </summary>
        private void InitiateOneDriveApi()
        {
            // Define the type of OneDrive API to instantiate based on the dropdown list selection
            switch (OneDriveTypeCombo.SelectedIndex)
            {
            case 0:
                OneDriveApi = new OneDriveConsumerApi(_configuration.AppSettings.Settings["OneDriveConsumerApiClientID"].Value, _configuration.AppSettings.Settings["OneDriveConsumerApiClientSecret"].Value);
                if (!string.IsNullOrEmpty(_configuration.AppSettings.Settings["OneDriveConsumerApiRedirectUri"].Value))
                {
                    OneDriveApi.AuthenticationRedirectUrl = _configuration.AppSettings.Settings["OneDriveConsumerApiRedirectUri"].Value;
                }
                break;

            case 1:
                OneDriveApi = new OneDriveForBusinessO365Api(_configuration.AppSettings.Settings["OneDriveForBusinessO365ApiClientID"].Value, _configuration.AppSettings.Settings["OneDriveForBusinessO365ApiClientSecret"].Value);
                break;

            case 2:
                OneDriveApi = new OneDriveGraphApi(_configuration.AppSettings.Settings["GraphApiApplicationId"].Value);
                break;
            }

            OneDriveApi.ProxyConfiguration = UseProxyCheckBox.Checked ? System.Net.WebRequest.DefaultWebProxy : null;
        }
Esempio n. 21
0
        private async void AuthenticationBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            // Get the currently displayed URL and show it in the textbox
            CurrentUrlTextBox.Text = e.Url.ToString();
            // WebRequest request = WebRequest.Create("https://login.live.com/oauth20_authorize.srf?pretty=false&client_id=233d9409-2bc0-404a-8f1e-c122a81615dc&scope=wl.basic+wl.signin+wl.skydrive&response_type=code&redirect_uri=https:%2f%2flogin.microsoftonline.com%2fcommon%2foauth2%2fnativeclient");
            // WebResponse response = request.GetResponse();
            // Check if the current URL contains the authorization token
            AuthorizationCodeTextBox.Text = OneDriveApi.GetAuthorizationTokenFromUrl(e.Url.ToString());

            // Verify if an authorization token was successfully extracted
            if (!string.IsNullOrEmpty(AuthorizationCodeTextBox.Text))
            {
                // Get an access token based on the authorization token that we now have
                await OneDriveApi.GetAccessToken();

                if (OneDriveApi.AccessToken != null)
                {
                    // Show the access token information in the textboxes
                    AccessTokenTextBox.Text      = OneDriveApi.AccessToken.AccessToken;
                    RefreshTokenTextBox.Text     = OneDriveApi.AccessToken.RefreshToken;
                    AccessTokenValidTextBox.Text = OneDriveApi.AccessTokenValidUntil.HasValue ? OneDriveApi.AccessTokenValidUntil.Value.ToString("dd-MM-yyyy HH:mm:ss") : "Not valid";

                    // Store the refresh token in the AppSettings so next time you don't have to log in anymore
                    _configuration.AppSettings.Settings["OneDriveApiRefreshToken"].Value = RefreshTokenTextBox.Text;
                    _configuration.Save(ConfigurationSaveMode.Modified);
                    return;
                }
            }

            // If we're on this page, but we didn't get an authorization token, it means that we just signed out, proceed with signing in again
            if (CurrentUrlTextBox.Text.StartsWith(OneDriveApi.SignoutUri))
            {
                var authenticateUri = OneDriveApi.GetAuthenticationUri();
                AuthenticationBrowser.Navigate(authenticateUri);
            }
        }
Esempio n. 22
0
        /// <summary>
        /// Uses a Microsoft OneDrive Cloud Storage Provider (OneDrive Consumer, OneDrive for Business, Microsoft Graph) to sync the KeePass database
        /// </summary>
        /// <param name="databaseConfig">Configuration of the database to sync</param>
        /// <param name="localKeePassDatabasePath">Path to where the KeePass database to sync resides</param>
        /// <param name="forceSync">Flag to indicate if the sync should always take place</param>
        /// <param name="updateStatus">Action to write status messages to to display in the UI</param>
        /// <returns>True if successful, false if failed</returns>
        public static async Task <bool> SyncUsingOneDriveCloudProvider(Configuration databaseConfig, string localKeePassDatabasePath, bool forceSync, Action <string> updateStatus)
        {
            // Connect to OneDrive
            OneDriveApi oneDriveApi = null;
            bool        retryGettingApiInstance;

            do
            {
                retryGettingApiInstance = false;
                try
                {
                    oneDriveApi = await Utilities.GetOneDriveApi(databaseConfig);
                }
                catch (KoenZomers.OneDrive.Api.Exceptions.TokenRetrievalFailedException e)
                {
                    // Failed to get a OneDrive API instance because retrieving an oAuth token failed. This could be because the oAuth token expired or has been removed. Show the login dialog again so we can get a new token.
                    databaseConfig.RefreshToken = null;
                    retryGettingApiInstance     = true;
                }
                catch (Exception e)
                {
                    // Build the error text to show to the end user
                    var errorMessage = new System.Text.StringBuilder();
                    errorMessage.Append("Failed to connect to ");
                    switch (databaseConfig.CloudStorageType.GetValueOrDefault(CloudStorageType.OneDriveConsumer))
                    {
                    case CloudStorageType.OneDriveConsumer:
                        errorMessage.Append("OneDrive");
                        break;

                    case CloudStorageType.OneDriveForBusiness:
                        errorMessage.Append("OneDrive for Business");
                        break;

                    case CloudStorageType.MicrosoftGraph:
                        errorMessage.Append("Microsoft Graph");
                        break;

                    default:
                        errorMessage.Append("cloud storage provider");
                        break;
                    }
                    errorMessage.AppendLine(":");
                    errorMessage.AppendLine();
                    errorMessage.AppendLine(e.Message);

                    // If there's an inner exception, show its message as well as it typically gives more detail why it went wrong
                    if (e.InnerException != null)
                    {
                        errorMessage.AppendLine(e.InnerException.Message);

                        // Verify if we're offline
                        if (e.InnerException.Message.Contains("remote name could not be resolved"))
                        {
                            // Offline, don't display a modal dialog but use the status bar instead
                            KeePassDatabase.UpdateStatus("Can't connect. Working offline.");
                            return(false);
                        }
                    }

                    MessageBox.Show(errorMessage.ToString(), "Connection failed", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                }
            } while (retryGettingApiInstance);

            if (oneDriveApi == null)
            {
                switch (databaseConfig.CloudStorageType.GetValueOrDefault(CloudStorageType.OneDriveConsumer))
                {
                case CloudStorageType.OneDriveConsumer: updateStatus("Failed to connect to OneDrive"); break;

                case CloudStorageType.OneDriveForBusiness: updateStatus("Failed to connect to OneDrive for Business"); break;

                case CloudStorageType.MicrosoftGraph: updateStatus("Failed to connect to Microsoft Graph"); break;

                default: updateStatus("Failed to connect to cloud service"); break;
                }

                return(false);
            }

            // Save the RefreshToken in the configuration so we can use it again next time
            databaseConfig.RefreshToken = oneDriveApi.AccessToken.RefreshToken;

            // Verify if we already have retrieved the name of this OneDrive
            if (string.IsNullOrEmpty(databaseConfig.OneDriveName))
            {
                // Fetch details about this OneDrive account
                var oneDriveAccount = await oneDriveApi.GetDrive();

                databaseConfig.OneDriveName = oneDriveAccount.Owner.User.DisplayName;
            }
            Configuration.Save();

            // Check if we have a location on OneDrive to sync with
            if (string.IsNullOrEmpty(databaseConfig.RemoteDatabasePath) && string.IsNullOrEmpty(databaseConfig.RemoteFolderId) && string.IsNullOrEmpty(databaseConfig.RemoteFileName))
            {
                // Ask the user where to store the database on OneDrive
                var oneDriveFilePickerDialog = new Forms.OneDriveFilePickerDialog(oneDriveApi)
                {
                    ExplanationText          = "Select where you want to store the KeePass database. Right click for additional options.",
                    AllowEnteringNewFileName = true,
                    FileName = new System.IO.FileInfo(localKeePassDatabasePath).Name
                };
                await oneDriveFilePickerDialog.LoadFolderItems();

                var result = oneDriveFilePickerDialog.ShowDialog();
                if (result != DialogResult.OK || string.IsNullOrEmpty(oneDriveFilePickerDialog.FileName))
                {
                    return(false);
                }

                databaseConfig.RemoteDatabasePath = (oneDriveFilePickerDialog.CurrentOneDriveItem.ParentReference != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.ParentReference.Path : "") + "/" + oneDriveFilePickerDialog.CurrentOneDriveItem.Name + "/" + oneDriveFilePickerDialog.FileName;
                databaseConfig.RemoteDriveId      = oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.ParentReference.DriveId : oneDriveFilePickerDialog.CurrentOneDriveItem.ParentReference.DriveId != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.ParentReference.DriveId : null;
                if (oneDriveFilePickerDialog.CurrentOneDriveItem.File != null || (oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem != null && oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.File != null))
                {
                    databaseConfig.RemoteItemId = oneDriveFilePickerDialog.CurrentOneDriveItem.File != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.Id : oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.Id;
                }
                else
                {
                    databaseConfig.RemoteFolderId = oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.ParentReference != null?string.IsNullOrEmpty(oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.ParentReference.Id) ? oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.Id : oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.ParentReference.Id : oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.Id : oneDriveFilePickerDialog.CurrentOneDriveItem.Id;
                }
                databaseConfig.RemoteFileName = oneDriveFilePickerDialog.FileName;
                Configuration.Save();
            }

            // Retrieve the metadata of the KeePass database on OneDrive
            OneDriveItem oneDriveItem;

            if (string.IsNullOrEmpty(databaseConfig.RemoteItemId))
            {
                // We don't have the ID of the KeePass file, check if the database is stored on the current user its drive or on a shared drive
                OneDriveItem folder;
                if (string.IsNullOrEmpty(databaseConfig.RemoteDriveId))
                {
                    // KeePass database is on the current user its drive
                    folder = await oneDriveApi.GetItemById(databaseConfig.RemoteFolderId);
                }
                else
                {
                    // KeePass database is on a shared drive
                    folder = await oneDriveApi.GetItemFromDriveById(databaseConfig.RemoteFolderId, databaseConfig.RemoteDriveId);
                }

                // Locate the KeePass file in the folder
                oneDriveItem = await oneDriveApi.GetItemInFolder(folder, databaseConfig.RemoteFileName);

                // Check if the KeePass file has been found
                if (oneDriveItem != null)
                {
                    // Store the direct Id to the KeePass file so we can save several API calls on future syncs
                    databaseConfig.RemoteItemId = oneDriveItem.Id;
                    Configuration.Save();
                }
            }
            else
            {
                // We have the ID of the KeePass file, check if it's on the current user its drive or on a shared drive
                if (string.IsNullOrEmpty(databaseConfig.RemoteDriveId))
                {
                    // KeePass database is on the current user its drive
                    oneDriveItem = await oneDriveApi.GetItemById(databaseConfig.RemoteItemId);
                }
                else
                {
                    // KeePass database is on a shared drive
                    oneDriveItem = await oneDriveApi.GetItemFromDriveById(databaseConfig.RemoteItemId, databaseConfig.RemoteDriveId);
                }
            }

            if (oneDriveItem == null)
            {
                // KeePass database not found on OneDrive
                updateStatus("Database does not exist yet on OneDrive, uploading it now");

                OneDriveItem oneDriveFolder;
                string       fileName;
                if (string.IsNullOrEmpty(databaseConfig.RemoteFolderId))
                {
                    oneDriveFolder = databaseConfig.RemoteDatabasePath.Contains("/") ? await oneDriveApi.GetFolderOrCreate(databaseConfig.RemoteDatabasePath.Remove(databaseConfig.RemoteDatabasePath.LastIndexOf("/", StringComparison.Ordinal))) : await oneDriveApi.GetDriveRoot();

                    fileName = databaseConfig.RemoteDatabasePath.Contains("/") ? databaseConfig.RemoteDatabasePath.Remove(0, databaseConfig.RemoteDatabasePath.LastIndexOf("/", StringComparison.Ordinal) + 1) : databaseConfig.RemoteDatabasePath;
                }
                else
                {
                    oneDriveFolder = databaseConfig.RemoteDriveId == null ? await oneDriveApi.GetItemById(databaseConfig.RemoteFolderId) : await oneDriveApi.GetItemFromDriveById(databaseConfig.RemoteFolderId, databaseConfig.RemoteDriveId);

                    fileName = databaseConfig.RemoteFileName;
                }

                if (oneDriveFolder == null)
                {
                    updateStatus("Unable to upload database to OneDrive. Remote path is invalid.");
                    return(false);
                }

                // Upload the database to OneDrive
                var newUploadResult = await oneDriveApi.UploadFileAs(localKeePassDatabasePath, fileName, oneDriveFolder);

                updateStatus(newUploadResult == null ? "Failed to upload the KeePass database" : "Successfully uploaded the new KeePass database to OneDrive");

                databaseConfig.LocalFileHash = Utilities.GetDatabaseFileHash(localKeePassDatabasePath);
                if (newUploadResult != null)
                {
                    databaseConfig.RemoteItemId  = newUploadResult.Id;
                    databaseConfig.LastCheckedAt = DateTime.Now;
                    databaseConfig.LastSyncedAt  = DateTime.Now;
                    databaseConfig.ETag          = newUploadResult.ETag;
                }
                Configuration.Save();
                return(false);
            }

            // Use the ETag from the OneDrive item to compare it against the local database config etag to see if the content has changed
            // Microsoft Graph API reports back a different ETag when uploading than the file actually gets assigned for some unknown reason. This would cause each sync attempt to sync again as the ETags differ. As a workaround we'll use the CTag which does seem reliable to detect a change to the file.
            if (!forceSync &&
                oneDriveItem.CTag == databaseConfig.ETag)
            {
                updateStatus("Databases are in sync");

                databaseConfig.LastCheckedAt = DateTime.Now;
                Configuration.Save();

                return(false);
            }

            // Download the database from OneDrive
            updateStatus("Downloading KeePass database from OneDrive");

            var temporaryKeePassDatabasePath = System.IO.Path.GetTempFileName();
            var downloadSuccessful           = await oneDriveApi.DownloadItemAndSaveAs(oneDriveItem, temporaryKeePassDatabasePath);

            if (!downloadSuccessful)
            {
                updateStatus("Failed to download the KeePass database from OneDrive");

                return(false);
            }

            // Sync database
            updateStatus("KeePass database downloaded, going to sync");

            // Ensure the database that needs to be synced is still the database currently selected in KeePass to avoid merging the downloaded database with the wrong database in KeePass
            if ((!KoenZomersKeePassOneDriveSyncExt.Host.Database.IOConnectionInfo.Path.StartsWith(AppDomain.CurrentDomain.BaseDirectory) && KoenZomersKeePassOneDriveSyncExt.Host.Database.IOConnectionInfo.Path != localKeePassDatabasePath) ||
                (KoenZomersKeePassOneDriveSyncExt.Host.Database.IOConnectionInfo.Path.StartsWith(AppDomain.CurrentDomain.BaseDirectory) && KoenZomersKeePassOneDriveSyncExt.Host.Database.IOConnectionInfo.Path.Remove(0, AppDomain.CurrentDomain.BaseDirectory.Length) != localKeePassDatabasePath))
            {
                updateStatus("Failed to sync. Please don't switch to another database before done.");

                return(false);
            }

            // Merge the downloaded database with the currently open KeePass database
            var syncSuccessful = KeePassDatabase.MergeDatabases(databaseConfig, temporaryKeePassDatabasePath);

            if (!syncSuccessful)
            {
                updateStatus("Failed to synchronize the KeePass databases");
                return(false);
            }

            // Upload the synced database
            updateStatus("Uploading the new KeePass database to OneDrive");

            var uploadResult = await oneDriveApi.UploadFileAs(temporaryKeePassDatabasePath, oneDriveItem.Name, oneDriveItem.ParentReference.Path.Equals("/drive/root:", StringComparison.CurrentCultureIgnoreCase)?await oneDriveApi.GetDriveRoot() : string.IsNullOrEmpty(databaseConfig.RemoteDriveId)?await oneDriveApi.GetItemById(oneDriveItem.ParentReference.Id) : await oneDriveApi.GetItemFromDriveById(oneDriveItem.ParentReference.Id, oneDriveItem.ParentReference.DriveId));

            if (uploadResult == null)
            {
                updateStatus("Failed to upload the KeePass database");
                return(false);
            }

            // Delete the temporary database used for merging
            System.IO.File.Delete(temporaryKeePassDatabasePath);

            // The ETag changes with every request of the item so we use the CTag instead which only changes when the file changes
            databaseConfig.ETag = uploadResult.CTag;

            return(true);
        }
Esempio n. 23
0
        private async void RefreshTokenButton_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(RefreshTokenTextBox.Text))
            {
                MessageBox.Show("You need to enter a refresh token first in the refresh token field in order to be able to retrieve a new access token based on a refresh token.", "OneDrive API", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            // Get a new access token based on the refresh token entered in the textbox
            OneDriveApi = await OneDriveApi.GetOneDriveApiFromRefreshToken(ClientId, ClientSecret, RefreshTokenTextBox.Text);

            if (OneDriveApi.AccessToken != null)
            {
                // Display the information of the new access token in the textboxes
                AccessTokenTextBox.Text = OneDriveApi.AccessToken.AccessToken;
                RefreshTokenTextBox.Text = OneDriveApi.AccessToken.RefreshToken;
                AccessTokenValidTextBox.Text = OneDriveApi.AccessTokenValidUntil.HasValue ? OneDriveApi.AccessTokenValidUntil.Value.ToString("dd-MM-yyyy HH:mm:ss") : "Not valid";
            }
        }
Esempio n. 24
0
        /// <summary>
        /// Applies the correct web proxy settings to the provided OneDriveApi instance based on KeePass proxy configuration
        /// </summary>
        /// <param name="oneDriveApi">OneDriveApi instance to apply the proper proxy settings to</param>
        public static void ApplyProxySettings(OneDriveApi oneDriveApi)
        {
            switch (KeePass.Program.Config.Integration.ProxyType)
            {
                case ProxyServerType.None:
                    oneDriveApi.UseProxy = false;
                    return;

                case ProxyServerType.Manual:
                    oneDriveApi.UseProxy = true;
                    oneDriveApi.ProxyConfiguration = new WebProxy(string.Concat(KeePass.Program.Config.Integration.ProxyAddress, ":", KeePass.Program.Config.Integration.ProxyPort));
                    oneDriveApi.ProxyConfiguration.UseDefaultCredentials = KeePass.Program.Config.Integration.ProxyAuthType == ProxyAuthType.Auto || KeePass.Program.Config.Integration.ProxyAuthType == ProxyAuthType.Default;

                    if (KeePass.Program.Config.Integration.ProxyAuthType == ProxyAuthType.Manual)
                    {
                        oneDriveApi.ProxyConfiguration.Credentials = new NetworkCredential(KeePass.Program.Config.Integration.ProxyUserName, KeePass.Program.Config.Integration.ProxyPassword);
                    }
                    break;

                case ProxyServerType.System:
                    oneDriveApi.UseProxy = true;
                    break;
            }
        }
Esempio n. 25
0
        public OneDriveFilePickerDialog(OneDriveApi oneDriveApi)
        {
            InitializeComponent();

            _oneDriveApi = oneDriveApi;
        }
Esempio n. 26
0
        private void Step1Button_Click(object sender, EventArgs e)
        {
            // Create a new instance of the OneDriveApi framework
            OneDriveApi = new OneDriveApi(ClientId, ClientSecret);

            // First sign the current user out to make sure he/she needs to authenticate again
            var signoutUri = OneDriveApi.GetSignOutUri();
            AuthenticationBrowser.Navigate(signoutUri);
        }
Esempio n. 27
0
        /// <summary>
        /// Uses a Microsoft OneDrive Cloud Storage Provider (OneDrive Consumer, OneDrive for Business, Microsoft Graph) to sync the KeePass database
        /// </summary>
        /// <param name="databaseConfig">Configuration of the database to sync</param>
        /// <param name="localKeePassDatabasePath">Path to where the KeePass database to sync resides</param>
        /// <param name="forceSync">Flag to indicate if the sync should always take place</param>
        /// <param name="updateStatus">Action to write status messages to to display in the UI</param>
        /// <returns>True if successful, false if failed</returns>
        public static async Task <bool> SyncUsingOneDriveCloudProvider(Configuration databaseConfig, string localKeePassDatabasePath, bool forceSync, Action <string> updateStatus)
        {
            // Connect to OneDrive
            OneDriveApi oneDriveApi = null;
            bool        retryGettingApiInstance;

            do
            {
                retryGettingApiInstance = false;
                try
                {
                    oneDriveApi = await Utilities.GetOneDriveApi(databaseConfig);
                }
                catch (KoenZomers.OneDrive.Api.Exceptions.TokenRetrievalFailedException)
                {
                    // Failed to get a OneDrive API instance because retrieving an oAuth token failed. This could be because the oAuth token expired or has been removed. Show the login dialog again so we can get a new token.
                    databaseConfig.RefreshToken = null;
                    retryGettingApiInstance     = true;
                }
                catch (Exception e)
                {
                    // Build the error text to show to the end user
                    var errorMessage = new System.Text.StringBuilder();
                    errorMessage.Append("Failed to connect to ");
                    switch (databaseConfig.CloudStorageType.GetValueOrDefault(CloudStorageType.OneDriveConsumer))
                    {
                    case CloudStorageType.OneDriveConsumer:
                        errorMessage.Append("OneDrive");
                        break;

                    case CloudStorageType.MicrosoftGraph:
                    case CloudStorageType.MicrosoftGraphDeviceLogin:
                        errorMessage.Append("Microsoft Graph");
                        break;

                    default:
                        errorMessage.Append("cloud storage provider");
                        break;
                    }
                    errorMessage.AppendLine(string.Format(" for database {0}:", databaseConfig.KeePassDatabase.Name));
                    errorMessage.AppendLine();

                    // Revert to the most inner exception to get the best details on what went wrong
                    while (e.InnerException != null)
                    {
                        e = e.InnerException;
                    }

                    errorMessage.AppendLine(e.Message);

                    // Verify if we're offline
                    if (e.Message.Contains("remote name could not be resolved"))
                    {
                        // Offline, don't display a modal dialog but use the status bar instead
                        KeePassDatabase.UpdateStatus("Can't connect. Working offline.");
                        return(false);
                    }

                    MessageBox.Show(errorMessage.ToString(), "Connection failed", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                }
            } while (retryGettingApiInstance);

            if (oneDriveApi == null)
            {
                switch (databaseConfig.CloudStorageType.GetValueOrDefault(CloudStorageType.OneDriveConsumer))
                {
                case CloudStorageType.OneDriveConsumer: updateStatus(string.Format("Failed to connect to OneDrive for database {0}", databaseConfig.KeePassDatabase.Name)); break;

                case CloudStorageType.MicrosoftGraph:
                case CloudStorageType.MicrosoftGraphDeviceLogin:
                    updateStatus(string.Format("Failed to connect to Microsoft Graph for database {0}", databaseConfig.KeePassDatabase.Name));
                    break;

                default: updateStatus(string.Format("Failed to connect to cloud service for database {0}", databaseConfig.KeePassDatabase.Name)); break;
                }

                return(false);
            }

            // Save the RefreshToken in the configuration so we can use it again next time
            databaseConfig.RefreshToken = oneDriveApi.AccessToken.RefreshToken;

            // Verify if we already have retrieved the name of this OneDrive
            if (string.IsNullOrEmpty(databaseConfig.OneDriveName))
            {
                // Fetch details about this OneDrive account
                var oneDriveAccount = await oneDriveApi.GetDrive();

                databaseConfig.OneDriveName = oneDriveAccount.Owner.User.DisplayName;
            }
            Configuration.Save();

            // Check if we have a location on OneDrive to sync with
            if (string.IsNullOrEmpty(databaseConfig.RemoteDatabasePath) && string.IsNullOrEmpty(databaseConfig.RemoteFolderId) && string.IsNullOrEmpty(databaseConfig.RemoteFileName))
            {
                // Ask the user where to store the database on OneDrive
                var oneDriveFilePickerDialog = new Forms.OneDriveFilePickerDialog(oneDriveApi)
                {
                    ExplanationText          = "Select where you want to store the KeePass database. Right click for additional options.",
                    AllowEnteringNewFileName = true,
                    FileName = new System.IO.FileInfo(localKeePassDatabasePath).Name
                };
                await oneDriveFilePickerDialog.LoadFolderItems();

                var result = oneDriveFilePickerDialog.ShowDialog();
                if (result != DialogResult.OK || string.IsNullOrEmpty(oneDriveFilePickerDialog.FileName))
                {
                    return(false);
                }

                databaseConfig.RemoteDatabasePath = (oneDriveFilePickerDialog.CurrentOneDriveItem.ParentReference != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.ParentReference.Path : "") + "/" + oneDriveFilePickerDialog.CurrentOneDriveItem.Name + "/" + oneDriveFilePickerDialog.FileName;
                databaseConfig.RemoteDriveId      = oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.ParentReference.DriveId : oneDriveFilePickerDialog.CurrentOneDriveItem.ParentReference.DriveId != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.ParentReference.DriveId : null;
                if (oneDriveFilePickerDialog.CurrentOneDriveItem.File != null || (oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem != null && oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.File != null))
                {
                    databaseConfig.RemoteItemId = oneDriveFilePickerDialog.CurrentOneDriveItem.File != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.Id : oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.Id;
                }
                else
                {
                    databaseConfig.RemoteFolderId = oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.ParentReference != null?string.IsNullOrEmpty(oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.ParentReference.Id) || oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.Folder != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.Id : oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.ParentReference.Id : oneDriveFilePickerDialog.CurrentOneDriveItem.RemoteItem.Id : oneDriveFilePickerDialog.CurrentOneDriveItem.Id;
                }
                databaseConfig.RemoteFileName = oneDriveFilePickerDialog.FileName;
                Configuration.Save();
            }

            // Retrieve the metadata of the KeePass database on OneDrive
            OneDriveItem oneDriveItem;

            if (string.IsNullOrEmpty(databaseConfig.RemoteItemId))
            {
                // We don't have the ID of the KeePass file, check if the database is stored on the current user its drive or on a shared drive
                OneDriveItem folder;
                if (string.IsNullOrEmpty(databaseConfig.RemoteDriveId))
                {
                    // KeePass database is on the current user its drive
                    if (string.IsNullOrEmpty(databaseConfig.RemoteFolderId))
                    {
                        // No direct reference to the folder on the drive available, try locating it by its remote path
                        oneDriveItem = await oneDriveApi.GetItem(databaseConfig.RemoteDatabasePath);
                    }
                    else
                    {
                        // Get the folder in which the KeePass file resides
                        folder = await oneDriveApi.GetItemById(databaseConfig.RemoteFolderId);

                        if (folder == null)
                        {
                            updateStatus(string.Format("Unable to download database {0} from OneDrive. Remote path cannot be found.", databaseConfig.KeePassDatabase.Name));
                            return(false);
                        }

                        // Locate the KeePass file in the folder
                        oneDriveItem = await oneDriveApi.GetItemInFolder(folder, databaseConfig.RemoteFileName);
                    }
                }
                else
                {
                    // KeePass database is on a shared drive or has not been uploaded yet
                    folder = await oneDriveApi.GetItemFromDriveById(databaseConfig.RemoteFolderId, databaseConfig.RemoteDriveId);

                    // Locate the KeePass file in the folder. Will return NULL if the file has not been uploaded yet.
                    oneDriveItem = await oneDriveApi.GetItemInFolder(folder, databaseConfig.RemoteFileName);
                }

                // Check if the KeePass file has been found
                if (oneDriveItem != null)
                {
                    // Store the direct Id to the KeePass file so we can save several API calls on future syncs
                    databaseConfig.RemoteItemId = oneDriveItem.Id;
                    Configuration.Save();
                }
            }
            else
            {
                // We have the ID of the KeePass file, check if it's on the current user its drive or on a shared drive
                if (string.IsNullOrEmpty(databaseConfig.RemoteDriveId))
                {
                    // KeePass database is on the current user its drive
                    oneDriveItem = await oneDriveApi.GetItemById(databaseConfig.RemoteItemId);
                }
                else
                {
                    // KeePass database is on a shared drive
                    oneDriveItem = await oneDriveApi.GetItemFromDriveById(databaseConfig.RemoteItemId, databaseConfig.RemoteDriveId);
                }
            }

            if (oneDriveItem == null)
            {
                // KeePass database not found on OneDrive
                updateStatus(string.Format("Database {0} does not exist yet on OneDrive, uploading it now", databaseConfig.KeePassDatabase.Name));

                OneDriveItem oneDriveFolder;
                string       fileName;
                if (string.IsNullOrEmpty(databaseConfig.RemoteFolderId))
                {
                    oneDriveFolder = databaseConfig.RemoteDatabasePath.Contains("/") ? await oneDriveApi.GetFolderOrCreate(databaseConfig.RemoteDatabasePath.Remove(databaseConfig.RemoteDatabasePath.LastIndexOf("/", StringComparison.Ordinal))) : await oneDriveApi.GetDriveRoot();

                    fileName = databaseConfig.RemoteDatabasePath.Contains("/") ? databaseConfig.RemoteDatabasePath.Remove(0, databaseConfig.RemoteDatabasePath.LastIndexOf("/", StringComparison.Ordinal) + 1) : databaseConfig.RemoteDatabasePath;
                }
                else
                {
                    oneDriveFolder = databaseConfig.RemoteDriveId == null ? await oneDriveApi.GetItemById(databaseConfig.RemoteFolderId) : await oneDriveApi.GetItemFromDriveById(databaseConfig.RemoteFolderId, databaseConfig.RemoteDriveId);

                    fileName = databaseConfig.RemoteFileName;
                }

                if (oneDriveFolder == null)
                {
                    updateStatus(string.Format("Unable to upload database {0} to OneDrive. Remote path is invalid.", databaseConfig.KeePassDatabase.Name));
                    return(false);
                }

                // Upload the database to OneDrive
                var newUploadResult = await oneDriveApi.UploadFileAs(localKeePassDatabasePath, fileName, oneDriveFolder);

                updateStatus(string.Format(newUploadResult == null ? "Failed to upload the KeePass database {0}" : "Successfully uploaded the new KeePass database {0} to OneDrive", databaseConfig.KeePassDatabase.Name));

                databaseConfig.LocalFileHash = Utilities.GetDatabaseFileHash(localKeePassDatabasePath);
                if (newUploadResult != null)
                {
                    databaseConfig.RemoteItemId  = newUploadResult.Id;
                    databaseConfig.LastCheckedAt = DateTime.Now;
                    databaseConfig.LastSyncedAt  = DateTime.Now;
                    databaseConfig.ETag          = newUploadResult.ETag;
                }
                Configuration.Save();
                return(false);
            }

            // Use the ETag from the OneDrive item to compare it against the local database config etag to see if the content has changed
            // Microsoft Graph API reports back a different ETag when uploading than the file actually gets assigned for some unknown reason. This would cause each sync attempt to sync again as the ETags differ. As a workaround we'll use the CTag which does seem reliable to detect a change to the file.
            if (!forceSync &&
                oneDriveItem.CTag == databaseConfig.ETag)
            {
                updateStatus(string.Format("Database {0} is in sync", databaseConfig.KeePassDatabase.Name));

                databaseConfig.LastCheckedAt = DateTime.Now;
                Configuration.Save();

                return(false);
            }

            // Download the database from OneDrive
            updateStatus(string.Format("Downloading KeePass database {0} from OneDrive", databaseConfig.KeePassDatabase.Name));

            var temporaryKeePassDatabasePath = System.IO.Path.GetTempFileName();
            var downloadSuccessful           = await oneDriveApi.DownloadItemAndSaveAs(oneDriveItem, temporaryKeePassDatabasePath);

            if (!downloadSuccessful)
            {
                updateStatus(string.Format("Failed to download the KeePass database {0} from OneDrive", databaseConfig.KeePassDatabase.Name));

                return(false);
            }

            // Sync database
            updateStatus(string.Format("KeePass database {0} downloaded, going to sync", databaseConfig.KeePassDatabase.Name));

            // Merge the downloaded database with the currently open KeePass database
            var syncSuccessful = KeePassDatabase.MergeDatabases(databaseConfig, temporaryKeePassDatabasePath);

            string localDatabaseToUpload;

            if (!syncSuccessful)
            {
                updateStatus(string.Format("Failed to synchronize the KeePass database {0}", databaseConfig.KeePassDatabase.Name));

                var confirm = MessageBox.Show("Unable to merge the databases. Did you just change the master password for this KeePass database? If so and you would like to OVERWRITE the KeePass database stored on your OneDrive with your local database, select Yes, otherwise select No.", "Confirm overwriting your KeePass database", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2);
                if (confirm != DialogResult.Yes)
                {
                    return(false);
                }

                // Upload the local database
                localDatabaseToUpload = databaseConfig.KeePassDatabase.IOConnectionInfo.Path;

                updateStatus(string.Format("Uploading the local KeePass database {0} to OneDrive", databaseConfig.KeePassDatabase.Name));
            }
            else
            {
                // Upload the synced database
                localDatabaseToUpload = temporaryKeePassDatabasePath;

                updateStatus(string.Format("Uploading the merged KeePass database {0} to OneDrive", databaseConfig.KeePassDatabase.Name));
            }

            OneDriveItem uploadResult = null;

            // Due to some issues with the OneDrive API throwing random errors for no reason, retry a few times to upload the database before it will be considered failed
            for (var uploadAttempts = 1; uploadAttempts <= 5; uploadAttempts++)
            {
                try
                {
                    if (!string.IsNullOrEmpty(databaseConfig.RemoteItemId))
                    {
                        // Database is already present on OneDrive, update it
                        uploadResult = await oneDriveApi.UpdateFile(localDatabaseToUpload, oneDriveItem);
                    }
                    else
                    {
                        // Database resides on the user its own OneDrive in the root folder
                        if (oneDriveItem.ParentReference.Path.Equals("/drive/root:", StringComparison.CurrentCultureIgnoreCase))
                        {
                            uploadResult = await oneDriveApi.UploadFileAs(localDatabaseToUpload, oneDriveItem.Name, await oneDriveApi.GetDriveRoot());
                        }
                        else
                        {
                            if (string.IsNullOrEmpty(databaseConfig.RemoteDriveId))
                            {
                                // Database resides on the user its own OneDrive in a folder
                                uploadResult = await oneDriveApi.UploadFileAs(localDatabaseToUpload, oneDriveItem.Name, await oneDriveApi.GetItemById(oneDriveItem.ParentReference.Id));
                            }
                            else
                            {
                                // Database resides on another OneDrive
                                uploadResult = await oneDriveApi.UploadFileAs(localDatabaseToUpload, oneDriveItem.Name, await oneDriveApi.GetItemFromDriveById(oneDriveItem.ParentReference.Id, oneDriveItem.ParentReference.DriveId));
                            }
                        }
                    }

                    // Uploading succeeded
                    break;
                }
                catch (ArgumentNullException e)
                {
                    // If any other exception than the one we will get if the OneDrive API throws the random error, then ensure we pass on the exception instead of swallowing it
                    if (e.ParamName != "oneDriveUploadSession")
                    {
                        throw;
                    }

                    updateStatus(string.Format("Uploading the new KeePass database {1} to OneDrive (attempt {0})", uploadAttempts + 1, databaseConfig.KeePassDatabase.Name));
                }
            }

            if (uploadResult == null)
            {
                updateStatus(string.Format("Failed to upload the KeePass database {0}", databaseConfig.KeePassDatabase.Name));
                return(false);
            }

            // Delete the temporary database used for merging
            System.IO.File.Delete(temporaryKeePassDatabasePath);

            // The ETag changes with every request of the item so we use the CTag instead which only changes when the file changes
            databaseConfig.ETag = uploadResult.CTag;

            return(true);
        }
Esempio n. 28
0
        /// <summary>
        /// Checks if a newer database exists on OneDrive compared to the locally opened version and syncs them if so
        /// </summary>
        /// <param name="localKeePassDatabasePath">Full path or relative path from the KeePass executable folder to where the KeePass database resides locally</param>
        /// <param name="updateStatus">Method to call to update the status</param>
        /// <param name="forceSync">If True, no attempts will be made to validate if the local copy differs from the remote copy and it will always sync. If False, it will try to validate if there are any changes and not sync if there are no changes.</param>
        public static async Task SyncDatabase(string localKeePassDatabasePath, Action <string> updateStatus, bool forceSync, Configuration databaseConfig)
        {
            // If something is already syncing, abort this attempt. This happens when the Import saves the resulting KeePass database. That by itself triggers another sync which doesn't have to go through the sync process as it just regards the temp database.
            if (KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning)
            {
                return;
            }

            // Set flag to block exiting KeePass until this is done
            KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = true;

            // Retrieve the KeePassOneDriveSync settings
            if (databaseConfig == null)
            {
                databaseConfig = Configuration.GetPasswordDatabaseConfiguration(localKeePassDatabasePath);
            }

            // Check if this database explicitly does not allow to be synced with OneDrive and if syncing is enabled on this database
            if (databaseConfig.DoNotSync || !databaseConfig.SyncingEnabled)
            {
                // Set flag to allow exiting KeePass
                KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                return;
            }

            // Check if the current database is synced with OneDrive
            if (string.IsNullOrEmpty(databaseConfig.RemoteDatabasePath) && string.IsNullOrEmpty(databaseConfig.RemoteFolderId) && string.IsNullOrEmpty(databaseConfig.RemoteFileName))
            {
                // Current database is not being syned with OneDrive, ask if it should be synced
                var oneDriveAskToStartSyncingForm = new OneDriveAskToStartSyncingDialog(databaseConfig);
                if (oneDriveAskToStartSyncingForm.ShowDialog() != DialogResult.OK)
                {
                    // Set flag to allow exiting KeePass
                    KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                    return;
                }

                // Ask which cloud service to connect to
                var oneDriveCloudTypeForm = new OneDriveCloudTypeForm {
                    ExplanationText = "Choose the cloud service you wish to store the KeePass database on:"
                };
                if (oneDriveCloudTypeForm.ShowDialog() != DialogResult.OK)
                {
                    // Set flag to allow exiting KeePass
                    KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                    return;
                }

                databaseConfig.CloudStorageType = oneDriveCloudTypeForm.ChosenCloudStorageType;
                Configuration.Save();
            }

            // Connect to OneDrive
            OneDriveApi oneDriveApi = null;
            bool        retryGettingApiInstance;

            do
            {
                retryGettingApiInstance = false;
                try
                {
                    oneDriveApi = await Utilities.GetOneDriveApi(databaseConfig);
                }
                catch (KoenZomers.OneDrive.Api.Exceptions.TokenRetrievalFailedException e)
                {
                    // Failed to get a OneDrive API instance because retrieving an oAuth token failed. This could be because the oAuth token expired or has been removed. Show the login dialog again so we can get a new token.
                    databaseConfig.RefreshToken = null;
                    retryGettingApiInstance     = true;
                }
                catch (Exception e)
                {
                    // Build the error text to show to the end user
                    var errorMessage = new System.Text.StringBuilder();
                    errorMessage.Append("Failed to connect to ");
                    switch (databaseConfig.CloudStorageType.GetValueOrDefault(CloudStorageType.OneDriveConsumer))
                    {
                    case CloudStorageType.OneDriveConsumer:
                        errorMessage.Append("OneDrive");
                        break;

                    case CloudStorageType.OneDriveForBusiness:
                        errorMessage.Append("OneDrive for Business");
                        break;

                    default:
                        errorMessage.Append("cloud storage provider");
                        break;
                    }
                    errorMessage.AppendLine(":");
                    errorMessage.AppendLine();
                    errorMessage.AppendLine(e.Message);

                    // If there's an inner exception, show its message as well as it typically gives more detail why it went wrong
                    if (e.InnerException != null)
                    {
                        errorMessage.AppendLine(e.InnerException.Message);

                        // Verify if we're offline
                        if (e.InnerException.Message.Contains("remote name could not be resolved"))
                        {
                            // Offline, don't display a modal dialog but use the status bar instead
                            UpdateStatus("Can't connect. Working offline.");

                            // Set flag to allow exiting KeePass
                            KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                            return;
                        }
                    }

                    MessageBox.Show(errorMessage.ToString(), "Connection failed", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                }
            } while (retryGettingApiInstance);

            if (oneDriveApi == null)
            {
                switch (databaseConfig.CloudStorageType.GetValueOrDefault(CloudStorageType.OneDriveConsumer))
                {
                case CloudStorageType.OneDriveConsumer: updateStatus("Failed to connect to OneDrive"); break;

                case CloudStorageType.OneDriveForBusiness: updateStatus("Failed to connect to OneDrive for Business"); break;

                default: updateStatus("Failed to connect to cloud service"); break;
                }

                // Set flag to allow exiting KeePass
                KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                return;
            }

            // Save the RefreshToken in the configuration so we can use it again next time
            databaseConfig.RefreshToken = oneDriveApi.AccessToken.RefreshToken;

            // Verify if we already have retrieved the name of this OneDrive
            if (string.IsNullOrEmpty(databaseConfig.OneDriveName))
            {
                // Fetch details about this OneDrive account
                var oneDriveAccount = await oneDriveApi.GetDrive();

                databaseConfig.OneDriveName = oneDriveAccount.Owner.User.DisplayName;
            }
            Configuration.Save();

            // Check if we have a location on OneDrive to sync with
            if (string.IsNullOrEmpty(databaseConfig.RemoteDatabasePath) && string.IsNullOrEmpty(databaseConfig.RemoteFolderId) && string.IsNullOrEmpty(databaseConfig.RemoteFileName))
            {
                // Ask the user where to store the database on OneDrive
                var oneDriveFilePickerDialog = new OneDriveFilePickerDialog(oneDriveApi)
                {
                    ExplanationText          = "Select where you want to store the KeePass database. Right click for additional options.",
                    AllowEnteringNewFileName = true
                };
                await oneDriveFilePickerDialog.LoadFolderItems();

                var result = oneDriveFilePickerDialog.ShowDialog();
                if (result != DialogResult.OK || string.IsNullOrEmpty(oneDriveFilePickerDialog.FileName))
                {
                    // Set flag to allow exiting KeePass
                    KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                    return;
                }
                databaseConfig.RemoteDatabasePath = (oneDriveFilePickerDialog.CurrentOneDriveItem.ParentReference != null ? oneDriveFilePickerDialog.CurrentOneDriveItem.ParentReference.Path : "") + "/" + oneDriveFilePickerDialog.CurrentOneDriveItem.Name + "/" + oneDriveFilePickerDialog.FileName;
                databaseConfig.RemoteFolderId     = oneDriveFilePickerDialog.CurrentOneDriveItem.Id;
                databaseConfig.RemoteFileName     = oneDriveFilePickerDialog.FileName;
                Configuration.Save();
            }

            // Retrieve the KeePass database from OneDrive
            var oneDriveItem = string.IsNullOrEmpty(databaseConfig.RemoteFolderId) ? await oneDriveApi.GetItem(databaseConfig.RemoteDatabasePath) : await oneDriveApi.GetItemInFolder(databaseConfig.RemoteFolderId, databaseConfig.RemoteFileName);

            if (oneDriveItem == null)
            {
                // KeePass database not found on OneDrive
                updateStatus("Database does not exist yet on OneDrive, uploading it now");

                OneDriveItem oneDriveFolder;
                string       fileName;
                if (string.IsNullOrEmpty(databaseConfig.RemoteFolderId))
                {
                    oneDriveFolder = databaseConfig.RemoteDatabasePath.Contains("/") ? await oneDriveApi.GetFolderOrCreate(databaseConfig.RemoteDatabasePath.Remove(databaseConfig.RemoteDatabasePath.LastIndexOf("/", StringComparison.Ordinal))) : await oneDriveApi.GetDriveRoot();

                    fileName = databaseConfig.RemoteDatabasePath.Contains("/") ? databaseConfig.RemoteDatabasePath.Remove(0, databaseConfig.RemoteDatabasePath.LastIndexOf("/", StringComparison.Ordinal) + 1) : databaseConfig.RemoteDatabasePath;
                }
                else
                {
                    oneDriveFolder = await oneDriveApi.GetItemById(databaseConfig.RemoteFolderId);

                    fileName = databaseConfig.RemoteFileName;
                }

                if (oneDriveFolder == null)
                {
                    updateStatus("Unable to upload database to OneDrive. Remote path is invalid.");

                    // Set flag to allow exiting KeePass
                    KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                    return;
                }

                // Upload the database to OneDrive
                var newUploadResult = await oneDriveApi.UploadFileAs(localKeePassDatabasePath, fileName, oneDriveFolder);

                updateStatus(newUploadResult == null ? "Failed to upload the KeePass database" : "Successfully uploaded the new KeePass database to OneDrive");

                databaseConfig.LocalFileHash = Utilities.GetDatabaseFileHash(localKeePassDatabasePath);
                if (newUploadResult != null)
                {
                    databaseConfig.LastCheckedAt = DateTime.Now;
                    databaseConfig.LastSyncedAt  = DateTime.Now;
                    databaseConfig.ETag          = newUploadResult.ETag;
                }
                Configuration.Save();

                // Set flag to allow exiting KeePass
                KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                return;
            }

            // Use the ETag from the OneDrive item to compare it against the local database config etag to see if the content has changed
            if (!forceSync && oneDriveItem.ETag == databaseConfig.ETag)
            {
                updateStatus("Databases are in sync");

                databaseConfig.LastCheckedAt = DateTime.Now;
                Configuration.Save();

                // Set flag to allow exiting KeePass
                KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                return;
            }

            // Download the database from OneDrive
            updateStatus("Downloading KeePass database from OneDrive");

            var temporaryKeePassDatabasePath = Path.GetTempFileName();
            var downloadSuccessful           = await oneDriveApi.DownloadItemAndSaveAs(oneDriveItem, temporaryKeePassDatabasePath);

            if (!downloadSuccessful)
            {
                updateStatus("Failed to download the KeePass database from OneDrive");

                // Set flag to allow exiting KeePass
                KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                return;
            }

            // Sync database
            updateStatus("KeePass database downloaded, going to sync");

            // Ensure the database that needs to be synced is still the database currently selected in KeePass to avoid merging the downloaded database with the wrong database in KeePass
            if ((!KoenZomersKeePassOneDriveSyncExt.Host.Database.IOConnectionInfo.Path.StartsWith(Environment.CurrentDirectory) && KoenZomersKeePassOneDriveSyncExt.Host.Database.IOConnectionInfo.Path != localKeePassDatabasePath) ||
                (KoenZomersKeePassOneDriveSyncExt.Host.Database.IOConnectionInfo.Path.StartsWith(Environment.CurrentDirectory) && KoenZomersKeePassOneDriveSyncExt.Host.Database.IOConnectionInfo.Path.Remove(0, Environment.CurrentDirectory.Length + 1) != localKeePassDatabasePath))
            {
                updateStatus("Failed to sync. Please don't switch to another database before done.");

                // Set flag to allow exiting KeePass
                KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                return;
            }

            var connectionInfo = IOConnectionInfo.FromPath(temporaryKeePassDatabasePath);
            var formatter      = KoenZomersKeePassOneDriveSyncExt.Host.FileFormatPool.Find("KeePass KDBX (2.x)");

            // Temporarily switch off syncing for this database to avoid the import operation, which causes a save, to create and endless loop
            databaseConfig.SyncingEnabled = false;

            // Import the current database with the downloaded database. Import causes a one way sync, syncing would try to update both ends which won't work for OneDrive.
            var importSuccessful = ImportUtil.Import(KoenZomersKeePassOneDriveSyncExt.Host.Database, formatter, new[] { connectionInfo }, true, KoenZomersKeePassOneDriveSyncExt.Host.MainWindow, false, KoenZomersKeePassOneDriveSyncExt.Host.MainWindow);

            // Enable syncing of this database again
            databaseConfig.SyncingEnabled = true;

            // Remove the temporary database from the Most Recently Used (MRU) list in KeePass as its added automatically on the import action
            KoenZomersKeePassOneDriveSyncExt.Host.MainWindow.FileMruList.RemoveItem(temporaryKeePassDatabasePath);

            if (!importSuccessful.GetValueOrDefault(false))
            {
                updateStatus("Failed to synchronize the KeePass databases");

                // Set flag to allow exiting KeePass
                KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                return;
            }

            // Upload the synced database
            updateStatus("Uploading the new KeePass database to OneDrive");

            var uploadResult = await oneDriveApi.UploadFileAs(temporaryKeePassDatabasePath, oneDriveItem.Name, oneDriveItem.ParentReference.Path.Equals("/drive/root:", StringComparison.CurrentCultureIgnoreCase)?await oneDriveApi.GetDriveRoot() : await oneDriveApi.GetItemById(oneDriveItem.ParentReference.Id));

            if (uploadResult == null)
            {
                updateStatus("Failed to upload the KeePass database");

                // Set flag to allow exiting KeePass
                KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;

                return;
            }

            // Delete the temporary database used for merging
            File.Delete(temporaryKeePassDatabasePath);

            // Update the KeePass UI so it shows the new entries
            KoenZomersKeePassOneDriveSyncExt.Host.MainWindow.UpdateUI(false, null, true, null, true, null, false);

            updateStatus("KeePass database has successfully been synchronized and uploaded");

            databaseConfig.LocalFileHash = Utilities.GetDatabaseFileHash(localKeePassDatabasePath);
            databaseConfig.ETag          = uploadResult.ETag;
            databaseConfig.LastSyncedAt  = DateTime.Now;
            databaseConfig.LastCheckedAt = DateTime.Now;
            Configuration.Save();

            // Set flag to allow exiting KeePass
            KoenZomersKeePassOneDriveSyncExt.IsSomethingStillRunning = false;
        }