diff --git a/AutoTypeCustomFieldPicker.sln b/AutoTypeCustomFieldPicker.sln new file mode 100644 index 0000000..40a7ea9 --- /dev/null +++ b/AutoTypeCustomFieldPicker.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoTypeCustomFieldPicker", "AutoTypeCustomFieldPicker\AutoTypeCustomFieldPicker.csproj", "{E6AC839D-012F-4339-B6E9-71EDF208720E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E6AC839D-012F-4339-B6E9-71EDF208720E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E6AC839D-012F-4339-B6E9-71EDF208720E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E6AC839D-012F-4339-B6E9-71EDF208720E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E6AC839D-012F-4339-B6E9-71EDF208720E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/AutoTypeCustomFieldPicker/AutoTypeCustomFieldPicker.csproj b/AutoTypeCustomFieldPicker/AutoTypeCustomFieldPicker.csproj new file mode 100644 index 0000000..08cbae1 --- /dev/null +++ b/AutoTypeCustomFieldPicker/AutoTypeCustomFieldPicker.csproj @@ -0,0 +1,81 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {E6AC839D-012F-4339-B6E9-71EDF208720E} + Library + Properties + AutoTypeCustomFieldPicker + AutoTypeCustomFieldPicker + v4.0 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + .exe + Resources\KeePass.exe + False + + + + + + + + + + + Form + + + DlgPickCustomField.cs + + + + + + + + + + + + + DlgPickCustomField.cs + + + + + + + + + \ No newline at end of file diff --git a/AutoTypeCustomFieldPicker/AutoTypeCustomFieldPickerExt.cs b/AutoTypeCustomFieldPicker/AutoTypeCustomFieldPickerExt.cs new file mode 100644 index 0000000..bfa85ff --- /dev/null +++ b/AutoTypeCustomFieldPicker/AutoTypeCustomFieldPickerExt.cs @@ -0,0 +1,53 @@ +using System.Windows.Forms; +using KeePass.Plugins; +using KeePass.Util; + +namespace AutoTypeCustomFieldPicker +{ + public sealed class AutoTypeCustomFieldPickerExt : Plugin + { + private const string PLACEHOLDER = "{PICKCUSTOMFIELD}"; + + private IPluginHost PluginHost = null; + private string CurrentPlaceholderResolved = string.Empty; + + public override bool Initialize(IPluginHost host) + { + this.PluginHost = host; + if (this.PluginHost == null) + return false; + + AutoType.FilterSendPre += this.AutoType_FilterSendPre; + AutoType.SequenceQuery += this.AutoType_SequenceQuery; + + return true; + } + + public override void Terminate() + { + AutoType.FilterSendPre -= this.AutoType_FilterSendPre; + AutoType.SequenceQuery -= this.AutoType_SequenceQuery; + } + + private void AutoType_FilterSendPre(object sender, AutoTypeEventArgs e) + { + if (!string.IsNullOrEmpty(this.CurrentPlaceholderResolved) && e.Entry.GetAutoTypeSequence().Contains(this.CurrentPlaceholderResolved)) + e.Entry.AutoType.DefaultSequence = e.Entry.AutoType.DefaultSequence.Replace(this.CurrentPlaceholderResolved, PLACEHOLDER); + } + + private void AutoType_SequenceQuery(object sender, SequenceQueryEventArgs e) + { + if (e.Entry.GetAutoTypeSequence().Contains(PLACEHOLDER)) + { + DlgPickCustomField picker = new DlgPickCustomField(); + picker.PickCustomField(PLACEHOLDER, e.Entry); + + if (picker.DialogResult == DialogResult.OK && picker.SelectedField != null) + { + this.CurrentPlaceholderResolved = picker.SelectedField.Value; + e.Entry.AutoType.DefaultSequence = e.Entry.AutoType.DefaultSequence.Replace(PLACEHOLDER, picker.SelectedField.Value); + } + } + } + } +} diff --git a/AutoTypeCustomFieldPicker/DlgPickCustomField.Designer.cs b/AutoTypeCustomFieldPicker/DlgPickCustomField.Designer.cs new file mode 100644 index 0000000..5c85df4 --- /dev/null +++ b/AutoTypeCustomFieldPicker/DlgPickCustomField.Designer.cs @@ -0,0 +1,106 @@ +namespace AutoTypeCustomFieldPicker +{ + partial class DlgPickCustomField + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label_PlaceholderInfo = new System.Windows.Forms.Label(); + this.listBox_CustomFields = new System.Windows.Forms.ListBox(); + this.button_Cancel = new System.Windows.Forms.Button(); + this.button_OK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label_PlaceholderInfo + // + this.label_PlaceholderInfo.AutoSize = true; + this.label_PlaceholderInfo.Location = new System.Drawing.Point(12, 9); + this.label_PlaceholderInfo.Name = "label_PlaceholderInfo"; + this.label_PlaceholderInfo.Size = new System.Drawing.Size(196, 13); + this.label_PlaceholderInfo.TabIndex = 0; + this.label_PlaceholderInfo.Text = "Pick a custom field for placeholder \"{0}\""; + // + // listBox_CustomFields + // + this.listBox_CustomFields.FormattingEnabled = true; + this.listBox_CustomFields.Location = new System.Drawing.Point(15, 25); + this.listBox_CustomFields.Name = "listBox_CustomFields"; + this.listBox_CustomFields.Size = new System.Drawing.Size(276, 160); + this.listBox_CustomFields.TabIndex = 1; + this.listBox_CustomFields.DoubleClick += new System.EventHandler(this.listBox_CustomFields_DoubleClick); + // + // button_Cancel + // + this.button_Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button_Cancel.Location = new System.Drawing.Point(216, 191); + this.button_Cancel.Name = "button_Cancel"; + this.button_Cancel.Size = new System.Drawing.Size(75, 23); + this.button_Cancel.TabIndex = 2; + this.button_Cancel.Text = "Cancel"; + this.button_Cancel.UseVisualStyleBackColor = true; + this.button_Cancel.Click += new System.EventHandler(this.button_Cancel_Click); + // + // button_OK + // + this.button_OK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button_OK.Location = new System.Drawing.Point(135, 191); + this.button_OK.Name = "button_OK"; + this.button_OK.Size = new System.Drawing.Size(75, 23); + this.button_OK.TabIndex = 3; + this.button_OK.Text = "OK"; + this.button_OK.UseVisualStyleBackColor = true; + this.button_OK.Click += new System.EventHandler(this.button_OK_Click); + // + // DlgPickCustomField + // + this.AcceptButton = this.button_OK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button_Cancel; + this.ClientSize = new System.Drawing.Size(309, 229); + this.Controls.Add(this.button_OK); + this.Controls.Add(this.button_Cancel); + this.Controls.Add(this.listBox_CustomFields); + this.Controls.Add(this.label_PlaceholderInfo); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "DlgPickCustomField"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "PickCustomField | KeePass"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label_PlaceholderInfo; + private System.Windows.Forms.ListBox listBox_CustomFields; + private System.Windows.Forms.Button button_Cancel; + private System.Windows.Forms.Button button_OK; + } +} \ No newline at end of file diff --git a/AutoTypeCustomFieldPicker/DlgPickCustomField.cs b/AutoTypeCustomFieldPicker/DlgPickCustomField.cs new file mode 100644 index 0000000..06c2e7b --- /dev/null +++ b/AutoTypeCustomFieldPicker/DlgPickCustomField.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Windows.Forms; +using KeePassLib; +using KeePassLib.Security; + +namespace AutoTypeCustomFieldPicker +{ + public partial class DlgPickCustomField : Form + { + public DlgPickCustomField() + { + InitializeComponent(); + } + + public MyFieldObject SelectedField; + + public void PickCustomField(string placeholder, PwEntry entry) + { + this.label_PlaceholderInfo.Text = string.Format(this.label_PlaceholderInfo.Text, placeholder); + + foreach (KeyValuePair item in entry.Strings) + this.listBox_CustomFields.Items.Add(new MyFieldObject(item.Key, item.Value.ReadString())); + + this.ShowDialog(); + } + + private void button_OK_Click(object sender, System.EventArgs e) + { + if (this.listBox_CustomFields.SelectedItem != null) + this.SelectedField = this.listBox_CustomFields.SelectedItem as MyFieldObject; + + this.Close(); + } + + private void listBox_CustomFields_DoubleClick(object sender, System.EventArgs e) + { + if (this.listBox_CustomFields.SelectedItem != null) + this.SelectedField = this.listBox_CustomFields.SelectedItem as MyFieldObject; + + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void button_Cancel_Click(object sender, System.EventArgs e) + { + this.Close(); + } + } +} diff --git a/AutoTypeCustomFieldPicker/DlgPickCustomField.resx b/AutoTypeCustomFieldPicker/DlgPickCustomField.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/AutoTypeCustomFieldPicker/DlgPickCustomField.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/AutoTypeCustomFieldPicker/MyFieldObject.cs b/AutoTypeCustomFieldPicker/MyFieldObject.cs new file mode 100644 index 0000000..6b6c9ab --- /dev/null +++ b/AutoTypeCustomFieldPicker/MyFieldObject.cs @@ -0,0 +1,19 @@ +namespace AutoTypeCustomFieldPicker +{ + public class MyFieldObject + { + public MyFieldObject(string key, string value) + { + this.Key = key; + this.Value = value; + } + + public string Key { get; set; } + public string Value { get; set; } + + public override string ToString() + { + return this.Key; + } + } +} diff --git a/AutoTypeCustomFieldPicker/Properties/AssemblyInfo.cs b/AutoTypeCustomFieldPicker/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..acd36f2 --- /dev/null +++ b/AutoTypeCustomFieldPicker/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("AutoTypeCustomFieldPicker")] +[assembly: AssemblyDescription("Pick custom fields in an Auto-Type sequence (similar to {PICKCHARS})")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Bernd Bestel")] +[assembly: AssemblyProduct("KeePass Plugin")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("c750ebd4-44a1-40a9-9895-7b548c66f9f8")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/AutoTypeCustomFieldPicker/Resources/KeePass.exe b/AutoTypeCustomFieldPicker/Resources/KeePass.exe new file mode 100644 index 0000000..a74a444 Binary files /dev/null and b/AutoTypeCustomFieldPicker/Resources/KeePass.exe differ diff --git a/AutoTypeCustomFieldPicker/UpdateInfo.txt b/AutoTypeCustomFieldPicker/UpdateInfo.txt new file mode 100644 index 0000000..d75369a --- /dev/null +++ b/AutoTypeCustomFieldPicker/UpdateInfo.txt @@ -0,0 +1,3 @@ +: +AutoTypeCustomFieldPicker:1.0.0.0 +: \ No newline at end of file diff --git a/KeePassAutoTypeCustomFieldPicker.plgx b/KeePassAutoTypeCustomFieldPicker.plgx new file mode 100644 index 0000000..7e5534a Binary files /dev/null and b/KeePassAutoTypeCustomFieldPicker.plgx differ diff --git a/README.md b/README.md index 376720c..9e31dbd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,36 @@ KeePassAutoTypeCustomFieldPicker ================================ -Pick custom fields in an Auto-Type sequence (similar to {PICKCHARS}) +Pick custom fields in an Auto-Type sequence (similar to `{PICKCHARS}`) + +Purpose +------- +On some sites, particularly banking related sites, there are login forms where you have to enter "The answer for security question 3 out of 5". +In KeePass, you probably have stored these answers in custom fields. + +With the current `{PICKCHARS}` placeholder you can pick single chars out of a field. +But for this use case you need a placeholder for a complete field value. + +To fix the time to when this will be implemented in KeePass itself, I have created this plugin. + +Usage +----- +Just use the new placeholder `{PICKCUSTOMFIELD}` in an Auto-Type sequence. +When you execute such a sequence, a window will popup and let you choose a custom field (just like `{PICKCHARS}` does). +The value of the picked custom field will be replaced in the Auto-Type sequence. + +Installation +------------- +Just download the KeePassAutoTypeCustomFieldPicker.plgx file, copy it to the KeePass application directory and restart KeePass. + +Limitions +--------- +- If you use `{PICKCUSTOMFIELD}` more than once in an Auto-Type sequence, the picker will only popup once und all placeholders will be replaced with the same value of the selected custom field (something like `{PICKCHARS:Password:ID=1}` is currently not implemented). + +####Warning +This is a "quick & dirty" implementation. +But it works and will not harm your KeePass database or something like that. +But anyways, use it at your own risk (I use it too ;)). + +####Licence +GPL v3 or later \ No newline at end of file diff --git a/licence.txt b/licence.txt new file mode 100644 index 0000000..4f47067 --- /dev/null +++ b/licence.txt @@ -0,0 +1,27 @@ +KeePassAutoTypeCustomFieldPicker is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +KeePassAutoTypeCustomFieldPicker is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with KeePassAutoTypeCustomFieldPicker (GPL.txt). If not, see http://www.gnu.org/licenses/. + + + +KeePassAutoTypeCustomFieldPicker ist Freie Software: Sie können es unter den Bedingungen +der GNU General Public License, wie von der Free Software Foundation, +Version 3 der Lizenz oder (nach Ihrer Option) jeder späteren +veröffentlichten Version, weiterverbreiten und/oder modifizieren. + +KeePassAutoTypeCustomFieldPicker wird in der Hoffnung, dass es nützlich sein wird, aber +OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite +Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. +Siehe die GNU General Public License für weitere Details. + +Sie sollten eine Kopie der GNU General Public License zusammen mit KeePassAutoTypeCustomFieldPicker +erhalten haben (GPL.txt). Wenn nicht, siehe http://www.gnu.org/licenses/. \ No newline at end of file diff --git a/plgx_create.bat b/plgx_create.bat new file mode 100644 index 0000000..5fd2405 --- /dev/null +++ b/plgx_create.bat @@ -0,0 +1,14 @@ +rem del AutoTypeCustomFieldPicker.plgx +rem robocopy . .\AutoTypeCustomFieldPicker_Temp *.* /MIR +rem +rem rd /s /q AutoTypeCustomFieldPicker_Temp\AutoTypeCustomFieldPicker_Temp +rem rd /s /q AutoTypeCustomFieldPicker_Temp\AutoTypeCustomFieldPicker\obj +rem rd /s /q AutoTypeCustomFieldPicker_Temp\AutoTypeCustomFieldPicker\bin +rem rd /s /q AutoTypeCustomFieldPicker_Temp\AutoTypeCustomFieldPicker\Resources +rem +rem AutoTypeCustomFieldPicker\Resources\KeePass.exe --plgx-create "AutoTypeCustomFieldPicker_Temp" +rem ren AutoTypeCustomFieldPicker_Temp.plgx AutoTypeCustomFieldPicker.plgx +rem +rem rd /s /q AutoTypeCustomFieldPicker_Temp + +AutoTypeCustomFieldPicker\Resources\KeePass.exe --plgx-create \ No newline at end of file