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