Esempio n. 1
0
        /// <summary>
        /// Download a KeePass database from SharePoint
        /// </summary>
        /// <param name="databaseConfig">Configuration of the database to sync</param>
        /// <param name="updateStatus">Action to write status messages to to display in the UI</param>
        /// <returns>Path to the local KeePass database or NULL if the process has been aborted</returns>
        public static async Task <string> OpenFromSharePoint(Configuration databaseConfig, Action <string> updateStatus)
        {
            if (!await EnsureSharePointCredentials(databaseConfig))
            {
                return(null);
            }

            using (var httpClient = CreateSharePointHttpClient(databaseConfig))
            {
                // Ask the user where to store the database on SharePoint
                var sharePointDocumentLibraryPickerDialog = new Forms.SharePointDocumentLibraryPickerDialog(httpClient)
                {
                    ExplanationText          = "Select the KeePass database to open. Right click for additional options.",
                    AllowEnteringNewFileName = false
                };
                await sharePointDocumentLibraryPickerDialog.LoadDocumentLibraryItems();

                var result = sharePointDocumentLibraryPickerDialog.ShowDialog();
                if (result != DialogResult.OK || string.IsNullOrEmpty(sharePointDocumentLibraryPickerDialog.SelectedDocumentLibraryServerRelativeUrl))
                {
                    updateStatus("Open KeePass database from SharePoint aborted");
                    return(null);
                }
                databaseConfig.RemoteFolderId = sharePointDocumentLibraryPickerDialog.SelectedDocumentLibraryServerRelativeUrl;
                databaseConfig.RemoteFileName = sharePointDocumentLibraryPickerDialog.FileName;

                // Show the save as dialog to select a location locally where to store the KeePass database
                var saveFiledialog = new SaveFileDialog
                {
                    Filter          = "KeePass databases (*.kdbx)|*.kdbx|All Files (*.*)|*.*",
                    Title           = "Select where to store the KeePass database locally",
                    CheckFileExists = false,
                    FileName        = sharePointDocumentLibraryPickerDialog.FileName
                };

                var saveFileDialogResult = saveFiledialog.ShowDialog();
                if (saveFileDialogResult != DialogResult.OK || string.IsNullOrEmpty(saveFiledialog.FileName))
                {
                    updateStatus("Open KeePass database from SharePoint aborted");
                    return(null);
                }

                // Download the KeePass database to the selected location
                updateStatus("Downloading KeePass database");

                // Retrieve the KeePass database from SharePoint
                var serverRelativeSharePointUrl = string.Concat(databaseConfig.RemoteFolderId, "/", databaseConfig.RemoteFileName);
                var downloadSuccessful          = await DownloadFile(saveFiledialog.FileName, serverRelativeSharePointUrl, httpClient);

                // Get the ETag of the database so we can determine if it's in sync
                databaseConfig.ETag = await GetEtagOfFile(httpClient, serverRelativeSharePointUrl);

                return(downloadSuccessful ? saveFiledialog.FileName : null);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Uses the Microsoft SharePoint platform (SharePoint 2013, 2016 or Online) 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> SyncUsingSharePointPlatform(Configuration databaseConfig, string localKeePassDatabasePath, bool forceSync, Action <string> updateStatus)
        {
            if (!await EnsureSharePointCredentials(databaseConfig))
            {
                return(false);
            }

            using (var httpClient = CreateSharePointHttpClient(databaseConfig))
            {
                // Check if we have a Document Library on SharePoint to sync with
                if (string.IsNullOrEmpty(databaseConfig.RemoteFolderId) && string.IsNullOrEmpty(databaseConfig.RemoteFileName))
                {
                    // Ask the user where to store the database on SharePoint
                    var sharePointDocumentLibraryPickerDialog = new Forms.SharePointDocumentLibraryPickerDialog(httpClient);
                    await sharePointDocumentLibraryPickerDialog.LoadDocumentLibraryItems();

                    sharePointDocumentLibraryPickerDialog.FileName = !string.IsNullOrEmpty(databaseConfig.RemoteFileName) ? databaseConfig.RemoteFileName : new System.IO.FileInfo(localKeePassDatabasePath).Name;
                    var result = sharePointDocumentLibraryPickerDialog.ShowDialog();
                    if (result != DialogResult.OK || string.IsNullOrEmpty(sharePointDocumentLibraryPickerDialog.SelectedDocumentLibraryServerRelativeUrl))
                    {
                        return(false);
                    }
                    databaseConfig.RemoteFolderId = sharePointDocumentLibraryPickerDialog.SelectedDocumentLibraryServerRelativeUrl;
                    databaseConfig.RemoteFileName = sharePointDocumentLibraryPickerDialog.FileName;
                    Configuration.Save();
                }

                // Ensure we have the SharePoint site name
                if (string.IsNullOrEmpty(databaseConfig.OneDriveName))
                {
                    // We don't have the SharePoint site name yet, retrieve it now by triggering TestConnection
                    await TestConnection(httpClient, databaseConfig);

                    Configuration.Save();
                }

                // Retrieve the KeePass database from SharePoint
                var serverRelativeSharePointUrl = string.Concat(databaseConfig.RemoteFolderId, "/", databaseConfig.RemoteFileName);
                var eTag = await GetEtagOfFile(httpClient, serverRelativeSharePointUrl);

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

                    // Upload the database to SharePoint
                    eTag = await UploadFile(databaseConfig.KeePassDatabase.IOConnectionInfo.Path, databaseConfig.RemoteFolderId, databaseConfig.RemoteFileName, httpClient);

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

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

                // Use the ETag from the SharePoint item to compare it against the local database config etag to see if the content has changed
                if (!forceSync && eTag == databaseConfig.ETag)
                {
                    updateStatus(string.Format("KeePass database {0} is in sync", databaseConfig.KeePassDatabase.Name));

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

                    return(false);
                }

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

                var temporaryKeePassDatabasePath = System.IO.Path.GetTempFileName();
                var downloadSuccessful           = DownloadFile(temporaryKeePassDatabasePath, serverRelativeSharePointUrl, httpClient);

                if (!await downloadSuccessful)
                {
                    updateStatus(string.Format("Failed to download the KeePass database {0} from SharePoint", 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(string.Format("Unable to merge the KeePass database {0}. 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 SharePoint site with your local database, select Yes, otherwise select No.", databaseConfig.KeePassDatabase.Name), "Confirm overwriting your KeePass database", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2);
                    if (confirm != DialogResult.Yes)
                    {
                        return(false);
                    }

                    // Upload the local database
                    updateStatus(string.Format("Uploading the local KeePass database {0} to SharePoint", databaseConfig.KeePassDatabase.Name));

                    localDatabaseToUpload = databaseConfig.KeePassDatabase.IOConnectionInfo.Path;
                }
                else
                {
                    // Upload the synced database
                    updateStatus(string.Format("Uploading the merged KeePass database {0} to SharePoint", databaseConfig.KeePassDatabase.Name));

                    localDatabaseToUpload = temporaryKeePassDatabasePath;
                }

                var uploadResult = await UploadFile(localDatabaseToUpload, databaseConfig.RemoteFolderId, databaseConfig.RemoteFileName, httpClient);

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

                databaseConfig.ETag = uploadResult;
                return(true);
            }
        }
        /// <summary>
        /// Uses the Microsoft SharePoint platform (SharePoint 2013, 2016 or Online) 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> SyncUsingSharePointPlatform(Configuration databaseConfig, string localKeePassDatabasePath, bool forceSync, Action <string> updateStatus)
        {
            if (!await EnsureSharePointCredentials(databaseConfig))
            {
                return(false);
            }

            using (var httpClient = CreateSharePointHttpClient(databaseConfig))
            {
                // Check if we have a Document Library on SharePoint to sync with
                if (string.IsNullOrEmpty(databaseConfig.RemoteFolderId) && string.IsNullOrEmpty(databaseConfig.RemoteFileName))
                {
                    // Ask the user where to store the database on SharePoint
                    var sharePointDocumentLibraryPickerDialog = new Forms.SharePointDocumentLibraryPickerDialog(httpClient);
                    await sharePointDocumentLibraryPickerDialog.LoadDocumentLibraryItems();

                    sharePointDocumentLibraryPickerDialog.FileName = !string.IsNullOrEmpty(databaseConfig.RemoteFileName) ? databaseConfig.RemoteFileName : new System.IO.FileInfo(localKeePassDatabasePath).Name;
                    var result = sharePointDocumentLibraryPickerDialog.ShowDialog();
                    if (result != DialogResult.OK || string.IsNullOrEmpty(sharePointDocumentLibraryPickerDialog.SelectedDocumentLibraryServerRelativeUrl))
                    {
                        return(false);
                    }
                    databaseConfig.RemoteFolderId = sharePointDocumentLibraryPickerDialog.SelectedDocumentLibraryServerRelativeUrl;
                    databaseConfig.RemoteFileName = sharePointDocumentLibraryPickerDialog.FileName;
                    Configuration.Save();
                }

                // Ensure we have the SharePoint site name
                if (string.IsNullOrEmpty(databaseConfig.OneDriveName))
                {
                    // We don't have the SharePoint site name yet, retrieve it now by triggering TestConnection
                    await TestConnection(httpClient, databaseConfig);

                    Configuration.Save();
                }

                // Retrieve the KeePass database from SharePoint
                var serverRelativeSharePointUrl = string.Concat(databaseConfig.RemoteFolderId, "/", databaseConfig.RemoteFileName);
                var eTag = await GetEtagOfFile(httpClient, serverRelativeSharePointUrl);

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

                    // Upload the database to SharePoint
                    eTag = await UploadFile(databaseConfig.KeePassDatabase.IOConnectionInfo.Path, databaseConfig.RemoteFolderId, databaseConfig.RemoteFileName, httpClient);

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

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

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

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

                    return(false);
                }

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

                var temporaryKeePassDatabasePath = System.IO.Path.GetTempFileName();
                var downloadSuccessful           = DownloadFile(temporaryKeePassDatabasePath, serverRelativeSharePointUrl, httpClient);

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

                    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(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.");

                    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 SharePoint");

                var uploadResult = await UploadFile(temporaryKeePassDatabasePath, databaseConfig.RemoteFolderId, databaseConfig.RemoteFileName, httpClient);

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

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

                databaseConfig.ETag = uploadResult;
                return(true);
            }
        }