KeeOtp / KeeOtp / KeeOtpExt.cs

using KeePass.Plugins;
using KeePass.Util;
using KeePass.Util.Spr;
using KeePassLib;
using KeePassLib.Utility;
using OtpSharp;
using System;
using System.Windows.Forms;

namespace KeeOtp
{
    public sealed class KeeOtpExt : Plugin
    {
        private IPluginHost host = null;
        private ToolStripItem otpSeperatorToolStripItem;
        private ToolStripItem otpDialogToolStripItem;
        private ToolStripItem otpCopyToolStripItem;

        private ToolStripItem otpTopDialogToolStripItem;
        private ToolStripItem otpTopSeperatorToolStripItem;

        public override bool Initialize(IPluginHost host)
        {
            if (host == null)
                return false;
            this.host = host;

            this.otpSeperatorToolStripItem = new ToolStripSeparator();
            host.MainWindow.EntryContextMenu.Items.Add(this.otpSeperatorToolStripItem);

            this.otpDialogToolStripItem = host.MainWindow.EntryContextMenu.Items.Add("Timed One Time Password");
            this.otpDialogToolStripItem.Click += new EventHandler(otpDialogToolStripItem_Click);

            this.otpCopyToolStripItem = host.MainWindow.EntryContextMenu.Items.Add("Copy TOTP to Clipboard");
            this.otpCopyToolStripItem.Click += otpCopyToolStripItem_Click;

            SprEngine.FilterCompile += new EventHandler<SprEventArgs>(SprEngine_FilterCompile);

            this.otpTopSeperatorToolStripItem = new ToolStripSeparator();
            host.MainWindow.ToolsMenu.DropDownItems.Add(this.otpTopSeperatorToolStripItem);
            this.otpTopDialogToolStripItem = host.MainWindow.ToolsMenu.DropDownItems.Add("Timed One Time Password",
                null,
                otpDialogToolStripItem_Click);

            return true; // Initialization successful
        }

        void SprEngine_FilterCompile(object sender, SprEventArgs e)
        {
            if ((e.Context.Flags & SprCompileFlags.ExtActive) == SprCompileFlags.ExtActive)
            {
                if (e.Text.IndexOf("{TOTP}", StringComparison.InvariantCultureIgnoreCase) >= 0)
                {
                    if (e.Context.Entry.Strings.Exists(OtpAuthData.StringDictionaryKey))
                    {
                        var data = OtpAuthData.FromString(e.Context.Entry.Strings.Get(OtpAuthData.StringDictionaryKey).ReadString());
                        var totp = new Totp(data.Key, step: data.Step, totpSize: data.Size);
                        var text = totp.ComputeTotp().ToString().PadLeft(data.Size, '0');

                        e.Text = StrUtil.ReplaceCaseInsensitive(e.Text, "{TOTP}", text);
                    }
                }
            }
        }

        public override void Terminate()
        {
            // Remove all of our menu items
            ToolStripItemCollection menu = host.MainWindow.EntryContextMenu.Items;
            menu.Remove(otpSeperatorToolStripItem);
            menu.Remove(otpDialogToolStripItem);
            menu.Remove(otpCopyToolStripItem);

            var toolsMenu = host.MainWindow.ToolsMenu;
            toolsMenu.DropDownItems.Remove(this.otpTopSeperatorToolStripItem);
            toolsMenu.DropDownItems.Remove(this.otpTopDialogToolStripItem);
        }

        void otpDialogToolStripItem_Click(object sender, EventArgs e)
        {
            PwEntry entry;
            if (GetSelectedSingleEntry(out entry))
            {
                ShowOneTimePasswords form = new ShowOneTimePasswords(entry, host);
                form.ShowDialog();
            }
        }

        void otpCopyToolStripItem_Click(object sender, EventArgs e)
        {
            PwEntry entry;
            if (this.GetSelectedSingleEntry(out entry))
            {
                if (!entry.Strings.Exists(OtpAuthData.StringDictionaryKey))
                {
                    if (MessageBox.Show("Must configure TOTP on this entry.  Do you want to do this now?", "Not Configured", MessageBoxButtons.YesNo) == DialogResult.Yes)
                    {
                        ShowOneTimePasswords form = new ShowOneTimePasswords(entry, host);
                        form.ShowDialog();
                    }
                }
                else
                {
                    var data = OtpAuthData.FromString(entry.Strings.Get(OtpAuthData.StringDictionaryKey).ReadString());
                    var totp = new Totp(data.Key, step: data.Step, totpSize: data.Size);
                    var text = totp.ComputeTotp().ToString().PadLeft(data.Size, '0');

                    if (ClipboardUtil.CopyAndMinimize(new KeePassLib.Security.ProtectedString(true, text), true, this.host.MainWindow, entry, this.host.Database))
                        this.host.MainWindow.StartClipboardCountdown();
                }
            }
        }

        private bool GetSelectedSingleEntry(out PwEntry entry)
        {
            entry = null;

            var entries = this.host.MainWindow.GetSelectedEntries();
            if (entries == null || entries.Length == 0)
            {
                MessageBox.Show("Please select an entry");
                return false;
            }
            else if (entries.Length > 1)
            {
                MessageBox.Show("Please select only one entry");
                return false;
            }
            else
            {
                // grab the entry that we care about
                entry = entries[0];
                return true;
            }
        }

        public override string UpdateUrl
        {
            get { return "https://s3.amazonaws.com/KeeOtp/version_manifest.txt"; }
        }
    }
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.