Devin Martin avatar Devin Martin committed 10d74fe

Initial version with S3 and dropbox support.

Comments (0)

Files changed (69)

+syntax: glob
+bin/*
+obj/*
+*.suo
+*.user
+*.orig
+TestResults
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeeCloud", "KeeCloud\KeeCloud.csproj", "{967E2FA7-FB8F-4578-9A90-8D32B476671A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{967E2FA7-FB8F-4578-9A90-8D32B476671A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{967E2FA7-FB8F-4578-9A90-8D32B476671A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{967E2FA7-FB8F-4578-9A90-8D32B476671A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{967E2FA7-FB8F-4578-9A90-8D32B476671A}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(MonoDevelopProperties) = preSolution
+		StartupItem = KeeCloud\KeeCloud.csproj
+	EndGlobalSection
+EndGlobal

KeeCloud/Forms/FormAuthorizationSuccess.Designer.cs

+namespace KeeCloud.Forms
+{
+    partial class FormAuthorizationSuccess
+    {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component Designer generated code
+
+        /// <summary> 
+        /// Required method for Designer support - do not modify 
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.labelUsernameHeader = new System.Windows.Forms.Label();
+            this.labelPasswordHeader = new System.Windows.Forms.Label();
+            this.labelUsername = new System.Windows.Forms.Label();
+            this.labelPassword = new System.Windows.Forms.Label();
+            this.buttonShow = new System.Windows.Forms.Button();
+            this.buttonSave = new System.Windows.Forms.Button();
+            this.SuspendLayout();
+            // 
+            // labelUsernameHeader
+            // 
+            this.labelUsernameHeader.AutoSize = true;
+            this.labelUsernameHeader.Location = new System.Drawing.Point(19, 48);
+            this.labelUsernameHeader.Name = "labelUsernameHeader";
+            this.labelUsernameHeader.Size = new System.Drawing.Size(58, 13);
+            this.labelUsernameHeader.TabIndex = 0;
+            this.labelUsernameHeader.Text = "Username:";
+            // 
+            // labelPasswordHeader
+            // 
+            this.labelPasswordHeader.AutoSize = true;
+            this.labelPasswordHeader.Location = new System.Drawing.Point(19, 88);
+            this.labelPasswordHeader.Name = "labelPasswordHeader";
+            this.labelPasswordHeader.Size = new System.Drawing.Size(56, 13);
+            this.labelPasswordHeader.TabIndex = 1;
+            this.labelPasswordHeader.Text = "Password:";
+            // 
+            // labelUsername
+            // 
+            this.labelUsername.AutoSize = true;
+            this.labelUsername.Location = new System.Drawing.Point(83, 48);
+            this.labelUsername.Name = "labelUsername";
+            this.labelUsername.Size = new System.Drawing.Size(39, 13);
+            this.labelUsername.TabIndex = 2;
+            this.labelUsername.Text = "uname";
+            // 
+            // labelPassword
+            // 
+            this.labelPassword.AutoSize = true;
+            this.labelPassword.Location = new System.Drawing.Point(83, 88);
+            this.labelPassword.Name = "labelPassword";
+            this.labelPassword.Size = new System.Drawing.Size(23, 13);
+            this.labelPassword.TabIndex = 3;
+            this.labelPassword.Text = "****";
+            // 
+            // buttonShow
+            // 
+            this.buttonShow.Location = new System.Drawing.Point(22, 132);
+            this.buttonShow.Name = "buttonShow";
+            this.buttonShow.Size = new System.Drawing.Size(100, 23);
+            this.buttonShow.TabIndex = 4;
+            this.buttonShow.Text = "Show Password";
+            this.buttonShow.UseVisualStyleBackColor = true;
+            this.buttonShow.Click += new System.EventHandler(this.buttonShow_Click);
+            // 
+            // buttonSave
+            // 
+            this.buttonSave.Location = new System.Drawing.Point(142, 131);
+            this.buttonSave.Name = "buttonSave";
+            this.buttonSave.Size = new System.Drawing.Size(86, 23);
+            this.buttonSave.TabIndex = 5;
+            this.buttonSave.Text = "Save as Entry";
+            this.buttonSave.UseVisualStyleBackColor = true;
+            this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click);
+            // 
+            // FormAuthorizationSuccess
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.Controls.Add(this.buttonSave);
+            this.Controls.Add(this.buttonShow);
+            this.Controls.Add(this.labelPassword);
+            this.Controls.Add(this.labelUsername);
+            this.Controls.Add(this.labelPasswordHeader);
+            this.Controls.Add(this.labelUsernameHeader);
+            this.Name = "FormAuthorizationSuccess";
+            this.Size = new System.Drawing.Size(484, 248);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Label labelUsernameHeader;
+        private System.Windows.Forms.Label labelPasswordHeader;
+        private System.Windows.Forms.Label labelUsername;
+        private System.Windows.Forms.Label labelPassword;
+        private System.Windows.Forms.Button buttonShow;
+        private System.Windows.Forms.Button buttonSave;
+    }
+}

KeeCloud/Forms/FormAuthorizationSuccess.cs

+using System;
+using System.Linq;
+using System.Windows.Forms;
+using KeeCloud.Providers;
+using KeePass.Plugins;
+using KeePassLib;
+using KeePassLib.Security;
+using KeeCloud.Utilities;
+
+namespace KeeCloud.Forms
+{
+    public partial class FormAuthorizationSuccess : UserControl
+    {
+        private readonly IPluginHost host;
+        private CredentialClaimResult claimResult;
+        private IProvider provider;
+        private bool shown = false;
+
+        public FormAuthorizationSuccess(IPluginHost host)
+        {
+            this.host = host;
+            InitializeComponent();
+        }
+
+        internal void SetResult(CredentialClaimResult result, IProvider provider)
+        {
+            this.claimResult = result;
+            this.provider = provider;
+
+            this.labelUsername.Text = result.UserName;
+
+            this.SetShown(false);
+
+            if (!this.host.Database.IsOpen)
+                this.buttonSave.Visible = false;
+        }
+
+        private void buttonSave_Click(object sender, EventArgs e)
+        {
+            if (this.host.Database.IsOpen)
+            {
+                PwEntry entry = new PwEntry(true, true);
+
+                entry.Strings.Set(StandardProtectedStrings.Title, new ProtectedString(false, string.Format("KeeCloud {0} credentials", this.provider.FriendlyName)));
+                entry.Strings.Set(StandardProtectedStrings.Url, new ProtectedString(false, this.provider.Uri.ToString()));
+                entry.Strings.Set(StandardProtectedStrings.Username, new ProtectedString(false, this.claimResult.UserName));
+                entry.Strings.Set(StandardProtectedStrings.Password, new ProtectedString(true, this.claimResult.Password));
+
+                if (this.host.Database.LastSelectedGroup != null)
+                {
+                    var uuid = this.host.Database.LastSelectedGroup.UuidBytes;
+                    var group = (from g in this.host.Database.GetAllGroups()
+                                 where g.Uuid.UuidBytes.SequenceEqual(uuid)
+                                 select g).FirstOrDefault();
+
+                    if (group == null)
+                        this.host.Database.RootGroup.AddEntry(entry, true);
+                    else
+                        group.AddEntry(entry, true);
+                }
+                else
+                    this.host.Database.RootGroup.AddEntry(entry, true);
+
+                this.host.MainWindow.UpdateUI(false, null, true, host.Database.RootGroup, true, null, true);
+            }
+            else
+                MessageBox.Show("Database isn't open");
+        }
+
+        private void buttonShow_Click(object sender, EventArgs e)
+        {
+            SetShown(!this.shown);
+        }
+
+        private void SetShown(bool show)
+        {
+            if (show)
+            {
+                this.buttonShow.Text = "Hide Password";
+                this.labelPassword.Text = this.claimResult.Password;
+            }
+            else
+            {
+                this.buttonShow.Text = "Show Password";
+                this.labelPassword.Text = string.Empty.PadLeft(this.claimResult.Password.Length, '*');
+            }
+            this.shown = show;
+        }
+    }
+}
Add a comment to this file

KeeCloud/Forms/FormAuthorizationSuccess.resources

Binary file added.

KeeCloud/Forms/FormAuthorizationSuccess.resx

+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

KeeCloud/Forms/FormAwaitAuthorization.Designer.cs

+namespace KeeCloud.Forms
+{
+    partial class FormAwaitAuthorization
+    {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component Designer generated code
+
+        /// <summary> 
+        /// Required method for Designer support - do not modify 
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.labelInstrucctions = new System.Windows.Forms.Label();
+            this.SuspendLayout();
+            // 
+            // labelInstrucctions
+            // 
+            this.labelInstrucctions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.labelInstrucctions.Location = new System.Drawing.Point(15, 69);
+            this.labelInstrucctions.Name = "labelInstrucctions";
+            this.labelInstrucctions.Size = new System.Drawing.Size(451, 121);
+            this.labelInstrucctions.TabIndex = 0;
+            this.labelInstrucctions.Text = "A browser window should have opened. You must authenticate with the service provi" +
+    "der. Once you are done, click next. If you click next before you have authentica" +
+    "ted then this process will fail.";
+            // 
+            // FormAwaitAuthorization
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.Controls.Add(this.labelInstrucctions);
+            this.Name = "FormAwaitAuthorization";
+            this.Size = new System.Drawing.Size(484, 248);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Label labelInstrucctions;
+    }
+}

KeeCloud/Forms/FormAwaitAuthorization.cs

+using System.Windows.Forms;
+
+namespace KeeCloud.Forms
+{
+    public partial class FormAwaitAuthorization : UserControl
+    {
+        public FormAwaitAuthorization()
+        {
+            InitializeComponent();
+        }
+    }
+}
Add a comment to this file

KeeCloud/Forms/FormAwaitAuthorization.resources

Binary file added.

KeeCloud/Forms/FormAwaitAuthorization.resx

+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

KeeCloud/Forms/FormCredentialWizard.Designer.cs

+namespace KeeCloud.Forms
+{
+    partial class FormCredentialWizard
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.pictureBoxBanner = new System.Windows.Forms.PictureBox();
+            this.panelContainer = new System.Windows.Forms.Panel();
+            this.buttonNext = new System.Windows.Forms.Button();
+            this.buttonCancel = new System.Windows.Forms.Button();
+            this.progressBar = new System.Windows.Forms.ProgressBar();
+            ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBanner)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // pictureBoxBanner
+            // 
+            this.pictureBoxBanner.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.pictureBoxBanner.Location = new System.Drawing.Point(0, 0);
+            this.pictureBoxBanner.Name = "pictureBoxBanner";
+            this.pictureBoxBanner.Size = new System.Drawing.Size(484, 65);
+            this.pictureBoxBanner.TabIndex = 0;
+            this.pictureBoxBanner.TabStop = false;
+            // 
+            // panelContainer
+            // 
+            this.panelContainer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.panelContainer.Location = new System.Drawing.Point(0, 71);
+            this.panelContainer.Name = "panelContainer";
+            this.panelContainer.Size = new System.Drawing.Size(484, 248);
+            this.panelContainer.TabIndex = 1;
+            // 
+            // buttonNext
+            // 
+            this.buttonNext.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+            this.buttonNext.Location = new System.Drawing.Point(397, 327);
+            this.buttonNext.Name = "buttonNext";
+            this.buttonNext.Size = new System.Drawing.Size(75, 23);
+            this.buttonNext.TabIndex = 2;
+            this.buttonNext.Text = "Next";
+            this.buttonNext.UseVisualStyleBackColor = true;
+            this.buttonNext.Click += new System.EventHandler(this.buttonNext_Click);
+            // 
+            // buttonCancel
+            // 
+            this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+            this.buttonCancel.Location = new System.Drawing.Point(316, 327);
+            this.buttonCancel.Name = "buttonCancel";
+            this.buttonCancel.Size = new System.Drawing.Size(75, 23);
+            this.buttonCancel.TabIndex = 3;
+            this.buttonCancel.Text = "Cancel";
+            this.buttonCancel.UseVisualStyleBackColor = true;
+            this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click);
+            // 
+            // progressBar
+            // 
+            this.progressBar.Location = new System.Drawing.Point(188, 182);
+            this.progressBar.Name = "progressBar";
+            this.progressBar.Size = new System.Drawing.Size(100, 23);
+            this.progressBar.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
+            this.progressBar.TabIndex = 4;
+            this.progressBar.Visible = false;
+            // 
+            // FormCredentialWizard
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(484, 362);
+            this.Controls.Add(this.progressBar);
+            this.Controls.Add(this.buttonCancel);
+            this.Controls.Add(this.buttonNext);
+            this.Controls.Add(this.panelContainer);
+            this.Controls.Add(this.pictureBoxBanner);
+            this.MinimumSize = new System.Drawing.Size(500, 400);
+            this.Name = "FormCredentialWizard";
+            this.Text = "Credential Configuration";
+            ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBanner)).EndInit();
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.PictureBox pictureBoxBanner;
+        private System.Windows.Forms.Panel panelContainer;
+        private System.Windows.Forms.Button buttonNext;
+        private System.Windows.Forms.Button buttonCancel;
+        private System.Windows.Forms.ProgressBar progressBar;
+    }
+}

KeeCloud/Forms/FormCredentialWizard.cs

+using KeeCloud.Providers;
+using KeeCloud.Utilities;
+using KeePass.Plugins;
+using KeePass.UI;
+using System;
+using System.Diagnostics;
+using System.Windows.Forms;
+
+namespace KeeCloud.Forms
+{
+    public partial class FormCredentialWizard : Form
+    {
+        private enum WizardState
+        {
+            UrlEntry,
+            AwaitingAuthorization,
+            Success
+        }
+
+        readonly FormSelectProvider selectionForm = new FormSelectProvider();
+        readonly FormAwaitAuthorization authorizationForm = new FormAwaitAuthorization();
+        readonly FormAuthorizationSuccess successForm;
+        ICredentialConfigurationProvider credentialConfigurationProvier;
+
+        WizardState wizardState = WizardState.UrlEntry;
+
+        public FormCredentialWizard(IPluginHost host)
+        {
+            this.successForm = new FormAuthorizationSuccess(host);
+
+            InitializeComponent();
+
+            this.pictureBoxBanner.Image = BannerFactory.CreateBanner(this.pictureBoxBanner.Width,
+                this.pictureBoxBanner.Height,
+                BannerStyle.Default,
+                Resource1.key_go,
+                this.Text,
+                "Enter a URL to go through the authentication process");
+
+            this.Icon = host.MainWindow.Icon;
+
+            this.panelContainer.Controls.Add(this.selectionForm);
+        }
+
+        private void buttonCancel_Click(object sender, EventArgs e)
+        {
+            if (MessageBox.Show("Are you sure you wish to cancel?", "Are you sure?", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
+                this.Close();
+        }
+
+        #region event handlers
+
+        private void EntryForm_StateChanged(bool allowNext)
+        {
+            this.buttonNext.Enabled = allowNext;
+        }
+
+        private void buttonNext_Click(object sender, EventArgs e)
+        {
+            switch (this.wizardState)
+            {
+                case WizardState.UrlEntry:
+                    this.BackgroundDisplay(true);
+                    var urlOperation = new AsyncOperationWithSynchronizationContext(() =>
+                    {
+                        this.credentialConfigurationProvier = this.selectionForm.SelectedProvider.CredentialConfigurationProvider;
+                        this.credentialConfigurationProvier.Initialize();
+                    },
+                        // continuation
+                    () =>
+                    {
+                        LaunchUrl(this.credentialConfigurationProvier.GetExternalAuthorizationUrl());
+
+                        this.panelContainer.Controls.Remove(this.selectionForm);
+                        this.panelContainer.Controls.Add(this.authorizationForm);
+                        // invoke authentication process
+                        this.wizardState = WizardState.AwaitingAuthorization;
+                    },
+                        // catch
+                    ecxeption =>
+                    {
+                        MessageBox.Show(ecxeption.Message, "Error");
+                        this.StartOver();
+                    },
+                        // finally
+                    () =>
+                    {
+                        this.BackgroundDisplay(false);
+                    });
+                    urlOperation.Run();
+
+                    break;
+                case WizardState.AwaitingAuthorization:
+                    this.BackgroundDisplay(true);
+                    CredentialClaimResult result = null;
+                    var awaitingAuthorizationOperation = new AsyncOperationWithSynchronizationContext(() =>
+                    {
+                        result = this.credentialConfigurationProvier.Claim();
+                    },
+                        // continuation
+                    () =>
+                    {
+                        if (result.IsSuccess)
+                        {
+                            this.panelContainer.Controls.Remove(this.authorizationForm);
+                            this.successForm.SetResult(result, this.selectionForm.SelectedProvider);
+                            this.panelContainer.Controls.Add(this.successForm);
+                            this.wizardState = WizardState.Success;
+                            this.buttonCancel.Visible = false;
+                            this.buttonNext.Text = "Done";
+                        }
+                        else
+                        {
+                            MessageBox.Show("Couldn't authorize with account", "Error");
+                            this.StartOver();
+                        }
+                    },
+                        // catch
+                    ecxeption =>
+                    {
+                        MessageBox.Show(ecxeption.Message, "Error");
+                        this.StartOver();
+                    },
+                        // finally
+                    () =>
+                    {
+                        this.BackgroundDisplay(false);
+                    });
+                    awaitingAuthorizationOperation.Run();
+                    break;
+                case WizardState.Success:
+                    this.Close();
+                    break;
+            }
+        }
+
+        #endregion
+
+        private void StartOver()
+        {
+            this.panelContainer.Controls.Remove(this.authorizationForm);
+            this.panelContainer.Controls.Remove(this.selectionForm);
+            this.panelContainer.Controls.Remove(this.successForm);
+
+            this.buttonNext.Text = "Next";
+            this.buttonNext.Enabled = true;
+            this.buttonCancel.Visible = true;
+            this.wizardState = WizardState.UrlEntry;
+            this.panelContainer.Controls.Add(this.selectionForm);
+        }
+
+        private void BackgroundDisplay(bool isRunningBackground)
+        {
+            this.panelContainer.Visible = !isRunningBackground;
+            this.progressBar.Visible = isRunningBackground;
+        }
+
+        private static void LaunchUrl(Uri uri)
+        {
+            Process.Start(uri.ToString());
+        }
+    }
+}
Add a comment to this file

KeeCloud/Forms/FormCredentialWizard.resources

Binary file added.

KeeCloud/Forms/FormCredentialWizard.resx

+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

KeeCloud/Forms/FormSelectProvider.Designer.cs

+namespace KeeCloud.Forms
+{
+    partial class FormSelectProvider
+    {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component Designer generated code
+
+        /// <summary> 
+        /// Required method for Designer support - do not modify 
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.labelInstructions = new System.Windows.Forms.Label();
+            this.comboBoxProviders = new System.Windows.Forms.ComboBox();
+            this.SuspendLayout();
+            // 
+            // labelInstructions
+            // 
+            this.labelInstructions.Location = new System.Drawing.Point(23, 24);
+            this.labelInstructions.Name = "labelInstructions";
+            this.labelInstructions.Size = new System.Drawing.Size(439, 69);
+            this.labelInstructions.TabIndex = 0;
+            this.labelInstructions.Text = "This wizard allows those providers that require linking to the account to work.\r\n" +
+    "\r\nPlease select a provider to integrate ";
+            // 
+            // comboBoxProviders
+            // 
+            this.comboBoxProviders.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.comboBoxProviders.FormattingEnabled = true;
+            this.comboBoxProviders.Location = new System.Drawing.Point(26, 97);
+            this.comboBoxProviders.Name = "comboBoxProviders";
+            this.comboBoxProviders.Size = new System.Drawing.Size(436, 21);
+            this.comboBoxProviders.TabIndex = 1;
+            this.comboBoxProviders.SelectedIndexChanged += new System.EventHandler(this.comboBoxProviders_SelectedIndexChanged);
+            // 
+            // FormSelectProvider
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.Controls.Add(this.comboBoxProviders);
+            this.Controls.Add(this.labelInstructions);
+            this.Name = "FormSelectProvider";
+            this.Size = new System.Drawing.Size(484, 248);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Label labelInstructions;
+        private System.Windows.Forms.ComboBox comboBoxProviders;
+
+    }
+}

KeeCloud/Forms/FormSelectProvider.cs

+using KeeCloud.Providers;
+using System;
+using System.Linq;
+using System.Windows.Forms;
+
+namespace KeeCloud.Forms
+{
+    public partial class FormSelectProvider : UserControl
+    {
+        private class DataItem
+        {
+            public DataItem(ProviderItem wr)
+            {
+                this.Provider = wr.Create(new Uri(wr.Protocol + @"://"));
+                this.FriendlyName = this.Provider.FriendlyName;
+            }
+
+            public string FriendlyName { get; set; }
+            public IProvider Provider { get; set; }
+        }
+
+        public IProvider SelectedProvider { get; private set; }
+
+        public FormSelectProvider()
+        {
+            InitializeComponent();
+            this.comboBoxProviders.DisplayMember = "FriendlyName";
+            this.comboBoxProviders.DataSource = ProviderRegistry.SupportedWebRequests.Select(wr => new DataItem(wr)).Where(wr => wr.Provider.CanConfigureCredentials).ToArray();
+        }
+
+        private void comboBoxProviders_SelectedIndexChanged(object sender, EventArgs e)
+        {
+            var item = (DataItem)this.comboBoxProviders.SelectedItem;
+            this.SelectedProvider = item.Provider;
+        }
+    }
+}

KeeCloud/Forms/FormSelectProvider.resx

+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
Add a comment to this file

KeeCloud/Forms/FormUrlEntry.resources

Binary file added.

Add a comment to this file

KeeCloud/Images/key_go.png

Added
New image

KeeCloud/KeeCloud.csproj

+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{967E2FA7-FB8F-4578-9A90-8D32B476671A}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>KeeCloud</RootNamespace>
+    <AssemblyName>KeeCloud</AssemblyName>
+    <FileAlignment>512</FileAlignment>
+    <ProductVersion>12.0.0</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>True</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>False</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;DUMMY;DEVELOPING</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>True</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="AWSSDK">
+      <HintPath>..\packages\AWSSDK.1.5.12.0\lib\AWSSDK.dll</HintPath>
+    </Reference>
+    <Reference Include="DropNet">
+      <HintPath>..\packages\DropNet.1.9.3\lib\net35\DropNet.dll</HintPath>
+    </Reference>
+    <Reference Include="KeePass" />
+    <Reference Include="RestSharp, Version=102.7.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\DropNet.1.9.3\lib\net35\RestSharp.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Forms\FormAuthorizationSuccess.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Forms\FormAuthorizationSuccess.Designer.cs">
+      <DependentUpon>FormAuthorizationSuccess.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Forms\FormAwaitAuthorization.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Forms\FormAwaitAuthorization.Designer.cs">
+      <DependentUpon>FormAwaitAuthorization.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Forms\FormSelectProvider.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Forms\FormSelectProvider.Designer.cs">
+      <DependentUpon>FormSelectProvider.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Providers\CredentialClaimResult.cs" />
+    <Compile Include="Forms\FormCredentialWizard.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Forms\FormCredentialWizard.Designer.cs">
+      <DependentUpon>FormCredentialWizard.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Providers\Dropbox\DropboxCredentialConfigurationProvider.cs" />
+    <Compile Include="Providers\Dropbox\Api.cs" />
+    <Compile Include="Providers\Dummy\DummyConfiguration.cs" />
+    <Compile Include="Providers\Dummy\DummyProvider.cs" />
+    <Compile Include="Providers\ICredentialConfigurationProvider.cs" />
+    <Compile Include="Providers\InitializeResult.cs" />
+    <Compile Include="Providers\IProvider.cs" />
+    <Compile Include="KeeCloudFileExt.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ProviderRegistry.cs" />
+    <Compile Include="Providers\Amazon\AmazonS3Provider.cs" />
+    <Compile Include="Resource1.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resource1.resx</DependentUpon>
+    </Compile>
+    <Compile Include="StandardProtectedStrings.cs" />
+    <Compile Include="Utilities\AsyncOperationWithSynchronizationContext.cs" />
+    <Compile Include="Utilities\DatabaseHelpers.cs" />
+    <Compile Include="WebRequests\SuccessWebResponse.cs" />
+    <Compile Include="WebRequests\ProviderWebRequest.cs" />
+    <Compile Include="Providers\Dropbox\DropboxProvider.cs" />
+    <Compile Include="ProviderItem.cs" />
+    <Compile Include="WebRequests\ProviderWebRequestCreator.cs" />
+    <Compile Include="WebRequests\GetWebResponse.cs" />
+    <Compile Include="WebRequests\RequestStream.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup />
+  <ItemGroup>
+    <EmbeddedResource Include="Forms\FormAuthorizationSuccess.resx">
+      <DependentUpon>FormAuthorizationSuccess.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Forms\FormAwaitAuthorization.resx">
+      <DependentUpon>FormAwaitAuthorization.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Forms\FormCredentialWizard.resx">
+      <DependentUpon>FormCredentialWizard.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Forms\FormSelectProvider.resx">
+      <DependentUpon>FormSelectProvider.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Resource1.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resource1.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <ItemGroup>
+    <Content Include="Images\key_go.png" />
+  </ItemGroup>
+</Project>

KeeCloud/KeeCloudFileExt.cs

+using KeeCloud.Forms;
+using KeePass.Plugins;
+using System.Diagnostics;
+using System.Windows.Forms;
+
+namespace KeeCloud
+{
+    public class KeeCloudExt : Plugin
+    {
+        private IPluginHost host = null;
+        private ToolStripItem seperator;
+        private ToolStripItem wizardItem;
+
+        public override bool Initialize(IPluginHost host)
+        {
+#if DEVELOPING
+            try
+            {
+                if (!Debugger.IsAttached)
+                    Debugger.Launch();
+            }
+            catch { } // do nothing if we can't debug
+#endif
+            this.host = host;
+
+            this.seperator = new ToolStripSeparator();
+            host.MainWindow.ToolsMenu.DropDown.Items.Add(this.seperator);
+
+            this.wizardItem = host.MainWindow.ToolsMenu.DropDown.Items.Add("URL Credential Wizard", Resource1.key_go, (sender, e) => this.LaunchWizard());
+
+            ProviderRegistry.RegisterAllIFRequired();
+            return true;
+        }
+
+        public override void Terminate()
+        {
+            host.MainWindow.ToolsMenu.DropDown.Items.Remove(this.seperator);
+            host.MainWindow.ToolsMenu.DropDown.Items.Remove(this.wizardItem);
+
+            base.Terminate();
+        }
+
+        private void LaunchWizard()
+        {
+            FormCredentialWizard form = new FormCredentialWizard(this.host);
+            form.Show();
+        }
+
+        /// <summary>
+        /// URL that contains the current version. This is used by KeePass to report to the user when updates are available
+        /// </summary>
+        public override string UpdateUrl
+        {
+            get { return "https://s3.amazonaws.com/KeeCloud/version_manifest.txt"; }
+        }
+    }
+}

KeeCloud/Properties/AssemblyInfo.cs

+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General assembly properties
+[assembly: AssemblyTitle("KeeCloud")]
+[assembly: AssemblyDescription("A plugin that allows KeePass to natively use several popular cloud based file repositories.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Devin Martin")]
+[assembly: AssemblyProduct("KeePass Plugin")]
+[assembly: AssemblyCopyright("Copyright © 2013 Devin Martin")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// COM settings
+[assembly: ComVisible(false)]
+
+// Assembly GUID
+[assembly: Guid("512735A7-5BFD-478D-8CDB-6E587198781E")]
+
+// Assembly version information
+[assembly: AssemblyVersion("1.0.0")]
+[assembly: AssemblyFileVersion("1.0.0")]

KeeCloud/ProviderItem.cs

+using KeeCloud.Providers;
+using System;
+
+namespace KeeCloud
+{
+    public class ProviderItem
+    {
+        private readonly string protocolPrefix;
+        private readonly Func<IProvider> providerFactory;
+
+        public ProviderItem(string protocol, Func<IProvider> providerFactory)
+        {
+            this.protocolPrefix = protocol;
+            this.providerFactory = providerFactory;
+        }
+
+        public string Protocol { get { return this.protocolPrefix; } }
+        public IProvider Create(Uri uri)
+        {
+            IProvider provider = providerFactory();
+            provider.Uri = uri;
+            return provider;
+        }
+    }
+}

KeeCloud/ProviderRegistry.cs

+using KeeCloud.WebRequests;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace KeeCloud
+{
+    public class ProviderRegistry
+    {
+        static readonly object registrationSync = new object();
+        static bool isRegistered = false;
+
+        public static IEnumerable<ProviderItem> SupportedWebRequests
+        {
+            get
+            {
+                // add a new yield return with a protocol prefix and a delegate to create for each supported handler in the plugin
+                yield return new ProviderItem("dropbox", () => new KeeCloud.Providers.Dropbox.DropboxProvider());
+                yield return new ProviderItem("s3", () => new KeeCloud.Providers.Amazon.AmazonS3Provider());
+
+
+                // this is a dummy provider used mainly for testing the UI of the credential configuration wizard
+                // as well as the base web request logic
+#if DUMMY
+                yield return new ProviderItem("dummy", () => new KeeCloud.Providers.Dummy.DummyProvider());
+#endif
+            }
+        }
+
+        /// <summary>
+        /// Register all supported prefixes with the .net framework
+        /// </summary>
+        public static void RegisterAllIFRequired()
+        {
+            lock (registrationSync)
+            {
+                if (!isRegistered)
+                {
+                    isRegistered = true;
+                    foreach (var supported in SupportedWebRequests)
+                    {
+                        ProviderWebRequest.RegisterPrefix(supported.Protocol + ":", ProviderWebRequestCreator.Instance);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Get a specific provider for the URI provided
+        /// </summary>
+        /// <param name="uri">URI for which to find a provider</param>
+        /// <returns>The matching provider</returns>
+        internal static ProviderItem GetProviderForUri(Uri uri)
+        {
+            ProviderItem item;
+
+            if (!TryGetProviderForScheme(uri.Scheme, out item))
+                throw new ArgumentException("uri");
+
+            return item;
+        }
+
+        /// <summary>
+        /// Get a specific provider for the scheme or protocol provided
+        /// </summary>
+        /// <param name="uri">URI for which to find a provider</param>
+        /// <returns>The matching provider</returns>
+        internal static bool TryGetProviderForScheme(string scheme, out ProviderItem provider)
+        {
+            provider = ProviderRegistry.SupportedWebRequests
+                .FirstOrDefault(w => w.Protocol.ToLowerInvariant() == scheme.ToLowerInvariant());
+
+            return (provider != null);
+        }
+    }
+}

KeeCloud/Providers/Amazon/AmazonS3Provider.cs

+using Amazon.Runtime;
+using Amazon.S3;
+using Amazon.S3.Model;
+using System;
+using System.IO;
+using System.Net;
+
+namespace KeeCloud.Providers.Amazon
+{
+    public class AmazonS3Provider : IProvider
+    {
+        public Uri Uri { get; set; }
+
+        Stream IProvider.Get(ICredentials credentials)
+        {
+            using (var client = this.GetClient(credentials))
+            {
+                string bucket;
+                string key;
+                this.GetBucketAndKey(out bucket, out key);
+
+                var request = new GetObjectRequest().WithBucketName(bucket).WithKey(key);
+
+                var response = client.GetObject(request);
+
+                MemoryStream returnStream = new MemoryStream();
+                this.CopyStream(response.ResponseStream, returnStream);
+                returnStream.Position = 0;
+                return returnStream;
+            }
+        }
+
+        void IProvider.Put(Stream stream, ICredentials credentials)
+        {
+            using (var client = this.GetClient(credentials))
+            {
+                string bucket;
+                string key;
+                this.GetBucketAndKey(out bucket, out key);
+
+                var request = new PutObjectRequest().WithBucketName(bucket).WithKey(key);
+
+                request.InputStream = stream;
+                client.PutObject(request);
+            }
+        }
+
+        public void Delete(ICredentials credentials)
+        {
+            using (var client = this.GetClient(credentials))
+            {
+                string bucket;
+                string key;
+                this.GetBucketAndKey(out bucket, out key);
+
+                var request = new DeleteObjectRequest().WithBucketName(bucket).WithKey(key);
+
+                client.DeleteObject(request);
+            }
+        }
+
+        void IProvider.Move(Uri destination, ICredentials credentials)
+        {
+            using (var client = this.GetClient(credentials))
+            {
+                string bucket;
+                string sourceKey;
+                string destinationKey;
+                this.GetBucketAndKey(out bucket, out sourceKey);
+                AmazonS3Provider.GetBucketAndKey(destination, out bucket, out destinationKey);
+
+                var request = new CopyObjectRequest().WithSourceBucket(bucket)
+                    .WithDestinationBucket(bucket)
+                    .WithSourceKey(sourceKey)
+                    .WithDestinationKey(destinationKey);
+
+                client.CopyObject(request);
+                this.Delete(credentials);
+            }
+        }
+
+        public bool CanConfigureCredentials { get { return false; } }
+
+        public ICredentialConfigurationProvider CredentialConfigurationProvider
+        {
+            get { throw new NotSupportedException("This provider doesn't support credential configuration"); }
+        }
+
+        string IProvider.FriendlyName { get { return "Amazon S3"; } }
+
+        private AmazonS3Client GetClient(ICredentials credentials)
+        {
+            var basicCredential = credentials.GetCredential(this.Uri, "basic");
+            var client = new AmazonS3Client(new BasicAWSCredentials(basicCredential.UserName, basicCredential.Password));
+            return client;
+        }
+
+        private static void GetBucketAndKey(Uri uri, out string bucket, out string key)
+        {
+            bucket = uri.OriginalString.Substring(uri.Scheme.Length + 3, uri.Authority.Length);
+            key = uri.PathAndQuery.TrimStart('/');
+        }
+
+        private void GetBucketAndKey(out string bucket, out string key)
+        {
+            AmazonS3Provider.GetBucketAndKey(this.Uri, out bucket, out key);
+        }
+
+        private void CopyStream(Stream input, Stream output)
+        {
+            int read = 0;
+            byte[] buffer = new byte[32000];
+            do
+            {
+                read = input.Read(buffer, 0, buffer.Length);
+
+                if (read > 0)
+                {
+                    output.Write(buffer, 0, read);
+                    output.Flush();
+                }
+            } while (read > 0);
+        }
+    }
+}

KeeCloud/Providers/CredentialClaimResult.cs

+
+namespace KeeCloud.Providers
+{
+    public class CredentialClaimResult
+    {
+        public CredentialClaimResult()
+        {
+        }
+
+        public CredentialClaimResult(string username, string password)
+        {
+            this.IsSuccess = true;
+            this.UserName = username;
+            this.Password = password;
+        }
+
+        public string UserName { get; private set; }
+        public string Password { get; private set; }
+        public bool IsSuccess { get; private set; }
+    }
+}

KeeCloud/Providers/Dropbox/Api.cs

+using DropNet;
+using System.Net;
+
+namespace KeeCloud.Providers.Dropbox
+{
+    class Api
+    {
+        /*
+        The consumer key and the secret key included here are dummy keys.
+        You should go to http://dropbox.com/developers to create your own application
+        and get your own keys.
+
+        This is done to prevent bots from scraping the keys from the source code posted on the web.
+        */
+        public const string consumerKey = "dummy";
+        public const string consumerSecret = "dummy";
+
+        public static DropNetClient Client
+        {
+            get
+            {
+                return new DropNetClient(consumerKey, consumerSecret);
+            }
+        }
+
+        public static DropNetClient AuthenticatedClient(NetworkCredential credential)
+        {
+            return new DropNetClient(consumerKey, consumerSecret, credential.UserName, credential.Password);
+        }
+    }
+}

KeeCloud/Providers/Dropbox/DropboxCredentialConfigurationProvider.cs

+using DropNet;
+using System;
+
+namespace KeeCloud.Providers.Dropbox
+{
+    public class DropboxCredentialConfigurationProvider : ICredentialConfigurationProvider
+    {
+        private DropNetClient authenticationClient = Api.Client;
+
+        public InitializeResult Initialize()
+        {
+            try
+            {
+                this.authenticationClient.GetToken();
+                return InitializeResult.Ok;
+            }
+            catch
+            {
+                return InitializeResult.Error;
+            }
+        }
+
+        public Uri GetExternalAuthorizationUrl()
+        {
+            return new Uri(this.authenticationClient.BuildAuthorizeUrl());
+        }
+
+        public CredentialClaimResult Claim()
+        {
+            try
+            {
+                var result = this.authenticationClient.GetAccessToken();
+                return new CredentialClaimResult(result.Token, result.Secret);
+            }
+            catch
+            {
+                return new CredentialClaimResult();
+            }
+        }
+    }
+}

KeeCloud/Providers/Dropbox/DropboxProvider.cs

+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+
+namespace KeeCloud.Providers.Dropbox
+{
+    public class DropboxProvider : IProvider
+    {
+        public Uri Uri { get; set; }
+
+        Stream IProvider.Get(ICredentials credentials)
+        {
+            var client = Api.AuthenticatedClient(this.GetNetworkCredential(credentials));
+            var data = client.GetFile(GetPath(this.Uri));
+            return new MemoryStream(data);
+        }
+
+        void IProvider.Put(Stream stream, ICredentials credentials)
+        {
+            var client = Api.AuthenticatedClient(this.GetNetworkCredential(credentials));
+
+            var path = GetPath(this.Uri);
+            client.UploadFile(Path.GetDirectoryName(path), Path.GetFileName(path), this.ReadAll(stream));
+        }
+
+        void IProvider.Delete(ICredentials credentials)
+        {
+            var client = Api.AuthenticatedClient(this.GetNetworkCredential(credentials));
+
+            var path = GetPath(this.Uri);
+            client.Delete(path);
+        }
+
+        void IProvider.Move(Uri destination, ICredentials credentials)
+        {
+            var client = Api.AuthenticatedClient(this.GetNetworkCredential(credentials));
+
+            var sourcePath = GetPath(this.Uri);
+            var destinationPath = GetPath(destination);
+            client.Move(sourcePath, destinationPath);
+        }
+
+        bool IProvider.CanConfigureCredentials { get { return true; } }
+
+        ICredentialConfigurationProvider IProvider.CredentialConfigurationProvider
+        {
+            get { return new DropboxCredentialConfigurationProvider(); }
+        }
+
+        string IProvider.FriendlyName { get { return "Dropbox"; } }
+
+        private NetworkCredential GetNetworkCredential(ICredentials credentials)
+        {
+            return credentials.GetCredential(this.Uri, "basic");
+        }
+
+        private static string GetPath(Uri uri)
+        {
+            var path = uri.OriginalString.Substring(uri.Scheme.Length + 3);
+            if (path.EndsWith("/"))
+                return path.TrimEnd('/');
+            else
+                return path;
+        }
+
+        private byte[] ReadAll(Stream stream)
+        {
+            List<byte> bytes = new List<byte>();
+            int read = 0;
+            byte[] buffer = new byte[32000];
+            do
+            {
+                read = stream.Read(buffer, 0, buffer.Length);
+                bytes.AddRange(buffer.Take(read));
+            } while (read > 0);
+
+            return bytes.ToArray();
+        }
+    }
+}

KeeCloud/Providers/Dummy/DummyConfiguration.cs

+using System;
+using System.Threading;
+
+namespace KeeCloud.Providers.Dummy
+{
+    public class DummyConfiguration : ICredentialConfigurationProvider
+    {
+        private Uri uri;
+
+        public DummyConfiguration(Uri uri)
+        {
+            this.uri = uri;
+        }
+        public InitializeResult Initialize()
+        {
+            if (!string.IsNullOrEmpty(this.uri.Authority) && this.uri.Authority.ToLowerInvariant() == "delay")
+                Thread.Sleep(1500);
+
+            if (!string.IsNullOrEmpty(this.uri.Authority) && this.uri.Authority.ToLowerInvariant() == "initexception")
+                throw new Exception("exception");
+
+            if (!string.IsNullOrEmpty(this.uri.Authority) && this.uri.Authority.ToLowerInvariant() == "initerror")
+                return InitializeResult.Error;
+            else
+                return InitializeResult.Ok;
+        }
+
+        public Uri GetExternalAuthorizationUrl()
+        {
+            return new Uri("https://www.google.com");
+        }
+
+        public CredentialClaimResult Claim()
+        {
+            if (!string.IsNullOrEmpty(this.uri.Authority) && this.uri.Authority.ToLowerInvariant() == "delay")
+                Thread.Sleep(1500);
+
+            if (!string.IsNullOrEmpty(this.uri.Authority) && this.uri.Authority.ToLowerInvariant() == "claimexception")
+                throw new Exception("exception");
+
+            if (!string.IsNullOrEmpty(this.uri.Authority) && this.uri.Authority.ToLowerInvariant() == "claimerror")
+                return new CredentialClaimResult();
+            else
+                return new CredentialClaimResult("username", "password");
+        }
+    }
+}

KeeCloud/Providers/Dummy/DummyProvider.cs

+using System;
+using System.IO;
+
+namespace KeeCloud.Providers.Dummy
+{
+    public class DummyProvider : IProvider
+    {
+        public Uri Uri { get; set; }
+
+        public System.IO.Stream Get(System.Net.ICredentials credentials)
+        {
+            return new FileStream(this.Uri.LocalPath, FileMode.Open);
+        }
+
+        public void Put(System.IO.Stream stream, System.Net.ICredentials credentials)
+        {
+            byte[] buffer = new byte[32000];
+            using (var fs = new FileStream(this.Uri.LocalPath, FileMode.Create))
+            {<