├── AMAZON_S3.md ├── ChangeLog.md ├── KeePassSync.sln ├── KeePassSync ├── Forms │ ├── AccountEntryGenerator.Designer.cs │ ├── AccountEntryGenerator.cs │ ├── AccountEntryGenerator.resx │ ├── OpenDbForm.Designer.cs │ ├── OpenDbForm.cs │ ├── OpenDbForm.resx │ ├── OpenForm.Designer.cs │ ├── OpenForm.cs │ ├── OpenForm.resx │ ├── OptionsForm.Designer.cs │ ├── OptionsForm.cs │ ├── OptionsForm.resx │ ├── SelectDatabaseForm.Designer.cs │ ├── SelectDatabaseForm.cs │ └── SelectDatabaseForm.resx ├── Interfaces │ ├── IOnlineProvider.cs │ └── IOptionsProvider.cs ├── KeePassSupport.cs ├── KeePassSync.csproj ├── MainInterface.cs ├── OptionsProvider_Registry.cs ├── Options_Registry.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Providers │ ├── S3 │ │ ├── AccountDetails.cs │ │ ├── AccountDetails.designer.cs │ │ ├── AccountDetails.resx │ │ ├── OurAmazonS3Client.cs │ │ └── S3Provider.cs │ └── SFTP │ │ ├── AccountDetails.Designer.cs │ │ ├── AccountDetails.cs │ │ ├── AccountDetails.resx │ │ └── main.cs ├── Resources │ └── Icons │ │ ├── Img_16x16_Open.png │ │ ├── Img_16x16_Options.png │ │ ├── Img_16x16_Plugin.png │ │ ├── Img_16x16_Sync.png │ │ ├── Img_48x48_Open.png │ │ ├── Img_48x48_Password.png │ │ ├── Img_48x48_Sync.png │ │ └── icons_url.txt ├── Util.cs └── app.config ├── LICENSE.txt ├── README.md └── Support ├── PLINK.EXE └── pscp.exe /AMAZON_S3.md: -------------------------------------------------------------------------------- 1 | # Amazon S3 (or compatible) Setup 2 | 3 | 4 | 5 | - [Non Amazon, S3 Compatible services](#non-amazon-s3-compatible-services) 6 | - [Setup for Cloudflare R2](#setup-for-cloudflare-r2) 7 | - [Setup for Backblaze B2](#setup-for-backblaze-b2) 8 | - [Standard Amazon s3 setup](#standard-amazon-s3-setup) 9 | - [Generate an access key user and get users ARN:](#generate-an-access-key-user-and-get-users-arn) 10 | - [Add the users permissions to a new \(or existing\) S3 storage bucket](#add-the-users-permissions-to-a-new-or-existing-s3-storage-bucket) 11 | 12 | 13 | 14 | 15 | ## Non Amazon, S3 Compatible services 16 | For Amazon S3 compatible storage services you will need to see that company's documentation for how to create a storage bucket and setup an access key. A few examples are below. NOTE: Not all providers support ACL/checksums so you may need to disable these features in the keepass options to use it. For a partial list of S3 compatible providers see: https://rclone.org/s3/ 17 | 18 | ## Setup for Cloudflare R2 19 | - Go to: https://dash.cloudflare.com/sign-up/r2 and create an account 20 | - Go to the R2 buckets page: https://dash.cloudflare.com/?to=/:account/r2 and click "Create bucket" 21 | - Name the bucket whatever you want, just copy this name down. You can leave location on automatic. Then click "Create Bucket". 22 | - Go to the R2 API Token page https://dash.cloudflare.com/?to=/:account/r2/api-tokens and click "Create API token" 23 | - Name the token anything you like, for permissions you can just do " 24 | Object Read & Write", under "Specify bucket(s)" click "Apply to specific buckets only 25 | " and select the bucket you just created. Leave the other items at default and click "Create API Token" 26 | - Copy the access key id, secret access key, and the "jurisdiction-specific endpoints for S3 Client" url (this is the service url). 27 | - Enter these 3 items in KeePassSync options. 28 | 29 | 30 | ## Setup for Backblaze B2 31 | 32 | - Go to: https://www.backblaze.com/cloud-storage and signup (make sure to choose a region from the dropdown below and on the right side of the "Sign Up Now" button (or you will get an odd error). 33 | - Once signed in go to: https://secure.backblaze.com/b2_buckets.htm and click "Create a Bucket". Name it whatever you would like, leave "Files in Bucket are" set to private, set the encryption to enabled if you like (not required) do NOT enable object lock. click "Create a Bucket" 34 | - One the bucket is created you will be taken back to your bucket list page. From here copy the endpoint url (ie: s3.us-west-007.backblazeb2.com). 35 | - Next click the "How to connect to this bucket" in the box showing that bucket on the bucket list. click "Create an app key". 36 | - On the app key page click "Add a New Application Key" give the key whatever name you want. You just need to copy the "Key ID" and the "Application key" and put these into keepass sync (along with the endpoint URL from above). 37 | - Enter these 3 items in KeePassSync options. 38 | 39 | 40 | ## Standard Amazon s3 setup 41 | You can give the user the ability to create buckets then you can just create the user and KPSync will do the rest, but a more secure way is to create the bucket yourself. There may be an easier way to do this but this will work: 42 | 43 | ### Generate an access key user and get users ARN: 44 | - Login to AWS on your account click your name in the upper right, go to Security Credentials. 45 | - Click users under Access Management on the left. 46 | - Click "Create User" button on the right. 47 | - Create a random username, it doesn't matter. 48 | - Click "Attach Policies Directly" and then just click "next" at the bottom right to not assign any properties. 49 | - Click "Create User" 50 | - Click on the user on the users list 51 | - Click "Security Credentials" on that page. 52 | - CLick "Create Access Key" near the bottom right" 53 | - Click "Other" 54 | - For "Description tag value" but whatever you like, ie "for keepass". 55 | - On the next page Copy the access key ID and secret to paste into keepass later, copy their ARN from the upper left on the page (should start with "arn:aws....") 56 | 57 | 58 | ### Add the users permissions to a new (or existing) S3 storage bucket 59 | 60 | - Next on the top left click "Services" go to storage and S3. 61 | - Click "Create Bucket", git it a name under bucket name, leave ACL's disabled, block all public access (checked by default) 62 | - Leave all other settings default and click create bucket. 63 | - Click on the new bucket in the list, click permissions, click edit next to bucket policy 64 | - Edit the bucket policy below replacing the one spot it says `USER_ARN_HERE` with your users arn, and then under resource replace the two `BUCKET_NAME_HERE` strings with the new buckets name, BE SURE not to edit the items before or after `BUCKET_NAME_HERE` they are required. 65 | ```json 66 | { 67 | "Version": "2012-10-17", 68 | "Statement": [ 69 | { 70 | "Sid": "PrimaryAccess", 71 | "Effect": "Allow", 72 | "Principal": { 73 | "AWS": "USER_ARN_HERE" 74 | }, 75 | "Action": [ 76 | "s3:ListBucket", 77 | "s3:PutObjectAcl", 78 | "s3:GetObject", 79 | "s3:GetObjectAcl", 80 | "s3:PutObject" 81 | ], 82 | "Resource": [ 83 | "arn:aws:s3:::BUCKET_NAME_HERE/*", 84 | "arn:aws:s3:::BUCKET_NAME_HERE" 85 | ] 86 | } 87 | ] 88 | } 89 | ``` 90 | 91 | - Click Save and now try putting the bucket name and key information into keepass sync! -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | 2024-07-10: v8.2 2 | - For SFTP check the application directory for keepass for psftp binaries 3 | - 4 | 5 | 2024-02-17: v8.1 6 | - Don't auto-lowercase S3 bucket names, legacy allows different cases 7 | - Don't compare sha1 hashes when they don't exist (legacy kpsync uploads) 8 | 9 | 2024-02-17: v8.0 10 | - Amazon S3 updated to use SDK 11 | - Project style changed and updated 12 | - DigitalBucket removed (adios) 13 | - Added update checks 14 | - Project migrated to GitHub and git 15 | - Use amazing PlgxBuildTasks to modernize plgx building 16 | 17 | 18 | 2016-04-01: v6.10 19 | - Unreleased, get databases in S3, minor other S3 updates, migration to .net 4.5 20 | 21 | 2012-01-16: v6.0 22 | - Compat with keepass 2.18 and higher 23 | - S3 permission preservation 24 | 25 | 2009-03-10: v2.11 26 | - Plugin distributed as PLGX rather than dll 27 | - Moved stock providers to be inside of main project 28 | - Now compatible with old versions from 2.09 or higher 29 | 30 | 31 | 2009-05-03: v2.10.1 32 | - DigitalBucket: Fixed New Database Initialization 33 | - SFTP: Added Key Authentication through option to use Paegent 34 | - SFTP: Command line arguments are now quoted so support spacing 35 | - SFTP: Added configurable timeout 36 | - SFTP: Added ability to change path for executables 37 | - SFTP: Added debug mode 38 | - SFTP: Added ability to set port for host 39 | - SFTP: Code Cleanup 40 | 41 | 42 | 2009-03-10: v2.10 43 | - Compatible with KeePass v2.10 44 | 45 | 2009-02-20: v2.09 46 | - Compatible with KeePass v2.09 47 | - Fixes to Double Creation Entries and Editing Problems 48 | - Fixes to Setup 49 | - Amazon S3 Provider Added 50 | - Background Sync Support 51 | 52 | 53 | 2009-03-14: v2.07 54 | - Compatible with KeePass v2.07 Beta 55 | 56 | 2008-11-02: v2.06 57 | - Compatible with KeePass v2.06 Beta 58 | 59 | 2008-08-06: v2.05.2 60 | - On open of DB, temp entry no longer hangs around 61 | - On first creation of syncEntry in database, sync doesn't fail because mergeIn() can't find file 62 | - On save, we sync, not just export. 63 | - Default button on openForm correct 64 | - On options form, switching providers now changes the entry in the edit entry form 65 | - Detects timeout with FTP/SCP provider 66 | - When plugins are in a subdirectory, KeePassSync still works 67 | - Completely removed ProviderInfo references 68 | - Providers are only initialized once at startup 69 | - Providers are only stored within the main interface, all other references just use a key and go through the main interface 70 | - Ripped out redundant ProviderInfo struct 71 | - Visual Studio solution now in VS2008 format 72 | - Unified options GUI for multiple online providers. 73 | - New FTP/SCP provider using Putty's plink.exe and pscp.exe 74 | - Fixed many stability bugs for options dialog 75 | - Changed the name of DigitalBucket to digitalbucket.net 76 | - Fixed crash when no KeePassSync providers are present 77 | - Updated docs 78 | - Added documents directory to the tree 79 | 80 | 81 | 2008-05-27: v2.05.1 82 | - Added documents to the tree and release packages 83 | - Removed reliance upon registry, it's still used but not required 84 | - Fixed issue of not being able to find login info after opening file from online provider 85 | - Cleaned up options interface. 86 | - Better code documentation 87 | - Post build events 88 | - Copyright info 89 | 90 | 2008-05-12: v2.05 91 | - Project started -------------------------------------------------------------------------------- /KeePassSync.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26014.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassSync", "KeePassSync\KeePassSync.csproj", "{B9CECCA9-6C93-4278-AB8E-C15628DB852C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {B9CECCA9-6C93-4278-AB8E-C15628DB852C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {B9CECCA9-6C93-4278-AB8E-C15628DB852C}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {B9CECCA9-6C93-4278-AB8E-C15628DB852C}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {B9CECCA9-6C93-4278-AB8E-C15628DB852C}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /KeePassSync/Forms/AccountEntryGenerator.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeePassSync.Forms { 2 | partial class AccountEntryGenerator { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose(bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose(); 15 | } 16 | base.Dispose(disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent() { 26 | this.m_BannerImage = new System.Windows.Forms.PictureBox(); 27 | this.button1 = new System.Windows.Forms.Button(); 28 | this.button2 = new System.Windows.Forms.Button(); 29 | this.m_CustomPanel = new System.Windows.Forms.GroupBox(); 30 | this.panel1 = new System.Windows.Forms.Panel(); 31 | ((System.ComponentModel.ISupportInitialize)(this.m_BannerImage)).BeginInit(); 32 | this.m_CustomPanel.SuspendLayout(); 33 | this.SuspendLayout(); 34 | // 35 | // m_BannerImage 36 | // 37 | this.m_BannerImage.Cursor = System.Windows.Forms.Cursors.Default; 38 | this.m_BannerImage.Dock = System.Windows.Forms.DockStyle.Top; 39 | this.m_BannerImage.Location = new System.Drawing.Point(0, 0); 40 | this.m_BannerImage.Name = "m_BannerImage"; 41 | this.m_BannerImage.Size = new System.Drawing.Size(335, 60); 42 | this.m_BannerImage.TabIndex = 0; 43 | this.m_BannerImage.TabStop = false; 44 | // 45 | // button1 46 | // 47 | this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 48 | this.button1.Location = new System.Drawing.Point(167, 294); 49 | this.button1.Name = "button1"; 50 | this.button1.Size = new System.Drawing.Size(75, 23); 51 | this.button1.TabIndex = 0; 52 | this.button1.Text = "Save"; 53 | this.button1.UseVisualStyleBackColor = true; 54 | this.button1.Click += new System.EventHandler(this.button1_Click); 55 | // 56 | // button2 57 | // 58 | this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 59 | this.button2.Location = new System.Drawing.Point(248, 294); 60 | this.button2.Name = "button2"; 61 | this.button2.Size = new System.Drawing.Size(75, 23); 62 | this.button2.TabIndex = 1; 63 | this.button2.Text = "Cancel"; 64 | this.button2.UseVisualStyleBackColor = true; 65 | this.button2.Click += new System.EventHandler(this.button2_Click); 66 | // 67 | // m_CustomPanel 68 | // 69 | this.m_CustomPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 70 | | System.Windows.Forms.AnchorStyles.Left) 71 | | System.Windows.Forms.AnchorStyles.Right))); 72 | this.m_CustomPanel.Controls.Add(this.panel1); 73 | this.m_CustomPanel.Location = new System.Drawing.Point(12, 66); 74 | this.m_CustomPanel.Name = "m_CustomPanel"; 75 | this.m_CustomPanel.Size = new System.Drawing.Size(311, 222); 76 | this.m_CustomPanel.TabIndex = 2; 77 | this.m_CustomPanel.TabStop = false; 78 | this.m_CustomPanel.Text = "Account Details"; 79 | this.m_CustomPanel.Enter += new System.EventHandler(this.m_CustomPanel_Enter); 80 | // 81 | // panel1 82 | // 83 | this.panel1.AutoScroll = true; 84 | this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; 85 | this.panel1.Location = new System.Drawing.Point(3, 16); 86 | this.panel1.Name = "panel1"; 87 | this.panel1.Size = new System.Drawing.Size(305, 203); 88 | this.panel1.TabIndex = 0; 89 | // 90 | // AccountEntryGenerator 91 | // 92 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 93 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 94 | this.ClientSize = new System.Drawing.Size(335, 329); 95 | this.Controls.Add(this.m_CustomPanel); 96 | this.Controls.Add(this.button1); 97 | this.Controls.Add(this.button2); 98 | this.Controls.Add(this.m_BannerImage); 99 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 100 | this.Name = "AccountEntryGenerator"; 101 | this.Text = "Entry Generator"; 102 | this.Load += new System.EventHandler(this.EntryGenerator_Load); 103 | ((System.ComponentModel.ISupportInitialize)(this.m_BannerImage)).EndInit(); 104 | this.m_CustomPanel.ResumeLayout(false); 105 | this.ResumeLayout(false); 106 | 107 | } 108 | 109 | #endregion 110 | 111 | private System.Windows.Forms.PictureBox m_BannerImage; 112 | private System.Windows.Forms.Button button1; 113 | private System.Windows.Forms.Button button2; 114 | private System.Windows.Forms.GroupBox m_CustomPanel; 115 | private System.Windows.Forms.Panel panel1; 116 | } 117 | } -------------------------------------------------------------------------------- /KeePassSync/Forms/AccountEntryGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Text; 7 | using System.Windows.Forms; 8 | using KeePassLib; 9 | 10 | namespace KeePassSync.Forms { 11 | public partial class AccountEntryGenerator : Form { 12 | private KeePassSyncExt m_MainInterface = null; 13 | private IOnlineProvider m_OnlineProvider = null; 14 | 15 | public AccountEntryGenerator(KeePassSyncExt mainInterface, IOnlineProvider onlineProvider) { 16 | InitializeComponent(); 17 | m_MainInterface = mainInterface; 18 | m_OnlineProvider = onlineProvider; 19 | 20 | panel1.Controls.Add(m_OnlineProvider.GetUserControl()); 21 | } 22 | 23 | private void ResizeDialog() { 24 | int maxWidth = 500; 25 | int maxHeight = 700; 26 | 27 | int panelHeight = panel1.Size.Height; 28 | int panelWidth = panel1.Size.Width; 29 | 30 | int diffHeight = m_OnlineProvider.GetUserControl().Size.Height - panelHeight; 31 | int diffWidth = m_OnlineProvider.GetUserControl().Size.Width - panelWidth; 32 | 33 | if (diffHeight < 0 || (diffHeight + panelHeight > maxHeight)) 34 | diffHeight = 0; 35 | 36 | if (diffWidth < 0 || (diffWidth + panelWidth > maxWidth)) 37 | diffWidth = 0; 38 | 39 | this.Size = this.Size + new System.Drawing.Size(diffWidth, diffHeight); 40 | 41 | } 42 | 43 | private void EntryGenerator_Load(object sender, EventArgs e) { 44 | ResizeDialog(); 45 | 46 | m_BannerImage.Image = KeePass.UI.BannerFactory.CreateBanner(m_BannerImage.Width, 47 | m_BannerImage.Height, KeePass.UI.BannerStyle.Default, Properties.Resources.Img_48x48_Sync, 48 | "KeePassSync Entry Editor", 49 | "This will create/edit an entry for the provider"); 50 | 51 | this.Icon = m_MainInterface.Host.MainWindow.Icon; 52 | this.Left = m_MainInterface.Host.MainWindow.Left + (m_MainInterface.Host.MainWindow.Width - this.Width) / 2; 53 | this.Top = m_MainInterface.Host.MainWindow.Top + (m_MainInterface.Host.MainWindow.Height - this.Height) / 2; 54 | } 55 | 56 | // @todo internal? 57 | public void EncodeEntry(PwEntry entry) { 58 | m_OnlineProvider.EncodeEntry(entry); 59 | } 60 | 61 | // @todo internal? 62 | public void DecodeEntry(PwEntry entry) { 63 | m_OnlineProvider.DecodeEntry(entry); 64 | } 65 | 66 | private void button2_Click(object sender, EventArgs e) { 67 | DialogResult = DialogResult.Cancel; 68 | this.Close(); 69 | } 70 | 71 | private void button1_Click(object sender, EventArgs e) { 72 | DialogResult = DialogResult.OK; 73 | this.Close(); 74 | } 75 | 76 | private void m_CustomPanel_Enter(object sender, EventArgs e) { 77 | 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /KeePassSync/Forms/AccountEntryGenerator.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /KeePassSync/Forms/OpenDbForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeePassSync.Forms { 2 | partial class OpenDbForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose(bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose(); 15 | } 16 | base.Dispose(disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent() { 26 | this.m_BannerImage = new System.Windows.Forms.PictureBox(); 27 | this.label1 = new System.Windows.Forms.Label(); 28 | this.m_cboProvider = new System.Windows.Forms.ComboBox(); 29 | this.label2 = new System.Windows.Forms.Label(); 30 | this.m_btnStoreCreate = new System.Windows.Forms.Button(); 31 | this.button1 = new System.Windows.Forms.Button(); 32 | this.button2 = new System.Windows.Forms.Button(); 33 | ((System.ComponentModel.ISupportInitialize)(this.m_BannerImage)).BeginInit(); 34 | this.SuspendLayout(); 35 | // 36 | // m_BannerImage 37 | // 38 | this.m_BannerImage.Dock = System.Windows.Forms.DockStyle.Top; 39 | this.m_BannerImage.Location = new System.Drawing.Point(0, 0); 40 | this.m_BannerImage.Name = "m_BannerImage"; 41 | this.m_BannerImage.Size = new System.Drawing.Size(378, 60); 42 | this.m_BannerImage.TabIndex = 0; 43 | this.m_BannerImage.TabStop = false; 44 | // 45 | // label1 46 | // 47 | this.label1.AutoSize = true; 48 | this.label1.Location = new System.Drawing.Point(12, 63); 49 | this.label1.MaximumSize = new System.Drawing.Size(350, 0); 50 | this.label1.Name = "label1"; 51 | this.label1.Size = new System.Drawing.Size(81, 13); 52 | this.label1.TabIndex = 12; 53 | this.label1.Text = "Select provider:"; 54 | // 55 | // m_cboProvider 56 | // 57 | this.m_cboProvider.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 58 | this.m_cboProvider.FormattingEnabled = true; 59 | this.m_cboProvider.Location = new System.Drawing.Point(12, 79); 60 | this.m_cboProvider.Name = "m_cboProvider"; 61 | this.m_cboProvider.Size = new System.Drawing.Size(354, 21); 62 | this.m_cboProvider.TabIndex = 11; 63 | // 64 | // label2 65 | // 66 | this.label2.AutoSize = true; 67 | this.label2.Location = new System.Drawing.Point(12, 138); 68 | this.label2.MaximumSize = new System.Drawing.Size(350, 0); 69 | this.label2.Name = "label2"; 70 | this.label2.Size = new System.Drawing.Size(349, 26); 71 | this.label2.TabIndex = 12; 72 | this.label2.Text = "Note: To connect to the provider, a temporary KeePass entry is needed. This will" + 73 | " not be stored in any database."; 74 | // 75 | // m_btnStoreCreate 76 | // 77 | this.m_btnStoreCreate.Location = new System.Drawing.Point(12, 106); 78 | this.m_btnStoreCreate.Name = "m_btnStoreCreate"; 79 | this.m_btnStoreCreate.Size = new System.Drawing.Size(101, 23); 80 | this.m_btnStoreCreate.TabIndex = 0; 81 | this.m_btnStoreCreate.Text = "Create Entry..."; 82 | this.m_btnStoreCreate.UseVisualStyleBackColor = true; 83 | // 84 | // button1 85 | // 86 | this.button1.Location = new System.Drawing.Point(210, 177); 87 | this.button1.Name = "button1"; 88 | this.button1.Size = new System.Drawing.Size(75, 23); 89 | this.button1.TabIndex = 13; 90 | this.button1.Text = "OK"; 91 | this.button1.UseVisualStyleBackColor = true; 92 | // 93 | // button2 94 | // 95 | this.button2.Location = new System.Drawing.Point(291, 177); 96 | this.button2.Name = "button2"; 97 | this.button2.Size = new System.Drawing.Size(75, 23); 98 | this.button2.TabIndex = 14; 99 | this.button2.Text = "Cancel"; 100 | this.button2.UseVisualStyleBackColor = true; 101 | // 102 | // OpenDbForm 103 | // 104 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 105 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 106 | this.ClientSize = new System.Drawing.Size(378, 212); 107 | this.Controls.Add(this.button2); 108 | this.Controls.Add(this.button1); 109 | this.Controls.Add(this.label1); 110 | this.Controls.Add(this.m_btnStoreCreate); 111 | this.Controls.Add(this.m_cboProvider); 112 | this.Controls.Add(this.label2); 113 | this.Controls.Add(this.m_BannerImage); 114 | this.Name = "OpenDbForm"; 115 | this.Text = "OpenDbForm"; 116 | this.Load += new System.EventHandler(this.OpenDbForm_Load); 117 | ((System.ComponentModel.ISupportInitialize)(this.m_BannerImage)).EndInit(); 118 | this.ResumeLayout(false); 119 | this.PerformLayout(); 120 | 121 | } 122 | 123 | #endregion 124 | 125 | private System.Windows.Forms.PictureBox m_BannerImage; 126 | private System.Windows.Forms.Label label1; 127 | private System.Windows.Forms.ComboBox m_cboProvider; 128 | private System.Windows.Forms.Label label2; 129 | private System.Windows.Forms.Button m_btnStoreCreate; 130 | private System.Windows.Forms.Button button1; 131 | private System.Windows.Forms.Button button2; 132 | } 133 | } -------------------------------------------------------------------------------- /KeePassSync/Forms/OpenDbForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Text; 7 | using System.Windows.Forms; 8 | 9 | namespace KeePassSync.Forms { 10 | public partial class OpenDbForm : Form { 11 | private KeePassSyncExt m_MainInterface; 12 | 13 | private OpenDbForm() { 14 | } 15 | 16 | public OpenDbForm(KeePassSyncExt mainInterface) { 17 | m_MainInterface = mainInterface; 18 | InitializeComponent(); 19 | } 20 | 21 | private void OpenDbForm_Load(object sender, EventArgs e) { 22 | m_BannerImage.Image = KeePass.UI.BannerFactory.CreateBanner(m_BannerImage.Width, 23 | m_BannerImage.Height, KeePass.UI.BannerStyle.Default, Properties.Resources.Img_48x48_Password, 24 | "Open Online Database", 25 | "Please enter your " + m_MainInterface.OnlineProvider.Name + " account information."); 26 | 27 | this.Icon = m_MainInterface.Host.MainWindow.Icon; 28 | 29 | this.Left = m_MainInterface.Host.MainWindow.Left + (m_MainInterface.Host.MainWindow.Width - this.Width) / 2; 30 | this.Top = m_MainInterface.Host.MainWindow.Top + (m_MainInterface.Host.MainWindow.Height - this.Height) / 2; 31 | 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /KeePassSync/Forms/OpenDbForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /KeePassSync/Forms/OpenForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeePassSync.Forms { 2 | partial class OpenForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose(bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose(); 15 | } 16 | base.Dispose(disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent() { 26 | this.m_BannerImage = new System.Windows.Forms.PictureBox(); 27 | this.m_btnOk = new System.Windows.Forms.Button(); 28 | this.m_btnCancel = new System.Windows.Forms.Button(); 29 | this.m_CustomPanel = new System.Windows.Forms.GroupBox(); 30 | this.panel1 = new System.Windows.Forms.Panel(); 31 | this.m_grpOnlineProvider = new System.Windows.Forms.GroupBox(); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.m_cboProvider = new System.Windows.Forms.ComboBox(); 34 | this.m_lnkCreateAccount = new System.Windows.Forms.LinkLabel(); 35 | ((System.ComponentModel.ISupportInitialize)(this.m_BannerImage)).BeginInit(); 36 | this.m_CustomPanel.SuspendLayout(); 37 | this.m_grpOnlineProvider.SuspendLayout(); 38 | this.SuspendLayout(); 39 | // 40 | // m_BannerImage 41 | // 42 | this.m_BannerImage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 43 | | System.Windows.Forms.AnchorStyles.Right))); 44 | this.m_BannerImage.Location = new System.Drawing.Point(0, 0); 45 | this.m_BannerImage.Name = "m_BannerImage"; 46 | this.m_BannerImage.Size = new System.Drawing.Size(390, 60); 47 | this.m_BannerImage.TabIndex = 0; 48 | this.m_BannerImage.TabStop = false; 49 | // 50 | // m_btnOk 51 | // 52 | this.m_btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 53 | this.m_btnOk.Location = new System.Drawing.Point(222, 388); 54 | this.m_btnOk.Name = "m_btnOk"; 55 | this.m_btnOk.Size = new System.Drawing.Size(75, 23); 56 | this.m_btnOk.TabIndex = 5; 57 | this.m_btnOk.Text = "OK"; 58 | this.m_btnOk.UseVisualStyleBackColor = true; 59 | this.m_btnOk.Click += new System.EventHandler(this.m_btnOk_Click); 60 | // 61 | // m_btnCancel 62 | // 63 | this.m_btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 64 | this.m_btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; 65 | this.m_btnCancel.Location = new System.Drawing.Point(303, 388); 66 | this.m_btnCancel.Name = "m_btnCancel"; 67 | this.m_btnCancel.Size = new System.Drawing.Size(75, 23); 68 | this.m_btnCancel.TabIndex = 6; 69 | this.m_btnCancel.Text = "Cancel"; 70 | this.m_btnCancel.UseVisualStyleBackColor = true; 71 | this.m_btnCancel.Click += new System.EventHandler(this.m_btnCancel_Click); 72 | // 73 | // m_CustomPanel 74 | // 75 | this.m_CustomPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 76 | | System.Windows.Forms.AnchorStyles.Left) 77 | | System.Windows.Forms.AnchorStyles.Right))); 78 | this.m_CustomPanel.Controls.Add(this.panel1); 79 | this.m_CustomPanel.Location = new System.Drawing.Point(12, 178); 80 | this.m_CustomPanel.Name = "m_CustomPanel"; 81 | this.m_CustomPanel.Size = new System.Drawing.Size(365, 204); 82 | this.m_CustomPanel.TabIndex = 8; 83 | this.m_CustomPanel.TabStop = false; 84 | this.m_CustomPanel.Text = "Account Details"; 85 | // 86 | // panel1 87 | // 88 | this.panel1.AutoScroll = true; 89 | this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; 90 | this.panel1.Location = new System.Drawing.Point(3, 16); 91 | this.panel1.Name = "panel1"; 92 | this.panel1.Size = new System.Drawing.Size(359, 185); 93 | this.panel1.TabIndex = 0; 94 | // 95 | // m_grpOnlineProvider 96 | // 97 | this.m_grpOnlineProvider.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 98 | | System.Windows.Forms.AnchorStyles.Right))); 99 | this.m_grpOnlineProvider.Controls.Add(this.label1); 100 | this.m_grpOnlineProvider.Controls.Add(this.m_cboProvider); 101 | this.m_grpOnlineProvider.Controls.Add(this.m_lnkCreateAccount); 102 | this.m_grpOnlineProvider.Location = new System.Drawing.Point(12, 66); 103 | this.m_grpOnlineProvider.Name = "m_grpOnlineProvider"; 104 | this.m_grpOnlineProvider.Size = new System.Drawing.Size(365, 106); 105 | this.m_grpOnlineProvider.TabIndex = 14; 106 | this.m_grpOnlineProvider.TabStop = false; 107 | this.m_grpOnlineProvider.Text = "Online Provider"; 108 | // 109 | // label1 110 | // 111 | this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 112 | | System.Windows.Forms.AnchorStyles.Right))); 113 | this.label1.AutoSize = true; 114 | this.label1.Location = new System.Drawing.Point(8, 18); 115 | this.label1.MaximumSize = new System.Drawing.Size(350, 0); 116 | this.label1.Name = "label1"; 117 | this.label1.Size = new System.Drawing.Size(337, 26); 118 | this.label1.TabIndex = 12; 119 | this.label1.Text = "These are online services that store your data. Most are free, be sure you choos" + 120 | "e a provider from a source you trust."; 121 | // 122 | // m_cboProvider 123 | // 124 | this.m_cboProvider.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 125 | | System.Windows.Forms.AnchorStyles.Right))); 126 | this.m_cboProvider.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 127 | this.m_cboProvider.FormattingEnabled = true; 128 | this.m_cboProvider.Location = new System.Drawing.Point(6, 56); 129 | this.m_cboProvider.Name = "m_cboProvider"; 130 | this.m_cboProvider.Size = new System.Drawing.Size(353, 21); 131 | this.m_cboProvider.TabIndex = 11; 132 | this.m_cboProvider.SelectionChangeCommitted += new System.EventHandler(this.OnCboProviderSelectionChangeCommitted); 133 | this.m_cboProvider.SelectedIndexChanged += new System.EventHandler(this.OnCboProviderSelectionChangeCommitted); 134 | // 135 | // m_lnkCreateAccount 136 | // 137 | this.m_lnkCreateAccount.AutoSize = true; 138 | this.m_lnkCreateAccount.Enabled = false; 139 | this.m_lnkCreateAccount.Location = new System.Drawing.Point(6, 80); 140 | this.m_lnkCreateAccount.Name = "m_lnkCreateAccount"; 141 | this.m_lnkCreateAccount.Size = new System.Drawing.Size(104, 13); 142 | this.m_lnkCreateAccount.TabIndex = 8; 143 | this.m_lnkCreateAccount.TabStop = true; 144 | this.m_lnkCreateAccount.Text = "Create an account..."; 145 | this.m_lnkCreateAccount.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLblCreateAccountClicked); 146 | // 147 | // OpenForm 148 | // 149 | this.AcceptButton = this.m_btnOk; 150 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 151 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 152 | this.CancelButton = this.m_btnCancel; 153 | this.ClientSize = new System.Drawing.Size(390, 423); 154 | this.Controls.Add(this.m_grpOnlineProvider); 155 | this.Controls.Add(this.m_CustomPanel); 156 | this.Controls.Add(this.m_btnCancel); 157 | this.Controls.Add(this.m_btnOk); 158 | this.Controls.Add(this.m_BannerImage); 159 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 160 | this.MaximizeBox = false; 161 | this.MinimizeBox = false; 162 | this.Name = "OpenForm"; 163 | this.ShowInTaskbar = false; 164 | this.Text = "Open Online Database"; 165 | this.Load += new System.EventHandler(this.OpenForm_Load); 166 | ((System.ComponentModel.ISupportInitialize)(this.m_BannerImage)).EndInit(); 167 | this.m_CustomPanel.ResumeLayout(false); 168 | this.m_grpOnlineProvider.ResumeLayout(false); 169 | this.m_grpOnlineProvider.PerformLayout(); 170 | this.ResumeLayout(false); 171 | 172 | } 173 | 174 | #endregion 175 | 176 | private System.Windows.Forms.PictureBox m_BannerImage; 177 | private System.Windows.Forms.Button m_btnOk; 178 | private System.Windows.Forms.Button m_btnCancel; 179 | private System.Windows.Forms.GroupBox m_CustomPanel; 180 | private System.Windows.Forms.Panel panel1; 181 | private System.Windows.Forms.GroupBox m_grpOnlineProvider; 182 | private System.Windows.Forms.Label label1; 183 | private System.Windows.Forms.ComboBox m_cboProvider; 184 | private System.Windows.Forms.LinkLabel m_lnkCreateAccount; 185 | } 186 | } -------------------------------------------------------------------------------- /KeePassSync/Forms/OpenForm.cs: -------------------------------------------------------------------------------- 1 | /* 2 | KeePassSync - Online Sync Plugin for KeePass Password Safe 3 | Copyright (C) 2008 Shawn Casey, shawn.casey@gmail.com 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.ComponentModel; 23 | using System.Data; 24 | using System.Drawing; 25 | using System.Text; 26 | using System.Windows.Forms; 27 | 28 | using KeePassSync; 29 | using KeePass; 30 | using KeePassLib; 31 | 32 | 33 | namespace KeePassSync.Forms { 34 | public partial class OpenForm : Form { 35 | private KeePassSyncExt m_MainInterface; 36 | private string m_OnlineProviderKey; 37 | public string OnlineProviderKey { get { return m_OnlineProviderKey; } } 38 | 39 | private PwEntry m_Entry; 40 | public PwEntry Entry { 41 | get { return m_Entry; } 42 | set { m_Entry = (PwEntry)value.CloneDeep(); } 43 | } 44 | 45 | public OpenForm(KeePassSyncExt mainInterface) { 46 | m_MainInterface = mainInterface; 47 | InitializeComponent(); 48 | // only do this here so i initialize the key on new() 49 | PopulateComboBox(); 50 | } 51 | 52 | private OpenForm() { 53 | } 54 | 55 | private void RefreshBannerImage() { 56 | string subString = "Please enter your account information."; 57 | if (m_OnlineProviderKey != null) { 58 | subString = "Please enter your " + m_MainInterface.GetOnlineProvider(m_OnlineProviderKey).Name + " account information."; 59 | } 60 | 61 | m_BannerImage.Image = KeePass.UI.BannerFactory.CreateBanner(m_BannerImage.Width, 62 | m_BannerImage.Height, KeePass.UI.BannerStyle.Default, Properties.Resources.Img_48x48_Password, 63 | "Open Online Database", 64 | subString); 65 | } 66 | 67 | private void OpenForm_Load(object sender, EventArgs e) { 68 | RefreshBannerImage(); 69 | ResetForm(); 70 | 71 | this.Icon = m_MainInterface.Host.MainWindow.Icon; 72 | 73 | this.Left = m_MainInterface.Host.MainWindow.Left + (m_MainInterface.Host.MainWindow.Width - this.Width) / 2; 74 | this.Top = m_MainInterface.Host.MainWindow.Top + (m_MainInterface.Host.MainWindow.Height - this.Height) / 2; 75 | } 76 | 77 | private void m_btnCancel_Click(object sender, EventArgs e) { 78 | DialogResult = DialogResult.Cancel; 79 | m_Entry = null; 80 | this.Close(); 81 | } 82 | 83 | private void m_btnOk_Click(object sender, EventArgs e) { 84 | DialogResult = DialogResult.OK; 85 | if (m_OnlineProviderKey != null) { 86 | if (m_Entry == null) { 87 | m_Entry = new PwEntry(true, true); 88 | if (m_Entry == null) { 89 | m_MainInterface.SetStatus(StatusPriority.eMessageBoxInfo, "Couldn't create KeePass entry."); 90 | } 91 | } 92 | m_MainInterface.GetOnlineProvider(m_OnlineProviderKey).EncodeEntry(m_Entry); 93 | } else { 94 | m_MainInterface.SetStatus(StatusPriority.eMessageBoxInfo, "Provider key invalid."); 95 | } 96 | this.Close(); 97 | } 98 | 99 | public void DecodeEntry(PwEntry entry) { 100 | m_MainInterface.GetOnlineProvider(m_OnlineProviderKey).DecodeEntry(entry); 101 | } 102 | 103 | private void ResetForm() { 104 | PopulateComboBox(); 105 | RefreshGuiStates(); 106 | ResetAccountDetails(); 107 | } 108 | 109 | private void ResetAccountDetails() { 110 | panel1.Controls.Clear(); 111 | if (m_OnlineProviderKey != null) { 112 | panel1.Controls.Add(m_MainInterface.GetOnlineProvider(m_OnlineProviderKey).GetUserControl()); 113 | ResizeDialog(); 114 | panel1.Enabled = true; 115 | } else { 116 | panel1.Enabled = false; 117 | } 118 | } 119 | 120 | private void PopulateComboBox() { 121 | m_cboProvider.Items.Clear(); 122 | 123 | if (m_MainInterface.OnlineProviders.Length == 0) { 124 | m_cboProvider.Items.Add("No providers installed..."); 125 | } else { 126 | foreach (IOnlineProvider provider in m_MainInterface.OnlineProviders) { 127 | int index = m_cboProvider.Items.Add(provider); 128 | 129 | // Set the default 130 | if ((m_OnlineProviderKey != null) && (m_OnlineProviderKey == provider.Key)) { 131 | m_cboProvider.SelectedItem = m_cboProvider.Items[index]; 132 | } 133 | } 134 | } 135 | 136 | if (m_cboProvider.Items.Count > 0 && m_cboProvider.SelectedItem == null) { 137 | m_cboProvider.SelectedItem = m_cboProvider.Items[0]; 138 | } 139 | } 140 | 141 | private void ResizeDialog() { 142 | int maxWidth = 500; 143 | int maxHeight = 700; 144 | 145 | int panelHeight = panel1.Size.Height; 146 | int panelWidth = panel1.Size.Width; 147 | 148 | int diffHeight = m_MainInterface.GetOnlineProvider(m_OnlineProviderKey).GetUserControl().Size.Height - panelHeight; 149 | int diffWidth = m_MainInterface.GetOnlineProvider(m_OnlineProviderKey).GetUserControl().Size.Width - panelWidth; 150 | 151 | if (diffHeight < 0 || (diffHeight + panelHeight > maxHeight)) 152 | diffHeight = 0; 153 | 154 | if (diffWidth < 0 || (diffWidth + panelWidth > maxWidth)) 155 | diffWidth = 0; 156 | 157 | this.Size = this.Size + new System.Drawing.Size(diffWidth, diffHeight); 158 | 159 | RefreshBannerImage(); 160 | } 161 | 162 | private void RefreshGuiStates() { 163 | if (m_OnlineProviderKey != null) { 164 | if (m_MainInterface.GetOnlineProvider(m_OnlineProviderKey).CreateAccountLink == null) { 165 | m_lnkCreateAccount.Enabled = false; 166 | } else { 167 | m_lnkCreateAccount.Enabled = true; 168 | } 169 | } 170 | } 171 | 172 | private void OnCboProviderSelectionChangeCommitted(object sender, EventArgs e) { 173 | // get the provider and show the entry generator 174 | if (m_cboProvider.SelectedItem.GetType().BaseType == typeof(IOnlineProvider)) { 175 | IOnlineProvider provider = (IOnlineProvider)((IOnlineProvider)m_cboProvider.SelectedItem).Clone(); 176 | if (provider != null) { 177 | if (!provider.IsInitialized) { 178 | provider.Initialize(m_MainInterface); 179 | } 180 | 181 | m_OnlineProviderKey = provider.Key; 182 | } 183 | } 184 | RefreshGuiStates(); 185 | ResetAccountDetails(); 186 | } 187 | 188 | private void OnLblCreateAccountClicked(object sender, LinkLabelLinkClickedEventArgs e) { 189 | if (m_cboProvider.SelectedItem != null) { 190 | IOnlineProvider provider = (IOnlineProvider)m_cboProvider.SelectedItem; 191 | if (provider != null && provider.CreateAccountLink != null) { 192 | if (provider.CreateAccountLink.StartsWith("http://") || provider.CreateAccountLink.StartsWith("https://")) { 193 | System.Diagnostics.Process.Start(provider.CreateAccountLink); 194 | } 195 | } 196 | } 197 | } 198 | } 199 | } -------------------------------------------------------------------------------- /KeePassSync/Forms/OpenForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /KeePassSync/Forms/OptionsForm.cs: -------------------------------------------------------------------------------- 1 | /* 2 | KeePassSync - Online Sync Plugin for KeePass Password Safe 3 | Copyright (C) 2008 Shawn Casey, shawn.casey@gmail.com 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | using System; 21 | using System.IO; 22 | using System.Collections.Generic; 23 | using System.Collections; 24 | using System.ComponentModel; 25 | using System.Data; 26 | using System.Drawing; 27 | using System.Text; 28 | using System.Windows.Forms; 29 | 30 | using KeePass.Plugins; 31 | using KeePass.Forms; 32 | using KeePass.Resources; 33 | using KeePassLib; 34 | using KeePassLib.Security; 35 | 36 | // For registry functions 37 | using Microsoft.Win32; 38 | 39 | 40 | // Get the data from a OnlineSyncPlugin entry inside the General section of KeePass 41 | namespace KeePassSync.Forms { 42 | public sealed partial class OptionsForm : Form { 43 | #region -- Data & Properties -- 44 | private KeePassSyncExt m_MainInterface = null; 45 | private PwEntry m_EditedEntry = null; 46 | private bool m_EditButtonEnabled = false; 47 | private bool m_CreatedEntry = false; 48 | 49 | private OptionsData m_OptionData = null; 50 | public OptionsData SavedOptions { get { return m_OptionData; } } 51 | 52 | private bool m_EntryChanged = false; 53 | public bool EntryChanged { get { return m_EntryChanged; } } 54 | 55 | private IOnlineProvider OnlineProvider { get { return m_MainInterface.GetOnlineProvider(m_OptionData.OnlineProviderKey); } } 56 | #endregion 57 | 58 | public OptionsForm(KeePassSyncExt mainInterface) { 59 | InitializeComponent(); 60 | m_MainInterface = mainInterface; 61 | m_OptionData = (OptionsData)m_MainInterface.Options.Clone(); 62 | ResetForm(); 63 | } 64 | 65 | private OptionsForm() { 66 | } 67 | 68 | private void PopulateComboBox() { 69 | if (m_OptionData != null) { 70 | m_cboProvider.Items.Clear(); 71 | 72 | if (m_MainInterface.OnlineProviders.Length == 0) { 73 | m_cboProvider.Items.Add("No providers installed..."); 74 | } else { 75 | foreach (IOnlineProvider provider in m_MainInterface.OnlineProviders) { 76 | int index = m_cboProvider.Items.Add(provider); 77 | 78 | // Set the default 79 | if ((m_OptionData.OnlineProviderKey != null) && (m_OptionData.OnlineProviderKey == provider.Key)) { 80 | m_cboProvider.SelectedItem = m_cboProvider.Items[index]; 81 | } 82 | } 83 | } 84 | 85 | if (m_cboProvider.Items.Count > 0 && m_cboProvider.SelectedItem == null) { 86 | m_cboProvider.SelectedItem = m_cboProvider.Items[0]; 87 | } 88 | } 89 | } 90 | 91 | private void ResetForm() { 92 | if (m_OptionData != null) { 93 | PopulateComboBox(); 94 | 95 | // Setup default merge 96 | // Very important that the tab order for the radio buttons must be the same as the MergeMethod enum 97 | int control = 0; 98 | for (int i = 0; i < m_grpMergeOptions.Controls.Count; i++) { 99 | RadioButton btn = m_grpMergeOptions.Controls[i] as RadioButton; 100 | if (btn != null) { 101 | btn.Checked = ((int)m_OptionData.MergeMethod == control); 102 | control++; 103 | } 104 | } 105 | } 106 | 107 | RefreshGuiStates(); 108 | } 109 | 110 | private void OnLblCreateAccountClicked(object sender, LinkLabelLinkClickedEventArgs e) { 111 | if (m_cboProvider.SelectedItem != null) { 112 | IOnlineProvider provider = (IOnlineProvider)m_cboProvider.SelectedItem; 113 | if (provider != null && provider.CreateAccountLink != null) { 114 | if (provider.CreateAccountLink.StartsWith("http://") || provider.CreateAccountLink.StartsWith("https://")) { 115 | System.Diagnostics.Process.Start(provider.CreateAccountLink); 116 | } 117 | } 118 | } 119 | } 120 | 121 | private void CopyData() { 122 | int control = 0; 123 | for (int i = 0; i < m_grpMergeOptions.Controls.Count; i++) { 124 | RadioButton btn = m_grpMergeOptions.Controls[i] as RadioButton; 125 | if (btn != null) { 126 | if (btn.Checked) { 127 | m_OptionData.MergeMethod = (PwMergeMethod)control; 128 | } 129 | control++; 130 | } 131 | } 132 | 133 | if (m_cboProvider.SelectedItem != null && m_cboProvider.SelectedItem.GetType().BaseType == typeof(IOnlineProvider)) { 134 | IOnlineProvider pi = m_cboProvider.SelectedItem as IOnlineProvider; 135 | m_OptionData.OnlineProviderKey = pi.Key; 136 | } else { 137 | m_OptionData.OnlineProviderKey = null; 138 | } 139 | 140 | if (m_EditedEntry != null) { 141 | if (m_OptionData.PasswordEntry != null) { 142 | m_OptionData.PasswordEntry.AssignProperties(m_EditedEntry, false, true, false); 143 | m_OptionData.PasswordEntry.Touch(true); 144 | } else { 145 | m_OptionData.PasswordEntry = m_EditedEntry; 146 | m_EditedEntry = m_OptionData.PasswordEntry.CloneDeep(); 147 | m_OptionData.PasswordEntry.Touch(true); 148 | } 149 | } 150 | } 151 | private void OnBtnOkClicked(object sender, EventArgs e) { 152 | // Don't do this now, too many issues with it such as what happens 153 | // when they don't validate, someone opens the entry directly and 154 | // inputs correct information. There is no sense in validating now 155 | // because you'll always have to return an error if incorrect. 156 | // 157 | // Once threading and all the events are implemented, this may be 158 | // viable to give the user a heads up 159 | 160 | //// Test the password to validate the options 161 | //m_OptionData.OnlineProvider.ValidateOptions(); 162 | 163 | DialogResult = DialogResult.OK; 164 | CopyData(); 165 | 166 | this.Close(); 167 | } 168 | 169 | private void RefreshGuiStates() { 170 | RefreshButtonText(); 171 | if (OnlineProvider != null) { 172 | if (OnlineProvider.CreateAccountLink == null) { 173 | m_lnkCreateAccount.Enabled = false; 174 | } else { 175 | m_lnkCreateAccount.Enabled = true; 176 | } 177 | } 178 | } 179 | 180 | private void OnBtnCancelClicked(object sender, EventArgs e) { 181 | if (m_CreatedEntry) { 182 | KeePassSupport.DeleteEntry(m_MainInterface.Host, m_EditedEntry); 183 | m_EditedEntry = null; 184 | } 185 | DialogResult = DialogResult.Cancel; 186 | m_EntryChanged = false; 187 | this.Close(); 188 | } 189 | 190 | private void OnFormLoad(object sender, EventArgs e) { 191 | m_BannerImage.Image = KeePass.UI.BannerFactory.CreateBanner(m_BannerImage.Width, 192 | m_BannerImage.Height, KeePass.UI.BannerStyle.Default, Properties.Resources.Img_48x48_Sync, 193 | "KeePassSync Options", 194 | "Here you setup your online account and sync options"); 195 | 196 | RetrieveKeepassEntry(OnlineProvider); 197 | 198 | this.Icon = m_MainInterface.Host.MainWindow.Icon; 199 | 200 | this.Left = m_MainInterface.Host.MainWindow.Left + (m_MainInterface.Host.MainWindow.Width - this.Width) / 2; 201 | this.Top = m_MainInterface.Host.MainWindow.Top + (m_MainInterface.Host.MainWindow.Height - this.Height) / 2; 202 | } 203 | 204 | private void OnCboProviderSelectionChangeCommitted(object sender, EventArgs e) { 205 | if (m_cboProvider.SelectedItem.GetType().BaseType == typeof(IOnlineProvider)) { 206 | m_OptionData.OnlineProviderKey = ((IOnlineProvider)m_cboProvider.SelectedItem).Key; 207 | if (RetrieveKeepassEntry(OnlineProvider)) { 208 | OnlineProvider.DecodeEntry(m_EditedEntry); 209 | } 210 | } 211 | 212 | RefreshGuiStates(); 213 | } 214 | 215 | private bool RetrieveKeepassEntry(IOnlineProvider provider) { 216 | bool ret = false; 217 | PwEntry entry = null; 218 | if (OnlineProvider != null) 219 | m_OptionData.PasswordEntry = KeePassSupport.FindEntry(m_MainInterface.Host, OnlineProvider); 220 | else 221 | m_OptionData.PasswordEntry = null; 222 | if (provider != null) { 223 | entry = KeePassSupport.FindEntry(m_MainInterface.Host, provider); 224 | } 225 | 226 | if (entry != null) { 227 | m_EditedEntry = entry.CloneDeep(); 228 | ret = true; 229 | } 230 | m_EditButtonEnabled = ret; 231 | 232 | RefreshButtonText(); 233 | 234 | return ret; 235 | } 236 | 237 | private void RefreshButtonText() { 238 | string[] buttonText = { "Create KeePass Entry", "Edit KeePass Entry" }; 239 | 240 | if (m_MainInterface.ValidDatabase) { 241 | m_btnStoreCreate.Enabled = true; 242 | 243 | if (m_EditButtonEnabled) { 244 | m_btnStoreCreate.Text = buttonText[1]; 245 | } else { 246 | m_btnStoreCreate.Text = buttonText[0]; 247 | } 248 | } else { 249 | m_btnStoreCreate.Enabled = false; 250 | } 251 | 252 | } 253 | 254 | 255 | private void m_btnStoreCreate_Click(object sender, EventArgs e) { 256 | // if editing the entry, the entry must be non-null, it's just a matter of using raw-editing or user-editing 257 | if (m_EditButtonEnabled) { 258 | if (m_EditedEntry == null) 259 | m_EditedEntry = m_OptionData.PasswordEntry.CloneDeep(); 260 | 261 | // Pass the entry to the provider for it to parse and populate it's account details 262 | // It will then show the entry in the form of it's own control 263 | // or if "Raw Mode" is enabled, show the KeePass entry directly. 264 | if (checkBox1.Checked) { 265 | m_EntryChanged = KeePassSupport.EditEntry(m_MainInterface.Host, m_EditedEntry); 266 | } else { 267 | m_EntryChanged = m_MainInterface.GetOnlineProvider(m_OptionData.OnlineProviderKey).EditEntry(m_EditedEntry); 268 | } 269 | } else { 270 | m_EditedEntry = KeePassSupport.CreateEntry(m_MainInterface.Host, Properties.Resources.Str_PasswordEntryTemplate.Replace("%1", m_MainInterface.GetOnlineProvider(m_OptionData.OnlineProviderKey).Name)); 271 | m_CreatedEntry = false; 272 | m_EntryChanged = true; 273 | 274 | if (checkBox1.Checked) { 275 | m_CreatedEntry = KeePassSupport.EditEntry(m_MainInterface.Host, m_EditedEntry); 276 | } else { 277 | m_CreatedEntry = m_MainInterface.GetOnlineProvider(m_OptionData.OnlineProviderKey).EditEntry(m_EditedEntry); 278 | } 279 | 280 | if (!m_CreatedEntry) { 281 | KeePassSupport.DeleteEntry(m_MainInterface.Host, m_EditedEntry); 282 | m_EditedEntry = null; 283 | m_EntryChanged = false; 284 | } 285 | } 286 | 287 | // This updates the provider's name based on the new provider's name and all of the accepted names. This allows 288 | // providers to rename their providers and still have the old KeePass entries work. 289 | if (m_EntryChanged) { 290 | m_EditButtonEnabled = true; 291 | RefreshButtonText(); 292 | KeePassSupport.UpdateEntryName(m_MainInterface.Host, m_EditedEntry, m_MainInterface.GetOnlineProvider(m_OptionData.OnlineProviderKey)); 293 | } 294 | } 295 | 296 | } 297 | } -------------------------------------------------------------------------------- /KeePassSync/Forms/OptionsForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | For security purposes, this plugin does not externally store account information. It is stored as an entry within the main database. In Raw Mode, you can edit the KeePass entry directly. More advanced providers may use more than username/password fields, so be careful editing KeePass entries in Raw Mode. 122 | 123 | -------------------------------------------------------------------------------- /KeePassSync/Forms/SelectDatabaseForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeePassSync.Forms { 2 | partial class SelectDatabaseForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose(bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose(); 15 | } 16 | base.Dispose(disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent() { 26 | this.m_lbDatabases = new System.Windows.Forms.ListBox(); 27 | this.m_btnOk = new System.Windows.Forms.Button(); 28 | this.m_btnCancel = new System.Windows.Forms.Button(); 29 | this.m_BannerImage = new System.Windows.Forms.PictureBox(); 30 | ((System.ComponentModel.ISupportInitialize)(this.m_BannerImage)).BeginInit(); 31 | this.SuspendLayout(); 32 | // 33 | // m_lbDatabases 34 | // 35 | this.m_lbDatabases.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 36 | | System.Windows.Forms.AnchorStyles.Left) 37 | | System.Windows.Forms.AnchorStyles.Right))); 38 | this.m_lbDatabases.FormattingEnabled = true; 39 | this.m_lbDatabases.Location = new System.Drawing.Point(12, 66); 40 | this.m_lbDatabases.Name = "m_lbDatabases"; 41 | this.m_lbDatabases.Size = new System.Drawing.Size(288, 212); 42 | this.m_lbDatabases.TabIndex = 0; 43 | this.m_lbDatabases.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.OnLbDatabasesMouseDoubleClick); 44 | // 45 | // m_btnOk 46 | // 47 | this.m_btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 48 | this.m_btnOk.Location = new System.Drawing.Point(144, 292); 49 | this.m_btnOk.Name = "m_btnOk"; 50 | this.m_btnOk.Size = new System.Drawing.Size(75, 23); 51 | this.m_btnOk.TabIndex = 2; 52 | this.m_btnOk.Text = "OK"; 53 | this.m_btnOk.UseVisualStyleBackColor = true; 54 | this.m_btnOk.Click += new System.EventHandler(this.OnBtnOkClick); 55 | // 56 | // m_btnCancel 57 | // 58 | this.m_btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 59 | this.m_btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; 60 | this.m_btnCancel.Location = new System.Drawing.Point(225, 292); 61 | this.m_btnCancel.Name = "m_btnCancel"; 62 | this.m_btnCancel.Size = new System.Drawing.Size(75, 23); 63 | this.m_btnCancel.TabIndex = 3; 64 | this.m_btnCancel.Text = "Cancel"; 65 | this.m_btnCancel.UseVisualStyleBackColor = true; 66 | this.m_btnCancel.Click += new System.EventHandler(this.OnBtnCancelClick); 67 | // 68 | // m_BannerImage 69 | // 70 | this.m_BannerImage.Dock = System.Windows.Forms.DockStyle.Top; 71 | this.m_BannerImage.Location = new System.Drawing.Point(0, 0); 72 | this.m_BannerImage.Name = "m_BannerImage"; 73 | this.m_BannerImage.Size = new System.Drawing.Size(312, 60); 74 | this.m_BannerImage.TabIndex = 4; 75 | this.m_BannerImage.TabStop = false; 76 | // 77 | // SelectDatabaseForm 78 | // 79 | this.AcceptButton = this.m_btnOk; 80 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 81 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 82 | this.CancelButton = this.m_btnCancel; 83 | this.ClientSize = new System.Drawing.Size(312, 327); 84 | this.Controls.Add(this.m_BannerImage); 85 | this.Controls.Add(this.m_btnCancel); 86 | this.Controls.Add(this.m_btnOk); 87 | this.Controls.Add(this.m_lbDatabases); 88 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 89 | this.MaximizeBox = false; 90 | this.MinimizeBox = false; 91 | this.Name = "SelectDatabaseForm"; 92 | this.ShowInTaskbar = false; 93 | this.Text = "Select Database"; 94 | this.Load += new System.EventHandler(this.SelectDatabaseForm_Load); 95 | ((System.ComponentModel.ISupportInitialize)(this.m_BannerImage)).EndInit(); 96 | this.ResumeLayout(false); 97 | 98 | } 99 | 100 | #endregion 101 | 102 | private System.Windows.Forms.ListBox m_lbDatabases; 103 | private System.Windows.Forms.Button m_btnOk; 104 | private System.Windows.Forms.Button m_btnCancel; 105 | private System.Windows.Forms.PictureBox m_BannerImage; 106 | } 107 | } -------------------------------------------------------------------------------- /KeePassSync/Forms/SelectDatabaseForm.cs: -------------------------------------------------------------------------------- 1 | /* 2 | KeePassSync - Online Sync Plugin for KeePass Password Safe 3 | Copyright (C) 2008 Shawn Casey, shawn.casey@gmail.com 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.ComponentModel; 23 | using System.Data; 24 | using System.Drawing; 25 | using System.Text; 26 | using System.Windows.Forms; 27 | 28 | using KeePass.Plugins; 29 | using KeePass.Forms; 30 | using KeePass.Resources; 31 | using KeePassLib; 32 | using KeePassLib.Security; 33 | 34 | // For registry functions 35 | using Microsoft.Win32; 36 | 37 | namespace KeePassSync.Forms { 38 | public sealed partial class SelectDatabaseForm : Form { 39 | private string m_SelectedDatabase; 40 | public string SelectedDatabase { get { return m_SelectedDatabase; } } 41 | 42 | private KeePassSyncExt m_MainInterface = null; 43 | 44 | public SelectDatabaseForm(KeePassSyncExt mainInterface) { 45 | m_MainInterface = mainInterface; 46 | InitializeComponent(); 47 | } 48 | 49 | private SelectDatabaseForm() { 50 | } 51 | 52 | public void SetList(string[] data) { 53 | for (int i = 0; i < data.Length; i++) { 54 | m_lbDatabases.Items.Add(data[i]); 55 | } 56 | m_lbDatabases.Refresh(); 57 | } 58 | 59 | private void OnBtnOkClick(object sender, EventArgs e) { 60 | if (m_lbDatabases.SelectedItems.Count == 1) { 61 | m_SelectedDatabase = m_lbDatabases.SelectedItems[0].ToString(); 62 | DialogResult = DialogResult.OK; 63 | this.Close(); 64 | } 65 | } 66 | 67 | private void OnBtnCancelClick(object sender, EventArgs e) { 68 | DialogResult = DialogResult.Cancel; 69 | m_SelectedDatabase = null; 70 | this.Close(); 71 | } 72 | 73 | 74 | private void OnLbDatabasesMouseDoubleClick(object sender, MouseEventArgs e) { 75 | if (m_lbDatabases.SelectedIndex >= 0) { 76 | Rectangle rect = m_lbDatabases.GetItemRectangle(m_lbDatabases.SelectedIndex); 77 | // if the mouse is in the range of the rect, then select it. 78 | if (rect.Contains(e.Location)) { 79 | OnBtnOkClick(this, new EventArgs()); 80 | } 81 | } 82 | } 83 | 84 | private void SelectDatabaseForm_Load(object sender, EventArgs e) { 85 | m_BannerImage.Image = KeePass.UI.BannerFactory.CreateBanner(m_BannerImage.Width, 86 | m_BannerImage.Height, KeePass.UI.BannerStyle.Default, Properties.Resources.Img_48x48_Open, 87 | "Select Database", 88 | "Choose online database to open"); 89 | 90 | this.Icon = m_MainInterface.Host.MainWindow.Icon; 91 | 92 | this.Left = m_MainInterface.Host.MainWindow.Left + (m_MainInterface.Host.MainWindow.Width - this.Width) / 2; 93 | this.Top = m_MainInterface.Host.MainWindow.Top + (m_MainInterface.Host.MainWindow.Height - this.Height) / 2; 94 | 95 | 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /KeePassSync/Forms/SelectDatabaseForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /KeePassSync/Interfaces/IOnlineProvider.cs: -------------------------------------------------------------------------------- 1 | /* 2 | KeePassSync - Online Sync Plugin for KeePass Password Safe 3 | Copyright (C) 2008 Shawn Casey, shawn.casey@gmail.com 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | using System.Windows.Forms; 21 | 22 | //using KeePass.Plugins; 23 | //using KeePass.Forms; 24 | //using KeePass.Resources; 25 | using KeePassLib; 26 | using System; 27 | //using KeePassLib.Security; 28 | 29 | namespace KeePassSync { 30 | public abstract class IOnlineProvider : ICloneable { 31 | protected KeePassSyncExt m_MainInterface; 32 | protected OptionsData m_OptionData; 33 | protected bool m_HandlerAdded = false; 34 | protected bool m_IsInitialized = false; 35 | 36 | /// 37 | /// Has the online provider been initialized for its internal services yet? 38 | /// 39 | public bool IsInitialized { get { return m_IsInitialized; } } 40 | 41 | /// 42 | /// Link for the user to create an account. This must start with either "http://" or "https://" to work with the options dialog linkage. 43 | /// 44 | public abstract string CreateAccountLink { get; } 45 | 46 | /// 47 | /// Preferred friendly-name of the provider. 48 | /// 49 | public abstract string Name { get; } 50 | 51 | /// 52 | /// Full path of the online provider's assembly. 53 | /// 54 | public string Path; 55 | 56 | /// 57 | /// Available friendly-names of the provider. Useful when a developer needs to rename his plugin or find a plugin that doesn't match the new name. 58 | /// 59 | public abstract string[] AcceptedNames { get; } 60 | 61 | /// 62 | /// Retrieves an array of the available databases from the online provider. Provider must have valid options. 63 | /// 64 | public abstract string[] Databases { get; } 65 | 66 | /// 67 | /// Key used in the options and as a hash to retrieve the OnlineProvider from the main interface. 68 | /// 69 | public string Key { get { return Path; } } 70 | 71 | public void OptionsChangedHandler(object sender, EventArgs e) { 72 | m_OptionData = m_MainInterface.Options; 73 | } 74 | 75 | 76 | /// 77 | /// This initializes the plugin and the plugin can then use the options provider to retrieve the 78 | /// latest options before every save and load. In the future, this could be optimized to receive 79 | /// an event whenever the options have been changed. (detected through watching the keys via win32 api) 80 | /// 81 | /// This MUST be called from a client provider, ala base.Initialize( mainInterface ) 82 | /// 83 | /// 84 | public virtual KeePassSyncErr Initialize(KeePassSyncExt mainInterface) { 85 | m_MainInterface = mainInterface; 86 | m_IsInitialized = true; 87 | 88 | // Don't add the handler twice 89 | if (!m_HandlerAdded) { 90 | m_MainInterface.OptionsChanged += this.OptionsChangedHandler; 91 | m_HandlerAdded = true; 92 | } 93 | 94 | m_OptionData = m_MainInterface.Options; 95 | 96 | return KeePassSyncErr.None; 97 | } 98 | 99 | ~IOnlineProvider() { 100 | if (m_MainInterface != null && m_HandlerAdded) { 101 | m_MainInterface.OptionsChanged -= OptionsChangedHandler; 102 | } 103 | } 104 | 105 | /// 106 | /// Stores a local file online. 107 | /// 108 | /// Remote filename 109 | /// Local filename 110 | /// True if successful, false otherwise. 111 | public abstract KeePassSyncErr PutFile(PwEntry entry, string remoteFilename, string localFilename); 112 | 113 | /// 114 | /// Retrieves an online file into a local file. 115 | /// 116 | /// Remote filename 117 | /// Local filename 118 | /// 119 | /// 0 - Successful 120 | /// 1 - File not found 121 | /// 2 - Error 122 | /// 123 | public abstract KeePassSyncErr GetFile(PwEntry entry, string remoteFilename, string localFilename); 124 | 125 | /// 126 | /// Checks to see if options are valid for the online provider. Tries to connect to the service and validate the username/password information. 127 | /// 128 | /// 129 | /// 130 | public abstract KeePassSyncErr ValidateOptions(OptionsData options); 131 | 132 | /// 133 | /// Retrieves an array of the available databases from the online provider. Provider doesn't need to have valid options. 134 | /// 135 | /// User for connection. 136 | /// Password for connection. 137 | /// Optional data for the provider. For FTP, this is a combination of FTP address and directory. 138 | /// 139 | /// @todo user/password encrypted 140 | public abstract string[] GetDatabases(PwEntry entry); 141 | 142 | /// 143 | /// Returns the UserControl to display within option dialogs. 144 | /// 145 | /// UserControl to be used within option dialogs 146 | public abstract UserControl GetUserControl(); 147 | 148 | /// 149 | /// This takes an existing entry and populates the internal provider's options control with 150 | /// information parsed from the entry. A dialog is displayed and the results of the dialog 151 | /// will then be recombined into a new entry. If the dialog is cancelled, the returned 152 | /// entry will be null. 153 | /// 154 | /// Starting entry to populate the internal account details control. 155 | /// A regenerated KeePass entry based on the user's modifications of the account details. If cancel is hit on the dialog, a null entry is returned. 156 | public bool EditEntry(PwEntry entry) { 157 | bool ret = false; 158 | 159 | KeePassSync.Forms.AccountEntryGenerator dialog = new KeePassSync.Forms.AccountEntryGenerator(m_MainInterface, this); 160 | 161 | if (dialog != null) { 162 | if (entry != null) 163 | dialog.DecodeEntry(entry); 164 | 165 | DialogResult res = dialog.ShowDialog(); 166 | if (res == DialogResult.OK) { 167 | if (entry != null) 168 | dialog.EncodeEntry(entry); 169 | ret = true; 170 | } 171 | } 172 | 173 | return ret; 174 | } 175 | 176 | /// 177 | /// Populates control with entry data. This uses the providers internal UserControl for data. 178 | /// 179 | /// 180 | abstract public void DecodeEntry(PwEntry entry); 181 | 182 | /// 183 | /// Populates entry with control data. This uses the providers internal UserControl for data. 184 | /// 185 | /// 186 | abstract public void EncodeEntry(PwEntry entry); 187 | 188 | public override string ToString() { 189 | return Name; 190 | } 191 | 192 | #region ICloneable Members 193 | 194 | public object Clone() { 195 | return this.MemberwiseClone(); 196 | } 197 | 198 | #endregion 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /KeePassSync/Interfaces/IOptionsProvider.cs: -------------------------------------------------------------------------------- 1 | /* 2 | KeePassSync - Online Sync Plugin for KeePass Password Safe 3 | Copyright (C) 2008 Shawn Casey, shawn.casey@gmail.com 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | namespace KeePassSync { 21 | /// 22 | /// Interface for the Options provider. This is an interface so that it's easily 23 | /// able to be switched from one implementation to another. Currently the only 24 | /// implementation is using the registry to store the options. 25 | /// 26 | public interface IOptionsProvider { 27 | /// 28 | /// This method stores the main plugin interface so that subsequent reads/writes 29 | /// have access to the one and only options object. 30 | /// 31 | /// Main plugin interface. 32 | void Initialize(KeePassSyncExt mainInterface); 33 | 34 | /// 35 | /// Reads option information from local store and puts into main interface's options object. 36 | /// 37 | /// 38 | bool Read(OptionsData mainOptions); 39 | 40 | /// 41 | /// Writes the options from the main interface to local store. 42 | /// 43 | /// 44 | bool Write(OptionsData mainOptions); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /KeePassSync/KeePassSupport.cs: -------------------------------------------------------------------------------- 1 | /* 2 | KeePassSync - Online Sync Plugin for KeePass Password Safe 3 | Copyright (C) 2008 Shawn Casey, shawn.casey@gmail.com 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Text; 23 | using System.Windows.Forms; 24 | using System.Diagnostics; 25 | 26 | using KeePass.Plugins; 27 | using KeePass.Forms; 28 | using KeePass.Resources; 29 | using KeePassLib; 30 | using KeePassLib.Security; 31 | 32 | namespace KeePassSync { 33 | public class KeePassSupport { 34 | public static PwEntry CreateAndEditEntry(IPluginHost host, string title) { 35 | PwEntry entry = null; 36 | if (host != null && host.Database != null) { 37 | entry = new PwEntry(true, true); 38 | host.Database.RootGroup.AddEntry(entry, false); 39 | 40 | if (entry != null) { 41 | PwGroup destGroup = host.Database.RootGroup; 42 | 43 | // Set some of the string fields 44 | entry.Strings.Set(PwDefs.TitleField, new ProtectedString(false, title)); 45 | entry.Strings.Set(PwDefs.NotesField, new ProtectedString(false, Properties.Resources.Str_EntryNotes)); 46 | // Finally tell the parent group that it owns this entry now 47 | 48 | if (destGroup != null) { 49 | destGroup.Entries.Add(entry); 50 | } 51 | 52 | PwEntryForm form = new PwEntryForm(); 53 | form.InitEx(entry, PwEditMode.EditExistingEntry, host.Database, host.MainWindow.ClientIcons, false, false); 54 | DialogResult res = form.ShowDialog(); 55 | 56 | if (res == DialogResult.OK) { 57 | host.MainWindow.UpdateUI(false, null, true, null, true, null, true); 58 | } else { 59 | DeleteEntry(host, entry); 60 | entry = null; 61 | } 62 | } 63 | } 64 | return entry; 65 | } 66 | 67 | public static PwEntry CreateEntry(IPluginHost host, string title) { 68 | PwEntry entry = null; 69 | if (host != null && host.Database != null) { 70 | entry = new PwEntry(true, true); 71 | if (entry != null) { 72 | PwGroup destGroup = host.Database.RootGroup; 73 | 74 | // Set some of the string fields 75 | entry.Strings.Set(PwDefs.TitleField, new ProtectedString(false, title)); 76 | entry.Strings.Set(PwDefs.NotesField, new ProtectedString(false, Properties.Resources.Str_EntryNotes)); 77 | // Finally tell the parent group that it owns this entry now 78 | 79 | if (destGroup != null) { 80 | destGroup.AddEntry(entry, true, true); 81 | host.MainWindow.UpdateUI(false, null, true, null, true, null, true); 82 | } 83 | } 84 | } 85 | return entry; 86 | } 87 | 88 | public static void DeleteEntry(IPluginHost host, PwEntry entry) { 89 | entry.ParentGroup.Entries.Remove(entry); 90 | host.MainWindow.UpdateUI(false, null, true, null, true, null, true); 91 | } 92 | 93 | public static void UpdateEntryName(IPluginHost host, PwEntry entry, IOnlineProvider provider) { 94 | if (entry != null) { 95 | entry.Strings.Set(PwDefs.TitleField, new ProtectedString(false, Properties.Resources.Str_PasswordEntryTemplate.Replace("%1", provider.Name))); 96 | host.MainWindow.UpdateUI(false, null, true, null, true, null, true); 97 | } 98 | } 99 | 100 | public static void RefreshGui(IPluginHost host, bool modified) { 101 | host.MainWindow.UpdateUI(false, null, true, null, true, null, modified); 102 | } 103 | 104 | public static bool EditEntry(IPluginHost host, PwEntry entry) { 105 | bool ret = false; 106 | if (entry != null) { 107 | PwEntryForm form = new PwEntryForm(); 108 | form.InitEx(entry, PwEditMode.EditExistingEntry, host.Database, host.MainWindow.ClientIcons, false, false); 109 | DialogResult res = form.ShowDialog(); 110 | 111 | if (res == DialogResult.OK) { 112 | host.MainWindow.UpdateUI(false, null, true, null, true, null, true); 113 | ret = true; 114 | } 115 | } 116 | 117 | return ret; 118 | } 119 | 120 | public static PwEntry FindEntry(IPluginHost host, IOnlineProvider provider) { 121 | Debug.Assert(host != null, "Invalid host"); 122 | Debug.Assert(provider != null, "Invalid IOnlineProvider"); 123 | PwEntry entry = null; 124 | 125 | string[] acceptedNames = provider.AcceptedNames; 126 | for (int i = 0; i < acceptedNames.Length; i++) { 127 | entry = KeePassSupport.GetEntry(host, Properties.Resources.Str_PasswordEntryTemplate.Replace("%1", acceptedNames[i])); 128 | if (entry != null) 129 | break; 130 | } 131 | 132 | return entry; 133 | } 134 | 135 | /// 136 | /// This finds an entry in the database. 137 | /// 138 | /// KeePass service handle 139 | /// Entry title to find 140 | /// 141 | public static PwEntry GetEntry(IPluginHost host, string title) { 142 | Debug.Assert(host != null, "Invalid host"); 143 | // Finally add our new group to an existing group as subgroup 144 | PwGroup group = host.Database.RootGroup; 145 | PwEntry entry = null; 146 | if (group != null) { 147 | // Find the entry 148 | KeePassLib.Collections.PwObjectList entries = host.Database.RootGroup.Entries; 149 | ProtectedString ps = new ProtectedString(false, title); 150 | for (uint i = 0; i < entries.UCount; i++) { 151 | if (entries.GetAt(i).Strings.Get(PwDefs.TitleField).ReadString() == title) { 152 | entry = entries.GetAt(i); 153 | break; 154 | } 155 | } 156 | } 157 | 158 | return entry; 159 | } 160 | 161 | /// 162 | /// Checks to see if the entry is in the active database, if not, create a new 163 | /// entry with the same values. 164 | /// 165 | /// 166 | /// 167 | /// True if entry was just added to the current database. 168 | public static bool CheckEntry(IPluginHost host, PwEntry entry) { 169 | bool ret = false; 170 | if (entry == null) 171 | return false; 172 | PwEntry newEntry = host.Database.RootGroup.FindEntry(entry.Uuid, true); 173 | if (newEntry == null) { 174 | newEntry = entry.CloneDeep(); 175 | 176 | if (newEntry != null) { 177 | PwGroup destGroup = host.Database.RootGroup; 178 | // Finally tell the parent group that it owns this entry now 179 | destGroup.Entries.Add(newEntry); 180 | host.MainWindow.UpdateUI(false, null, true, null, true, null, true); 181 | ret = true; 182 | } 183 | } 184 | return ret; 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /KeePassSync/KeePassSync.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net472 4 | Library 5 | true 6 | false 7 | publish\ 8 | true 9 | Disk 10 | false 11 | Foreground 12 | 7 13 | Days 14 | false 15 | false 16 | true 17 | 0 18 | true 19 | 20 | 1.0.0.%2a 21 | preview 22 | false 23 | true 24 | false 25 | true 26 | true 27 | 28 | 29 | true 30 | 31 | 32 | 33 | ..\..\keepass\KeePass.exe 34 | False 35 | 36 | 37 | 38 | 39 | 40 | UserControl 41 | 42 | 43 | UserControl 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | all 53 | runtime; build; native; contentfiles; analyzers; buildtransitive 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /KeePassSync/OptionsProvider_Registry.cs: -------------------------------------------------------------------------------- 1 | /* 2 | KeePassSync - Online Sync Plugin for KeePass Password Safe 3 | Copyright (C) 2008 Shawn Casey, shawn.casey@gmail.com 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | using System; 21 | 22 | using KeePassLib; 23 | 24 | // For registry functions 25 | using Microsoft.Win32; 26 | 27 | namespace KeePassSync { 28 | public class OptionsProvider_Registry : IOptionsProvider { 29 | private KeePassSyncExt m_MainInterface; 30 | 31 | public void Initialize(KeePassSyncExt mainInterface) { 32 | m_MainInterface = mainInterface; 33 | } 34 | 35 | public bool Read(OptionsData mainOptions) { 36 | string keyName = "Software\\KeePass Plugin\\" + Properties.Resources.Str_Title; 37 | 38 | // Attempt to open the key 39 | RegistryKey key = Registry.CurrentUser.OpenSubKey(keyName); 40 | // If the return value is null, the key doesn't exist 41 | if (key == null) 42 | key = Registry.CurrentUser.CreateSubKey(keyName); 43 | 44 | if (key != null) { 45 | if (key.GetValue("MergeMethod") != null) 46 | mainOptions.MergeMethod = (PwMergeMethod)(int)key.GetValue("MergeMethod"); 47 | 48 | if (key.GetValue("PreviousDatabaseLocation") != null) 49 | mainOptions.PreviousDatabaseLocation = (string)key.GetValue("PreviousDatabaseLocation"); 50 | 51 | if (key.GetValue("OnlineProviderPath") != null) { 52 | string path = (string)key.GetValue("OnlineProviderPath"); 53 | 54 | // See if the provider set in the registry is available within KeePass 55 | IOnlineProvider[] providers = Util.DiscoverProviders(); 56 | foreach (IOnlineProvider provider in providers) { 57 | if (is_the_provider(provider, path)) { 58 | mainOptions.OnlineProviderKey = provider.Key; 59 | break; 60 | } 61 | } 62 | } 63 | } 64 | 65 | return (key != null); 66 | } 67 | private bool is_the_provider(IOnlineProvider provider, String path) { 68 | if (provider.Path == path) 69 | return true; 70 | if (path.EndsWith("KeePassSync_FTP.dll", StringComparison.CurrentCultureIgnoreCase) && provider.Path == "SFTP") 71 | return true; 72 | if (path.EndsWith("KeePassSync_S3.dll", StringComparison.CurrentCultureIgnoreCase) && provider.Path == "S3") 73 | return true; 74 | if (path.EndsWith("KeePassSync_digitalBucket.net.dll", StringComparison.CurrentCultureIgnoreCase) && provider.Path == "DigitalBucket") 75 | return true; 76 | 77 | return false; 78 | } 79 | public bool Write(OptionsData mainOptions) { 80 | string keyName = "Software\\KeePass Plugin\\" + Properties.Resources.Str_Title; 81 | 82 | // Attempt to open the key 83 | RegistryKey key = Registry.CurrentUser.OpenSubKey(keyName, true); 84 | 85 | // The key doesn't exist; create it / open it 86 | if (key == null) 87 | key = Registry.CurrentUser.CreateSubKey(keyName); 88 | 89 | if (key != null) { 90 | key.SetValue("MergeMethod", (int)mainOptions.MergeMethod); 91 | 92 | if (mainOptions.PreviousDatabaseLocation != null) 93 | key.SetValue("PreviousDatabaseLocation", mainOptions.PreviousDatabaseLocation); 94 | 95 | if (m_MainInterface.OnlineProvider != null && m_MainInterface.OnlineProvider.Path != null) 96 | key.SetValue("OnlineProviderPath", m_MainInterface.OnlineProvider.Path); 97 | } 98 | 99 | return (key != null); 100 | } 101 | 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /KeePassSync/Options_Registry.cs: -------------------------------------------------------------------------------- 1 | /* 2 | KeePassSync - Online Sync Plugin for KeePass Password Safe 3 | Copyright (C) 2008 Shawn Casey, shawn.casey@gmail.com 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Text; 23 | 24 | using KeePass.Plugins; 25 | using KeePass.Forms; 26 | using KeePass.Resources; 27 | using KeePassLib; 28 | using KeePassLib.Security; 29 | 30 | // For registry functions 31 | using Microsoft.Win32; 32 | 33 | namespace KeePassSync 34 | { 35 | public class Options_Registry : IOptionsProvider 36 | { 37 | private KeePassSyncExt m_MainInterface; 38 | 39 | public void Initialize(KeePassSyncExt mainInterface) 40 | { 41 | m_MainInterface = mainInterface; 42 | } 43 | 44 | public bool Read() 45 | { 46 | string keyName = "Software\\KeePass Plugin\\" + Properties.Resources.Str_AppTitle; 47 | 48 | // Attempt to open the key 49 | RegistryKey key = Registry.CurrentUser.OpenSubKey(keyName); 50 | // If the return value is null, the key doesn't exist 51 | if (key == null) 52 | key = Registry.CurrentUser.CreateSubKey(keyName); 53 | 54 | if (key != null) 55 | { 56 | if (key.GetValue("MergeMethod") != null) 57 | m_MainInterface.Options.MergeMethod = (PwMergeMethod)(int)key.GetValue("MergeMethod"); 58 | 59 | if (key.GetValue("PreviousDatabaseLocation") != null) 60 | m_MainInterface.Options.PreviousDatabaseLocation = (string)key.GetValue("PreviousDatabaseLocation"); 61 | 62 | if (key.GetValue("OnlineProviderPath") != null) 63 | { 64 | string path = (string)key.GetValue("OnlineProviderPath"); 65 | 66 | // See if the provider set in the registry is available within KeePass 67 | ProviderInfo[] providers = Util.DiscoverProviders(); 68 | foreach (ProviderInfo provider in providers) 69 | { 70 | if (provider.OnlineProviderPath == path) 71 | { 72 | m_MainInterface.Options.ProviderInfo = provider; 73 | break; 74 | } 75 | } 76 | } 77 | } 78 | 79 | return (key != null); 80 | } 81 | 82 | public bool Write() 83 | { 84 | string keyName = "Software\\KeePass Plugin\\" + Properties.Resources.Str_AppTitle; 85 | 86 | // Attempt to open the key 87 | RegistryKey key = Registry.CurrentUser.OpenSubKey(keyName, true); 88 | 89 | // The key doesn't exist; create it / open it 90 | if (key == null) 91 | key = Registry.CurrentUser.CreateSubKey(keyName); 92 | 93 | if (key != null) 94 | { 95 | key.SetValue("MergeMethod", (int)m_MainInterface.Options.MergeMethod); 96 | 97 | if (m_MainInterface.Options.PreviousDatabaseLocation != null) 98 | key.SetValue("PreviousDatabaseLocation", m_MainInterface.Options.PreviousDatabaseLocation); 99 | 100 | if (m_MainInterface.Options.ProviderInfo != null && m_MainInterface.Options.ProviderInfo.OnlineProviderPath != null) 101 | key.SetValue("OnlineProviderPath", m_MainInterface.Options.ProviderInfo.OnlineProviderPath); 102 | } 103 | 104 | return (key != null); 105 | } 106 | 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /KeePassSync/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("KeePassSync")] 9 | [assembly: AssemblyDescription("Online Sync Plugin for KeePass Password Safe")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("KeePass Plugin")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9effd9d0-f6d0-4667-9794-7ae8dab1e60b")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("8.2.0.0")] 35 | [assembly: AssemblyFileVersion("8.2.0.0")] 36 | -------------------------------------------------------------------------------- /KeePassSync/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace KeePassSync.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("KeePassSync.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap Img_16x16_Open { 67 | get { 68 | object obj = ResourceManager.GetObject("Img_16x16_Open", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Drawing.Bitmap. 75 | /// 76 | internal static System.Drawing.Bitmap Img_16x16_Options { 77 | get { 78 | object obj = ResourceManager.GetObject("Img_16x16_Options", resourceCulture); 79 | return ((System.Drawing.Bitmap)(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// Looks up a localized resource of type System.Drawing.Bitmap. 85 | /// 86 | internal static System.Drawing.Bitmap Img_16x16_Plugin { 87 | get { 88 | object obj = ResourceManager.GetObject("Img_16x16_Plugin", resourceCulture); 89 | return ((System.Drawing.Bitmap)(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// Looks up a localized resource of type System.Drawing.Bitmap. 95 | /// 96 | internal static System.Drawing.Bitmap Img_16x16_Sync { 97 | get { 98 | object obj = ResourceManager.GetObject("Img_16x16_Sync", resourceCulture); 99 | return ((System.Drawing.Bitmap)(obj)); 100 | } 101 | } 102 | 103 | /// 104 | /// Looks up a localized resource of type System.Drawing.Bitmap. 105 | /// 106 | internal static System.Drawing.Bitmap Img_48x48_Open { 107 | get { 108 | object obj = ResourceManager.GetObject("Img_48x48_Open", resourceCulture); 109 | return ((System.Drawing.Bitmap)(obj)); 110 | } 111 | } 112 | 113 | /// 114 | /// Looks up a localized resource of type System.Drawing.Bitmap. 115 | /// 116 | internal static System.Drawing.Bitmap Img_48x48_Password { 117 | get { 118 | object obj = ResourceManager.GetObject("Img_48x48_Password", resourceCulture); 119 | return ((System.Drawing.Bitmap)(obj)); 120 | } 121 | } 122 | 123 | /// 124 | /// Looks up a localized resource of type System.Drawing.Bitmap. 125 | /// 126 | internal static System.Drawing.Bitmap Img_48x48_Sync { 127 | get { 128 | object obj = ResourceManager.GetObject("Img_48x48_Sync", resourceCulture); 129 | return ((System.Drawing.Bitmap)(obj)); 130 | } 131 | } 132 | 133 | /// 134 | /// Looks up a localized string similar to Would you like to create/edit your %1 online settings?. 135 | /// 136 | internal static string Str_EditCreateQuestion { 137 | get { 138 | return ResourceManager.GetString("Str_EditCreateQuestion", resourceCulture); 139 | } 140 | } 141 | 142 | /// 143 | /// Looks up a localized string similar to Don't rename this entry or your online password information will be lost.. 144 | /// 145 | internal static string Str_EntryNotes { 146 | get { 147 | return ResourceManager.GetString("Str_EntryNotes", resourceCulture); 148 | } 149 | } 150 | 151 | /// 152 | /// Looks up a localized string similar to There has been an unhandled exception in the options provider.. 153 | /// 154 | internal static string Str_ErrExceptionOptions { 155 | get { 156 | return ResourceManager.GetString("Str_ErrExceptionOptions", resourceCulture); 157 | } 158 | } 159 | 160 | /// 161 | /// Looks up a localized string similar to There is no provider selected in the options.. 162 | /// 163 | internal static string Str_ErrNoProviderSelected { 164 | get { 165 | return ResourceManager.GetString("Str_ErrNoProviderSelected", resourceCulture); 166 | } 167 | } 168 | 169 | /// 170 | /// Looks up a localized string similar to Unable to open database.. 171 | /// 172 | internal static string Str_ErrOpenDatabase { 173 | get { 174 | return ResourceManager.GetString("Str_ErrOpenDatabase", resourceCulture); 175 | } 176 | } 177 | 178 | /// 179 | /// Looks up a localized string similar to Can't retrieve KeePassSync options.. 180 | /// 181 | internal static string Str_ErrOptions { 182 | get { 183 | return ResourceManager.GetString("Str_ErrOptions", resourceCulture); 184 | } 185 | } 186 | 187 | /// 188 | /// Looks up a localized string similar to Couldn't initialize the %1 provider.. 189 | /// 190 | internal static string Str_ErrProviderInitialization { 191 | get { 192 | return ResourceManager.GetString("Str_ErrProviderInitialization", resourceCulture); 193 | } 194 | } 195 | 196 | /// 197 | /// Looks up a localized string similar to Possible connection issue. Unable to retrieve databases. Test your connection and try again.. 198 | /// 199 | internal static string Str_ErrRetrieveDatabase { 200 | get { 201 | return ResourceManager.GetString("Str_ErrRetrieveDatabase", resourceCulture); 202 | } 203 | } 204 | 205 | /// 206 | /// Looks up a localized string similar to Unable to sync the database.. 207 | /// 208 | internal static string Str_ErrSync { 209 | get { 210 | return ResourceManager.GetString("Str_ErrSync", resourceCulture); 211 | } 212 | } 213 | 214 | /// 215 | /// Looks up a localized string similar to Error during options validation.. 216 | /// 217 | internal static string Str_ErrValidatingOptions_Error { 218 | get { 219 | return ResourceManager.GetString("Str_ErrValidatingOptions_Error", resourceCulture); 220 | } 221 | } 222 | 223 | /// 224 | /// Looks up a localized string similar to Error during options validation, not connected.. 225 | /// 226 | internal static string Str_ErrValidatingOptions_NotConnected { 227 | get { 228 | return ResourceManager.GetString("Str_ErrValidatingOptions_NotConnected", resourceCulture); 229 | } 230 | } 231 | 232 | /// 233 | /// Looks up a localized string similar to Timeout occured during options validation.. 234 | /// 235 | internal static string Str_ErrValidatingOptions_Timeout { 236 | get { 237 | return ResourceManager.GetString("Str_ErrValidatingOptions_Timeout", resourceCulture); 238 | } 239 | } 240 | 241 | /// 242 | /// Looks up a localized string similar to This database doesn't have valid online credentials necessary for synchronization.. 243 | /// 244 | internal static string Str_OptionsChanged { 245 | get { 246 | return ResourceManager.GetString("Str_OptionsChanged", resourceCulture); 247 | } 248 | } 249 | 250 | /// 251 | /// Looks up a localized string similar to KeePassSync (%1). 252 | /// 253 | internal static string Str_PasswordEntryTemplate { 254 | get { 255 | return ResourceManager.GetString("Str_PasswordEntryTemplate", resourceCulture); 256 | } 257 | } 258 | 259 | /// 260 | /// Looks up a localized string similar to Synchronized database (%1). 261 | /// 262 | internal static string Str_Synced { 263 | get { 264 | return ResourceManager.GetString("Str_Synced", resourceCulture); 265 | } 266 | } 267 | 268 | /// 269 | /// Looks up a localized string similar to Synchronizing database (%1).... 270 | /// 271 | internal static string Str_Syncing { 272 | get { 273 | return ResourceManager.GetString("Str_Syncing", resourceCulture); 274 | } 275 | } 276 | 277 | /// 278 | /// Looks up a localized string similar to KeePassSync. 279 | /// 280 | internal static string Str_Title { 281 | get { 282 | return ResourceManager.GetString("Str_Title", resourceCulture); 283 | } 284 | } 285 | 286 | /// 287 | /// Looks up a localized string similar to Would you like to try again?. 288 | /// 289 | internal static string Str_TryAgain { 290 | get { 291 | return ResourceManager.GetString("Str_TryAgain", resourceCulture); 292 | } 293 | } 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /KeePassSync/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\Icons\Img_16x16_Open.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | 125 | ..\Resources\Icons\Img_16x16_Options.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 126 | 127 | 128 | ..\Resources\Icons\Img_16x16_Plugin.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 129 | 130 | 131 | ..\Resources\Icons\Img_16x16_Sync.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 132 | 133 | 134 | ..\Resources\Icons\Img_48x48_Open.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 135 | 136 | 137 | ..\Resources\Icons\Img_48x48_Password.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 138 | 139 | 140 | ..\Resources\Icons\Img_48x48_Sync.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 141 | 142 | 143 | Would you like to create/edit your %1 online settings? 144 | 145 | 146 | Don't rename this entry or your online password information will be lost. 147 | 148 | 149 | There has been an unhandled exception in the options provider. 150 | 151 | 152 | There is no provider selected in the options. 153 | 154 | 155 | Unable to open database. 156 | 157 | 158 | Can't retrieve KeePassSync options. 159 | 160 | 161 | Couldn't initialize the %1 provider. 162 | 163 | 164 | Possible connection issue. Unable to retrieve databases. Test your connection and try again. 165 | 166 | 167 | Unable to sync the database. 168 | 169 | 170 | Error during options validation. 171 | 172 | 173 | Error during options validation, not connected. 174 | 175 | 176 | Timeout occured during options validation. 177 | 178 | 179 | This database doesn't have valid online credentials necessary for synchronization. 180 | 181 | 182 | KeePassSync (%1) 183 | 184 | 185 | Synchronized database (%1) 186 | 187 | 188 | Synchronizing database (%1)... 189 | 190 | 191 | KeePassSync 192 | 193 | 194 | Would you like to try again? 195 | 196 | -------------------------------------------------------------------------------- /KeePassSync/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace KeePassSync.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /KeePassSync/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /KeePassSync/Providers/S3/AccountDetails.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace KeePassSync.Providers.S3 { 5 | public partial class AccountDetails : UserControl { 6 | public string AccessKey { 7 | get { return txtAccessKey.Text; } 8 | set { txtAccessKey.Text = value; } 9 | } 10 | 11 | public string SecretAccessKey { 12 | get { return txtSecretAccessKey.Text; } 13 | set { txtSecretAccessKey.Text = value; } 14 | } 15 | 16 | public string BucketName { 17 | get { return txtBucketName.Text; } 18 | set { txtBucketName.Text = value; } 19 | } 20 | public bool CreateBackups { 21 | get { return cbxDailyBackups.Checked; } 22 | set { cbxDailyBackups.Checked = value; } 23 | 24 | } 25 | public string ServiceURL { 26 | get { return txtServiceUrl.Text; } 27 | set { txtServiceUrl.Text = value; } 28 | } 29 | public bool UseChecksums { 30 | get { return cbxTransferChecksums.Checked; } 31 | set { cbxTransferChecksums.Checked = value; } 32 | } 33 | public bool UseACLs { 34 | get { return cbxCopyACLS.Checked; } 35 | set { cbxCopyACLS.Checked = value; } 36 | } 37 | 38 | public AccountDetails() { 39 | InitializeComponent(); 40 | } 41 | 42 | private void AccountDetails_Load(object sender, EventArgs e) { 43 | 44 | } 45 | 46 | private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { 47 | System.Diagnostics.Process.Start("https://github.com/mitchcapper/KeePassSync/blob/master/AMAZON_S3.md"); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /KeePassSync/Providers/S3/AccountDetails.designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeePassSync.Providers.S3 { 2 | partial class AccountDetails { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose(bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose(); 15 | } 16 | base.Dispose(disposing); 17 | } 18 | 19 | #region Component Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent() { 26 | this.label1 = new System.Windows.Forms.Label(); 27 | this.txtAccessKey = new System.Windows.Forms.TextBox(); 28 | this.label3 = new System.Windows.Forms.Label(); 29 | this.txtBucketName = new System.Windows.Forms.TextBox(); 30 | this.label4 = new System.Windows.Forms.Label(); 31 | this.txtSecretAccessKey = new System.Windows.Forms.TextBox(); 32 | this.label6 = new System.Windows.Forms.Label(); 33 | this.label2 = new System.Windows.Forms.Label(); 34 | this.cbxDailyBackups = new System.Windows.Forms.CheckBox(); 35 | this.linkLabel1 = new System.Windows.Forms.LinkLabel(); 36 | this.cbxTransferChecksums = new System.Windows.Forms.CheckBox(); 37 | this.label5 = new System.Windows.Forms.Label(); 38 | this.cbxCopyACLS = new System.Windows.Forms.CheckBox(); 39 | this.label7 = new System.Windows.Forms.Label(); 40 | this.txtServiceUrl = new System.Windows.Forms.TextBox(); 41 | this.label8 = new System.Windows.Forms.Label(); 42 | this.SuspendLayout(); 43 | // 44 | // label1 45 | // 46 | this.label1.AutoSize = true; 47 | this.label1.Location = new System.Drawing.Point(6, 53); 48 | this.label1.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 49 | this.label1.Name = "label1"; 50 | this.label1.Size = new System.Drawing.Size(157, 25); 51 | this.label1.TabIndex = 0; 52 | this.label1.Text = "Access Key ID:"; 53 | // 54 | // txtAccessKey 55 | // 56 | this.txtAccessKey.Location = new System.Drawing.Point(212, 47); 57 | this.txtAccessKey.Margin = new System.Windows.Forms.Padding(26, 6, 6, 6); 58 | this.txtAccessKey.Name = "txtAccessKey"; 59 | this.txtAccessKey.Size = new System.Drawing.Size(390, 31); 60 | this.txtAccessKey.TabIndex = 2; 61 | // 62 | // label3 63 | // 64 | this.label3.AutoSize = true; 65 | this.label3.Location = new System.Drawing.Point(6, 153); 66 | this.label3.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 67 | this.label3.Name = "label3"; 68 | this.label3.Size = new System.Drawing.Size(146, 25); 69 | this.label3.TabIndex = 4; 70 | this.label3.Text = "Bucket Name:"; 71 | // 72 | // txtBucketName 73 | // 74 | this.txtBucketName.Location = new System.Drawing.Point(162, 147); 75 | this.txtBucketName.Margin = new System.Windows.Forms.Padding(6); 76 | this.txtBucketName.Name = "txtBucketName"; 77 | this.txtBucketName.Size = new System.Drawing.Size(440, 31); 78 | this.txtBucketName.TabIndex = 4; 79 | // 80 | // label4 81 | // 82 | this.label4.AutoSize = true; 83 | this.label4.Location = new System.Drawing.Point(6, 103); 84 | this.label4.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 85 | this.label4.Name = "label4"; 86 | this.label4.Size = new System.Drawing.Size(199, 25); 87 | this.label4.TabIndex = 6; 88 | this.label4.Text = "Access Key Secret:"; 89 | // 90 | // txtSecretAccessKey 91 | // 92 | this.txtSecretAccessKey.Location = new System.Drawing.Point(212, 97); 93 | this.txtSecretAccessKey.Margin = new System.Windows.Forms.Padding(6); 94 | this.txtSecretAccessKey.Name = "txtSecretAccessKey"; 95 | this.txtSecretAccessKey.PasswordChar = '*'; 96 | this.txtSecretAccessKey.Size = new System.Drawing.Size(390, 31); 97 | this.txtSecretAccessKey.TabIndex = 3; 98 | // 99 | // label6 100 | // 101 | this.label6.AutoSize = true; 102 | this.label6.Location = new System.Drawing.Point(16, 388); 103 | this.label6.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 104 | this.label6.MaximumSize = new System.Drawing.Size(600, 0); 105 | this.label6.Name = "label6"; 106 | this.label6.Size = new System.Drawing.Size(569, 50); 107 | this.label6.TabIndex = 9; 108 | this.label6.Text = "If the bucket does not exist it will be greated automatically (assuming this key " + 109 | "has create rights). "; 110 | // 111 | // label2 112 | // 113 | this.label2.AutoSize = true; 114 | this.label2.Location = new System.Drawing.Point(6, 268); 115 | this.label2.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 116 | this.label2.Name = "label2"; 117 | this.label2.Size = new System.Drawing.Size(520, 25); 118 | this.label2.TabIndex = 11; 119 | this.label2.Text = "Create Daily Backups (last 30 days, 1 backup a day):"; 120 | // 121 | // cbxDailyBackups 122 | // 123 | this.cbxDailyBackups.AutoSize = true; 124 | this.cbxDailyBackups.Location = new System.Drawing.Point(574, 267); 125 | this.cbxDailyBackups.Margin = new System.Windows.Forms.Padding(6); 126 | this.cbxDailyBackups.Name = "cbxDailyBackups"; 127 | this.cbxDailyBackups.Size = new System.Drawing.Size(28, 27); 128 | this.cbxDailyBackups.TabIndex = 12; 129 | this.cbxDailyBackups.UseVisualStyleBackColor = true; 130 | // 131 | // linkLabel1 132 | // 133 | this.linkLabel1.AutoSize = true; 134 | this.linkLabel1.Location = new System.Drawing.Point(6, 13); 135 | this.linkLabel1.Name = "linkLabel1"; 136 | this.linkLabel1.Size = new System.Drawing.Size(184, 25); 137 | this.linkLabel1.TabIndex = 13; 138 | this.linkLabel1.TabStop = true; 139 | this.linkLabel1.Text = "Setup Instructions"; 140 | this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); 141 | // 142 | // cbxTransferChecksums 143 | // 144 | this.cbxTransferChecksums.AutoSize = true; 145 | this.cbxTransferChecksums.Location = new System.Drawing.Point(574, 308); 146 | this.cbxTransferChecksums.Margin = new System.Windows.Forms.Padding(6); 147 | this.cbxTransferChecksums.Name = "cbxTransferChecksums"; 148 | this.cbxTransferChecksums.Size = new System.Drawing.Size(28, 27); 149 | this.cbxTransferChecksums.TabIndex = 15; 150 | this.cbxTransferChecksums.UseVisualStyleBackColor = true; 151 | // 152 | // label5 153 | // 154 | this.label5.AutoSize = true; 155 | this.label5.Location = new System.Drawing.Point(6, 309); 156 | this.label5.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 157 | this.label5.Name = "label5"; 158 | this.label5.Size = new System.Drawing.Size(502, 25); 159 | this.label5.TabIndex = 14; 160 | this.label5.Text = "Use Transfer Checksums (not all services support):"; 161 | // 162 | // cbxCopyACLS 163 | // 164 | this.cbxCopyACLS.AutoSize = true; 165 | this.cbxCopyACLS.Location = new System.Drawing.Point(574, 350); 166 | this.cbxCopyACLS.Margin = new System.Windows.Forms.Padding(6); 167 | this.cbxCopyACLS.Name = "cbxCopyACLS"; 168 | this.cbxCopyACLS.Size = new System.Drawing.Size(28, 27); 169 | this.cbxCopyACLS.TabIndex = 17; 170 | this.cbxCopyACLS.UseVisualStyleBackColor = true; 171 | // 172 | // label7 173 | // 174 | this.label7.AutoSize = true; 175 | this.label7.Location = new System.Drawing.Point(6, 351); 176 | this.label7.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 177 | this.label7.Name = "label7"; 178 | this.label7.Size = new System.Drawing.Size(514, 25); 179 | this.label7.TabIndex = 16; 180 | this.label7.Text = "If existing entry exists, copy its ACL (not all support):"; 181 | // 182 | // txtServiceUrl 183 | // 184 | this.txtServiceUrl.Location = new System.Drawing.Point(162, 205); 185 | this.txtServiceUrl.Margin = new System.Windows.Forms.Padding(6); 186 | this.txtServiceUrl.Name = "txtServiceUrl"; 187 | this.txtServiceUrl.Size = new System.Drawing.Size(440, 31); 188 | this.txtServiceUrl.TabIndex = 18; 189 | // 190 | // label8 191 | // 192 | this.label8.Location = new System.Drawing.Point(6, 184); 193 | this.label8.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 194 | this.label8.Name = "label8"; 195 | this.label8.Size = new System.Drawing.Size(157, 77); 196 | this.label8.TabIndex = 19; 197 | this.label8.Text = "Service URL (leave blank for Amazon):"; 198 | // 199 | // AccountDetails 200 | // 201 | this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); 202 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 203 | this.Controls.Add(this.txtServiceUrl); 204 | this.Controls.Add(this.label8); 205 | this.Controls.Add(this.cbxCopyACLS); 206 | this.Controls.Add(this.label7); 207 | this.Controls.Add(this.cbxTransferChecksums); 208 | this.Controls.Add(this.label5); 209 | this.Controls.Add(this.linkLabel1); 210 | this.Controls.Add(this.cbxDailyBackups); 211 | this.Controls.Add(this.label2); 212 | this.Controls.Add(this.label6); 213 | this.Controls.Add(this.txtSecretAccessKey); 214 | this.Controls.Add(this.label4); 215 | this.Controls.Add(this.txtBucketName); 216 | this.Controls.Add(this.label3); 217 | this.Controls.Add(this.txtAccessKey); 218 | this.Controls.Add(this.label1); 219 | this.Margin = new System.Windows.Forms.Padding(6); 220 | this.Name = "AccountDetails"; 221 | this.Size = new System.Drawing.Size(624, 451); 222 | this.Load += new System.EventHandler(this.AccountDetails_Load); 223 | this.ResumeLayout(false); 224 | this.PerformLayout(); 225 | 226 | } 227 | 228 | #endregion 229 | 230 | private System.Windows.Forms.Label label1; 231 | private System.Windows.Forms.TextBox txtAccessKey; 232 | private System.Windows.Forms.Label label3; 233 | private System.Windows.Forms.TextBox txtBucketName; 234 | private System.Windows.Forms.Label label4; 235 | private System.Windows.Forms.TextBox txtSecretAccessKey; 236 | private System.Windows.Forms.Label label6; 237 | private System.Windows.Forms.Label label2; 238 | private System.Windows.Forms.CheckBox cbxDailyBackups; 239 | private System.Windows.Forms.LinkLabel linkLabel1; 240 | private System.Windows.Forms.CheckBox cbxTransferChecksums; 241 | private System.Windows.Forms.Label label5; 242 | private System.Windows.Forms.CheckBox cbxCopyACLS; 243 | private System.Windows.Forms.Label label7; 244 | private System.Windows.Forms.TextBox txtServiceUrl; 245 | private System.Windows.Forms.Label label8; 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /KeePassSync/Providers/S3/AccountDetails.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /KeePassSync/Providers/S3/OurAmazonS3Client.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Amazon.S3; 3 | using Amazon.S3.Model; 4 | using Amazon.Runtime.Internal; 5 | using Amazon.S3.Model.Internal.MarshallTransformations; 6 | using System.Threading.Tasks; 7 | using Amazon.Runtime; 8 | using Amazon.Runtime.Internal.Util; 9 | 10 | 11 | namespace KeePassSync.Providers.S3 { 12 | 13 | //just used to work around some 3rd party client oddities 14 | internal class OurAmazonS3Client : AmazonS3Client { 15 | public OurAmazonS3Client(string awsAccessKeyId, string awsSecretAccessKey, AmazonS3Config clientConfig, List HeadersToStrip = null) : base(awsAccessKeyId, awsSecretAccessKey, clientConfig) { 16 | if (HeadersToStrip != null) 17 | RuntimePipeline.AddHandlerBefore(new HeaderStripHandler(HeadersToStrip)); 18 | 19 | 20 | } 21 | 22 | public class HeaderStripHandler : IPipelineHandler { 23 | private List headersToStrip; 24 | 25 | public HeaderStripHandler(List headersToStrip) { 26 | this.headersToStrip = headersToStrip; 27 | } 28 | 29 | public ILogger Logger { get; set; } 30 | public IPipelineHandler InnerHandler { get; set; } 31 | public IPipelineHandler OuterHandler { get; set; } 32 | 33 | public async Task InvokeAsync(IExecutionContext executionContext) where T : AmazonWebServiceResponse, new() { 34 | RemoveBadHeaders(executionContext); 35 | if (InnerHandler == null) 36 | return default(T); 37 | return await InnerHandler.InvokeAsync(executionContext); 38 | } 39 | 40 | private void RemoveBadHeaders(IExecutionContext executionContext) { 41 | if (headersToStrip != null) { 42 | foreach (var header in headersToStrip) 43 | executionContext.RequestContext.Request.Headers.Remove(header); 44 | } 45 | } 46 | 47 | public void InvokeSync(IExecutionContext executionContext) { 48 | RemoveBadHeaders(executionContext); 49 | if (InnerHandler == null) 50 | return; 51 | InnerHandler.InvokeSync(executionContext); 52 | } 53 | } 54 | 55 | public override CopyObjectResponse CopyObject(CopyObjectRequest request) { 56 | var invokeOptions = new InvokeOptions(); 57 | invokeOptions.RequestMarshaller = CopyObjectRequestMarshaller.Instance; 58 | invokeOptions.ResponseUnmarshaller = CopyObjectResponseUnmarshaller.Instance; 59 | 60 | return Invoke(request, invokeOptions); 61 | } 62 | 63 | } 64 | 65 | } 66 | 67 | -------------------------------------------------------------------------------- /KeePassSync/Providers/S3/S3Provider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Net; 5 | using System.Security.Cryptography; 6 | using System.Windows.Forms; 7 | using KeePassLib; 8 | using KeePassLib.Security; 9 | using Amazon.S3; 10 | using Amazon.S3.Model; 11 | using Amazon.S3.Util; 12 | 13 | 14 | namespace KeePassSync.Providers.S3 { 15 | 16 | public class S3Provider : IOnlineProvider { 17 | #region -- Private data -- 18 | private const string m_Name = "S3"; 19 | private string[] m_AcceptedNames = { "S3" }; 20 | private AccountDetails m_UserControl; 21 | #endregion 22 | 23 | private const string access_key_id_field = PwDefs.UserNameField; 24 | private const string bucket_name_field = PwDefs.UrlField; 25 | private const string use_checksums_field = "use_checksums"; 26 | private const string use_acls_field = "use_acls"; 27 | private const string custom_service_url_field = "service_url"; 28 | private const string create_backups_field = "create_backups"; 29 | 30 | private const string secret_access_key_field = PwDefs.PasswordField; 31 | private bool memprotect_secret_access_key = true; 32 | 33 | 34 | public override KeePassSyncErr Initialize(KeePassSyncExt mainInterface) { 35 | KeePassSyncErr ret = base.Initialize(mainInterface); 36 | 37 | m_UserControl = new AccountDetails(); 38 | 39 | m_IsInitialized = (ret == KeePassSyncErr.None); 40 | 41 | return ret; 42 | } 43 | public override void DecodeEntry(PwEntry entry) { 44 | m_UserControl.AccessKey = read_PwEntry_string(entry, access_key_id_field); 45 | m_UserControl.SecretAccessKey = read_PwEntry_string(entry, secret_access_key_field); 46 | m_UserControl.BucketName = read_PwEntry_string(entry, bucket_name_field); 47 | 48 | m_UserControl.CreateBackups = GetBoolField(entry, create_backups_field); 49 | m_UserControl.UseACLs = GetBoolField(entry, use_acls_field); 50 | m_UserControl.UseChecksums = GetBoolField(entry, use_checksums_field); 51 | m_UserControl.ServiceURL = read_PwEntry_string(entry, custom_service_url_field); 52 | } 53 | private bool GetBoolField(PwEntry entry, String fieldname) { 54 | var str = read_PwEntry_string(entry, fieldname); 55 | return str == "true"; 56 | } 57 | private void SetBoolField(PwEntry entry, String fieldname, bool value) { 58 | write_PwEntry_string(entry, fieldname, value ? "true" : "false", false); 59 | } 60 | 61 | public override void EncodeEntry(PwEntry entry) { 62 | write_PwEntry_string(entry, access_key_id_field, m_UserControl.AccessKey, false); 63 | write_PwEntry_string(entry, secret_access_key_field, m_UserControl.SecretAccessKey, memprotect_secret_access_key); 64 | write_PwEntry_string(entry, bucket_name_field, m_UserControl.BucketName, false); 65 | write_PwEntry_string(entry, custom_service_url_field, m_UserControl.ServiceURL, false); 66 | SetBoolField(entry, create_backups_field, m_UserControl.CreateBackups); 67 | SetBoolField(entry, use_acls_field, m_UserControl.UseACLs); 68 | SetBoolField(entry, use_checksums_field, m_UserControl.UseChecksums); 69 | } 70 | public void write_PwEntry_string(PwEntry entry, String key, String value, bool in_memory_encrypt) { 71 | entry.Strings.Set(key, new ProtectedString(in_memory_encrypt, value)); 72 | } 73 | public string read_PwEntry_string(PwEntry entry, String key) { 74 | ProtectedString str = entry.Strings.Get(key); 75 | if (str == null) 76 | return ""; 77 | return str.ReadString(); 78 | } 79 | public override KeePassSyncErr ValidateOptions(OptionsData options) { 80 | KeePassSyncErr ret = KeePassSyncErr.None; 81 | PwEntry entry = m_OptionData.PasswordEntry; 82 | AccountDetails old_details = m_UserControl; 83 | m_UserControl = new AccountDetails(); 84 | DecodeEntry(entry); 85 | ret = verify_bucket_or_create(BucketName); 86 | m_UserControl = old_details; 87 | return ret; 88 | } 89 | 90 | public override string CreateAccountLink { 91 | get { return "http://aws.amazon.com/s3/"; } 92 | } 93 | public override string Name { 94 | get { return m_Name; } 95 | } 96 | 97 | public override string[] AcceptedNames { 98 | get { return m_AcceptedNames; } 99 | } 100 | 101 | public override string[] Databases { 102 | get { 103 | return GetDatabases(m_OptionData.PasswordEntry); 104 | } 105 | } 106 | private bool UsePayloadSigning { get { return String.IsNullOrWhiteSpace(m_UserControl.ServiceURL); } } 107 | private AmazonS3Client GetClient() { 108 | var isS3Official = String.IsNullOrWhiteSpace(m_UserControl.ServiceURL); 109 | if (!isS3Official && m_UserControl.ServiceURL.StartsWith("http", StringComparison.CurrentCultureIgnoreCase) == false) 110 | m_UserControl.ServiceURL = "https://" + m_UserControl.ServiceURL; 111 | 112 | var url = isS3Official ? "https://s3.amazonaws.com" : m_UserControl.ServiceURL; 113 | var cfg = new AmazonS3Config { ServiceURL = url }; 114 | //cfg.ProxyHost = "127.0.0.1";cfg.ProxyPort = 1234; 115 | List headerRemove= null; 116 | if (!isS3Official) { 117 | headerRemove = new List {"x-amz-tagging-directive"}; 118 | } 119 | 120 | 121 | var client = new OurAmazonS3Client(m_UserControl.AccessKey, m_UserControl.SecretAccessKey, cfg,headerRemove); 122 | 123 | return client; 124 | 125 | } 126 | public override KeePassSyncErr PutFile(PwEntry entry, string remoteFilename, string localFilename) { 127 | try { 128 | DecodeEntry(entry); 129 | using (var fs = File.OpenRead(localFilename)) { 130 | KeePassSyncErr err = verify_bucket_or_create(BucketName); 131 | if (err != KeePassSyncErr.None) 132 | return err; 133 | 134 | var client = GetClient(); 135 | S3AccessControlList acl = null; 136 | if (FileExists(remoteFilename)) { 137 | string backupFilename = remoteFilename + ".bkup_day" + DateTime.Today.Day; 138 | if (m_UserControl.UseACLs) 139 | acl = client.GetACL(new GetACLRequest() { BucketName = BucketName, Key = remoteFilename }).AccessControlList; 140 | if (m_UserControl.CreateBackups) { 141 | var copy = new CopyObjectRequest { DestinationBucket = BucketName, SourceBucket = BucketName, SourceKey = remoteFilename, DestinationKey = backupFilename }; 142 | 143 | 144 | client.CopyObject(copy); 145 | } 146 | 147 | 148 | } 149 | var hash = GetSHA1(fs); //s3 will auto seek to start on stream after 150 | var req = new PutObjectRequest { BucketName = BucketName, Key = remoteFilename, InputStream = fs, AutoCloseStream = false, DisablePayloadSigning = !UsePayloadSigning }; 151 | if (m_UserControl.UseChecksums) 152 | req.ChecksumSHA1 = hash; 153 | client.PutObject(req); 154 | if (acl != null) { 155 | try { 156 | client.PutACL(new PutACLRequest { BucketName = BucketName, Key = remoteFilename, AccessControlList = acl }); 157 | } catch (AmazonS3Exception s3e) { 158 | if (s3e.ErrorCode != "AccessControlListNotSupported") 159 | throw s3e; 160 | } 161 | } 162 | 163 | 164 | } 165 | } catch (Exception e) { 166 | return convert_exception(e); 167 | } 168 | return KeePassSyncErr.None; 169 | } 170 | private string GetSHA1(Stream stream) { 171 | using (var sha1 = SHA1.Create()) { 172 | return Convert.ToBase64String(sha1.ComputeHash(stream)); 173 | } 174 | 175 | } 176 | public override UserControl GetUserControl() { 177 | return m_UserControl; 178 | } 179 | public override string[] GetDatabases(PwEntry entry) { 180 | var client = GetClient(); 181 | DecodeEntry(entry); 182 | List databases = new List(); 183 | var files = client.ListObjectsV2(new ListObjectsV2Request { BucketName = BucketName }); 184 | foreach (var file in files.S3Objects) { 185 | if (file.Key.EndsWith(".kdbx")) 186 | databases.Add(file.Key); 187 | } 188 | return databases.ToArray(); 189 | } 190 | 191 | private bool FileExists(string filename) { 192 | 193 | var client = GetClient(); 194 | try { 195 | var meta = client.GetObjectMetadata(BucketName, filename); 196 | return true; 197 | } catch (AmazonS3Exception s3) { 198 | if (s3.StatusCode != HttpStatusCode.NotFound) 199 | throw s3; 200 | return false; 201 | } 202 | } 203 | //public string BucketName => m_UserControl.BucketName?.ToLower(); 204 | //public string BucketName { get { return m_UserControl.BucketName == null ? null : m_UserControl.BucketName.ToLower(); } } 205 | public string BucketName { get { return m_UserControl.BucketName == null ? null : m_UserControl.BucketName; } } 206 | public override KeePassSyncErr GetFile(PwEntry entry, string remoteFilename, string localFilename) { 207 | DecodeEntry(entry); 208 | var client = GetClient(); 209 | try { 210 | verify_bucket_or_create(BucketName); 211 | var req = new GetObjectRequest { BucketName = BucketName, Key = remoteFilename }; 212 | if (m_UserControl.UseChecksums) 213 | req.ChecksumMode = ChecksumMode.ENABLED; 214 | 215 | var obj = client.GetObject(req); 216 | using (var memStream = new MemoryStream()) { 217 | using (var resp = obj.ResponseStream) { 218 | resp.CopyTo(memStream); 219 | } 220 | memStream.Seek(0, SeekOrigin.Begin); 221 | var hash = GetSHA1(memStream); 222 | 223 | //the alg must have been set to sha1 during upload for this to work, prior to 2024 we didn't use sha, in addition if a user manually copied it might lose the SHA checksum 224 | if (m_UserControl.UseChecksums && obj.ResponseMetadata.ChecksumAlgorithm == Amazon.Runtime.CoreChecksumAlgorithm.SHA1 && !obj.ChecksumSHA1.Equals(hash, StringComparison.OrdinalIgnoreCase)) 225 | //throw new Exception($"File downloaded but our hash of: {hash} does not match server hash of: {obj.ChecksumSHA1}"); 226 | throw new Exception("File downloaded but our hash of: " + hash + " does not match server hash of: " + obj.ChecksumSHA1); 227 | 228 | using (var fs = File.OpenWrite(localFilename)) { 229 | memStream.Seek(0, SeekOrigin.Begin); 230 | memStream.CopyTo(fs); 231 | } 232 | } 233 | } catch (Exception e) { 234 | var ae = e as AmazonS3Exception; 235 | if (e.Message == "The specified key does not exist." || (ae != null && ae.ErrorCode=="NoSuchKey") )//errorcode check for 3rd parties that may not conform 236 | return KeePassSyncErr.FileNotFound; 237 | return convert_exception(e); 238 | } 239 | return KeePassSyncErr.None; 240 | 241 | } 242 | private KeePassSyncErr convert_exception(Exception e) { 243 | if (e.GetType() == typeof(WebException)) { 244 | WebException w_exp = (WebException)e; 245 | if (w_exp.Status == WebExceptionStatus.ConnectFailure || w_exp.Status == WebExceptionStatus.NameResolutionFailure) 246 | return KeePassSyncErr.NotConnected; 247 | 248 | } 249 | KeePassSyncErr ret; 250 | string msg; 251 | StatusPriority priority = StatusPriority.eMessageBoxFatal; 252 | switch (e.Message) { 253 | case "The specified bucket is not valid.": 254 | ret = KeePassSyncErr.Error; 255 | msg = "Unable to access or create the bucket, make sure bucketname is only lowercase characters and numbers and that you own it (if it exists) min 3 chars max 63"; 256 | break; 257 | case "Access Denied": 258 | ret = KeePassSyncErr.Error; 259 | msg = "If the bucket exists, does the access key you are using have read/write access to it? if it doesn't exist do you have permissions with this access key to create? If not create yourself"; 260 | break; 261 | case "The specified key does not exist.": 262 | ret = KeePassSyncErr.FileNotFound; 263 | msg = "Tried to get file we could not find"; 264 | priority = StatusPriority.eStatusBar; 265 | break; 266 | case "The request signature we calculated does not match the signature you provided. Check your key and signing method.": 267 | case "The AWS Access Key Id you provided does not exist in our records.": 268 | ret = KeePassSyncErr.InvalidCredentials; 269 | msg = "Invalid Credentials"; 270 | break; 271 | default: 272 | msg = e.Message + "\r\n" + e.StackTrace; 273 | ret = KeePassSyncErr.Error; 274 | break; 275 | } 276 | m_MainInterface.SetStatus(priority, "KeyPassSync_S3: " + msg); 277 | return ret; 278 | } 279 | 280 | 281 | private KeePassSyncErr verify_bucket_or_create(String bucket_name) { 282 | try { 283 | var client = GetClient(); 284 | if (!AmazonS3Util.DoesS3BucketExistV2(client, bucket_name)) 285 | client.PutBucket(bucket_name); 286 | return KeePassSyncErr.None; 287 | 288 | } catch (Exception e) { 289 | return convert_exception(e); 290 | } 291 | } 292 | 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /KeePassSync/Providers/SFTP/AccountDetails.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeePassSync.Providers.SFTP { 2 | partial class AccountDetails { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose(bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose(); 15 | } 16 | base.Dispose(disposing); 17 | } 18 | 19 | #region Component Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent() { 26 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AccountDetails)); 27 | this.label1 = new System.Windows.Forms.Label(); 28 | this.label2 = new System.Windows.Forms.Label(); 29 | this.txtHost = new System.Windows.Forms.TextBox(); 30 | this.txtUsername = new System.Windows.Forms.TextBox(); 31 | this.label3 = new System.Windows.Forms.Label(); 32 | this.txtDirectory = new System.Windows.Forms.TextBox(); 33 | this.label4 = new System.Windows.Forms.Label(); 34 | this.txtPassword = new System.Windows.Forms.TextBox(); 35 | this.label6 = new System.Windows.Forms.Label(); 36 | this.label7 = new System.Windows.Forms.Label(); 37 | this.checkPaegent = new System.Windows.Forms.CheckBox(); 38 | this.txtPort = new System.Windows.Forms.TextBox(); 39 | this.label5 = new System.Windows.Forms.Label(); 40 | this.txtExecPath = new System.Windows.Forms.TextBox(); 41 | this.label8 = new System.Windows.Forms.Label(); 42 | this.checkKeepassRoot = new System.Windows.Forms.CheckBox(); 43 | this.label9 = new System.Windows.Forms.Label(); 44 | this.checkDebug = new System.Windows.Forms.CheckBox(); 45 | this.comboTimeout = new System.Windows.Forms.ComboBox(); 46 | this.SuspendLayout(); 47 | // 48 | // label1 49 | // 50 | this.label1.AutoSize = true; 51 | this.label1.Location = new System.Drawing.Point(3, 33); 52 | this.label1.Name = "label1"; 53 | this.label1.Size = new System.Drawing.Size(58, 13); 54 | this.label1.TabIndex = 0; 55 | this.label1.Text = "Username:"; 56 | // 57 | // label2 58 | // 59 | this.label2.AutoSize = true; 60 | this.label2.Location = new System.Drawing.Point(3, 6); 61 | this.label2.Name = "label2"; 62 | this.label2.Size = new System.Drawing.Size(32, 13); 63 | this.label2.TabIndex = 1; 64 | this.label2.Text = "Host:"; 65 | // 66 | // txtHost 67 | // 68 | this.txtHost.Location = new System.Drawing.Point(64, 3); 69 | this.txtHost.Name = "txtHost"; 70 | this.txtHost.Size = new System.Drawing.Size(157, 20); 71 | this.txtHost.TabIndex = 1; 72 | // 73 | // txtUsername 74 | // 75 | this.txtUsername.Location = new System.Drawing.Point(64, 30); 76 | this.txtUsername.Name = "txtUsername"; 77 | this.txtUsername.Size = new System.Drawing.Size(157, 20); 78 | this.txtUsername.TabIndex = 3; 79 | // 80 | // label3 81 | // 82 | this.label3.AutoSize = true; 83 | this.label3.Location = new System.Drawing.Point(3, 85); 84 | this.label3.Name = "label3"; 85 | this.label3.Size = new System.Drawing.Size(52, 13); 86 | this.label3.TabIndex = 4; 87 | this.label3.Text = "Directory:"; 88 | // 89 | // txtDirectory 90 | // 91 | this.txtDirectory.Location = new System.Drawing.Point(64, 82); 92 | this.txtDirectory.Name = "txtDirectory"; 93 | this.txtDirectory.Size = new System.Drawing.Size(239, 20); 94 | this.txtDirectory.TabIndex = 6; 95 | // 96 | // label4 97 | // 98 | this.label4.AutoSize = true; 99 | this.label4.Location = new System.Drawing.Point(3, 59); 100 | this.label4.Name = "label4"; 101 | this.label4.Size = new System.Drawing.Size(56, 13); 102 | this.label4.TabIndex = 6; 103 | this.label4.Text = "Password:"; 104 | // 105 | // txtPassword 106 | // 107 | this.txtPassword.Location = new System.Drawing.Point(64, 56); 108 | this.txtPassword.Name = "txtPassword"; 109 | this.txtPassword.PasswordChar = '*'; 110 | this.txtPassword.Size = new System.Drawing.Size(157, 20); 111 | this.txtPassword.TabIndex = 4; 112 | // 113 | // label6 114 | // 115 | this.label6.AutoSize = true; 116 | this.label6.Location = new System.Drawing.Point(21, 211); 117 | this.label6.MaximumSize = new System.Drawing.Size(350, 0); 118 | this.label6.Name = "label6"; 119 | this.label6.Size = new System.Drawing.Size(341, 91); 120 | this.label6.TabIndex = 9; 121 | this.label6.Text = resources.GetString("label6.Text"); 122 | // 123 | // label7 124 | // 125 | this.label7.AutoSize = true; 126 | this.label7.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 127 | this.label7.Location = new System.Drawing.Point(3, 196); 128 | this.label7.Name = "label7"; 129 | this.label7.Size = new System.Drawing.Size(44, 13); 130 | this.label7.TabIndex = 10; 131 | this.label7.Text = "Notes:"; 132 | // 133 | // checkPaegent 134 | // 135 | this.checkPaegent.AutoSize = true; 136 | this.checkPaegent.Location = new System.Drawing.Point(228, 57); 137 | this.checkPaegent.Name = "checkPaegent"; 138 | this.checkPaegent.Size = new System.Drawing.Size(126, 17); 139 | this.checkPaegent.TabIndex = 5; 140 | this.checkPaegent.Text = "Use Paegent Instead"; 141 | this.checkPaegent.UseVisualStyleBackColor = true; 142 | this.checkPaegent.CheckedChanged += new System.EventHandler(this.checkPaegent_CheckedChanged); 143 | // 144 | // txtPort 145 | // 146 | this.txtPort.Location = new System.Drawing.Point(259, 3); 147 | this.txtPort.Name = "txtPort"; 148 | this.txtPort.Size = new System.Drawing.Size(32, 20); 149 | this.txtPort.TabIndex = 2; 150 | this.txtPort.Text = "22"; 151 | // 152 | // label5 153 | // 154 | this.label5.AutoSize = true; 155 | this.label5.Location = new System.Drawing.Point(227, 6); 156 | this.label5.Name = "label5"; 157 | this.label5.Size = new System.Drawing.Size(29, 13); 158 | this.label5.TabIndex = 12; 159 | this.label5.Text = "Port:"; 160 | // 161 | // txtExecPath 162 | // 163 | this.txtExecPath.Location = new System.Drawing.Point(114, 112); 164 | this.txtExecPath.Name = "txtExecPath"; 165 | this.txtExecPath.Size = new System.Drawing.Size(164, 20); 166 | this.txtExecPath.TabIndex = 7; 167 | // 168 | // label8 169 | // 170 | this.label8.AutoSize = true; 171 | this.label8.Location = new System.Drawing.Point(3, 115); 172 | this.label8.Name = "label8"; 173 | this.label8.Size = new System.Drawing.Size(105, 13); 174 | this.label8.TabIndex = 14; 175 | this.label8.Text = "PLINK/PSFTP Path:"; 176 | // 177 | // checkKeepassRoot 178 | // 179 | this.checkKeepassRoot.AutoSize = true; 180 | this.checkKeepassRoot.Location = new System.Drawing.Point(286, 114); 181 | this.checkKeepassRoot.Name = "checkKeepassRoot"; 182 | this.checkKeepassRoot.Size = new System.Drawing.Size(93, 17); 183 | this.checkKeepassRoot.TabIndex = 8; 184 | this.checkKeepassRoot.Text = "Keepass Root"; 185 | this.checkKeepassRoot.UseVisualStyleBackColor = true; 186 | this.checkKeepassRoot.CheckedChanged += new System.EventHandler(this.checkKeepassRoot_CheckedChanged); 187 | // 188 | // label9 189 | // 190 | this.label9.AutoSize = true; 191 | this.label9.Location = new System.Drawing.Point(3, 142); 192 | this.label9.Name = "label9"; 193 | this.label9.Size = new System.Drawing.Size(93, 13); 194 | this.label9.TabIndex = 17; 195 | this.label9.Text = "Timeout Seconds:"; 196 | // 197 | // checkDebug 198 | // 199 | this.checkDebug.AutoSize = true; 200 | this.checkDebug.Location = new System.Drawing.Point(9, 170); 201 | this.checkDebug.Name = "checkDebug"; 202 | this.checkDebug.Size = new System.Drawing.Size(88, 17); 203 | this.checkDebug.TabIndex = 10; 204 | this.checkDebug.Text = "Debug Mode"; 205 | this.checkDebug.UseVisualStyleBackColor = true; 206 | // 207 | // comboTimeout 208 | // 209 | this.comboTimeout.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 210 | this.comboTimeout.FormattingEnabled = true; 211 | this.comboTimeout.Items.AddRange(new object[] { 212 | "1", 213 | "2", 214 | "3", 215 | "4", 216 | "5", 217 | "6", 218 | "7", 219 | "8", 220 | "9", 221 | "10", 222 | "11", 223 | "12", 224 | "13", 225 | "14", 226 | "15", 227 | "16", 228 | "17", 229 | "18", 230 | "19", 231 | "20", 232 | "21", 233 | "22", 234 | "23", 235 | "24", 236 | "25", 237 | "26", 238 | "27", 239 | "28", 240 | "29", 241 | "30", 242 | "31", 243 | "32", 244 | "33", 245 | "34", 246 | "35", 247 | "36", 248 | "37", 249 | "38", 250 | "39", 251 | "40"}); 252 | this.comboTimeout.Location = new System.Drawing.Point(114, 138); 253 | this.comboTimeout.Name = "comboTimeout"; 254 | this.comboTimeout.Size = new System.Drawing.Size(57, 21); 255 | this.comboTimeout.TabIndex = 9; 256 | // 257 | // AccountDetails 258 | // 259 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 260 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 261 | this.Controls.Add(this.comboTimeout); 262 | this.Controls.Add(this.checkDebug); 263 | this.Controls.Add(this.label9); 264 | this.Controls.Add(this.checkKeepassRoot); 265 | this.Controls.Add(this.txtExecPath); 266 | this.Controls.Add(this.label8); 267 | this.Controls.Add(this.txtPort); 268 | this.Controls.Add(this.label5); 269 | this.Controls.Add(this.checkPaegent); 270 | this.Controls.Add(this.label7); 271 | this.Controls.Add(this.label6); 272 | this.Controls.Add(this.txtPassword); 273 | this.Controls.Add(this.label4); 274 | this.Controls.Add(this.txtDirectory); 275 | this.Controls.Add(this.label3); 276 | this.Controls.Add(this.txtUsername); 277 | this.Controls.Add(this.txtHost); 278 | this.Controls.Add(this.label2); 279 | this.Controls.Add(this.label1); 280 | this.Name = "AccountDetails"; 281 | this.Size = new System.Drawing.Size(381, 312); 282 | this.Load += new System.EventHandler(this.AccountDetails_Load); 283 | this.ResumeLayout(false); 284 | this.PerformLayout(); 285 | 286 | } 287 | 288 | #endregion 289 | 290 | private System.Windows.Forms.Label label1; 291 | private System.Windows.Forms.Label label2; 292 | private System.Windows.Forms.TextBox txtHost; 293 | private System.Windows.Forms.TextBox txtUsername; 294 | private System.Windows.Forms.Label label3; 295 | private System.Windows.Forms.TextBox txtDirectory; 296 | private System.Windows.Forms.Label label4; 297 | private System.Windows.Forms.TextBox txtPassword; 298 | private System.Windows.Forms.Label label6; 299 | private System.Windows.Forms.Label label7; 300 | private System.Windows.Forms.CheckBox checkPaegent; 301 | private System.Windows.Forms.TextBox txtPort; 302 | private System.Windows.Forms.Label label5; 303 | private System.Windows.Forms.TextBox txtExecPath; 304 | private System.Windows.Forms.Label label8; 305 | private System.Windows.Forms.CheckBox checkKeepassRoot; 306 | private System.Windows.Forms.Label label9; 307 | private System.Windows.Forms.CheckBox checkDebug; 308 | private System.Windows.Forms.ComboBox comboTimeout; 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /KeePassSync/Providers/SFTP/AccountDetails.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace KeePassSync.Providers.SFTP { 5 | public partial class AccountDetails : UserControl { 6 | public string Username { 7 | get { return txtUsername.Text; } 8 | set { txtUsername.Text = value; } 9 | } 10 | 11 | public string Password { 12 | get { return txtPassword.Text; } 13 | set { txtPassword.Text = value; } 14 | } 15 | public bool UsePaegentInstead { 16 | get { return checkPaegent.Checked; } 17 | set { checkPaegent.Checked = value; } 18 | } 19 | public string Host { 20 | get { return txtHost.Text; } 21 | set { txtHost.Text = value; } 22 | } 23 | 24 | public string Directory { 25 | get { return txtDirectory.Text; } 26 | set { txtDirectory.Text = value; } 27 | } 28 | public string Port { 29 | get { 30 | if (String.IsNullOrEmpty(txtPort.Text)) 31 | return "22"; 32 | return txtPort.Text; 33 | } 34 | set { 35 | if (String.IsNullOrEmpty(value)) 36 | txtPort.Text = "22"; 37 | else 38 | txtPort.Text = value; 39 | } 40 | } 41 | public bool DebugMode { 42 | get { return checkDebug.Checked; } 43 | set { checkDebug.Checked = value; } 44 | } 45 | public int TimeoutSeconds { 46 | get { return Int32.Parse(comboTimeout.SelectedItem as string); } 47 | set { 48 | comboTimeout.SelectedItem = value.ToString(); 49 | if (comboTimeout.SelectedIndex == -1 || comboTimeout.SelectedItem.ToString() != value.ToString()) 50 | comboTimeout.SelectedItem = "7"; 51 | 52 | } 53 | } 54 | public string ExecRoot { 55 | get { return checkKeepassRoot.Checked ? "" : txtExecPath.Text; } 56 | set { 57 | if (String.IsNullOrEmpty(value)) { 58 | checkKeepassRoot.Checked = true; 59 | txtExecPath.Text = ""; 60 | } else { 61 | checkKeepassRoot.Checked = false; 62 | txtExecPath.Text = value; 63 | } 64 | } 65 | } 66 | public AccountDetails() { 67 | InitializeComponent(); 68 | ExecRoot = ""; 69 | TimeoutSeconds = -1; 70 | Port = ""; 71 | } 72 | 73 | private void AccountDetails_Load(object sender, EventArgs e) { 74 | 75 | } 76 | 77 | private void checkPaegent_CheckedChanged(object sender, EventArgs e) { 78 | txtPassword.ReadOnly = checkPaegent.Checked; 79 | } 80 | 81 | private void checkKeepassRoot_CheckedChanged(object sender, EventArgs e) { 82 | txtExecPath.ReadOnly = checkKeepassRoot.Checked; 83 | } 84 | 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /KeePassSync/Providers/SFTP/AccountDetails.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 1. This will launch the included Putty pscp.exe program for transfer. 122 | 2. Database retieval using KeePassSync->Open will use plink.exe. 123 | 3. pscp.exe doesn't like fully qualified paths, use relative paths to the home directory instead. 124 | 4. Paths are most likely case sensitive. 125 | 5. Debug mode enables verbose output from all commands and shows the command window rather than hiding it. 126 | 127 | -------------------------------------------------------------------------------- /KeePassSync/Providers/SFTP/main.cs: -------------------------------------------------------------------------------- 1 | /* 2 | KeePassSync - Online Sync Plugin for KeePass Password Safe 3 | Copyright (C) 2008 Shawn Casey, shawn.casey@gmail.com 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | using System; 21 | using System.Collections; 22 | using System.Diagnostics; 23 | using System.IO; 24 | using KeePassLib; 25 | using KeePassLib.Security; 26 | 27 | namespace KeePassSync.Providers.SFTP { 28 | public class FtpProvider : IOnlineProvider { 29 | #region -- Private data -- 30 | private const string m_Name = "SCP/SFTP"; 31 | private const string ONLINE_DB_PREFIX = "Keepass-"; 32 | private string fields_username = PwDefs.UserNameField; 33 | 34 | private string fields_password = PwDefs.PasswordField; 35 | private bool memprotect_password = true; 36 | 37 | private string fields_host = PwDefs.UrlField; 38 | private string fields_port = "Port"; 39 | private string fields_directory = "DirectoryField"; 40 | private string fields_exec_path = "ExecPath"; 41 | private string fields_timeout = "Timeout"; 42 | private string fields_debug_mode = "Debug"; 43 | private string fields_paegent = "Paegent"; 44 | 45 | private string[] m_AcceptedNames = { "SCP/SFTP", "SCP/FTP" }; 46 | private AccountDetails m_UserControl = null; 47 | #endregion 48 | 49 | private enum EXEC { PLINK, PSCP }; 50 | private string str_qwt(string str) { 51 | return "\"" + str + "\""; 52 | } 53 | private KeePassSyncErr command_plink(String command) { 54 | return _run_command(EXEC.PLINK, "", command, false); 55 | } 56 | private KeePassSyncErr command_scp(String source_file, String dest_file, bool is_get) { 57 | if (!is_get) 58 | source_file = str_qwt(source_file); 59 | else 60 | dest_file = str_qwt(dest_file); 61 | 62 | return _run_command(EXEC.PSCP, source_file, dest_file, is_get); 63 | } 64 | private KeePassSyncErr _run_command(EXEC exec, String command_before, String command_after, bool is_get) { 65 | KeePassSyncErr ret = KeePassSyncErr.None; 66 | if (String.IsNullOrEmpty(m_UserControl.Host)) 67 | return KeePassSyncErr.Error; 68 | 69 | try { 70 | System.Diagnostics.Process process = new Process(); 71 | if (process == null) 72 | return KeePassSyncErr.Error; 73 | 74 | string commandStr = "-batch"; 75 | if (m_UserControl.UsePaegentInstead) 76 | commandStr += " -agent"; 77 | else 78 | commandStr += " -pw " + str_qwt(m_UserControl.Password); 79 | commandStr += " -P " + str_qwt(m_UserControl.Port); 80 | if (m_UserControl.DebugMode) { 81 | process.StartInfo.CreateNoWindow = false; 82 | commandStr += " -v"; 83 | process.StartInfo.WindowStyle = ProcessWindowStyle.Normal; 84 | } else { 85 | process.StartInfo.CreateNoWindow = true; 86 | process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; 87 | } 88 | if (!String.IsNullOrEmpty(command_before) && (exec != EXEC.PSCP || !is_get)) 89 | commandStr += " " + command_before; 90 | 91 | string host_str = m_UserControl.Username + "@" + m_UserControl.Host; 92 | 93 | if (exec == EXEC.PSCP && is_get) 94 | host_str += ":" + command_before; 95 | 96 | if (exec == EXEC.PSCP && !is_get) 97 | host_str += ":" + command_after; 98 | 99 | commandStr += " " + str_qwt(host_str); 100 | 101 | if (!String.IsNullOrEmpty(command_after) && (exec != EXEC.PSCP || is_get)) 102 | commandStr += " " + command_after; 103 | 104 | String exec_path = m_UserControl.ExecRoot; 105 | if (String.IsNullOrEmpty(exec_path)){ 106 | exec_path = KeePassSyncExt.PluginDirectory; 107 | if (! File.Exists(System.IO.Path.Combine( exec_path,"pscp.exe"))) 108 | exec_path = KeePassSyncExt.KeePassDir; 109 | } 110 | switch (exec) { 111 | case EXEC.PSCP: 112 | exec_path += "\\" + "pscp.exe"; 113 | break; 114 | case EXEC.PLINK: 115 | exec_path += "\\" + "plink.exe"; 116 | break; 117 | } 118 | if (!System.IO.File.Exists(exec_path)) { 119 | m_MainInterface.SetStatus(StatusPriority.eMessageBoxInfo, "Unable to find pscp/plink.exe at the path: " + exec_path + " specified please check"); 120 | return KeePassSyncErr.Error; 121 | } 122 | process.StartInfo.FileName = exec_path; 123 | process.StartInfo.Arguments = commandStr; 124 | 125 | process.StartInfo.WorkingDirectory = KeePassSyncExt.PluginDirectory; 126 | process.Start(); 127 | bool exitedOnTime = process.WaitForExit(m_UserControl.TimeoutSeconds * 1000); 128 | 129 | if (exitedOnTime) 130 | ret = KeePassSyncErr.None; 131 | else { 132 | m_MainInterface.SetStatus(StatusPriority.eMessageBoxInfo, "A timeout occurred validating options using FTP/SCP provider.\n\nAre you sure you've authenticated your server?\nSee docs\\KeePassSync-readme.txt for details."); 133 | ret = KeePassSyncErr.Timeout; 134 | } 135 | 136 | 137 | } catch { 138 | ret = KeePassSyncErr.Error; 139 | } 140 | return ret; 141 | } 142 | private string KeepassDirFilename { get { return KeePassSyncExt.PluginDirectory + "\\KeePassSyncDir.txt"; } } 143 | public override KeePassSyncErr Initialize(KeePassSyncExt mainInterface) { 144 | KeePassSyncErr ret = base.Initialize(mainInterface); 145 | 146 | m_UserControl = new AccountDetails(); 147 | 148 | m_IsInitialized = (ret == KeePassSyncErr.None); 149 | 150 | return ret; 151 | } 152 | 153 | public override KeePassSyncErr ValidateOptions(OptionsData options) { 154 | KeePassSyncErr ret = KeePassSyncErr.None; 155 | PwEntry entry = m_OptionData.PasswordEntry; 156 | AccountDetails old_details = m_UserControl; 157 | m_UserControl = new AccountDetails(); 158 | DecodeEntry(entry); 159 | ret = command_plink("ls"); 160 | m_UserControl = old_details; 161 | return ret; 162 | } 163 | 164 | 165 | /// 166 | /// First delete the file and then save it. This service provider automatically 167 | /// renames the sent file much like Windows Explorer does when there is a duplicate 168 | /// filename on copy. 169 | /// 170 | /// 171 | /// 172 | /// 173 | public override KeePassSyncErr PutFile(PwEntry entry, string databaseName, string filename) { 174 | DecodeEntry(entry); 175 | KeePassSyncErr ret = KeePassSyncErr.Error; 176 | System.Diagnostics.Process process = new Process(); 177 | 178 | string directory = m_UserControl.Directory; 179 | if (directory != "" && !directory.EndsWith("/")) 180 | directory += "/"; 181 | 182 | string remoteDatabaseName = ONLINE_DB_PREFIX + databaseName; 183 | 184 | // Backup the existing file 185 | string backupName = remoteDatabaseName + ".bak"; 186 | 187 | ret = command_plink("mv " + str_qwt(directory + remoteDatabaseName) + " " + str_qwt(directory + backupName)); 188 | 189 | 190 | 191 | // Send the new file 192 | if (ret == KeePassSyncErr.None) { 193 | ret = command_scp(filename, directory + remoteDatabaseName, false); 194 | if (ret == KeePassSyncErr.None) 195 | ret = CheckRemoteFileExists(remoteDatabaseName); 196 | } 197 | return ret; 198 | } 199 | 200 | private KeePassSyncErr CheckRemoteFileExists(string remoteDatabaseName) { 201 | KeePassSyncErr ret = KeePassSyncErr.Error; 202 | 203 | try { 204 | ret = RemoteDatabaseListing(KeepassDirFilename); 205 | if (ret == KeePassSyncErr.None) { 206 | string directory = m_UserControl.Directory; 207 | if (directory != "" && !directory.EndsWith("/")) 208 | directory += "/"; 209 | 210 | // read the text file for databases 211 | ret = KeePassSyncErr.FileNotFound; 212 | string[] lines = File.ReadAllLines(KeepassDirFilename); 213 | if (lines.Length > 0) { 214 | foreach (string line in lines) { 215 | if (line == (directory + remoteDatabaseName)) { 216 | ret = KeePassSyncErr.None; 217 | break; 218 | } 219 | } 220 | } 221 | } else { 222 | ret = KeePassSyncErr.FileNotFound; 223 | } 224 | 225 | } catch { 226 | ret = KeePassSyncErr.Error; 227 | } 228 | 229 | if (File.Exists(KeepassDirFilename)) 230 | File.Delete(KeepassDirFilename); 231 | 232 | return ret; 233 | } 234 | 235 | public override KeePassSyncErr GetFile(PwEntry entry, string databaseName, string filename) { 236 | Debug.Assert(entry != null, "Invalid entry"); 237 | DecodeEntry(entry); 238 | KeePassSyncErr ret = KeePassSyncErr.None; 239 | if (File.Exists(filename)) 240 | File.Delete(filename); 241 | 242 | string directory = m_UserControl.Directory; 243 | if (directory != "" && !directory.EndsWith("/")) 244 | directory += "/"; 245 | 246 | string remoteDatabaseName = ONLINE_DB_PREFIX + databaseName; 247 | 248 | ret = command_scp(directory + remoteDatabaseName, filename, true); 249 | 250 | if (ret == KeePassSyncErr.None && !File.Exists(filename)) 251 | ret = KeePassSyncErr.FileNotFound; 252 | 253 | 254 | return ret; 255 | } 256 | 257 | 258 | public override string CreateAccountLink { 259 | get { return null; } 260 | } 261 | 262 | public override string Name { 263 | get { return m_Name; } 264 | } 265 | 266 | public override string[] AcceptedNames { 267 | get { return m_AcceptedNames; } 268 | } 269 | 270 | public override string[] Databases { 271 | get { 272 | return GetDatabases(m_OptionData.PasswordEntry); 273 | } 274 | } 275 | 276 | private KeePassSyncErr RemoteDatabaseListing(string localListingFileFullPath) { 277 | KeePassSyncErr ret = KeePassSyncErr.Error; 278 | 279 | if (File.Exists(localListingFileFullPath)) 280 | File.Delete(localListingFileFullPath); 281 | 282 | // Generate directory listing 283 | string remoteDirectory = m_UserControl.Directory; 284 | if (remoteDirectory != "" && !remoteDirectory.EndsWith("/")) 285 | remoteDirectory += "/"; 286 | 287 | ret = command_plink("ls -1 " + str_qwt(remoteDirectory + ONLINE_DB_PREFIX + "*") + " > " + str_qwt(remoteDirectory + "KeePassSyncDir.txt")); 288 | 289 | 290 | if (ret == KeePassSyncErr.None) { 291 | ret = command_scp(remoteDirectory + "KeePassSyncDir.txt", localListingFileFullPath, true); 292 | if (ret == KeePassSyncErr.None && !File.Exists(localListingFileFullPath)) 293 | ret = KeePassSyncErr.Error; 294 | } 295 | 296 | 297 | return ret; 298 | } 299 | 300 | public override string[] GetDatabases(PwEntry entry) { 301 | Debug.Assert(entry != null, "Invalid entry"); 302 | AccountDetails old_details = m_UserControl; 303 | m_UserControl = new AccountDetails(); 304 | DecodeEntry(entry); 305 | 306 | 307 | // Use plink to issue directory command as text file 308 | // plink -pw password user@host "dir > out.txt" 309 | // use pscp to download the file 310 | // then plink to delete the file again 311 | // pscp doesn't like a full path, it likes it relative to the home folder 312 | KeePassSyncErr err = RemoteDatabaseListing(KeepassDirFilename); 313 | if (err == KeePassSyncErr.None) { 314 | // Generate directory listing 315 | string remoteDirectory = m_UserControl.Directory; 316 | if (remoteDirectory != "" && !remoteDirectory.EndsWith("/")) 317 | remoteDirectory += "/"; 318 | 319 | // read the text file for databases 320 | string[] lines = File.ReadAllLines(KeepassDirFilename); 321 | ArrayList databases = null; 322 | if (lines.Length > 0) { 323 | databases = new ArrayList(); 324 | foreach (string line in lines) { 325 | databases.Add(line.Substring(remoteDirectory.Length + ONLINE_DB_PREFIX.Length)); 326 | } 327 | m_UserControl = old_details; 328 | return (string[])databases.ToArray(typeof(string)); 329 | } 330 | } else if (err == KeePassSyncErr.Timeout) 331 | m_MainInterface.SetStatus(StatusPriority.eMessageBoxInfo, "A timeout occurred retrieving databases.\n\nAre you sure you've authenticated your server?\nSee docs\\KeePassSync-readme.txt for details."); 332 | else 333 | m_MainInterface.SetStatus(StatusPriority.eMessageBoxInfo, "A general error occurred retrieving databases.\n\nAre you sure you've authenticated your server?\nSee docs\\KeePassSync-readme.txt for details."); 334 | 335 | if (File.Exists(KeepassDirFilename)) 336 | File.Delete(KeepassDirFilename); 337 | m_UserControl = old_details; 338 | return null; 339 | } 340 | 341 | public override System.Windows.Forms.UserControl GetUserControl() { 342 | return m_UserControl; 343 | } 344 | public string read_PwEntry_string(PwEntry entry, String key) { 345 | ProtectedString str = entry.Strings.Get(key); 346 | if (str == null) 347 | return ""; 348 | return str.ReadString(); 349 | } 350 | public bool read_PwEntry_bool(PwEntry entry, String key) { 351 | String val = read_PwEntry_string(entry, key); 352 | if (val == "true") 353 | return true; 354 | return false; 355 | } 356 | public override void DecodeEntry(PwEntry entry) { 357 | Debug.Assert(entry != null, "Invalid entry"); 358 | m_UserControl.Username = read_PwEntry_string(entry, fields_username); 359 | m_UserControl.Password = read_PwEntry_string(entry, fields_password); 360 | m_UserControl.Host = read_PwEntry_string(entry, fields_host); 361 | m_UserControl.Port = read_PwEntry_string(entry, fields_port); 362 | m_UserControl.Directory = read_PwEntry_string(entry, fields_directory); 363 | m_UserControl.ExecRoot = read_PwEntry_string(entry, fields_exec_path); 364 | int timeout = 0; 365 | Int32.TryParse(read_PwEntry_string(entry, fields_timeout), out timeout); 366 | m_UserControl.TimeoutSeconds = timeout; 367 | m_UserControl.DebugMode = read_PwEntry_bool(entry, fields_debug_mode); 368 | m_UserControl.UsePaegentInstead = read_PwEntry_bool(entry, fields_paegent); 369 | 370 | } 371 | public void write_PwEntry_string(PwEntry entry, String key, String value, bool in_memory_encrypt) { 372 | entry.Strings.Set(key, new ProtectedString(in_memory_encrypt, value)); 373 | } 374 | public void write_PwEntry_bool(PwEntry entry, String key, bool value, bool in_memory_encrypt) { 375 | write_PwEntry_string(entry, key, value ? "true" : "false", in_memory_encrypt); 376 | } 377 | public override void EncodeEntry(PwEntry entry) { 378 | Debug.Assert(entry != null, "Invalid entry"); 379 | write_PwEntry_string(entry, fields_username, m_UserControl.Username, false); 380 | write_PwEntry_string(entry, fields_password, m_UserControl.Password, memprotect_password); 381 | write_PwEntry_string(entry, fields_host, m_UserControl.Host, false); 382 | write_PwEntry_string(entry, fields_port, m_UserControl.Port, false); 383 | write_PwEntry_string(entry, fields_directory, m_UserControl.Directory, false); 384 | write_PwEntry_string(entry, fields_exec_path, m_UserControl.ExecRoot, false); 385 | write_PwEntry_string(entry, fields_timeout, m_UserControl.TimeoutSeconds.ToString(), false); 386 | write_PwEntry_bool(entry, fields_debug_mode, m_UserControl.DebugMode, false); 387 | write_PwEntry_bool(entry, fields_paegent, m_UserControl.UsePaegentInstead, false); 388 | 389 | 390 | } 391 | 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /KeePassSync/Resources/Icons/Img_16x16_Open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchcapper/KeePassSync/2b713b9971313168f47b22ec6832469da4eb1447/KeePassSync/Resources/Icons/Img_16x16_Open.png -------------------------------------------------------------------------------- /KeePassSync/Resources/Icons/Img_16x16_Options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchcapper/KeePassSync/2b713b9971313168f47b22ec6832469da4eb1447/KeePassSync/Resources/Icons/Img_16x16_Options.png -------------------------------------------------------------------------------- /KeePassSync/Resources/Icons/Img_16x16_Plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchcapper/KeePassSync/2b713b9971313168f47b22ec6832469da4eb1447/KeePassSync/Resources/Icons/Img_16x16_Plugin.png -------------------------------------------------------------------------------- /KeePassSync/Resources/Icons/Img_16x16_Sync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchcapper/KeePassSync/2b713b9971313168f47b22ec6832469da4eb1447/KeePassSync/Resources/Icons/Img_16x16_Sync.png -------------------------------------------------------------------------------- /KeePassSync/Resources/Icons/Img_48x48_Open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchcapper/KeePassSync/2b713b9971313168f47b22ec6832469da4eb1447/KeePassSync/Resources/Icons/Img_48x48_Open.png -------------------------------------------------------------------------------- /KeePassSync/Resources/Icons/Img_48x48_Password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchcapper/KeePassSync/2b713b9971313168f47b22ec6832469da4eb1447/KeePassSync/Resources/Icons/Img_48x48_Password.png -------------------------------------------------------------------------------- /KeePassSync/Resources/Icons/Img_48x48_Sync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchcapper/KeePassSync/2b713b9971313168f47b22ec6832469da4eb1447/KeePassSync/Resources/Icons/Img_48x48_Sync.png -------------------------------------------------------------------------------- /KeePassSync/Resources/Icons/icons_url.txt: -------------------------------------------------------------------------------- 1 | http://www.icon-king.com/?p=15 -------------------------------------------------------------------------------- /KeePassSync/Util.cs: -------------------------------------------------------------------------------- 1 | /* 2 | KeePassSync - Online Sync Plugin for KeePass Password Safe 3 | Copyright (C) 2008 Shawn Casey, shawn.casey@gmail.com 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | using System; 21 | using System.Collections; 22 | using System.Reflection; 23 | using System.IO; 24 | namespace KeePassSync { 25 | public class Util { 26 | public static class HexStringConverter { 27 | public static byte[] ToByteArray(String HexString) { 28 | int NumberChars = HexString.Length; 29 | byte[] bytes = new byte[NumberChars / 2]; 30 | for (int i = 0; i < NumberChars; i += 2) { 31 | bytes[i / 2] = Convert.ToByte(HexString.Substring(i, 2), 16); 32 | } 33 | return bytes; 34 | } 35 | 36 | public static String ToHexArray(byte[] bytes) { 37 | char[] c = new char[bytes.Length * 2]; 38 | byte b; 39 | for (int y = 0, x = 0; y < bytes.Length; ++y, ++x) { 40 | b = ((byte)(bytes[y] >> 4)); 41 | c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 42 | b = ((byte)(bytes[y] & 0xF)); 43 | c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 44 | } 45 | return new string(c); 46 | } 47 | } 48 | 49 | private static IOnlineProvider init_provider(IOnlineProvider provider, string Path) { 50 | provider.Path = Path; 51 | return provider; 52 | } 53 | 54 | public static IOnlineProvider[] DiscoverProviders() { 55 | ArrayList providers = new ArrayList(); 56 | string[] ignoreDlls = { //primarily old versions 57 | "KeePassSync_FTP.dll", 58 | "KeePassSync_S3.dll", 59 | "KeePassSync.dll", 60 | "KeePassSync_digitalBucket.net.dll" 61 | }; 62 | 63 | providers.Add(init_provider(new Providers.S3.S3Provider(), "S3")); 64 | providers.Add(init_provider(new Providers.SFTP.FtpProvider(), "SFTP")); 65 | // Search through the directory for DLLs 66 | 67 | foreach (string filename in Directory.GetFiles(KeePassSyncExt.PluginDirectory, "*.dll")) { 68 | if (!filename.StartsWith("KeePassSync", StringComparison.CurrentCultureIgnoreCase)) 69 | continue; 70 | bool skip = false; 71 | foreach (string ignore in ignoreDlls) { 72 | if (filename.ToLower().EndsWith(ignore.ToLower())) { 73 | skip = true; 74 | break; 75 | } 76 | } 77 | 78 | if (skip) 79 | continue; 80 | 81 | IOnlineProvider provider = Util.LoadOnlineProvider(filename); 82 | if (provider != null) 83 | providers.Add(provider); 84 | } 85 | 86 | return (IOnlineProvider[])providers.ToArray(typeof(IOnlineProvider)); 87 | } 88 | 89 | public static IOnlineProvider LoadOnlineProvider(string providerPath) { 90 | IOnlineProvider provider = null; 91 | try { 92 | Assembly asm = Assembly.LoadFrom(providerPath); 93 | if (asm != null) { 94 | Type[] types = asm.GetTypes(); 95 | if (types != null) { 96 | for (int i = 0; i < types.Length; i++) { 97 | if (types[i].IsClass && !types[i].IsAbstract && types[i].BaseType.Name == "IOnlineProvider") { 98 | object o = asm.CreateInstance(types[i].FullName); 99 | provider = o as IOnlineProvider; 100 | provider.Path = asm.Location; 101 | } 102 | } 103 | } 104 | } 105 | return provider; 106 | } catch { 107 | return null; 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /KeePassSync/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | What is KeePassSync? 2 | --------------- 3 | 4 | KeePassSync is a KeePass plugin that synchronizes your database using an online storage provider of your choice, any Rclone/Rsync compat storage, or FTP/SFTP. This allows two or more computers to easily keep their data in sync. It was originally created in 2008 by Shawn Casey, shawn.casey@gmail.com and is currently maintained in this GitHub repository. If you are looking for a provider recommendation consider CloudFlare R2. It is free for KeePass databases up to 10GB. 5 | 6 | This plugin will NOT work with KeePass v1.x. Thanks to https://github.com/walterpg/plgx-build-tasks for modernizing the PLGX build process. 7 | 8 | 9 | 10 | - [Requirements](#requirements) 11 | - [Changes](#changes) 12 | - [How to install](#how-to-install) 13 | - [How to use](#how-to-use) 14 | - [Services](#services) 15 | - [How to compile](#how-to-compile) 16 | - [Service Specific Notes](#service-specific-notes) 17 | - [Amazon S3 \(and other compatible providers\)](#amazon-s3-and-other-compatible-providers) 18 | - [SFTP/FTP](#sftpftp) 19 | - [Help!?!](#help) 20 | 21 | 22 | 23 | 24 | Requirements 25 | ------------- 26 | 27 | - KeePass 2.09 or higher 28 | 29 | Changes 30 | ------------- 31 | See [Change Log](ChangeLog.md) for details 32 | 33 | How to install 34 | --------------- 35 | 36 | To install a plugin, follow these steps: 37 | 38 | 1. Download the plgx of the plugin from the releases page at: https://github.com/mitchcapper/KeePassSync/releases 39 | 2. Copy the plgx file to the KeePass Plugins folder 40 | 3. Restart KeePass in order to load the new plugin. 41 | 42 | Note: If you have a very-old version of KeePassSync please delete the KeePassSync*.dll from the plugin folder. 43 | 44 | To "uninstall" a plugin, delete the the PLGX. 45 | 46 | How to use 47 | ----------- 48 | 49 | From the KeePass main menu, select Tools->KeePassSync->Show Options... 50 | 51 | You then select your online provider you wish to use. If you don't have an online provider account, you can create an account for the provider by clicking on the link beneath the selection box. Your online account information is securely stored as a KeePass entry. To create the entry, click the "Create Keepass Entry" button. It's important that you not rename this entry after it's created. You can move it around, but keep the same name. The username/password in this entry will be used to connect to the selected online provider. 52 | 53 | Once you do that, you can immediately sync with your online provider which will transmit changes from your database and apply them to the server version. How the synchronization is resolved is configurable in the "General" tab of the KeePassSync options. I use "Synchronize". If this is the first time your database is synchronized, your database will be uploaded to the online provider. 54 | 55 | Once you go to another computer, you will want to open the database from the online provider. You don't have to create an entry, but you will have to select from the options which provider you want to use. After that, select "Tools->KeePassSync->Open", select which provider you want to use. Input your account details for your online provider, click ok, and a list of previously synchronized databases will appear. Select which database you wish to open locally and declare a storage location for it. From then on, you may open the local database normally and synchronize whenever you want. 56 | 57 | For each services specific configuration guide please see that section below. 58 | 59 | Services 60 | --------------- 61 | 62 | KeePassSync supports the following services natively (although other users can add other services): 63 | 64 | - FTP/SFTP (through plink/psftp from PUTTY) 65 | 66 | - Amazon S3 or S3 Compatible services, this includes: 67 | - [Cloudflare R2](https://www.cloudflare.com/developer-platform/r2/) - free forever basically, 10GB a month which is way more than any keepass DB 68 | - [Rclone Serve S3](https://rclone.org/commands/rclone_serve_s3/) - Free open source software to use as an interface to anything RClone can interface with 69 | - [Backblaze B2](https://www.backblaze.com/cloud-storage) - Very cheap 70 | - Alibaba Cloud 71 | - DigitalOcean 72 | - Dreamhost 73 | - [Synology C2](https://c2.synology.com/en-us) 74 | - Linode Object Storage 75 | - IDrive E2 76 | - Huawei OBS 77 | - IBM COS S3 78 | - [Google GCS](https://cloud.google.com/storage) 79 | - Any of the many other compat providers, for several more see https://rclone.org/s3/ 80 | 81 | 82 | How to compile 83 | --------------- 84 | 85 | This solution is compiled using Visual Studio 2022. 86 | 87 | For more information: http://keepass.info/help/v2_dev/plg_index.html 88 | 89 | ## Service Specific Notes 90 | 91 | ### Amazon S3 (and other compatible providers) 92 | 93 | Please see the dedicated [Amazon S3](AMAZON_S3.md) instructions. 94 | 95 | ### SFTP/FTP 96 | 97 | The FTP provider uses SCP to transfer the files, you will have to manually establish a relationship with your FTP server. Have no fear, it's easy to do. Simply go to the directory you installed KeePassSync and type this: 98 | 99 | plink -pw (PASSWORD) (USERNAME)@(HOST) "ls" 100 | 101 | ...of course substituting PASSWORD, USERNAME, and HOST with appropriate values. 102 | 103 | Help!?! 104 | ------- 105 | 106 | Create an issue on the github issues section 107 | -------------------------------------------------------------------------------- /Support/PLINK.EXE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchcapper/KeePassSync/2b713b9971313168f47b22ec6832469da4eb1447/Support/PLINK.EXE -------------------------------------------------------------------------------- /Support/pscp.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchcapper/KeePassSync/2b713b9971313168f47b22ec6832469da4eb1447/Support/pscp.exe --------------------------------------------------------------------------------