├── doc ├── .gitignore ├── images │ ├── logo.png │ ├── vs-attach.png │ ├── vs-output-tab.png │ ├── vs-continue-without-code.png │ ├── vs-attach-to-process-keepass.png │ ├── vs-dotnet-desktop-development.png │ ├── win10-keeagent-zip-contents.png │ ├── win10-keepass2-plugins-folder.png │ └── win10-keepass2-plugins-folder-drag-and-drop.png ├── integrations │ ├── images │ │ ├── win10-keepass-help-menu.png │ │ ├── win10-keepass-group-menu.png │ │ ├── win10-keepass-tools-menu.png │ │ ├── win10-keepass-application-menu.png │ │ ├── win10-keepass-entry-menu-expanded.png │ │ ├── win10-keepass-group-context-menu.png │ │ ├── win10-keepass-context-menu-expanded.png │ │ └── win10-keepass-notification-tray-menu.png │ ├── index.rst │ └── menu-items.rst ├── usage │ ├── images │ │ ├── win10-keepass-keeagent-dialog.png │ │ ├── win10-keepass-add-entry-entry-tab.png │ │ ├── win10-keepass-entry-keeagent-tab.png │ │ ├── win10-keepass-add-entry-advanced-tab.png │ │ ├── win10-keepass-add-entry-keeagent-tab.png │ │ ├── win10-keepass-context-menu-load-ssh-key.png │ │ ├── win10-keepass-global-options-keeagent-tab.png │ │ ├── win10-keepass-keeagent-manager-agent-mode.png │ │ ├── win10-keepass-keeagent-manager-client-mode.png │ │ ├── win10-keepass-keeagent-manager-file-browser.png │ │ ├── win10-keepass-keeagent-manager-select-entry-dialog.png │ │ └── win10-keepass-entry-keeagent-tab-private-key-file-location.png │ ├── index.rst │ ├── quick-start.rst │ ├── keeagent-manager.rst │ └── tips-and-tricks.rst ├── pyproject.toml ├── index.rst ├── README.md ├── installation.rst └── troubleshooting.rst ├── KeeAgent ├── Test.kdbx ├── Resources │ ├── help-3.png │ ├── KeeAgent-icon.ico │ ├── KeeAgent-icon.png │ ├── KeeAgent-icon-mono.ico │ └── CREDIT.txt ├── KeePass.exe.config ├── PublicKeyRequiredException.cs ├── Properties │ ├── DataSources │ │ ├── EntrySettings.datasource │ │ ├── DatabaseSettings.datasource │ │ ├── EntrySettings.LocationData.datasource │ │ ├── EntrySettings.DestinationConstraint.datasource │ │ └── EntrySettings.DestinationConstraint.KeySpec.datasource │ ├── AssemblyInfo.cs │ └── Resources.Designer.cs ├── UI │ ├── AttachmentBindingList.cs │ ├── InPlaceMessage.cs │ ├── DatabaseSettingsPanel.cs │ ├── ManageKeyFileDialog.cs │ ├── DecryptProgressDialog.cs │ ├── PasswordDialog.cs │ ├── UIHelper.cs │ ├── TreeViewEx.cs │ ├── PasswordDialog.Designer.cs │ ├── SystemIcon.cs │ ├── InPlaceMessage.Designer.cs │ ├── DecryptProgressDialog.Designer.cs │ ├── GroupBoxEx.cs │ ├── DatabaseSettingsPanel.Designer.cs │ ├── HostKeysDialog.cs │ ├── Validate.cs │ ├── ManageDialog.Designer.cs │ ├── ManageKeyFileDialog.Designer.cs │ ├── ManageDialog.cs │ ├── EntryPickerDialog.resx │ ├── ManageKeyFileDialog.resx │ ├── DecryptProgressDialog.resx │ └── HostKeysDialog.resx ├── NoAttachmentException.cs ├── NotificationOptions.cs ├── DatabaseSettings.cs ├── KeeAgentUiThread.cs ├── KeePass.config.xml ├── Options.cs └── KeeAgentColumnProvider.cs ├── graphics └── KeeAgent-icon.xcf ├── .gitmodules ├── LICENSE.txt ├── .vscode ├── settings.json ├── extensions.json ├── tasks.json └── launch.json ├── scripts └── msbuild.ps1 ├── .gitignore ├── KeeAgentTestProject ├── Resources │ ├── dsa.ppk │ ├── withoutPassphrase.ppk │ ├── withPassphrase.ppk │ ├── ssh2-rsa-non-ascii-passphrase.ppk │ └── 4095-bits.ppk ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── KeeAgentExtInitTest.cs ├── KeeAgentTestProject.csproj ├── OptionsTest.cs └── IOProtocolExtTest.cs ├── .github └── workflows │ └── build.yml ├── README.md ├── .readthedocs.yml ├── HACKING.md ├── KeeAgent.sln └── .editorconfig /doc/.gitignore: -------------------------------------------------------------------------------- 1 | .venv/ 2 | _build/ 3 | -------------------------------------------------------------------------------- /KeeAgent/Test.kdbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/KeeAgent/Test.kdbx -------------------------------------------------------------------------------- /doc/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/images/logo.png -------------------------------------------------------------------------------- /doc/images/vs-attach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/images/vs-attach.png -------------------------------------------------------------------------------- /graphics/KeeAgent-icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/graphics/KeeAgent-icon.xcf -------------------------------------------------------------------------------- /KeeAgent/Resources/help-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/KeeAgent/Resources/help-3.png -------------------------------------------------------------------------------- /doc/images/vs-output-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/images/vs-output-tab.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "SshAgentLib"] 2 | path = SshAgentLib 3 | url = https://github.com/dlech/SshAgentLib.git 4 | -------------------------------------------------------------------------------- /KeeAgent/Resources/KeeAgent-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/KeeAgent/Resources/KeeAgent-icon.ico -------------------------------------------------------------------------------- /KeeAgent/Resources/KeeAgent-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/KeeAgent/Resources/KeeAgent-icon.png -------------------------------------------------------------------------------- /doc/images/vs-continue-without-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/images/vs-continue-without-code.png -------------------------------------------------------------------------------- /KeeAgent/Resources/KeeAgent-icon-mono.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/KeeAgent/Resources/KeeAgent-icon-mono.ico -------------------------------------------------------------------------------- /doc/images/vs-attach-to-process-keepass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/images/vs-attach-to-process-keepass.png -------------------------------------------------------------------------------- /doc/images/vs-dotnet-desktop-development.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/images/vs-dotnet-desktop-development.png -------------------------------------------------------------------------------- /doc/images/win10-keeagent-zip-contents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/images/win10-keeagent-zip-contents.png -------------------------------------------------------------------------------- /doc/images/win10-keepass2-plugins-folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/images/win10-keepass2-plugins-folder.png -------------------------------------------------------------------------------- /doc/integrations/images/win10-keepass-help-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/integrations/images/win10-keepass-help-menu.png -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-keeagent-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-keeagent-dialog.png -------------------------------------------------------------------------------- /doc/integrations/images/win10-keepass-group-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/integrations/images/win10-keepass-group-menu.png -------------------------------------------------------------------------------- /doc/integrations/images/win10-keepass-tools-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/integrations/images/win10-keepass-tools-menu.png -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-add-entry-entry-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-add-entry-entry-tab.png -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-entry-keeagent-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-entry-keeagent-tab.png -------------------------------------------------------------------------------- /doc/images/win10-keepass2-plugins-folder-drag-and-drop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/images/win10-keepass2-plugins-folder-drag-and-drop.png -------------------------------------------------------------------------------- /doc/integrations/images/win10-keepass-application-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/integrations/images/win10-keepass-application-menu.png -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-add-entry-advanced-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-add-entry-advanced-tab.png -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-add-entry-keeagent-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-add-entry-keeagent-tab.png -------------------------------------------------------------------------------- /doc/integrations/images/win10-keepass-entry-menu-expanded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/integrations/images/win10-keepass-entry-menu-expanded.png -------------------------------------------------------------------------------- /doc/integrations/images/win10-keepass-group-context-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/integrations/images/win10-keepass-group-context-menu.png -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-context-menu-load-ssh-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-context-menu-load-ssh-key.png -------------------------------------------------------------------------------- /doc/integrations/images/win10-keepass-context-menu-expanded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/integrations/images/win10-keepass-context-menu-expanded.png -------------------------------------------------------------------------------- /doc/integrations/images/win10-keepass-notification-tray-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/integrations/images/win10-keepass-notification-tray-menu.png -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-global-options-keeagent-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-global-options-keeagent-tab.png -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-keeagent-manager-agent-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-keeagent-manager-agent-mode.png -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-keeagent-manager-client-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-keeagent-manager-client-mode.png -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-keeagent-manager-file-browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-keeagent-manager-file-browser.png -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-keeagent-manager-select-entry-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-keeagent-manager-select-entry-dialog.png -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | KeeAgent is licensed under GPLv2 (see GPL2.txt). 2 | 3 | It also includes lots of other software with varying licenses. 4 | 5 | See SshAgentLib/LICENSE.txt for more information. 6 | -------------------------------------------------------------------------------- /doc/usage/images/win10-keepass-entry-keeagent-tab-private-key-file-location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlech/KeeAgent/HEAD/doc/usage/images/win10-keepass-entry-keeagent-tab-private-key-file-location.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "restructuredtext.confPath": "${workspaceFolder}/doc", 3 | "restructuredtext.builtDocumentationPath": "${workspaceRoot}/doc/_build/html", 4 | "omnisharp.useModernNet": false 5 | } 6 | -------------------------------------------------------------------------------- /doc/integrations/index.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | KeePass Integrations 3 | ==================== 4 | 5 | This section gives detailed information on all of the ways KeeAgent is integrated 6 | into KeePass. 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | 11 | menu-items 12 | -------------------------------------------------------------------------------- /doc/usage/index.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Usage 3 | ===== 4 | 5 | Read the :doc:`quick-start` for a basic introduction or jump ahead to the more 6 | detailed information. 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | 11 | quick-start 12 | options 13 | keeagent-manager 14 | tips-and-tricks 15 | -------------------------------------------------------------------------------- /KeeAgent/KeePass.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /KeeAgent/Resources/CREDIT.txt: -------------------------------------------------------------------------------- 1 | KeeAgent*.* 2 | Copyright (C) 2013 David Lechner 3 | Derived from http://openclipart.org/detail/10458/hat-outline-by-rygle-10458 4 | and Ext/Icons/Finals/key-bw.png from the KeePass 2.x 5 | source code. 6 | 7 | help-3.png 8 | Copyright (C) ???? David Vignoni 9 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 6 | "ms-dotnettools.csharp", 7 | "ms-vscode.mono-debug", 8 | "lextudio.restructuredtext" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /KeeAgent/PublicKeyRequiredException.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | // Copyright (c) 2022 David Lechner 3 | 4 | using System; 5 | 6 | namespace KeeAgent 7 | { 8 | [Serializable] 9 | internal sealed class PublicKeyRequiredException : Exception 10 | { 11 | public PublicKeyRequiredException() 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/msbuild.ps1: -------------------------------------------------------------------------------- 1 | # Convience script to find msbuild.exe when it is not in $env:PATH 2 | # from https://github.com/microsoft/vswhere/wiki/Find-MSBuild#powershell 3 | 4 | $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" 5 | $path = & "$vswhere" -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1 6 | if ($path) { 7 | & $path $args 8 | } 9 | -------------------------------------------------------------------------------- /doc/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | package-mode = false 3 | name = "keeagent-doc" 4 | version = "0.1.0" 5 | description = "KeeAgent Documentation" 6 | authors = ["David Lechner "] 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.10" 10 | sphinx = "^7.3.7" 11 | sphinx-rtd-theme = "^2.0.0" 12 | 13 | [tool.poetry.dev-dependencies] 14 | 15 | [build-system] 16 | requires = ["poetry>=0.12"] 17 | build-backend = "poetry.masonry.api" 18 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. KeeAgent documentation master file, created by 2 | sphinx-quickstart on Fri Jan 26 10:42:29 2018. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to KeeAgent's documentation! 7 | ==================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | installation 15 | usage/index 16 | integrations/index 17 | troubleshooting 18 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # Building docs locally 2 | 3 | ## Prerequisites 4 | 5 | - [Python 3.x](https://python.org) 6 | - [Poetry](https://python-poetry.org) 7 | 8 | ## Commands 9 | 10 | ### Windows 11 | 12 | cd doc 13 | poetry install # one time setup of virtual environment 14 | poetry run make.bat html # build docs 15 | Invoke-Item .\_build\html\index.html # open in browser 16 | 17 | ### Linux 18 | 19 | cd doc 20 | poetry install # one time setup of virtual environment 21 | poetry run make html # build docs 22 | xdg-open _build/html/index.html # open in browser 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | KeeAgent*.tar.gz 2 | KeeAgent*.zip 3 | KeeAgent.plgx 4 | Local.proj 5 | 6 | #ignore thumbnails created by windows 7 | Thumbs.db 8 | #Ignore files build by Visual Studio 9 | *.obj 10 | *.exe 11 | *.pdb 12 | *.user 13 | *.aps 14 | *.pch 15 | *.vspscc 16 | *_i.c 17 | *_p.c 18 | *.ncb 19 | *.suo 20 | *.tlb 21 | *.tlh 22 | *.bak 23 | *.cache 24 | *.ilk 25 | *.log 26 | [Bb]in 27 | [Dd]ebug*/ 28 | *.lib 29 | *.sbr 30 | obj/ 31 | [Rr]elease*/ 32 | _ReSharper*/ 33 | [Tt]est[Rr]esult* 34 | _UpgradeReport* 35 | *.zip 36 | .vs/ 37 | 38 | *.resources 39 | *.userprefs 40 | test-results*/ 41 | [Pp]ackages/ 42 | 43 | #ignore jetbrains rider files 44 | .idea/ 45 | -------------------------------------------------------------------------------- /KeeAgent/Properties/DataSources/EntrySettings.datasource: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | KeeAgent.EntrySettings, KeeAgent, Version=0.3.1.0, Culture=neutral, PublicKeyToken=null 10 | -------------------------------------------------------------------------------- /KeeAgent/Properties/DataSources/DatabaseSettings.datasource: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | KeeAgent.DatabaseSettings, KeeAgent, Version=0.2.0.2, Culture=neutral, PublicKeyToken=null 10 | -------------------------------------------------------------------------------- /KeeAgent/Properties/DataSources/EntrySettings.LocationData.datasource: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | KeeAgent.EntrySettings+LocationData, KeeAgent, Version=0.3.3.0, Culture=neutral, PublicKeyToken=null 10 | -------------------------------------------------------------------------------- /KeeAgent/Properties/DataSources/EntrySettings.DestinationConstraint.datasource: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | KeeAgent.EntrySettings+DestinationConstraint, KeeAgent, Version=0.13.0.20997, Culture=neutral, PublicKeyToken=null 10 | -------------------------------------------------------------------------------- /KeeAgent/Properties/DataSources/EntrySettings.DestinationConstraint.KeySpec.datasource: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | KeeAgent.EntrySettings+DestinationConstraint+KeySpec, KeeAgent, Version=0.13.0.20997, Culture=neutral, PublicKeyToken=null 10 | -------------------------------------------------------------------------------- /KeeAgentTestProject/Resources/dsa.ppk: -------------------------------------------------------------------------------- 1 | PuTTY-User-Key-File-2: ssh-dss 2 | Encryption: aes256-cbc 3 | Comment: KeeAgent SSH2-DSA, with pass 4 | Public-Lines: 10 5 | AAAAB3NzaC1kc3MAAACBAKBYHO7twBGbR3dv+eRr8RNjLd42gq5RglXTtzJ9wQzA 6 | ivz7glbaJObFSGK68FekUhNWY6bLUCSZdj71g/MNKzqhZdfBdgWMScIWzOyOu3ip 7 | vrlKetq3/KbZsgmeDbeterPj+NBQDrercqMxXqHjgz0WCjPLlo4Kb7u7cfa6djdP 8 | AAAAFQDGY/dtGLZuX55XFqZM886xuUCg8QAAAIBBwAdPjFe1KLrIPrpV3qw4+kee 9 | nVGnfVKc4zOe3ntri6cViv7XJXi9W38bUTjIxIIX9BBlUnkG0Z1iaYP8p3qlqhzW 10 | 7wL8cjg/S2i+sCSlq8lLTXt58+aoIshazPpVteauF5Q6H60MkFhC7E1Tay2oTo5w 11 | MuNv8INSoyXMzFK+NwAAAIEAh5atc6nmvZEjqQnUI/WnCOd7nFnn0lKqjIb2JzZn 12 | T3UwKSyh9sQvegtOCQjmS4zkfBUx4iP/JRAgc4mCuhrDQiZiQPj7CyYQTyUccti9 13 | 9yDQ7qnbivqJRQfV6I48Jcy0K/u7PDJAsHjpym7lnn8HBa0BahwUM6enAazraiY0 14 | 5No= 15 | Private-Lines: 1 16 | vBygW8EkAVj/vHoUkmIytDmtSC52ka2Oz0kT2HxJ67U= 17 | Private-MAC: d40042812cebee69616b63528eb3c707dae09b7e 18 | -------------------------------------------------------------------------------- /KeeAgent/UI/AttachmentBindingList.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | // Copyright (c) 2022 David Lechner 3 | 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Linq; 7 | using KeePassLib.Collections; 8 | using KeePassLib.Security; 9 | 10 | namespace KeeAgent.UI 11 | { 12 | /// 13 | /// Binding list wrapper for PwEntry attachments. 14 | /// 15 | public class AttachmentBindingList : BindingList> 16 | { 17 | /// 18 | /// Creates a new list. 19 | /// 20 | /// The binary dictionary. 21 | public AttachmentBindingList(ProtectedBinaryDictionary binaries) : base(binaries.ToList()) 22 | { 23 | AllowEdit = false; 24 | AllowNew = false; 25 | AllowRemove = false; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /KeeAgentTestProject/Resources/withoutPassphrase.ppk: -------------------------------------------------------------------------------- 1 | PuTTY-User-Key-File-2: ssh-rsa 2 | Encryption: none 3 | Comment: KeeAgent test file, without passphrase 4 | Public-Lines: 4 5 | AAAAB3NzaC1yc2EAAAABJQAAAIEAlBEmrFXHVcN7Go43z4fdJz9uP2hSEgc/rEur 6 | aHoRGAvi3dPyH3IOyUwK3dfRLWnxMyK3yeHLlFLyMYwEIgFJVXGER+4ooywRPCk0 7 | S9vISRY54cxQkIVWCZ/QKhSB+W7OnU4yWmorFmXNg5+7HPwlf+sL0VbxdI0SoYBV 8 | oK3decU= 9 | Private-Lines: 8 10 | AAAAgBwDPqr7eL0y0hnH4QuWPpi4+S6XMh8WIM2RxnuMtyA5mZ+WzPExQRFTk1pn 11 | Gbx706+6dcw/eYrDlZqryW43mEBNcotbs38w1MNPy5fWNqt0Aj3aMCWONEKyg4/E 12 | C5JpftrbIiLUQftjx21FtXzNljAbTspGKuAEfNipQiz1KrDtAAAAQQDzDrB6hyAP 13 | U3l9a88tnMOBjN/enEWyBukFpeTZAwrYFP1qX0pxuRh9IEGPDdBtHI/VSz8ZJSWi 14 | OY/5o/LEcOjVAAAAQQCb85JFyCv2EANzuOxmeER4oSi1kTsszS3GBSjBiuiyP61d 15 | jFffp4P92EmgNyaZgV+FaUCBxRyJ/AYICsBHQcUxAAAAQFCEMyHDV9+eu6AUkkIH 16 | EsGWtbmkLvkNClNXdtzzZLnsMmBiImsubWYWzkO8nzeR8qO3rgl2wTW6YtP46Zet 17 | c9w= 18 | Private-MAC: 889afa7412587789dc6d023054cb09eafe63a7bb 19 | -------------------------------------------------------------------------------- /KeeAgentTestProject/Resources/withPassphrase.ppk: -------------------------------------------------------------------------------- 1 | PuTTY-User-Key-File-2: ssh-rsa 2 | Encryption: aes256-cbc 3 | Comment: KeeAgent test file, with passphrase 4 | Public-Lines: 4 5 | AAAAB3NzaC1yc2EAAAABJQAAAIEA2y6R3DB+rdDe9CKPvVJPKGeJIZ0KkuF6o3hm 6 | 3dYHduIfJtDOx5HJXE1Mx7sRgfsMtZuQi9Su2BOZa9N4CoqdCdYS7cuKJxKUds2d 7 | Ca9oKNy5bhUTpBDGMcXJKETzEdwQw0q+opUUdASLFkmompVEttYZIGwmFxVr40Tq 8 | ZjnJ4aM= 9 | Private-Lines: 8 10 | APLGzZsv1OQ3kHVWqUXc15PF8zKIXKHUX0vGR3ZShPl4vuPHJqBwBFxsQ+TZjCur 11 | DBuCVAvVNonH7JHRIwKE20Pxzx+A9DN9p+8lZCeg8ZlqgQ6HN3FgZhbGcWySDiLm 12 | ghulnPK8VX72V9EOB/r1lWIGBcCoAhWHamf8PQ7xiOKgxB9aLh0hSz9r7pDumnH2 13 | 4yHMychAcMx/YVgxUbpvIZ57L2hwzioP/3s8Xzt56lUeV2b80eWodkgh6hWcyE1I 14 | 60PIQQ62LSXmiN+jpMjE4+X9cWkfvY6OaxOAHiDeiWErK36zqhdiSr64sjIBCMQt 15 | LH1GznycalVaZyPXNH4Wagohznzj/eF6pNVzRhBrp5NG9f9oU4LG5G+VS1RNgeLv 16 | c6B1Jlhfji44cYWTqVqTcgWHRbV/tyr7xWXWrmqwTeWhwxmXeUrxLCw4gGP4qGVE 17 | R0C7fsKX02kNS62vABUK8w== 18 | Private-MAC: 716800c0c9c188f1f586c7a979b7c62ca94fc8f8 19 | -------------------------------------------------------------------------------- /KeeAgentTestProject/Resources/ssh2-rsa-non-ascii-passphrase.ppk: -------------------------------------------------------------------------------- 1 | PuTTY-User-Key-File-2: ssh-rsa 2 | Encryption: aes256-cbc 3 | Comment: rsa-key-20120818 4 | Public-Lines: 4 5 | AAAAB3NzaC1yc2EAAAABJQAAAIBzAyJ8l/gz/x+rv+H06+G0u3jsMfnerDEAnbt+ 6 | MkUmoNE1T/zupE4tnojTmTv+d9qrb930iz3vKqgHHK3YfCN4OsSl043e1hvQiSaV 7 | QKdXrlVASRyJ9gavHhKndx1mb5aV8C4SFD5/3sEUFJU5yH6bPUhmPphzSswGoNY1 8 | S3qdlQ== 9 | Private-Lines: 8 10 | FDyEqyZ12/KIckibxhC678DjVptE17L9ROTRN7vCMQmU70c1xOfAKDiT6vM7Uggu 11 | jM2Cnjd6A+iAVlF2238la6R7UJ4zsFwome3nEaKtXbxmWG3VLMcxLSCFsuTZOI69 12 | L615GflzHnm1pZMifIUvyLpsg9DwC7ElGounU8fb2U69BtCsWEbm+w8nS8ypeXnZ 13 | yu0JNEzqaoQJqpoPoXdDYZ3eKaLLLOlmKK8kj6GwYqTgboUhU49iAX6yz2PeRinK 14 | S2tYu+eChBgJGLpD7HAMk8eT5gaUrlGK571PCwVoC5rwKjHWB95zDgoNNPyQ6RZG 15 | fGQ4VTw2bxXQoWkQpnt9incQTq1oouEtXXWyKv7UcO/+JHKcujTe1FjpzmdHlHrt 16 | FV+RbHPHtx8h6q4CacOTWFYGAZEAIPmtlfuit32HKQGbrKJ6eDe73nkaovgZZ6sT 17 | G9F/SOUy8DAPxkJKVoz27w== 18 | Private-MAC: e9ee3de8e33405272b75d36b7efdba5680c91978 19 | -------------------------------------------------------------------------------- /KeeAgent/NoAttachmentException.cs: -------------------------------------------------------------------------------- 1 | // 2 | // NoAttachmentException.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2013 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System; 23 | 24 | namespace KeeAgent 25 | { 26 | class NoAttachmentException : Exception 27 | { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /KeeAgent/NotificationOptions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationOptions.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2012-2013 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | namespace KeeAgent 23 | { 24 | public enum NotificationOptions 25 | { 26 | AlwaysAsk, 27 | AskOnce, 28 | Balloon, 29 | Never 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build DLL/PLGX 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: windows-2022 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | with: 13 | submodules: true 14 | 15 | - name: Install prerequisites 16 | run: | 17 | choco install keepass.install --version=2.50 18 | nuget restore 19 | 20 | - name: Setup MSBuild.exe 21 | uses: microsoft/setup-msbuild@v2 22 | 23 | - name: Build DLL 24 | run: msbuild /property:Configuration=ReleaseDll /t:build KeeAgent.sln 25 | 26 | - uses: actions/upload-artifact@v4 27 | with: 28 | name: KeeAgent.dll 29 | path: KeeAgent/bin/ReleaseDll/KeeAgent.dll 30 | 31 | - name: Build PLGX 32 | run: msbuild /property:Configuration=ReleasePlgx /t:build KeeAgent.sln 33 | 34 | - name: List PLGX 35 | run: ~\.nuget\packages\plgxtool\1.0.3\tools\PlgxTool.exe -l .\KeeAgent\bin\ReleasePlgx\KeeAgent.plgx 36 | 37 | - uses: actions/upload-artifact@v4 38 | with: 39 | name: KeeAgent.plgx 40 | path: KeeAgent/bin/ReleasePlgx/KeeAgent.plgx 41 | -------------------------------------------------------------------------------- /KeeAgent/DatabaseSettings.cs: -------------------------------------------------------------------------------- 1 | // 2 | // DatabaseSettings.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2013-2014 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System; 23 | 24 | namespace KeeAgent 25 | { 26 | public class DatabaseSettings 27 | { 28 | public DatabaseSettings() 29 | { 30 | } 31 | 32 | public bool AllowAutoLoadExpiredEntryKey { get; set; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /KeeAgent/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("KeeAgent")] 8 | [assembly: AssemblyDescription("SSH authentication agent plugin for KeePass 2.x")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("David Lechner")] 11 | [assembly: AssemblyProduct("KeePass Plugin")] 12 | [assembly: AssemblyCopyright("2012-2024")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("73dddcd4-0cae-4744-b87f-d65f835a3264")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | [assembly: AssemblyVersion("0.13.8.0")] 32 | [assembly: AssemblyFileVersion("0.13.8.0")] 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | KeeAgent is a plugin for KeePass 2.x. It allows other programs to access SSH 4 | keys stored in your KeePass database for authentication. It can either act as a 5 | stand-alone agent or it can interface with an external agent. 6 | 7 | 8 | DOWNLOAD 9 | -------- 10 | 11 | #### Official release 12 | 13 | Get the latest stable official release of KeeAgent at . 14 | 15 | #### Chocolatey 📦 16 | 17 | You can [use Chocolatey to install](https://community.chocolatey.org/packages/keepass-plugin-keeagent#install) it in a more automated manner: 18 | 19 | ``` 20 | choco install keepass-plugin-keeagent 21 | ``` 22 | 23 | To [upgrade KeePass Plugin KeeAgent](https://community.chocolatey.org/packages/keepass-plugin-keeagent#upgrade) to the [latest release version](https://community.chocolatey.org/packages/keepass-plugin-keeagent#versionhistory) for enjoying the newest features, run the following command from the command line or from PowerShell: 24 | 25 | ``` 26 | choco upgrade keepass-plugin-keeagent 27 | ``` 28 | 29 | 30 | USAGE 31 | ----- 32 | 33 | Documentation is at https://keeagent.readthedocs.io/en/latest/ 34 | 35 | 36 | HACKING 37 | ------- 38 | 39 | Pull requests are welcome! See [HACKING.md](./HACKING.md) for more info. 40 | 41 | 42 | COPYRIGHT 43 | --------- 44 | 45 | (C) 2012-2024 David Lechner 46 | -------------------------------------------------------------------------------- /KeeAgent/UI/InPlaceMessage.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | // Copyright (c) 2022 David Lechner 3 | 4 | using System.ComponentModel; 5 | using System.Windows.Forms; 6 | 7 | namespace KeeAgent.UI 8 | { 9 | /// 10 | /// Label-like control for displaying an in-place message with icon. 11 | /// 12 | public partial class InPlaceMessage : UserControl 13 | { 14 | /// 15 | /// Creates a new in-place message control. 16 | /// 17 | public InPlaceMessage() 18 | { 19 | InitializeComponent(); 20 | label1.TextChanged += (s, e) => OnTextChanged(e); 21 | } 22 | 23 | /// 24 | /// Gets and sets the icon. 25 | /// 26 | [Category("Appearance"), DefaultValue(SystemIcon.StockIconId.Info)] 27 | public SystemIcon.StockIconId StockIcon { 28 | get { return systemIcon1.StockIcon; } 29 | set { systemIcon1.StockIcon = value; } 30 | } 31 | 32 | /// 33 | /// Gets and sets the message text. 34 | /// 35 | [Bindable(true)] 36 | [Browsable(true)] 37 | [DefaultValue("")] 38 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] 39 | public override string Text { 40 | get { return label1.Text; } 41 | set { label1.Text = value; } 42 | } 43 | 44 | public override void ResetText() 45 | { 46 | Text = ""; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Read the Docs configuration file for Sphinx projects 4 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 5 | 6 | # Required 7 | version: 2 8 | 9 | # Set the OS, Python version and other tools you might need 10 | build: 11 | os: ubuntu-22.04 12 | tools: 13 | python: "3.12" 14 | # You can also specify other tool versions: 15 | # nodejs: "20" 16 | # rust: "1.70" 17 | # golang: "1.20" 18 | jobs: 19 | post_create_environment: 20 | # Install poetry 21 | # https://python-poetry.org/docs/#installing-manually 22 | - pip install poetry 23 | post_install: 24 | # VIRTUAL_ENV needs to be set manually for now. 25 | # See https://github.com/readthedocs/readthedocs.org/pull/11152/ 26 | - cd doc && VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install 27 | 28 | # Build documentation in the "docs/" directory with Sphinx 29 | sphinx: 30 | configuration: doc/conf.py 31 | # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs 32 | # builder: "dirhtml" 33 | # Fail on all warnings to avoid broken references 34 | # fail_on_warning: true 35 | 36 | # Optionally build your docs in additional formats such as PDF and ePub 37 | formats: 38 | - pdf 39 | # - epub 40 | 41 | # Optional but recommended, declare the Python requirements required 42 | # to build your documentation 43 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 44 | # python: 45 | # install: 46 | # - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /HACKING.md: -------------------------------------------------------------------------------- 1 | 2 | ### Building KeeAgent in Visual Studio (Windows) 3 | 4 | #### Setting up the KeeAgent solution in Visual Studio 5 | 6 | ##### Setup Debug Properties 7 | 8 | These are not saved in KeeAgent.csproj, so you have to manually set them up. 9 | * Open the project properties for the KeeAgent project. 10 | * On the *Debug* tab, in the *Start Action* section, select *Start external 11 | program:* and enter `/bin/Debug/KeePass.exe`, where 12 | `` is the actual path on your machine. 13 | 14 | If you have not tried to build the project yet, then you will get an error 15 | that the program does not exist. Ignore the error. 16 | * Then in the *Start Options* section, set *Command line arguments* to 17 | `--debug --pw:test Test.kdbx`. 18 | * Do the same for the *Release* and *ReleasePlgx* configurations, substituting 19 | the configuration name for *Debug* in `bin/Debug/KeePass.exe`. 20 | 21 | Also leave out the `--debug` command line argument for these configurations. 22 | 23 | 24 | ### Building KeeAgent in Visual Studio Code (Linux/MacOS/Windows) 25 | 26 | * Get the code and open it in Visual Studio Code: 27 | 28 | git clone --recursive https://github.com/dlech/KeeAgent.git 29 | cd KeeAgent 30 | nuget restore 31 | code . 32 | 33 | * Install suggested extensions in VS Code 34 | 35 | * Run using VS Code debugger (F5) 36 | 37 | If `msbuild` is not present, change `tasks.json` to us `xbuild` instead. 38 | 39 | 40 | ### Building KeeAgent from the Command Line (Linux/MacOS) 41 | 42 | * Make sure you have mono (>= v3.2.x) 43 | 44 | * Get the code: 45 | 46 | git clone --recursive https://github.com/dlech/KeeAgent.git 47 | cd KeeAgent 48 | 49 | * Restore the nuget packages: 50 | 51 | wget https://dist.nuget.org/win-x86-commandline/latest/nuget.exe 52 | mono nuget.exe restore 53 | 54 | * And build: 55 | 56 | xbuild /property:Configuration=ReleasePlgx KeeAgent.sln 57 | 58 | * The plgx file will be at `bin/ReleasePlgx/KeeAgent.plgx`. 59 | -------------------------------------------------------------------------------- /KeeAgent/KeeAgentUiThread.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Windows.Forms; 4 | 5 | namespace KeeAgent 6 | { 7 | /// 8 | /// Provides a separate UI thread for interactive communication without interlocking with the MainWindow. 9 | /// 10 | public sealed class KeeAgentUiThread : IDisposable 11 | { 12 | private const string ComponentName = "KeeAgent Interactive UI"; 13 | private SynchronizationContext _synchronizationContext; 14 | 15 | public KeeAgentUiThread() 16 | { 17 | var uiThread = new Thread(UiThreadMain) { 18 | Name = ComponentName, 19 | IsBackground = true // active background thread will not block the application shutdown process 20 | }; 21 | uiThread.SetApartmentState(ApartmentState.STA); 22 | uiThread.Start(); 23 | } 24 | 25 | private void UiThreadMain() 26 | { 27 | _synchronizationContext = new WindowsFormsSynchronizationContext(); 28 | SynchronizationContext.SetSynchronizationContext(_synchronizationContext); 29 | Application.Run(); 30 | } 31 | 32 | /// 33 | /// Performs message loop shutdown. 34 | /// 35 | public void Dispose() 36 | { 37 | if (_synchronizationContext == null) { 38 | return; 39 | } 40 | 41 | var synchronizationContext = _synchronizationContext; 42 | _synchronizationContext = null; 43 | synchronizationContext.Post(_ => Application.ExitThread(), null); 44 | } 45 | 46 | /// 47 | /// Invokes a delegate on a separate UI Thread, dedicated for the KeeAgent Plugin 48 | /// 49 | /// The delegate to call. 50 | /// The method was called in while the SynchronizationContext is not 51 | /// captured yet or have been disposed already 52 | public void Invoke(Action action) 53 | { 54 | if (_synchronizationContext == null) { 55 | throw new InvalidOperationException( 56 | "KeeAgentInteractiveUi: the SynchronizationContext is not captured yet or have been disposed already"); 57 | } 58 | 59 | _synchronizationContext.Send(_ => action.Invoke(), null); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /KeeAgent/UI/DatabaseSettingsPanel.cs: -------------------------------------------------------------------------------- 1 | // 2 | // DatabaseSettingsPanel.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2013-2014 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System; 23 | using System.Diagnostics; 24 | using System.Drawing; 25 | using System.Windows.Forms; 26 | using KeePassLib; 27 | 28 | namespace KeeAgent.UI 29 | { 30 | public partial class DatabaseSettingsPanel : UserControl 31 | { 32 | 33 | private PwDatabase mDatabase; 34 | 35 | public DatabaseSettingsPanel(PwDatabase aDatabase) 36 | { 37 | mDatabase = aDatabase; 38 | 39 | InitializeComponent(); 40 | 41 | // make transparent so tab styling shows 42 | SetStyle(ControlStyles.SupportsTransparentBackColor, true); 43 | BackColor = Color.Transparent; 44 | 45 | mDatabaseSettingsBindingSource.DataSource = mDatabase.GetKeeAgentSettings(); 46 | } 47 | 48 | protected override void OnLoad(EventArgs e) 49 | { 50 | base.OnLoad(e); 51 | if (ParentForm != null) { 52 | ParentForm.FormClosing += (s, e2) => { 53 | if (ParentForm.DialogResult == DialogResult.OK) { 54 | var settings = mDatabaseSettingsBindingSource.DataSource as DatabaseSettings; 55 | mDatabase.SetKeeAgentSettings(settings); 56 | } 57 | }; 58 | } 59 | } 60 | 61 | private void mHelpButton_Click(object sender, EventArgs e) 62 | { 63 | Process.Start(Properties.Resources.WebHelpDatabaseSettings); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /KeeAgent/UI/ManageKeyFileDialog.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | // Copyright (c) 2022 David Lechner 3 | 4 | using System; 5 | using System.Linq; 6 | using System.Windows.Forms; 7 | using KeePassLib.Security; 8 | 9 | namespace KeeAgent.UI 10 | { 11 | /// 12 | /// Dialog box for managing SSH key file locations. 13 | /// 14 | public partial class ManageKeyFileDialog : Form 15 | { 16 | /// 17 | /// Creates a new key file dialog. 18 | /// 19 | public ManageKeyFileDialog() 20 | { 21 | InitializeComponent(); 22 | 23 | if (Type.GetType("Mono.Runtime") == null) { 24 | Icon = Properties.Resources.KeeAgent_icon; 25 | } 26 | else { 27 | Icon = Properties.Resources.KeeAgent_icon_mono; 28 | } 29 | 30 | // Each key panel needs it's own binding context, otherwise 31 | // the two combo boxes will be magically linked because they 32 | // share the same data source. 33 | privateKeyLocationPanel.BindingContext = new BindingContext(); 34 | 35 | var getAttachment = new Func(name => { 36 | if (Attachments == null) { 37 | return null; 38 | } 39 | 40 | return Attachments.FirstOrDefault(a => a.Key == name).Value; 41 | }); 42 | 43 | privateKeyLocationPanel.KeyLocationChanged += (s, e) => { 44 | privateKeyLocationPanel.ErrorMessage = UI.Validate.Location( 45 | privateKeyLocationPanel.KeyLocation, getAttachment); 46 | }; 47 | } 48 | 49 | /// 50 | /// Gets and sets the attachments data source. 51 | /// 52 | public AttachmentBindingList Attachments { 53 | get { 54 | return privateKeyLocationPanel.Attachments; 55 | } 56 | set { 57 | privateKeyLocationPanel.Attachments = value; 58 | } 59 | } 60 | 61 | /// 62 | /// Gets and sets the private key location data source. 63 | /// 64 | public EntrySettings.LocationData KeyLocation { 65 | get { 66 | return privateKeyLocationPanel.KeyLocation; 67 | } 68 | set { 69 | privateKeyLocationPanel.KeyLocation = value; 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build", 8 | "type": "shell", 9 | "command": "${workspaceFolder}/scripts/msbuild.ps1", 10 | "args": [ 11 | "/property:GenerateFullPaths=true", 12 | "/t:build", 13 | "KeeAgent.sln" 14 | ], 15 | "group": "build", 16 | "presentation": { 17 | "reveal": "silent" 18 | }, 19 | "problemMatcher": "$msCompile" 20 | }, 21 | { 22 | "label": "release", 23 | "type": "shell", 24 | "command": "${workspaceFolder}/scripts/msbuild.ps1", 25 | "args": [ 26 | "/property:GenerateFullPaths=true", 27 | "/property:Configuration=ReleasePlgx", 28 | "/t:build", 29 | "KeeAgent.sln" 30 | ], 31 | "group": "build", 32 | "presentation": { 33 | "reveal": "silent" 34 | }, 35 | "problemMatcher": "$msCompile" 36 | }, 37 | { 38 | "label": "build-mono", 39 | "type": "shell", 40 | "command": "xbuild", 41 | "args": [ 42 | "/property:GenerateFullPaths=true", 43 | "/t:build", 44 | "KeeAgent.sln" 45 | ], 46 | "group": "build", 47 | "presentation": { 48 | "reveal": "silent" 49 | }, 50 | "problemMatcher": "$msCompile" 51 | }, 52 | { 53 | "label": "release-mono", 54 | "type": "shell", 55 | "command": "xbuild", 56 | "args": [ 57 | "/property:GenerateFullPaths=true", 58 | "/property:Configuration=ReleasePlgx", 59 | "/t:build", 60 | "KeeAgent.sln" 61 | ], 62 | "group": "build", 63 | "presentation": { 64 | "reveal": "silent" 65 | }, 66 | "problemMatcher": "$msCompile" 67 | } 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /KeeAgentTestProject/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // 2 | // AssemblyInfo.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2012-2013 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System.Reflection; 23 | using System.Runtime.CompilerServices; 24 | using System.Runtime.InteropServices; 25 | 26 | // General Information about an assembly is controlled through the following 27 | // set of attributes. Change these attribute values to modify the information 28 | // associated with an assembly. 29 | [assembly: AssemblyTitle("KeeAgentTestProject")] 30 | [assembly: AssemblyDescription("")] 31 | [assembly: AssemblyConfiguration("")] 32 | [assembly: AssemblyCompany("David Lechner")] 33 | [assembly: AssemblyProduct("KeeAgentTestProject")] 34 | [assembly: AssemblyCopyright("Copyright \u00A9 2012-2013")] 35 | [assembly: AssemblyTrademark("")] 36 | [assembly: AssemblyCulture("")] 37 | 38 | // Setting ComVisible to false makes the types in this assembly not visible 39 | // to COM components. If you need to access a type in this assembly from 40 | // COM, set the ComVisible attribute to true on that type. 41 | [assembly: ComVisible(false)] 42 | 43 | // The following GUID is for the ID of the typelib if this project is exposed to COM 44 | [assembly: Guid("dd62eb00-76ed-484d-a67e-1c32bf265ca8")] 45 | 46 | // Version information for an assembly consists of the following four values: 47 | // 48 | // Major Version 49 | // Minor Version 50 | // Build Number 51 | // Revision 52 | // 53 | // You can specify all the values or you can default the Build and Revision Numbers 54 | // by using the '*' as shown below: 55 | [assembly: AssemblyVersion("1.0.0.0")] 56 | [assembly: AssemblyFileVersion("1.0.0.0")] 57 | -------------------------------------------------------------------------------- /KeeAgent/KeePass.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | true 7 | 8 | 9 | 10 | 11 | 12 | false 13 | false 14 | true 15 | 16 | 17 | 18 | 19 | 20 | Title 21 | 90 22 | 23 | 24 | PluginExt 25 | SSH Key Status 26 | 90 27 | 28 | 29 | UserName 30 | 90 31 | 32 | 33 | Password 34 | 90 35 | true 36 | 37 | 38 | Url 39 | 90 40 | 41 | 42 | 43 | 44 | false 45 | 46 | 47 | 48 | KeeAgent.AlwaysConfirm 49 | false 50 | 51 | 52 | KeeAgent.ShowBalloon 53 | true 54 | 55 | 56 | KeeAgent.AgentMode 57 | Auto 58 | 59 | 60 | KeeAgent.UnlockOnActivity 61 | true 62 | 63 | 64 | KeeAgent.UseCygwinSocket 65 | false 66 | 67 | 68 | KeeAgent.UseMsysSocket 69 | false 70 | 71 | 72 | KeeAgent.UseWindowsOpenSshPipe 73 | false 74 | 75 | 76 | KeeAgent.UnixSocketPath 77 | 78 | 79 | 80 | KeeAgent.UserPicksKeyOnRequestIdentities 81 | false 82 | 83 | 84 | KeeAgent.IgnoreMissingExternalKeyFilesName 85 | false 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /KeeAgent/UI/DecryptProgressDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace KeeAgent.UI 6 | { 7 | public partial class DecryptProgressDialog : Form 8 | { 9 | private class BackgroundProgress : IProgress 10 | { 11 | private BackgroundWorker worker; 12 | 13 | public BackgroundProgress(BackgroundWorker worker) 14 | { 15 | this.worker = worker; 16 | } 17 | 18 | public void Report(double value) 19 | { 20 | var percent = (int)(100 * value); 21 | worker.ReportProgress(percent); 22 | } 23 | } 24 | 25 | public delegate object DecryptFunc(IProgress progress); 26 | 27 | public DecryptProgressDialog() 28 | { 29 | InitializeComponent(); 30 | } 31 | 32 | public int Progress { get { return progressBar.Value; } } 33 | 34 | public Exception Error { get; private set; } 35 | 36 | public object Result { get; private set; } 37 | 38 | public void Start(DecryptFunc decrypt) 39 | { 40 | if (decrypt == null) { 41 | throw new ArgumentNullException("decrypt"); 42 | } 43 | 44 | backgroundWorker.RunWorkerAsync(decrypt); 45 | } 46 | 47 | private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 48 | { 49 | var decrypt = (DecryptFunc)e.Argument; 50 | var progress = new BackgroundProgress(backgroundWorker); 51 | e.Result = decrypt(progress); 52 | } 53 | 54 | private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 55 | { 56 | progressBar.Style = ProgressBarStyle.Continuous; 57 | progressBar.Value = e.ProgressPercentage; 58 | 59 | // HACK: avoid lag due to animation 60 | // https://stackoverflow.com/q/6071626/1976323 61 | if (e.ProgressPercentage > 0) { 62 | progressBar.Value = e.ProgressPercentage - 1; 63 | progressBar.Value = e.ProgressPercentage; 64 | } 65 | } 66 | 67 | private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 68 | { 69 | if (e.Cancelled) { 70 | throw new NotSupportedException(); 71 | } 72 | 73 | if (e.Error == null) { 74 | DialogResult = DialogResult.OK; 75 | } 76 | else { 77 | DialogResult = DialogResult.Abort; 78 | } 79 | 80 | Error = e.Error; 81 | Result = e.Result; 82 | 83 | Close(); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /KeeAgent/UI/PasswordDialog.cs: -------------------------------------------------------------------------------- 1 | // 2 | // PasswordDialog.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2012-2013 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System; 23 | using System.Windows.Forms; 24 | using dlech.SshAgentLib; 25 | 26 | namespace KeeAgent.UI 27 | { 28 | public partial class PasswordDialog : Form 29 | { 30 | readonly SecureEdit secureEdit; 31 | 32 | public PasswordDialog() 33 | { 34 | InitializeComponent(); 35 | 36 | if (Type.GetType("Mono.Runtime") == null) { 37 | Icon = Properties.Resources.KeeAgent_icon; 38 | } 39 | else { 40 | Icon = Properties.Resources.KeeAgent_icon_mono; 41 | } 42 | 43 | secureEdit = new SecureEdit(); 44 | secureEdit.Attach(passwordTextBox, null, true); 45 | } 46 | 47 | public PasswordDialog(string message) : this() 48 | { 49 | SetMessage(message); 50 | } 51 | 52 | public void SetMessage(string message) 53 | { 54 | messageLabel.Text = message; 55 | } 56 | 57 | public byte[] GetPassword() 58 | { 59 | return secureEdit.ToUtf8(); 60 | } 61 | 62 | /// 63 | /// Clean up any resources being used. 64 | /// 65 | /// 66 | /// true if managed resources should be disposed; otherwise, false. 67 | /// 68 | protected override void Dispose(bool disposing) 69 | { 70 | secureEdit.Detach(); 71 | if (disposing && (components != null)) { 72 | components.Dispose(); 73 | } 74 | base.Dispose(disposing); 75 | } 76 | 77 | private void okButton_Click(object sender, EventArgs e) 78 | { 79 | DialogResult = DialogResult.OK; 80 | Close(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /KeeAgent/UI/UIHelper.cs: -------------------------------------------------------------------------------- 1 | // 2 | // UIHelper.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2012-2013 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System.Windows.Forms; 23 | using KeePass.Plugins; 24 | 25 | namespace KeeAgent.UI 26 | { 27 | public class UIHelper 28 | { 29 | private IPluginHost mPluginHost; 30 | 31 | public UIHelper(IPluginHost pluginHost) 32 | { 33 | this.mPluginHost = pluginHost; 34 | } 35 | 36 | /// 37 | /// Shows message using the preferred notification method. 38 | /// Currently, this is only via the notification icon. 39 | /// 40 | /// The message to display 41 | public void ShowBalloonNotification(string aMessage) 42 | { 43 | MethodInvoker invoker = delegate () { 44 | if (mPluginHost.MainWindow.MainNotifyIcon != null) { 45 | mPluginHost.MainWindow.MainNotifyIcon.ShowBalloonTip( 46 | 5000, Translatable.KeeAgent, 47 | aMessage, ToolTipIcon.Info); 48 | } 49 | }; 50 | InvokeMainWindow(invoker, true); 51 | } 52 | 53 | /// 54 | /// Invokes a method on the main window thread 55 | /// 56 | /// the method to invoke 57 | /// set to true to invoke asynchronously 58 | private void InvokeMainWindow(MethodInvoker aInvoker, bool aAsync) 59 | { 60 | if (this.mPluginHost.MainWindow.InvokeRequired) { 61 | if (aAsync) { 62 | mPluginHost.MainWindow.BeginInvoke(aInvoker); 63 | } 64 | else { 65 | mPluginHost.MainWindow.Invoke(aInvoker); 66 | } 67 | } 68 | else { 69 | aInvoker.Invoke(); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /doc/usage/quick-start.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | Quick Start 3 | =========== 4 | 5 | This is a quick walk-through of the basics using KeeAgent. 6 | 7 | 1. Add a new entry to your database (**Edit > Add Entry**...). 8 | 9 | 2. On the **Entry** tab, give the entry a title. 10 | 11 | 3. Enter the passphrase for the SSH key you are going to use in the **Password** 12 | field. The plugin needs this to decrypt the file. Leave the **Password** 13 | field blank if the key is not encrypted. 14 | 15 | .. figure:: images/win10-keepass-add-entry-entry-tab.png 16 | :alt: screenshot of the KeePass Add Entry dialog on the Entry tab 17 | 18 | .. tip:: The remaining fields in the **Entry**, such as **User name** and 19 | **URL**, are not used by KeeAgent and can be left blank or used for 20 | anything you want. 21 | 22 | .. todo:: Add new tip about use of URL field by KeeAgent. 23 | 24 | 4. On the **Advanced** tab, attach your private key file using the **Attach** 25 | button. Select the key using the file dialog. This can be a PuTTY private key 26 | file (.ppk) or an OpenSSH private key file. After you have selected key and 27 | clicked **OK**, the file will appear in the list of attachments. 28 | 29 | .. figure:: images/win10-keepass-add-entry-advanced-tab.png 30 | :alt: screenshot of the KeePass Add Entry dialog on the Advanced tab 31 | 32 | 5. On the **KeeAgent** tab, check the box that says **Allow KeeAgent to use this 33 | entry**. 34 | 35 | 6. In the Location group, the file that you just attached should be 36 | automatically selected as the **Attachment**. Verify that this happened. 37 | If you have more than one attachment, you may have to select the correct 38 | file. 39 | 40 | .. figure:: images/win10-keepass-add-entry-keeagent-tab.png 41 | :alt: screenshot of the KeePass Add Entry dialog on the KeeAgent tab 42 | 43 | 7. Click **OK** to save the entry and close the **Edit Entry** dialog. 44 | 45 | 8. Right-click on the new entry and select **Load SSH Key**. The key is now 46 | loaded into the agent and can be used by client programs such as PuTTY. 47 | 48 | .. figure:: images/win10-keepass-context-menu-load-ssh-key.png 49 | :alt: Screenshot of KeePass with the context menu open showing "Load SSH 50 | Key" selected. 51 | 52 | 9. Click on **Tools > KeeAgent**. This displays a list of currently loaded keys 53 | and allows you to add or remove keys. 54 | 55 | .. figure:: images/win10-keepass-keeagent-dialog.png 56 | :alt: Screenshot of the KeeAgent manager dialog window 57 | -------------------------------------------------------------------------------- /KeeAgent/UI/TreeViewEx.cs: -------------------------------------------------------------------------------- 1 | // 2 | // TreeViewEx.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2012-2013 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System.Drawing; 23 | using System.Windows.Forms; 24 | 25 | namespace KeeAgent.UI 26 | { 27 | /// 28 | /// nodes can be disabled by setting ForeColor to SystemColors.GrayText 29 | /// 30 | public class TreeViewEx : TreeView 31 | { 32 | // used to prevent clicking on disabled nodes 33 | protected override void WndProc(ref Message m) 34 | { 35 | const int WM_LBUTTONDOWN = 0x0201; 36 | const int WM_LBUTTONUP = 0x0202; 37 | const int WM_LBUTTONDBLCLK = 0x0203; 38 | const int WM_RBUTTONDOWN = 0x0204; 39 | const int WM_RBUTTONUP = 0x0205; 40 | const int WM_RBUTTONDBLCLK = 0x0206; 41 | 42 | 43 | if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_LBUTTONUP || 44 | m.Msg == WM_LBUTTONDBLCLK || m.Msg == WM_RBUTTONDOWN || 45 | m.Msg == WM_RBUTTONUP || m.Msg == WM_RBUTTONDBLCLK) { 46 | 47 | var posData = m.LParam.ToInt32(); 48 | var xPos = posData & 0xFF; 49 | var yPos = posData >> 16; 50 | 51 | var pos = new Point(xPos, yPos); 52 | var node = GetNodeAt(pos); 53 | if (node != null) { 54 | var bounds = node.Bounds; 55 | bounds.X -= 19; 56 | bounds.Width += 20; 57 | if (bounds.Contains(pos) && node.ForeColor == SystemColors.GrayText) { 58 | return; 59 | } 60 | } 61 | } 62 | base.WndProc(ref m); 63 | } 64 | 65 | // cancel selection just in case we get selected somehow 66 | protected override void OnBeforeSelect(TreeViewCancelEventArgs e) 67 | { 68 | base.OnBeforeSelect(e); 69 | if (e.Node.ForeColor == SystemColors.GrayText) { 70 | e.Cancel = true; 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Debug .dll", 9 | "type": "clr", 10 | "request": "launch", 11 | "program": "${workspaceRoot}/KeeAgent/bin/Debug/KeePass.exe", 12 | "cwd": "${workspaceRoot}", 13 | "args": [ 14 | "--pw=test", 15 | "${workspaceRoot}/KeeAgent/bin/Debug/Test.kdbx" 16 | ], 17 | "preLaunchTask": "build" 18 | }, 19 | { 20 | "name": "Debug .plgx", 21 | "type": "clr", 22 | "request": "launch", 23 | "program": "${workspaceRoot}/KeeAgent/bin/ReleasePlgx/KeePass.exe", 24 | "cwd": "${workspaceRoot}", 25 | "args": [ 26 | "--pw=test", 27 | "${workspaceRoot}/KeeAgent/bin/ReleasePlgx/Test.kdbx" 28 | ], 29 | "preLaunchTask": "release" 30 | }, 31 | { 32 | "name": "Mono: Debug .dll", 33 | "type": "mono", 34 | "request": "launch", 35 | "program": "${workspaceRoot}/KeeAgent/bin/Debug/KeePass.exe", 36 | "cwd": "${workspaceRoot}", 37 | "args": [ 38 | "--pw=test", 39 | "${workspaceRoot}/KeeAgent/bin/Debug/Test.kdbx" 40 | ], 41 | "preLaunchTask": "build-mono" 42 | }, 43 | { 44 | "name": "Mono: Debug .dll - Agent mode", 45 | "type": "mono", 46 | "request": "launch", 47 | "program": "${workspaceRoot}/KeeAgent/bin/Debug/KeePass.exe", 48 | "cwd": "${workspaceRoot}", 49 | "env": { "SSH_AUTH_SOCK": null }, 50 | "args": [ 51 | "--pw=test", 52 | "${workspaceRoot}/KeeAgent/bin/Debug/Test.kdbx" 53 | ], 54 | "preLaunchTask": "build-mono" 55 | }, 56 | { 57 | "name": "Mono: Debug .plgx", 58 | "type": "mono", 59 | "request": "launch", 60 | "program": "${workspaceRoot}/KeeAgent/bin/ReleasePlgx/KeePass.exe", 61 | "cwd": "${workspaceRoot}", 62 | "args": [ 63 | "--pw=test", 64 | "${workspaceRoot}/KeeAgent/bin/ReleasePlgx/Test.kdbx" 65 | ], 66 | "preLaunchTask": "release-mono" 67 | } 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /KeeAgentTestProject/Resources/4095-bits.ppk: -------------------------------------------------------------------------------- 1 | PuTTY-User-Key-File-2: ssh-rsa 2 | Encryption: aes256-cbc 3 | Comment: rsa-key-20120523 4 | Public-Lines: 12 5 | AAAAB3NzaC1yc2EAAAABJQAAAgB4UTbZk7x8cZbGi17+bXaEqp4b4GL0rHUtV4Zh 6 | NuwQcqP87glOzkNJ4W/ifr3P3VE4TMtB8lPdUy89ahHm+4eIK8C7MCFAgJJbz4ah 7 | GwccLyP1pM9u7SbAfKBeG+e56PXBxWfV+HvRAd+9dt3swicvkjVM840krcEmKwKI 8 | hdnvLj9vKNZLJ0Al5a1CTcABuHOCP+5//9UhoytBvRBpNEuGbis91US50f1OQHe0 9 | 7rl/Iu57tPRObOi82ItNzvOzec49LRifTg/vT3yNlnGfaeapPtNGLgVaPcPS7yrE 10 | 1DjsZoQ1T8Dpw3MVIaL8QCjihEo63oTZnmaXKU+UFiCfp8QmukzteXBAqutZFDlQ 11 | MDQjGWi3YgZV8miz4k3+LKUNH4iYlTMKirz804ww0Uj9819YRgNU8G7FjlPSHoDD 12 | Uc6KE0fGsmJ1hXfgQYQKwsJQjvNTOgbN/DLHfeaZroko14O306KGx74Eoqk5WV3B 13 | g1AHtEGwSojXmHVDiw4DRM7hQB30KrMFBurIPdzR7MgO9Db9OK8df3zixMLPjwCu 14 | E5ocdGJqqKz0lV3oeaSjEgU423RE/xNZpxxTohM49h7U9DEN3cZ4+/B3U8BEc/Hk 15 | /hyE/a3wtutZGWhslqhtp7bI+gygBoNnnFqa1pMGY6/xkLDr+HDgIVKWLwEtUImy 16 | qojEqQ== 17 | Private-Lines: 28 18 | lZZiGDyhbYjVa9/42LaG/u0UJEosYOFA0/YRrTJ6tHT8YyzR54CFOEQA9Qnh8eKt 19 | YNnqaK8KE8dgXQlrf2yrOpeHSfg11VbRh/SmNpVusp3jIMgGljFH4jRSaXlZM1Fs 20 | 3gWyqw8HnibGytFtO++eaMNeRoFs6V2dgy+Pgv6x6oT5Bf7YUC5MIgRFXEpFR9Ic 21 | 4g/Bw8kpUhCqkfJHVgoISsDE5tqvrGKVvn5jCbOHSfRvnXaDcgEOYk7MurfZQ/p4 22 | r+ZDqfPDvVVue3BOVvKSXF57gCrNP36wFYj4/5QJBvhaaQIiSuH6yAn7Te1gdBjy 23 | OcCn8bfSv37vVqs+eXTxa0dkQwTmuTpYdYBdpu1PD4fo2eTU4l1xyrrnfReQJlmO 24 | FY1IEHq+PdmpLufdOXfK+yRmrbjAQeMSCBFfJag6v85dnwi2uRIkyNZQ/ZiWKZEb 25 | UoYbX8NL666+Wf9G8sF0sTpwqWYpO/NEtlv2BszlKnk7VWzaotIgzilehV0O8hlg 26 | 0y0+Vl1laDVhKkkPsSAnFKJywCGDKxejulpAjDz+JjvlKH3BpjTciUZgPfDnD6Lg 27 | krTfaZBqaVtA5FDfhinvzia4rsksajV2uy4Qn9rqwhXzopMpS7TPJdkQAcm2pijV 28 | uvUZ8tvEbnBtQsw/xUp+lrgt7gtZ1pelfD92xxYryBviewiQi8tqOAmh2n+jN+/V 29 | idNQOcp68Xa6vOzbnnXjlIV0qXmaDrYHwRkFet/yITiUd6IhqiCRginmiWTv6DdQ 30 | wLjrvouDBYP+KfdlxsM/Hu0hM8heAqntWOWmL2TxP+mHX6BhSUsisJaeP12SlLIf 31 | 1IK+KdDP13XZFg1QGa2FX4oWTCFxJJFthqf37/GSYVbHI9j63o2HxCJc/A6aiJ0r 32 | sKHFL25S9omTiUfS7PqBMk63vUO3tShNWdD1j0fNGoiAiHTk15/u9KVKwGnkGZhD 33 | tRDou+wEHAGXZRqZCteRuOuDZfP6h8qoxCW3WiCrFE+k+mn8TYTVUuUsoFXu/pdC 34 | qSfjPJAEVqT4HnyKqUcPx01AN8YUBHe/JPHTHZOvHGw9bECNm9xOpP0RxDLghFOh 35 | ma0BESjCabqfr7OVRCm7NTAfLuNVriNjawq9Hb6ayUal2iho/GeaVKeUy/Ambp6M 36 | ijr/vUQFFAiTI8nO8p8qND8m3wKxFaYEM6qRJpj4mhSqmb8x8ltAGcDEPTNaTbLx 37 | Riq55TwynepFBj8FwIT725VCSdyR7O/5Jra+7rtrxRmuG6W/oPm9tTvRKWcq8ei4 38 | MlceHGc+/UMK+NoFpV3dJhuybpOyfPl58HsutOyDwDUJLf0b5ebAMCdZNCSktbZo 39 | rooi61KRqwMnTCxib9FCw4wqBMsDio2DXH4Q2MU46w01L0aKsdjZq3twWxNIYN4W 40 | 0PrpZPqNXXNE+807pAzOOV2AlhacjtNSeB8Vmp/jmpP8rnDxpU+/NunsYOdzVP4J 41 | dQyJHGfE96n8JnjIH0L5/mDYr0C86r84TN71WQB6e8hPpiRVE1OaG5AfXikf9JTb 42 | CveEG9ZNhNZI9eQGnTTjE9pJLsjUTWJCBw93aCjlZEDijNEKZlFpOS6hhYd6YZ00 43 | UqazKqVQ7KQrwJB+YEuY4aG5ArQhj93xphVF16ttTwvRSDjSUBy5Oyx2qcM8Cmck 44 | GQVfGBvwFzMCUYyuNv+y3GwjYhKJ+pzFMJASfAK9SVYqWNRjzuFBsfNnZkZ3G+za 45 | 9FCv0WFBZs1MkKWWETk8gA== 46 | Private-MAC: 5d0ef7ed9eebc515454c344d79ddeb8ab365b3f8 47 | -------------------------------------------------------------------------------- /KeeAgentTestProject/KeeAgentExtInitTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // KeeAgentExtInitTest.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2012-2013 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System; 23 | using System.Windows.Forms; 24 | using KeeAgent; 25 | using KeePass.Plugins; 26 | using KeePassPluginDevTools.Control; 27 | using NUnit.Framework; 28 | 29 | namespace KeeAgentTestProject 30 | { 31 | /// 32 | ///This is a test class for KeeAgentExtTest and is intended 33 | ///to contain all KeeAgentExtTest Unit Tests 34 | /// 35 | [TestFixture()] 36 | public class KeeAgentExtInitTest 37 | { 38 | 39 | //Use ClassCleanup to run code after all tests in a class have run 40 | [TestFixtureTearDown()] 41 | public static void Cleanup() 42 | { 43 | KeePassControl.ExitAll(); 44 | } 45 | 46 | /// 47 | ///A test for Initialize and Terminate 48 | /// 49 | [Test()] 50 | public void InitializeTest() 51 | { 52 | const string initalizeResultName = "KEEAGENT_INIT_RESULT"; 53 | 54 | using (KeePassAppDomain testDomain1 = new KeePassAppDomain()) { 55 | testDomain1.StartKeePass(true, true, 1, true); 56 | testDomain1.DoCallBack(delegate() 57 | { 58 | IPluginHost td1PluginHost = KeePass.Program.MainForm.PluginHost; 59 | try { 60 | KeeAgentExt td1KeeAgentExt = new KeeAgentExt(); 61 | KeePass.Program.MainForm.Invoke((MethodInvoker)delegate() 62 | { 63 | bool td1InitalizeResult = td1KeeAgentExt.Initialize(td1PluginHost); 64 | td1KeeAgentExt.Terminate(); 65 | AppDomain.CurrentDomain.SetData(initalizeResultName, 66 | td1InitalizeResult); 67 | }); 68 | } catch (Exception) { 69 | // TODO do we want to pass this exception back to test? 70 | } 71 | }); 72 | 73 | bool expected = true; 74 | bool actual = (bool)testDomain1.GetData(initalizeResultName); 75 | Assert.AreEqual(expected, actual); 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /KeeAgent/UI/PasswordDialog.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeeAgent.UI 2 | { 3 | partial class PasswordDialog 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | 11 | #region Windows Form Designer generated code 12 | 13 | /// 14 | /// Required method for Designer support - do not modify 15 | /// the contents of this method with the code editor. 16 | /// 17 | private void InitializeComponent() 18 | { 19 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PasswordDialog)); 20 | this.passwordTextBox = new System.Windows.Forms.TextBox(); 21 | this.messageLabel = new System.Windows.Forms.Label(); 22 | this.okButton = new System.Windows.Forms.Button(); 23 | this.cancelButton = new System.Windows.Forms.Button(); 24 | this.SuspendLayout(); 25 | // 26 | // passwordTextBox 27 | // 28 | resources.ApplyResources(this.passwordTextBox, "passwordTextBox"); 29 | this.passwordTextBox.Name = "passwordTextBox"; 30 | // 31 | // messageLabel 32 | // 33 | resources.ApplyResources(this.messageLabel, "messageLabel"); 34 | this.messageLabel.Name = "messageLabel"; 35 | // 36 | // okButton 37 | // 38 | resources.ApplyResources(this.okButton, "okButton"); 39 | this.okButton.Name = "okButton"; 40 | this.okButton.UseVisualStyleBackColor = true; 41 | // 42 | // cancelButton 43 | // 44 | resources.ApplyResources(this.cancelButton, "cancelButton"); 45 | this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; 46 | this.cancelButton.Name = "cancelButton"; 47 | this.cancelButton.UseVisualStyleBackColor = true; 48 | // 49 | // PasswordDialog 50 | // 51 | this.AcceptButton = this.okButton; 52 | resources.ApplyResources(this, "$this"); 53 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 54 | this.CancelButton = this.cancelButton; 55 | this.ControlBox = false; 56 | this.Controls.Add(this.cancelButton); 57 | this.Controls.Add(this.okButton); 58 | this.Controls.Add(this.messageLabel); 59 | this.Controls.Add(this.passwordTextBox); 60 | this.MaximizeBox = false; 61 | this.MinimizeBox = false; 62 | this.Name = "PasswordDialog"; 63 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; 64 | this.ResumeLayout(false); 65 | this.PerformLayout(); 66 | 67 | } 68 | 69 | #endregion 70 | 71 | private System.Windows.Forms.TextBox passwordTextBox; 72 | private System.Windows.Forms.Label messageLabel; 73 | private System.Windows.Forms.Button okButton; 74 | private System.Windows.Forms.Button cancelButton; 75 | } 76 | } -------------------------------------------------------------------------------- /doc/installation.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Installation 3 | ============ 4 | 5 | KeeAgent, like any other KeePass 2.x plugin, is installed by copying the ``.plgx`` 6 | file to the ``Plugins`` folder of the KeePass 2.x installation. The location 7 | of this folder depends on how you installed KeePass 2.x (e.g. using an installer 8 | or using the portable version). 9 | 10 | 11 | Windows 12 | ======= 13 | 14 | .. tip:: Users of the Chocolatey package manager may find a `KeeAgent package`__ 15 | there (maintained by a 3rd party). 16 | 17 | .. __: https://chocolatey.org/packages/keepass-plugin-keeagent 18 | 19 | 20 | 1. Download KeeAgent from https://lechnology.com/software/keeagent 21 | 22 | 2. Open the zip file 23 | 24 | .. figure:: images/win10-keeagent-zip-contents.png 25 | :alt: screenshot of Windows Explorer showing the contents of the 26 | downloaded KeeAgent zip file 27 | 28 | 3. In another Explorer window, open the KeePass 2.x Plugins folder. 29 | 30 | .. figure:: images/win10-keepass2-plugins-folder.png 31 | :alt: screenshot of Windows Explorer showing KeePass 2.x Plugins directory 32 | 33 | .. note:: If you used the Windows installer to install KeePass, then the folder 34 | will be ``C:\Program Files\KeePass Password Safe 2\Plugins`` (or 35 | ``Program Files (x86)`` for older versions of KeePass). 36 | 37 | If you are using the portable version of KeePass 2.x, then hopefully 38 | you remember where you installed it. 39 | 40 | 4. Drag and drop the ``KeeAgent.plgx`` file from the zip file to the KeePass 2.x 41 | Plugins folder, replacing the existing file if you have previously installed 42 | KeeAgent. 43 | 44 | .. figure:: images/win10-keepass2-plugins-folder-drag-and-drop.png 45 | :alt: screenshot of Windows Explorer showing dropping a file into the 46 | KeePass 2.x Plugins directory 47 | 48 | 49 | Linux 50 | ===== 51 | 52 | Packaging for Linux distributions is maintained by 3rd parties. 53 | 54 | Arch 55 | ---- 56 | 57 | There are several 3rd party AUR packages for KeeAgent. 58 | 59 | And, you may find something about `KeeAgent on the Arch Wiki`__. 60 | 61 | .. __: https://wiki.archlinux.org/index.php/SSH_keys#KeePass2_with_KeeAgent_plugin 62 | 63 | 64 | Everyone Else 65 | ------------- 66 | 67 | This assumes that you already have KeePass 2.x (and therefore Mono) already 68 | successfully installed. If you have not already, install the ``mono-complete`` 69 | package from your distro. Then extract ``KeeAgent.plgx`` from the zip file 70 | and copy it to the ``Plugins`` folder where ``KeePass.exe`` is located. This 71 | is usually at ``/usr/lib/keepass2/Plugins/`` unless you are using the portable 72 | version of KeePass 2.x, in which case, hopefully you remember where you 73 | installed it. 74 | 75 | 76 | macOS 77 | ===== 78 | 79 | On macOS, it is assumed that you are using the portable version of KeePass 2.x. 80 | 81 | * Open the folder that contains ``KeePass.exe``. 82 | * Drag and drop ``KeeAgent.plgx`` into the ``Plugins`` subdirectory. 83 | * Restart KeePass if it was already running. 84 | -------------------------------------------------------------------------------- /KeeAgent/UI/SystemIcon.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | // Copyright (c) 2022 David Lechner 3 | 4 | using System; 5 | using System.ComponentModel; 6 | using System.Drawing; 7 | using System.Runtime.InteropServices; 8 | using System.Windows.Forms; 9 | 10 | namespace KeeAgent.UI 11 | { 12 | /// 13 | /// A control that gets a properly scaled system icon. 14 | /// 15 | public class SystemIcon : PictureBox 16 | { 17 | [DllImport("Comctl32.dll")] 18 | private static extern int LoadIconWithScaleDown( 19 | IntPtr hinstance, 20 | IntPtr pszName, 21 | int cx, 22 | int cy, 23 | out IntPtr phico); 24 | 25 | [DllImport("User32.dll")] 26 | private static extern bool DestroyIcon(IntPtr hIcon); 27 | 28 | public enum StockIconId : uint 29 | { 30 | Info = 32516, // IDI_INFORMATION 31 | Warning = 32515, // IDI_WARNING 32 | Error = 32513, // IDI_ERROR, 33 | Help = 32514, // IDI_QUESTION 34 | } 35 | 36 | /// 37 | /// Creates a new system icon. 38 | /// 39 | public SystemIcon() 40 | { 41 | BackColor = Color.Transparent; 42 | SizeMode = PictureBoxSizeMode.CenterImage; 43 | 44 | stockIconId = StockIconId.Info; 45 | SizeChanged += (s, e) => UpdateImage(); 46 | UpdateImage(); 47 | } 48 | 49 | private StockIconId stockIconId; 50 | 51 | /// 52 | /// Gets and sets the stock icon type. 53 | /// 54 | [Category("Appearance"), DefaultValue(StockIconId.Info)] 55 | public StockIconId StockIcon { 56 | get { 57 | return stockIconId; 58 | } 59 | set { 60 | stockIconId = value; 61 | UpdateImage(); 62 | } 63 | } 64 | 65 | private void UpdateImage() 66 | { 67 | // Use ugly icons on mono - it's the best we can do 68 | if (Type.GetType("Mono.Runtime") != null) { 69 | Icon icon; 70 | 71 | switch (stockIconId) { 72 | case StockIconId.Info: 73 | icon = SystemIcons.Information; 74 | break; 75 | case StockIconId.Warning: 76 | icon = SystemIcons.Warning; 77 | break; 78 | case StockIconId.Error: 79 | icon = SystemIcons.Error; 80 | break; 81 | case StockIconId.Help: 82 | icon = SystemIcons.Question; 83 | break; 84 | default: 85 | throw new NotSupportedException("unsupported icon id"); 86 | } 87 | 88 | Image = new Icon(icon, Size.Width, Size.Height).ToBitmap(); 89 | 90 | return; 91 | } 92 | 93 | IntPtr handle; 94 | 95 | Marshal.ThrowExceptionForHR( 96 | LoadIconWithScaleDown(IntPtr.Zero, (IntPtr)stockIconId, Size.Width, Size.Height, out handle)); 97 | 98 | try { 99 | Image = Icon.FromHandle(handle).ToBitmap(); 100 | } 101 | finally { 102 | DestroyIcon(handle); 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /KeeAgent/UI/InPlaceMessage.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeeAgent.UI 2 | { 3 | partial class InPlaceMessage 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) { 17 | components.Dispose(); 18 | } 19 | base.Dispose(disposing); 20 | } 21 | 22 | #region Component Designer generated code 23 | 24 | /// 25 | /// Required method for Designer support - do not modify 26 | /// the contents of this method with the code editor. 27 | /// 28 | private void InitializeComponent() 29 | { 30 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InPlaceMessage)); 31 | this.systemIcon1 = new KeeAgent.UI.SystemIcon(); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | ((System.ComponentModel.ISupportInitialize)(this.systemIcon1)).BeginInit(); 34 | this.SuspendLayout(); 35 | // 36 | // systemIcon1 37 | // 38 | this.systemIcon1.BackColor = System.Drawing.Color.Transparent; 39 | this.systemIcon1.Image = ((System.Drawing.Image)(resources.GetObject("systemIcon1.Image"))); 40 | this.systemIcon1.Location = new System.Drawing.Point(3, 3); 41 | this.systemIcon1.Name = "systemIcon1"; 42 | this.systemIcon1.Size = new System.Drawing.Size(16, 16); 43 | this.systemIcon1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; 44 | this.systemIcon1.TabIndex = 0; 45 | this.systemIcon1.TabStop = false; 46 | // 47 | // label1 48 | // 49 | this.label1.AutoSize = true; 50 | this.label1.Location = new System.Drawing.Point(25, 4); 51 | this.label1.Name = "label1"; 52 | this.label1.Size = new System.Drawing.Size(61, 13); 53 | this.label1.TabIndex = 1; 54 | this.label1.Text = ""; 55 | // 56 | // InPlaceMessage 57 | // 58 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 59 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 60 | this.BackColor = System.Drawing.Color.Transparent; 61 | this.Controls.Add(this.label1); 62 | this.Controls.Add(this.systemIcon1); 63 | this.Name = "InPlaceMessage"; 64 | this.Size = new System.Drawing.Size(406, 26); 65 | ((System.ComponentModel.ISupportInitialize)(this.systemIcon1)).EndInit(); 66 | this.ResumeLayout(false); 67 | this.PerformLayout(); 68 | 69 | } 70 | 71 | #endregion 72 | 73 | private SystemIcon systemIcon1; 74 | private System.Windows.Forms.Label label1; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /doc/integrations/menu-items.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | Menu Items 3 | ========== 4 | 5 | KeeAgent adds several menu items to KeePass. 6 | 7 | 8 | Main / Application Menu 9 | ======================= 10 | 11 | This is the KeePass application menu. 12 | 13 | .. figure:: images/win10-keepass-application-menu.png 14 | :alt: KeePass - Application Menu 15 | 16 | 17 | Group Menu 18 | ---------- 19 | 20 | The *Group Menu* is accessed by clicking on *Group* in the main application menu 21 | or by right-clicking on an group in the group navigation pane on the left side 22 | of the main window in KeePass. 23 | 24 | .. figure:: images/win10-keepass-group-menu.png 25 | :alt: Screenshot of KeePass main window group menu on Windows 10 26 | 27 | .. figure:: images/win10-keepass-group-context-menu.png 28 | :alt: Screenshot of KeePass main window group context menu on Windows 10 29 | 30 | **Load SSH Keys** (Ctrl+M) 31 | Loads keys from the selected group in to the agent. 32 | 33 | .. note:: This menu item is only visible if the selected group contains any 34 | SSH keys. 35 | 36 | 37 | Entry Menu 38 | ---------- 39 | 40 | The *Entry Menu* is accessed by clicking *Entry* in the main application menu 41 | or by right-clicking on an entry in the entry list. 42 | 43 | .. figure:: images/win10-keepass-entry-menu-expanded.png 44 | :alt: Screenshot of KeePass main window entry menu on Windows 10 45 | 46 | .. figure:: images/win10-keepass-context-menu-expanded.png 47 | :alt: Screenshot of KeePass main window entry context menu on Windows 10 48 | 49 | **Load SSH Key** (Ctrl+M) 50 | Loads key from the selected entry in to the agent. 51 | 52 | .. note:: This menu item is only visible if the selected entry has the *Allow 53 | KeeAgent to use this entry* option checked. 54 | 55 | .. warning:: If the key is already loaded in the agent, it will be replaced. 56 | This could potentially change any constraints the key has. 57 | 58 | **URL(s) > Load SSH Key and Open URL** (Ctrl+Shift+M) 59 | Loads key from the selected entry in to the agent and then opens the URL 60 | for the entry. 61 | 62 | This item is basically a shortcut for the combination of the *Load SSH Key* 63 | and *URL(s) > Open* menu items. 64 | 65 | 66 | Tools Menu 67 | ---------- 68 | 69 | KeeAgent adds one item to the Tools menu. 70 | 71 | .. figure:: images/win10-keepass-tools-menu.png 72 | :alt: KeePass - Tools menu - KeeAgent 73 | 74 | KeeAgent 75 | Opens the KeeAgent Manager dialog. 76 | 77 | .. todo:: Add link to page on KeeAgent manager. 78 | 79 | 80 | Help Menu 81 | --------- 82 | 83 | KeeAgent adds one item to the Help menu. 84 | 85 | .. figure:: images/win10-keepass-help-menu.png 86 | :alt: KeePass - Help menu - KeeAgent 87 | 88 | KeeAgent 89 | Opens the KeeAgent documentation in a web browser. 90 | 91 | 92 | Notification Tray Icon Menu 93 | =========================== 94 | 95 | .. figure:: images/win10-keepass-notification-tray-menu.png 96 | :alt: KeePass - Tray Icon Menu - KeeAgent 97 | 98 | KeeAgent 99 | Opens the KeeAgent Manager dialog. (Same as *Tools > KeeAgent* in the application menu.) 100 | 101 | .. tip:: If you are missing this icon on your Linux desktop, check out `this 102 | plugin`__. 103 | 104 | .. __: https://github.com/dlech/Keebuntu 105 | -------------------------------------------------------------------------------- /KeeAgent/UI/DecryptProgressDialog.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeeAgent.UI 2 | { 3 | partial class DecryptProgressDialog 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) { 17 | components.Dispose(); 18 | } 19 | base.Dispose(disposing); 20 | } 21 | 22 | #region Windows Form Designer generated code 23 | 24 | /// 25 | /// Required method for Designer support - do not modify 26 | /// the contents of this method with the code editor. 27 | /// 28 | private void InitializeComponent() 29 | { 30 | this.progressBar = new System.Windows.Forms.ProgressBar(); 31 | this.backgroundWorker = new System.ComponentModel.BackgroundWorker(); 32 | this.SuspendLayout(); 33 | // 34 | // progressBar 35 | // 36 | this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 37 | | System.Windows.Forms.AnchorStyles.Right))); 38 | this.progressBar.Location = new System.Drawing.Point(12, 12); 39 | this.progressBar.MarqueeAnimationSpeed = 10; 40 | this.progressBar.Name = "progressBar"; 41 | this.progressBar.Size = new System.Drawing.Size(231, 23); 42 | this.progressBar.Style = System.Windows.Forms.ProgressBarStyle.Marquee; 43 | this.progressBar.TabIndex = 0; 44 | // 45 | // backgroundWorker 46 | // 47 | this.backgroundWorker.WorkerReportsProgress = true; 48 | this.backgroundWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker_DoWork); 49 | this.backgroundWorker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker_ProgressChanged); 50 | this.backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker_RunWorkerCompleted); 51 | // 52 | // DecryptProgressDialog 53 | // 54 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 55 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 56 | this.AutoSize = true; 57 | this.ClientSize = new System.Drawing.Size(255, 49); 58 | this.ControlBox = false; 59 | this.Controls.Add(this.progressBar); 60 | this.MaximizeBox = false; 61 | this.MinimizeBox = false; 62 | this.Name = "DecryptProgressDialog"; 63 | this.ShowInTaskbar = false; 64 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; 65 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 66 | this.Text = "Decrypting SSH Private Key"; 67 | this.ResumeLayout(false); 68 | 69 | } 70 | 71 | #endregion 72 | 73 | private System.Windows.Forms.ProgressBar progressBar; 74 | private System.ComponentModel.BackgroundWorker backgroundWorker; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /KeeAgent/UI/GroupBoxEx.cs: -------------------------------------------------------------------------------- 1 | // 2 | // GroupBoxEx.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2012-2013 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System; 23 | using System.ComponentModel; 24 | using System.Windows.Forms; 25 | 26 | namespace KeeAgent.UI 27 | { 28 | public class GroupBoxEx : GroupBox 29 | { 30 | private string pSelectedRadioButton = string.Empty; 31 | 32 | public event EventHandler SelectedRadioButtonChanged; 33 | 34 | /// 35 | /// 36 | /// 37 | [Category("Appearance")] 38 | public string SelectedRadioButton { 39 | get { 40 | return pSelectedRadioButton; 41 | } 42 | set { 43 | if (value == null) { 44 | value = string.Empty; 45 | } 46 | if (value == pSelectedRadioButton) { 47 | return; 48 | } 49 | if (value == string.Empty) { 50 | foreach (var control in Controls) { 51 | var radioButton = Controls[value] as RadioButton; 52 | if (radioButton != null) { 53 | radioButton.Checked = false; 54 | } 55 | } 56 | } 57 | else { 58 | var selectedRadioButton = Controls[value] as RadioButton; 59 | if (selectedRadioButton == null) { 60 | throw new ArgumentException("unknown radio button"); 61 | } 62 | selectedRadioButton.Checked = true; 63 | pSelectedRadioButton = value; 64 | OnSelectedRadioButtonChanged(); 65 | } 66 | } 67 | } 68 | 69 | private void OnSelectedRadioButtonChanged() 70 | { 71 | if (SelectedRadioButtonChanged != null) { 72 | SelectedRadioButtonChanged(this, new EventArgs()); 73 | } 74 | // Workaround for strange behavior of data binding: 75 | // If we change the SelecteRadioButton property and then change another 76 | // data bound property in this group box, the SelectedRadioButton changes 77 | // will be reverted by the data binding code. To get around this, after we 78 | // have notified the the listeners, we select a control outside of the 79 | // group box and then select the usual next control. 80 | Parent.SelectNextControl(this, true, false, false, true); 81 | SelectNextControl(this, true, true, true, true); 82 | } 83 | 84 | protected override void OnControlAdded(ControlEventArgs e) 85 | { 86 | base.OnControlAdded(e); 87 | var radioButton = e.Control as RadioButton; 88 | if (radioButton != null) { 89 | radioButton.CheckedChanged += (s, e2) => { 90 | if (radioButton.Checked) { 91 | SelectedRadioButton = radioButton.Name; 92 | } 93 | }; 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /KeeAgent/UI/DatabaseSettingsPanel.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeeAgent.UI 2 | { 3 | partial class DatabaseSettingsPanel 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) { 17 | components.Dispose(); 18 | } 19 | base.Dispose(disposing); 20 | } 21 | 22 | #region Windows Form Designer generated code 23 | 24 | /// 25 | /// Required method for Designer support - do not modify 26 | /// the contents of this method with the code editor. 27 | /// 28 | private void InitializeComponent() 29 | { 30 | this.components = new System.ComponentModel.Container(); 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DatabaseSettingsPanel)); 32 | this.mHelpButton = new System.Windows.Forms.Button(); 33 | this.allowAutoLoadExpiredCheckBox = new System.Windows.Forms.CheckBox(); 34 | this.mDatabaseSettingsBindingSource = new System.Windows.Forms.BindingSource(this.components); 35 | ((System.ComponentModel.ISupportInitialize)(this.mDatabaseSettingsBindingSource)).BeginInit(); 36 | this.SuspendLayout(); 37 | // 38 | // mHelpButton 39 | // 40 | resources.ApplyResources(this.mHelpButton, "mHelpButton"); 41 | this.mHelpButton.Image = global::KeeAgent.Properties.Resources.Help_png; 42 | this.mHelpButton.Name = "mHelpButton"; 43 | this.mHelpButton.UseVisualStyleBackColor = true; 44 | this.mHelpButton.Click += new System.EventHandler(this.mHelpButton_Click); 45 | // 46 | // allowAutoLoadExpiredCheckBox 47 | // 48 | resources.ApplyResources(this.allowAutoLoadExpiredCheckBox, "allowAutoLoadExpiredCheckBox"); 49 | this.allowAutoLoadExpiredCheckBox.DataBindings.Add(new System.Windows.Forms.Binding("Checked", this.mDatabaseSettingsBindingSource, "AllowAutoLoadExpiredEntryKey", true)); 50 | this.allowAutoLoadExpiredCheckBox.Name = "allowAutoLoadExpiredCheckBox"; 51 | this.allowAutoLoadExpiredCheckBox.UseVisualStyleBackColor = true; 52 | // 53 | // mDatabaseSettingsBindingSource 54 | // 55 | this.mDatabaseSettingsBindingSource.DataSource = typeof(KeeAgent.DatabaseSettings); 56 | // 57 | // DatabaseSettingsPanel 58 | // 59 | resources.ApplyResources(this, "$this"); 60 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 61 | this.Controls.Add(this.allowAutoLoadExpiredCheckBox); 62 | this.Controls.Add(this.mHelpButton); 63 | this.Name = "DatabaseSettingsPanel"; 64 | ((System.ComponentModel.ISupportInitialize)(this.mDatabaseSettingsBindingSource)).EndInit(); 65 | this.ResumeLayout(false); 66 | this.PerformLayout(); 67 | 68 | } 69 | 70 | #endregion 71 | 72 | private System.Windows.Forms.BindingSource mDatabaseSettingsBindingSource; 73 | private System.Windows.Forms.Button mHelpButton; 74 | private System.Windows.Forms.CheckBox allowAutoLoadExpiredCheckBox; 75 | 76 | } 77 | } -------------------------------------------------------------------------------- /KeeAgent.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33815.320 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeeAgent", "KeeAgent\KeeAgent.csproj", "{742863F2-52ED-41E0-92A1-8EEA60EB75EF}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A3C09426-AEFA-4170-B530-3A0F3B13903D}" 9 | ProjectSection(SolutionItems) = preProject 10 | .editorconfig = .editorconfig 11 | CHANGELOG.txt = CHANGELOG.txt 12 | LICENSE.txt = LICENSE.txt 13 | README.md = README.md 14 | EndProjectSection 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SshAgentLib", "SshAgentLib\SshAgentLib\SshAgentLib.csproj", "{9163B6B6-0603-4C6E-BC67-7111ED8CDDE1}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SshAgentLib.Ui.WinForms", "SshAgentLib\Ui\WinForms\SshAgentLib.Ui.WinForms.csproj", "{3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | ReleaseDll|Any CPU = ReleaseDll|Any CPU 25 | ReleasePlgx|Any CPU = ReleasePlgx|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {742863F2-52ED-41E0-92A1-8EEA60EB75EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {742863F2-52ED-41E0-92A1-8EEA60EB75EF}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {742863F2-52ED-41E0-92A1-8EEA60EB75EF}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {742863F2-52ED-41E0-92A1-8EEA60EB75EF}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {742863F2-52ED-41E0-92A1-8EEA60EB75EF}.ReleaseDll|Any CPU.ActiveCfg = ReleaseDll|Any CPU 33 | {742863F2-52ED-41E0-92A1-8EEA60EB75EF}.ReleaseDll|Any CPU.Build.0 = ReleaseDll|Any CPU 34 | {742863F2-52ED-41E0-92A1-8EEA60EB75EF}.ReleasePlgx|Any CPU.ActiveCfg = ReleasePlgx|Any CPU 35 | {742863F2-52ED-41E0-92A1-8EEA60EB75EF}.ReleasePlgx|Any CPU.Build.0 = ReleasePlgx|Any CPU 36 | {9163B6B6-0603-4C6E-BC67-7111ED8CDDE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {9163B6B6-0603-4C6E-BC67-7111ED8CDDE1}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {9163B6B6-0603-4C6E-BC67-7111ED8CDDE1}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {9163B6B6-0603-4C6E-BC67-7111ED8CDDE1}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {9163B6B6-0603-4C6E-BC67-7111ED8CDDE1}.ReleaseDll|Any CPU.ActiveCfg = Release|Any CPU 41 | {9163B6B6-0603-4C6E-BC67-7111ED8CDDE1}.ReleaseDll|Any CPU.Build.0 = Release|Any CPU 42 | {9163B6B6-0603-4C6E-BC67-7111ED8CDDE1}.ReleasePlgx|Any CPU.ActiveCfg = Release|Any CPU 43 | {9163B6B6-0603-4C6E-BC67-7111ED8CDDE1}.ReleasePlgx|Any CPU.Build.0 = Release|Any CPU 44 | {3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}.ReleaseDll|Any CPU.ActiveCfg = Release|Any CPU 49 | {3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}.ReleaseDll|Any CPU.Build.0 = Release|Any CPU 50 | {3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}.ReleasePlgx|Any CPU.ActiveCfg = Release|Any CPU 51 | {3BEB6FAE-B14D-4281-8168-DB2A4A0C5FC4}.ReleasePlgx|Any CPU.Build.0 = Release|Any CPU 52 | EndGlobalSection 53 | GlobalSection(SolutionProperties) = preSolution 54 | HideSolutionNode = FALSE 55 | EndGlobalSection 56 | EndGlobal 57 | -------------------------------------------------------------------------------- /KeeAgent/UI/HostKeysDialog.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | // Copyright (c) 2022 David Lechner 3 | 4 | using System; 5 | using System.Data; 6 | using System.Linq; 7 | using System.Windows.Forms; 8 | using SshAgentLib.Keys; 9 | 10 | namespace KeeAgent.UI 11 | { 12 | public partial class HostKeysDialog : Form 13 | { 14 | public HostKeysDialog() 15 | { 16 | InitializeComponent(); 17 | 18 | // fix up layout in Mono 19 | if (Type.GetType("Mono.Runtime") != null) { 20 | dataGridView1.Anchor = AnchorStyles.Top | AnchorStyles.Left; 21 | dataGridView1.Height -= 20; 22 | okButton.Top -= 20; 23 | cancelButton.Top -= 20; 24 | } 25 | } 26 | 27 | public void AddKeySpec(EntrySettings.DestinationConstraint.KeySpec spec) 28 | { 29 | keySpecBindingSource.Add(spec.DeepCopy()); 30 | } 31 | 32 | public EntrySettings.DestinationConstraint.KeySpec[] GetKeySpecs() 33 | { 34 | return keySpecBindingSource.Cast() 35 | .Where(x => !string.IsNullOrWhiteSpace(x.HostKey)).Select(x => x.DeepCopy()).ToArray(); 36 | } 37 | 38 | private void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) 39 | { 40 | var view = (DataGridView)sender; 41 | 42 | foreach (DataGridViewRow row in view.Rows) { 43 | 44 | if (row.IsNewRow) { 45 | continue; 46 | } 47 | 48 | try { 49 | var k = row.DataBoundItem as EntrySettings.DestinationConstraint.KeySpec; 50 | 51 | if (string.IsNullOrWhiteSpace(k.HostKey)) { 52 | row.ErrorText = "host key is required"; 53 | continue; 54 | } 55 | 56 | SshPublicKey.Parse(k.HostKey); 57 | 58 | // no error, so hide error badge 59 | row.ErrorText = string.Empty; 60 | } 61 | catch (Exception ex) { 62 | row.ErrorText = ex.Message; 63 | } 64 | } 65 | } 66 | 67 | private void dataGridView1_MouseUp(object sender, MouseEventArgs e) 68 | { 69 | var grid = sender as DataGridView; 70 | 71 | var hitTest = grid.HitTest(e.X, e.Y); 72 | 73 | if (hitTest.Type == DataGridViewHitTestType.RowHeader) { 74 | var clickedRow = grid.Rows[hitTest.RowIndex]; 75 | 76 | grid.CurrentCell = clickedRow.Cells[0]; 77 | 78 | if (grid.CurrentRow.IsNewRow) { 79 | // can't remove uncommitted new row 80 | deleteToolStripMenuItem.Enabled = false; 81 | } 82 | else { 83 | deleteToolStripMenuItem.Enabled = true; 84 | } 85 | } 86 | else if (hitTest.Type == DataGridViewHitTestType.Cell) { 87 | var clickedCell = grid.Rows[hitTest.RowIndex].Cells[hitTest.ColumnIndex]; 88 | 89 | grid.CurrentCell = clickedCell; 90 | 91 | if (grid.CurrentRow.IsNewRow) { 92 | // can't remove uncommitted new row 93 | deleteToolStripMenuItem.Enabled = false; 94 | } 95 | else { 96 | deleteToolStripMenuItem.Enabled = true; 97 | } 98 | } 99 | else { 100 | deleteToolStripMenuItem.Enabled = false; 101 | } 102 | } 103 | 104 | private void deleteToolStripMenuItem_Click(object sender, EventArgs e) 105 | { 106 | try { 107 | dataGridView1.Rows.Remove(dataGridView1.CurrentRow); 108 | } 109 | catch { 110 | // don't crash the program 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /KeeAgent/UI/Validate.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | // Copyright (c) 2022 David Lechner 3 | 4 | using System; 5 | using System.IO; 6 | using KeePassLib.Security; 7 | using SshAgentLib.Keys; 8 | 9 | namespace KeeAgent.UI 10 | { 11 | /// 12 | /// Miscellaneous validators. 13 | /// 14 | public static class Validate 15 | { 16 | /// 17 | /// Validates the location data. 18 | /// 19 | /// 20 | /// The location data to check. 21 | /// 22 | /// 23 | /// Callback function to get the attachment by name. 24 | /// 25 | /// 26 | /// null if the data is valid, otherwise an error message suitable for display to the user. 27 | /// 28 | public static string Location( 29 | EntrySettings.LocationData location, 30 | Func getAttachment) 31 | { 32 | // we don't actually expect this to happen 33 | if (location == null) { 34 | return null; 35 | } 36 | 37 | if (!location.SelectedType.HasValue) { 38 | return "No private key file type is selected. Select an option and try again."; 39 | } 40 | 41 | if (location.SelectedType.Value == EntrySettings.LocationType.Attachment) { 42 | var attachment = getAttachment(location.AttachmentName); 43 | 44 | if (attachment == null) { 45 | return string.Format( 46 | "Attachment '{0}' is missing.", location.AttachmentName); 47 | } 48 | 49 | SshPrivateKey privateKey; 50 | 51 | try { 52 | privateKey = SshPrivateKey.Read(new MemoryStream(attachment.ReadData())); 53 | } 54 | catch { 55 | return string.Format( 56 | "attachment '{0}' is not a supported private key file.", location.AttachmentName); 57 | } 58 | 59 | SshPublicKey publicKey = privateKey.PublicKey; 60 | 61 | var certAttachment = getAttachment(location.AttachmentName + "-cert.pub"); 62 | 63 | if (certAttachment != null) { 64 | publicKey = SshPublicKey.Read(new MemoryStream(certAttachment.ReadData())); 65 | } 66 | 67 | var pubAttachment = getAttachment(location.AttachmentName + ".pub"); 68 | 69 | if (pubAttachment != null) { 70 | publicKey = SshPublicKey.Read(new MemoryStream(pubAttachment.ReadData())); 71 | } 72 | 73 | if (publicKey == null) { 74 | return string.Format( 75 | "This file uses a legacy format that requires a '{0}.pub' file in the same location.", 76 | location.AttachmentName); 77 | } 78 | } 79 | 80 | if (location.SelectedType.Value == EntrySettings.LocationType.File) { 81 | var file = location.FileName.ExpandEnvironmentVariables(); 82 | 83 | if (!File.Exists(file)) { 84 | return string.Format("The private key file '{0}' does not exist.", file); 85 | } 86 | 87 | SshPrivateKey privateKey; 88 | 89 | try { 90 | privateKey = SshPrivateKey.Read(File.OpenRead(file)); 91 | } 92 | catch { 93 | return string.Format("'{0}' is not a supported private key file.", file); 94 | } 95 | 96 | SshPublicKey publicKey = privateKey.PublicKey; 97 | 98 | if (File.Exists(file + "-cert.pub")) { 99 | publicKey = SshPublicKey.Read(File.OpenRead(file + "-cert.pub")); 100 | } 101 | else if (File.Exists(file + ".pub")) { 102 | publicKey = SshPublicKey.Read(File.OpenRead(file + ".pub")); 103 | } 104 | 105 | if (publicKey == null) { 106 | return string.Format( 107 | "This file uses a legacy format that requires a '{0}.pub' file in the same location.", 108 | file); 109 | } 110 | } 111 | 112 | return null; 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /KeeAgent/Options.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | // Copyright (c) 2012-2017,2022 David Lechner 3 | 4 | using System; 5 | using dlech.SshAgentLib; 6 | 7 | namespace KeeAgent 8 | { 9 | [Serializable] 10 | public class Options 11 | { 12 | public Options() 13 | { 14 | /* set default values */ 15 | } 16 | 17 | /// 18 | /// Show notification balloon when client uses keys (Agent mode only) 19 | /// 20 | public bool ShowBalloon { get; set; } 21 | 22 | /// 23 | /// Cause all keys to have confirm constraint set even if it is not requested (Agent mode only) 24 | /// 25 | public bool AlwaysConfirm { get; set; } 26 | 27 | /// 28 | /// Replaced by ShowBalloon and AlwaysConfirm 29 | /// 30 | [Obsolete()] 31 | public NotificationOptions Notification { get; set; } 32 | 33 | /// 34 | /// Turns on debug logging - currently not working 35 | /// 36 | public bool LoggingEnabled { get; set; } 37 | 38 | /// 39 | /// The file name for the debug log file 40 | /// 41 | public string LogFileName { get; set; } 42 | 43 | /// 44 | /// Specifies which mode to run the agent in. 45 | /// 46 | public AgentMode AgentMode { get; set; } 47 | 48 | /// 49 | /// When true, all databases will be unlocked when an SSH keys is requested (Agent mode only). 50 | /// 51 | public bool UnlockOnActivity { get; set; } 52 | 53 | /// 54 | /// When true and using PageantAgent, a socket file will be created at 55 | /// CygwinSocketPath that can be used with cygwin 56 | /// 57 | public bool UseCygwinSocket { get; set; } 58 | 59 | /// 60 | /// The path for the file created when is enabled. 61 | /// 62 | public string CygwinSocketPath { get; set; } 63 | 64 | /// 65 | /// When true and using PageantAgent, a socket file will be created at 66 | /// MsysSocketPath that can be used with msys 67 | /// 68 | public bool UseMsysSocket { get; set; } 69 | 70 | /// 71 | /// The path for the file created when is enabled. 72 | /// 73 | public string MsysSocketPath { get; set; } 74 | 75 | /// 76 | /// When true and using PageantAgent, a socket file will be created at 77 | /// UnixSocketPath that can be used with WSL 78 | /// 79 | public bool UseWslSocket { get; set; } 80 | 81 | /// 82 | /// The path for the file created when is enabled. 83 | /// 84 | public string WslSocketPath { get; set; } 85 | 86 | /// 87 | /// When true and using PageantAgent, a named pipe will be created 88 | /// at //./pipe/openssh-ssh-agent that can be used with Windows OpenSSH 89 | /// 90 | public bool UseWindowsOpenSshPipe { get; set; } 91 | 92 | /// 93 | /// The path for creating a unix socket in Agent mode on unix-like platforms 94 | /// 95 | /// The unix socket path. 96 | public string UnixSocketPath { get; set; } 97 | 98 | /// 99 | /// When true, the user will be prompted to select a keys from the 100 | /// loaded keys in response to a client program requesting a list of 101 | /// identities. 102 | /// 103 | public static bool UserPicksKeyOnRequestIdentities { get; set; } 104 | 105 | /// 106 | /// When true, we will not display a warning about missing keyfiles 107 | /// in the filesystem. 108 | /// 109 | public static bool IgnoreMissingExternalKeyFiles { get; set; } 110 | 111 | /// 112 | /// When true, we will not display a progress bar during SSH key decryption. 113 | /// 114 | public bool DisableKeyDecryptionProgressBar { get; set; } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /doc/usage/keeagent-manager.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | KeeAgent Manager 3 | ================ 4 | 5 | The KeeAgent Manager lists the keys that are currently loaded into the agent. 6 | From here, you can lock and unlock the agent as well as add and remove keys. 7 | The KeeAgent manager is opened from Tools > KeeAgent or from the notification 8 | tray icon menu. 9 | 10 | .. figure:: images/win10-keepass-keeagent-manager-client-mode.png 11 | :alt: Screenshot of the KeeAgent Manager window in Agent Mode 12 | 13 | .. figure:: images/win10-keepass-keeagent-manager-client-mode.png 14 | :alt: Screenshot of the KeeAgent Manager window in Client Mode 15 | 16 | **Mode Indication** 17 | 18 | The "mode" being used by KeeAgent is displayed in the title bar of the 19 | KeeAgent manager. *Agent Mode* indicates that KeeAgent is acting as the SSH 20 | agent. *Client Mode* indicates that KeeAgent is using an external SSH agent. 21 | See Global Options for more information. 22 | 23 | **List Columns** 24 | 25 | - **C** (Confirm Constraint - Agent mode only): Checked indicates that the 26 | user must confirm the use of the key every time a client requests to use 27 | the key for authentication. 28 | 29 | - **L** (Lifetime Constraint - Agent mode only): Checked indicates that the 30 | key will be automatically removed after a period of time. 31 | 32 | - **Type**: The encryption algorithm used by the key. 33 | 34 | - **Size**: The size (in bits) of the key. 35 | 36 | - **Fingerprint**: The MD5 hash of the key. 37 | 38 | - **Comment**: The comment associated with the key. 39 | 40 | - **Source**: (Agent mode only): The source of the key. This can be one of 41 | the following: the name of a database and the path of the entry in the 42 | database, the name of a file or "External client" if the key was loaded 43 | through a utility such as ``ssh-add``. 44 | 45 | **Lock and Unlock Buttons** 46 | 47 | Clicking *Lock* will prompt you for a passphrase. The passphrase can be 48 | anything - it is temporary. After entering a passphrase, the agent will be 49 | locked. This means that no keys can be added or removed or used for 50 | authentication until the agent is unlocked. To unlock, click *Unlock* and 51 | enter the same passphrase that you used when you locked the agent. 52 | 53 | .. note:: Locking and unlocking the agent is completely independent of 54 | locking and unlocking databases in KeePass. 55 | 56 | .. note:: Pageant does not support locking/unlocking, so if you are in 57 | *Client Mode* and connecting to Pageant, these buttons will not be shown. 58 | 59 | **Add.. Button** 60 | 61 | - **From KeePass...**: Shows a dialog that allows you to load a key from 62 | an entry in any of the databases currently open in KeePass. Select an 63 | entry and optionally select constrains, then click *OK* to load the key 64 | into the agent. 65 | 66 | .. note:: If you are in Client Mode and using Pageant, the checkboxes 67 | for constraints will not be shown. Pageant does not support constraints. 68 | 69 | .. figure:: images/win10-keepass-keeagent-manager-select-entry-dialog.png 70 | :alt: Screenshot of the KeeAgent Manager Select Entry dialog box 71 | 72 | - **From File...**: Shows a file browser dialog that allows you to load a 73 | key from an external file. You can also selectively add constraints to 74 | the keys. 75 | 76 | .. note:: Constraint checkboxes are integrated into the file dialog on 77 | Windows only. If you are on another OS, hold down the Control key 78 | when you click OK and you will get a separate dialog to enter 79 | constraints. 80 | 81 | .. note:: If you are in Client Mode and using Pageant, the checkboxes 82 | for constraints will not be shown. Pageant does not support constraints. 83 | 84 | .. figure:: images/win10-keepass-keeagent-manager-file-browser.png 85 | :alt: Screenshot of KeeAgent Manager file browser dialog box 86 | 87 | **Remove Button** 88 | 89 | Removes the selected key(s) from the agent. 90 | 91 | **Remove All Button** 92 | 93 | Removes all keys from the agent. 94 | 95 | **Refresh Button** (Client mode only) 96 | 97 | Sends a request to the agent for a current list of keys. 98 | -------------------------------------------------------------------------------- /KeeAgentTestProject/KeeAgentTestProject.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {D181A56F-743F-429F-BA31-1827C39A176C} 7 | Library 8 | Properties 9 | KeeAgentTestProject 10 | KeeAgentTestProject 11 | 512 12 | 13 | 14 | True 15 | full 16 | False 17 | bin\Debug\ 18 | DEBUG;TRACE 19 | prompt 20 | 4 21 | 22 | 23 | pdbonly 24 | True 25 | bin\Release\ 26 | TRACE 27 | prompt 28 | 4 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | ..\lib\NUnit\nunit.framework.dll 43 | 44 | 45 | ..\lib\IOProtocolExt\IOProtocolExt.dll 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | True 54 | True 55 | Resources.resx 56 | 57 | 58 | 59 | 60 | 61 | {742863F2-52ED-41E0-92A1-8EEA60EB75EF} 62 | KeeAgent 63 | 64 | 65 | {10938016-dee2-4a25-9a5a-8fd3444379ca} 66 | KeePass 67 | 68 | 69 | {9163B6B6-0603-4C6E-BC67-7111ED8CDDE1} 70 | SshAgentLib 71 | 72 | 73 | 74 | 75 | PublicResXFileCodeGenerator 76 | Resources.Designer.cs 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 94 | -------------------------------------------------------------------------------- /KeeAgentTestProject/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.269 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace KeeAgentTestProject.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | public class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | public static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("KeeAgentTestProject.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | public static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | public static byte[] _4095_bits_ppk { 64 | get { 65 | object obj = ResourceManager.GetObject("_4095_bits_ppk", resourceCulture); 66 | return ((byte[])(obj)); 67 | } 68 | } 69 | 70 | public static byte[] dsa_ppk { 71 | get { 72 | object obj = ResourceManager.GetObject("dsa_ppk", resourceCulture); 73 | return ((byte[])(obj)); 74 | } 75 | } 76 | 77 | public static byte[] non_ascii_passphrase_ppk { 78 | get { 79 | object obj = ResourceManager.GetObject("non_ascii_passphrase_ppk", resourceCulture); 80 | return ((byte[])(obj)); 81 | } 82 | } 83 | 84 | public static byte[] withoutPassphrase_ppk { 85 | get { 86 | object obj = ResourceManager.GetObject("withoutPassphrase_ppk", resourceCulture); 87 | return ((byte[])(obj)); 88 | } 89 | } 90 | 91 | public static byte[] withPassphrase_ppk { 92 | get { 93 | object obj = ResourceManager.GetObject("withPassphrase_ppk", resourceCulture); 94 | return ((byte[])(obj)); 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /doc/troubleshooting.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Troubleshooting 3 | =============== 4 | 5 | Here are some suggestions for troubleshooting KeeAgent. 6 | 7 | 8 | Common issues 9 | ============= 10 | 11 | **Problem:** 12 | 13 | After upgrading my OS, my 1024-bit RSA key no longer works with KeeAgent in 14 | Client mode. 15 | 16 | **Solution:** 17 | 18 | OpenSSH dropped support for RSA keys <= 1024-bit in v7.6 because they are 19 | no longer considered secure. This version of OpenSSH ships with Ubuntu 18.04 20 | and macOS High Sierra. Create a new, larger key. 21 | 22 | **Problem:** 23 | 24 | Connecting to a server fails when too many keys are loaded in KeeAgent. For 25 | example, you might get an error message like this:: 26 | 27 | Server sent disconnect message type 2 (protocol error): "Too many authentication failures for user" 28 | 29 | Many servers will only try the first 6 keys before returning an error. This 30 | number will vary from server to server though. 31 | 32 | **Solution:** 33 | 34 | To work around this, limit the number of keys that load automatically, use 35 | the *Show selection dialog when a client program requests a list of keys* 36 | option or consider having the keys saved to a temporary file as described 37 | in :doc:`usage/tips-and-tricks`. 38 | 39 | **Problem:** 40 | 41 | When I start KeePass, I get an error message like this:: 42 | 43 | The following plugin is incompatible with the current KeePass version: 44 | Have a look at the plugin's website for an appropriate version. 45 | 46 | **Solution:** 47 | 48 | Run KeePass.exe from a command prompt with the ``--debug`` option (and ``--saveplgxcr`` 49 | for KeePass versions older than 2.31). This should give more detailed information 50 | on the cause of the error. Report the error using the link for other issues below. 51 | 52 | **Problem:** 53 | 54 | Keys will not load with the confirm constraint. 55 | 56 | **Solution:** 57 | 58 | On Windows, if you are using Pageant and running KeeAgent in client mode, then 59 | constraints will not work. Pageant does not support constraints. 60 | 61 | On Linux, if you are using a GNOME based desktop (includes Cinnamon, MATE, Unity, 62 | others), follow the instructions for disabling the SSH agent in GNOME keyring. 63 | 64 | **Problem:** 65 | 66 | "The plugin cannot be loaded A newer .NET framework is required." error on Linux 67 | and KeePass version is less than 2.52. 68 | 69 | **Solution:** 70 | 71 | Use workaround described in `issue #343 `_. 72 | 73 | 74 | Other issues 75 | ============ 76 | 77 | Read everything here and still having problems? 78 | 79 | Report your issues on `GitHub`_. 80 | 81 | .. _`GitHub`: https://github.com/dlech/keeagent/issues 82 | 83 | 84 | Debugging 85 | ========= 86 | 87 | You can use Visual Studio to see a limited amount of debug information. 88 | 89 | Prerequisite: `Visual Studio 2022 `_ 90 | with the *.NET desktop development* workload installed. 91 | 92 | .. figure:: images/vs-dotnet-desktop-development.png 93 | :alt: screenshot of Visual Studio Installer with .NET desktop development workload selected 94 | 95 | 1. Start *KeePass*. 96 | 97 | 2. Start *Visual Studio*. 98 | 99 | 3. Select *Continue without code*. 100 | 101 | .. figure:: images/vs-continue-without-code.png 102 | :alt: screenshot of Visual Studio 2022 start screen "Continue without code" hyperlink 103 | 104 | 4. Click the *Attach* button. 105 | 106 | .. figure:: images/vs-attach.png 107 | :alt: screenshot of Visual Studio 2022 start screen "Attach" button 108 | 109 | 5. Select *KeePass* from the list of processes. Use the filter to find it quickly. 110 | 111 | .. figure:: images/vs-attach-to-process-keepass.png 112 | :alt: screenshot of Visual Studio 2022 "Attach to Process" dialog with "KeePass.exe" selected. 113 | 114 | 6. Click the *Attach* button. 115 | 116 | 7. Select the *Output* tab. 117 | 118 | .. figure:: images/vs-output-tab.png 119 | :alt: screenshot of Visual Studio 2022 "Output" tab 120 | 121 | 8. Reproduce the issue in KeePass/KeeAgent. 122 | 123 | 9. Look for any useful information in the *Output* tab. 124 | -------------------------------------------------------------------------------- /KeeAgent/UI/ManageDialog.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeeAgent.UI 2 | { 3 | partial class ManageDialog 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) { 17 | components.Dispose(); 18 | } 19 | base.Dispose(disposing); 20 | } 21 | 22 | #region Windows Form Designer generated code 23 | 24 | /// 25 | /// Required method for Designer support - do not modify 26 | /// the contents of this method with the code editor. 27 | /// 28 | private void InitializeComponent() 29 | { 30 | this.components = new System.ComponentModel.Container(); 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ManageDialog)); 32 | this.dataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); 33 | this.addButtonMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); 34 | this.addButtonFromKeePassMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 35 | this.addButtonFromFileMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 36 | this.keyInfoView = new dlech.SshAgentLib.WinForms.KeyInfoView(); 37 | this.addButtonMenuStrip.SuspendLayout(); 38 | this.SuspendLayout(); 39 | // 40 | // dataGridViewTextBoxColumn1 41 | // 42 | this.dataGridViewTextBoxColumn1.DataPropertyName = "Value"; 43 | resources.ApplyResources(this.dataGridViewTextBoxColumn1, "dataGridViewTextBoxColumn1"); 44 | this.dataGridViewTextBoxColumn1.Name = "dataGridViewTextBoxColumn1"; 45 | this.dataGridViewTextBoxColumn1.ReadOnly = true; 46 | // 47 | // addButtonMenuStrip 48 | // 49 | this.addButtonMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 50 | this.addButtonFromKeePassMenuItem, 51 | this.addButtonFromFileMenuItem}); 52 | this.addButtonMenuStrip.Name = "addButtonMenuStrip"; 53 | this.addButtonMenuStrip.ShowImageMargin = false; 54 | resources.ApplyResources(this.addButtonMenuStrip, "addButtonMenuStrip"); 55 | // 56 | // addButtonFromKeePassMenuItem 57 | // 58 | this.addButtonFromKeePassMenuItem.Name = "addButtonFromKeePassMenuItem"; 59 | resources.ApplyResources(this.addButtonFromKeePassMenuItem, "addButtonFromKeePassMenuItem"); 60 | this.addButtonFromKeePassMenuItem.Click += new System.EventHandler(this.addButtonFromKeePassMenuItem_Click); 61 | // 62 | // addButtonFromFileMenuItem 63 | // 64 | this.addButtonFromFileMenuItem.Name = "addButtonFromFileMenuItem"; 65 | resources.ApplyResources(this.addButtonFromFileMenuItem, "addButtonFromFileMenuItem"); 66 | this.addButtonFromFileMenuItem.Click += new System.EventHandler(this.addButtonFromFileMenuItem_Click); 67 | // 68 | // keyInfoView 69 | // 70 | this.keyInfoView.AddButtonSplitMenu = this.addButtonMenuStrip; 71 | resources.ApplyResources(this.keyInfoView, "keyInfoView"); 72 | this.keyInfoView.Name = "keyInfoView"; 73 | this.keyInfoView.AddFromFileHelpRequested += new System.EventHandler(this.keyInfoView_AddFromFileHelpRequested); 74 | // 75 | // ManageDialog 76 | // 77 | resources.ApplyResources(this, "$this"); 78 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 79 | this.Controls.Add(this.keyInfoView); 80 | this.HelpButton = true; 81 | this.KeyPreview = true; 82 | this.MaximizeBox = false; 83 | this.MinimizeBox = false; 84 | this.Name = "ManageDialog"; 85 | this.ShowInTaskbar = false; 86 | this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.ManageDialog_HelpButtonClicked); 87 | this.HelpRequested += new System.Windows.Forms.HelpEventHandler(this.ManageDialog_HelpRequested); 88 | this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ManageDialog_KeyDown); 89 | this.addButtonMenuStrip.ResumeLayout(false); 90 | this.ResumeLayout(false); 91 | 92 | } 93 | 94 | #endregion 95 | 96 | private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn1; 97 | private dlech.SshAgentLib.WinForms.KeyInfoView keyInfoView; 98 | private System.Windows.Forms.ContextMenuStrip addButtonMenuStrip; 99 | private System.Windows.Forms.ToolStripMenuItem addButtonFromKeePassMenuItem; 100 | private System.Windows.Forms.ToolStripMenuItem addButtonFromFileMenuItem; 101 | } 102 | } -------------------------------------------------------------------------------- /doc/usage/tips-and-tricks.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Tips and Tricks 3 | =============== 4 | 5 | Creating URL Overrides to Open a Connection 6 | =========================================== 7 | 8 | Having lots of SSH keys loaded in KeeAgent can be a problem for many servers. 9 | To work around this, many ssh programs allow you to specify an identity file when 10 | connecting so that it knows which key to use instead of having to try all the 11 | keys that are loaded. 12 | 13 | Since SSH keys in KeeAgent are usually saved as attachments embedded in the 14 | database, there is an option in the *Entry Settings* to save the key to an actual 15 | file on disk when the key is loaded in KeeAgent. 16 | 17 | .. figure:: images/win10-keepass-entry-keeagent-tab-private-key-file-location.png 18 | :alt: Screenshot of Private Key File Location with "Save attachments to 19 | temporary file when key is loaded" checked 20 | 21 | Once you have selected this option, there will be two placeholders available for 22 | use in KeePass. 23 | 24 | - ``{KEEAGENT:KEYFILEPATH}`` returns the full path. e.g. ``C:\path\to\keyfile.ppk`` 25 | - ``{KEEAGENT:IDENTFILEOPT}`` returns the identity file command line option 26 | that is used by both PuTTY.exe and ssh. e.g. ``-i "C:\path\to\keyfile.ppk"`` 27 | 28 | You can use these placeholders to create URL overrides. Global overrides are at 29 | *Tools > Options > Integration (tab) > URL Scheme Overrides...* or they can be 30 | specified per-entry on the *Properties* tab of *Entry Settings*. 31 | 32 | .. note:: The placeholders also work with the *External File* location in 33 | addition to attachments. 34 | 35 | Example: 36 | 37 | Open an ssh connection using PuTTY with the username and host specified in 38 | the database entry. The entry must have the Username and URL fields filled 39 | out for this to work. 40 | :: 41 | 42 | cmd://"C:\Program Files (x86)\PuTTY\PuTTY.exe" -ssh {USERNAME}@{URL:RMVSCM} {KEEAGENT:IDENTFILEOPT} 43 | 44 | .. tip:: Read more about the PuTTY command line `here`__. For example, the 45 | ``-load`` option is useful to load a saved session associated with the key. 46 | 47 | .. __: http://the.earth.li/~sgtatham/putty/latest/htmldoc/Chapter3.html#using-cmdline 48 | 49 | 50 | Using KeeAgent on Windows 51 | ========================= 52 | 53 | 54 | Client mode with Pageant 55 | ------------------------ 56 | 57 | KeeAgent (in Agent Mode) is designed to work much like ``ssh-agent`` on Linux/BSD/etc... 58 | Pageant is very similar, but there are some notable differences. Because of the 59 | more limited features of Pageant, it is recommended to run in Agent mode on 60 | Windows instead of using Pageant. However, if you have a good reason to run 61 | KeeAgent in Client Mode along with Pageant, here are some things to be aware of: 62 | 63 | - Pageant does not support locking. 64 | - Pageant does not support constraints. 65 | - Pageant does not support ECDSA or Ed25519 keys (except in the development version). 66 | 67 | 68 | Cygwin and MSYS 69 | --------------- 70 | 71 | KeeAgent can natively communicate with ssh programs running in Cygwin and 72 | MSYS. It is enabled in the :ref:`global-options` dialog. 73 | 74 | There are two implementations of sockets that are found in the various versions 75 | of Cygwin and MSYS. MSYS is really just a fork of Cygwin, so it depends on which 76 | fork the code is based on. So, unless you are using msysGit, try the "Cygwin 77 | socket file" first and if that does not work, try the "msysGit socket file". 78 | In some cases, you may need both enabled to support multiple versions of 79 | Cygwin/MSYS. 80 | 81 | 82 | Windows OpenSSH 83 | --------------- 84 | 85 | Although recent versions of Windows ship with OpenSSH out of the box, the 86 | included version is quite out of date. Consider installing the latest version 87 | with ``winget`` or ``choco`` instead or get them straight from the source from the 88 | `GitHub releases `_ page. 89 | 90 | These tools are compatible with KeeAgent when **Enable agent for Windows OpenSSH** 91 | is selected in the :ref:`global-options`. 92 | 93 | 94 | Windows Subsystem for Linux (WSL) 95 | --------------------------------- 96 | 97 | KeeAgent can be used with `WSL `_. 98 | 99 | For WSL1, simply select **Create WSL1 compatible socket file** in the 100 | :ref:`global-options` and set the ``SSH_AUTH_SOCK`` environment variable 101 | in your WSL1 shell to match. 102 | 103 | For WSL2, the environment is more isolated from Windows, so it is not possible 104 | to use the WSL1 socket. Instead, you can use the Windows OpenSSH programs 105 | from inside a WSL2 shell by running ``ssh.exe`` instead of ``ssh``. 106 | 107 | .. tip:: You can make a bash alias or symlink to make ``ssh`` an alias for 108 | ``ssh.exe``. For example:: 109 | 110 | sudo ln -s $(which ssh.exe) /usr/local/bin/ 111 | 112 | Alternately, there are a number of 3rd party solutions for providing a socket 113 | bridge to connect programs inside of WSL2 to an external SSH agent. 114 | -------------------------------------------------------------------------------- /KeeAgent/UI/ManageKeyFileDialog.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KeeAgent.UI 2 | { 3 | partial class ManageKeyFileDialog 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) { 17 | components.Dispose(); 18 | } 19 | base.Dispose(disposing); 20 | } 21 | 22 | #region Windows Form Designer generated code 23 | 24 | /// 25 | /// Required method for Designer support - do not modify 26 | /// the contents of this method with the code editor. 27 | /// 28 | private void InitializeComponent() 29 | { 30 | this.cancelButton = new System.Windows.Forms.Button(); 31 | this.okButton = new System.Windows.Forms.Button(); 32 | this.privateKeyLocationPanel = new KeeAgent.UI.KeyLocationPanel(); 33 | this.SuspendLayout(); 34 | // 35 | // cancelButton 36 | // 37 | this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 38 | this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; 39 | this.cancelButton.Location = new System.Drawing.Point(456, 143); 40 | this.cancelButton.Margin = new System.Windows.Forms.Padding(2); 41 | this.cancelButton.Name = "cancelButton"; 42 | this.cancelButton.Size = new System.Drawing.Size(75, 23); 43 | this.cancelButton.TabIndex = 2; 44 | this.cancelButton.Text = "&Cancel"; 45 | this.cancelButton.UseVisualStyleBackColor = true; 46 | // 47 | // okButton 48 | // 49 | this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 50 | this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK; 51 | this.okButton.Location = new System.Drawing.Point(377, 143); 52 | this.okButton.Margin = new System.Windows.Forms.Padding(2); 53 | this.okButton.Name = "okButton"; 54 | this.okButton.Size = new System.Drawing.Size(75, 23); 55 | this.okButton.TabIndex = 3; 56 | this.okButton.Text = "&OK"; 57 | this.okButton.UseVisualStyleBackColor = true; 58 | // 59 | // privateKeyLocationPanel 60 | // 61 | this.privateKeyLocationPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 62 | | System.Windows.Forms.AnchorStyles.Right))); 63 | this.privateKeyLocationPanel.Attachments = null; 64 | this.privateKeyLocationPanel.BackColor = System.Drawing.Color.Transparent; 65 | this.privateKeyLocationPanel.ErrorMessage = ""; 66 | this.privateKeyLocationPanel.KeyLocation = null; 67 | this.privateKeyLocationPanel.Location = new System.Drawing.Point(15, 15); 68 | this.privateKeyLocationPanel.Margin = new System.Windows.Forms.Padding(6); 69 | this.privateKeyLocationPanel.Name = "privateKeyLocationPanel"; 70 | this.privateKeyLocationPanel.Size = new System.Drawing.Size(512, 118); 71 | this.privateKeyLocationPanel.TabIndex = 0; 72 | this.privateKeyLocationPanel.Title = "Private Key File Location"; 73 | // 74 | // ManageKeyFilesDialog 75 | // 76 | this.AcceptButton = this.okButton; 77 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 78 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 79 | this.CancelButton = this.cancelButton; 80 | this.ClientSize = new System.Drawing.Size(542, 177); 81 | this.Controls.Add(this.okButton); 82 | this.Controls.Add(this.cancelButton); 83 | this.Controls.Add(this.privateKeyLocationPanel); 84 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 85 | this.Margin = new System.Windows.Forms.Padding(2); 86 | this.MaximizeBox = false; 87 | this.MinimizeBox = false; 88 | this.Name = "ManageKeyFilesDialog"; 89 | this.ShowInTaskbar = false; 90 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; 91 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 92 | this.Text = "Manage Private Key File"; 93 | this.ResumeLayout(false); 94 | 95 | } 96 | 97 | #endregion 98 | 99 | private KeyLocationPanel privateKeyLocationPanel; 100 | private System.Windows.Forms.Button cancelButton; 101 | private System.Windows.Forms.Button okButton; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /KeeAgent/KeeAgentColumnProvider.cs: -------------------------------------------------------------------------------- 1 | // 2 | // KeyStatusColumnProvider.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2012-2014 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System; 23 | using System.Diagnostics; 24 | using System.Linq; 25 | using System.Windows.Forms; 26 | 27 | using dlech.SshAgentLib; 28 | using KeePass.UI; 29 | using SshAgentLib.Keys; 30 | 31 | namespace KeeAgent 32 | { 33 | class KeeAgentColumnProvider : ColumnProvider, IDisposable 34 | { 35 | const string sshKeyStatusColumnName = "SSH Key Status"; 36 | readonly string[] columnNames = { 37 | sshKeyStatusColumnName 38 | }; 39 | 40 | KeeAgentExt ext; 41 | 42 | public override string[] ColumnNames { 43 | get { return columnNames.ToArray(); } 44 | } 45 | 46 | public KeeAgentColumnProvider(KeeAgentExt ext) 47 | { 48 | if (ext == null) 49 | throw new ArgumentNullException("ext"); 50 | this.ext = ext; 51 | ext.agent.KeyAdded += Agent_KeyAddedOrRemoved; 52 | ext.agent.KeyRemoved += Agent_KeyAddedOrRemoved; 53 | var agentModeAgent = ext.agent as Agent; 54 | if (agentModeAgent != null) { 55 | agentModeAgent.Locked += Agent_Locked; 56 | } 57 | } 58 | 59 | ~KeeAgentColumnProvider() 60 | { 61 | Dispose(false); 62 | } 63 | 64 | public override string GetCellData(string columnName, KeePassLib.PwEntry entry) 65 | { 66 | switch (columnName) { 67 | case sshKeyStatusColumnName: 68 | var agentModeAgent = ext.agent as Agent; 69 | if (agentModeAgent != null && agentModeAgent.IsLocked) { 70 | return "Agent Locked"; 71 | } 72 | try { 73 | var key = entry.TryGetSshPublicKey(); 74 | 75 | if (key == null) { 76 | return "Missing .pub file"; 77 | } 78 | 79 | if (ext.agent.Contains(key)) { 80 | return "Loaded"; 81 | } 82 | } 83 | catch (FormatException) { 84 | return "Error"; 85 | } 86 | catch (InvalidOperationException) { 87 | return ""; 88 | } 89 | catch (Exception ex) { 90 | Debug.Fail(ex.Message); 91 | return "*Error"; 92 | } 93 | return "Not Loaded"; 94 | } 95 | Debug.Fail(string.Format("Unknown column name: {0}", columnName)); 96 | return string.Empty; 97 | } 98 | 99 | public override bool SupportsCellAction(string columnName) 100 | { 101 | switch (columnName) { 102 | case sshKeyStatusColumnName: 103 | return true; 104 | default: 105 | return false; 106 | } 107 | } 108 | 109 | public override void PerformCellAction(string columnName, KeePassLib.PwEntry entry) 110 | { 111 | switch (columnName) { 112 | case sshKeyStatusColumnName: 113 | try { 114 | var key = entry.TryGetSshPublicKey(); 115 | 116 | var agentKey = ext.agent.ListKeys().SingleOrDefault(k => key.Matches(k.GetPublicKeyBlob())); 117 | 118 | if (agentKey == null) { 119 | ext.AddEntry(entry, null); 120 | } 121 | else { 122 | ext.RemoveKey(agentKey); 123 | } 124 | } 125 | catch (Exception ex) { 126 | Debug.Fail(ex.Message); 127 | } 128 | break; 129 | default: 130 | Debug.Fail(string.Format("Unsupported column: {0}", columnName)); 131 | break; 132 | } 133 | } 134 | 135 | internal void Agent_KeyAddedOrRemoved(object sender, SshKeyEventArgs e) 136 | { 137 | UpdateUI(); 138 | } 139 | 140 | private void Agent_Locked(object sender, Agent.LockEventArgs e) 141 | { 142 | UpdateUI(); 143 | } 144 | 145 | void UpdateUI() 146 | { 147 | ext.pluginHost.MainWindow.Invoke((MethodInvoker)delegate () { 148 | // only update the entry list 149 | ext.pluginHost.MainWindow.UpdateUI(false, null, false, null, true, null, false); 150 | }); 151 | } 152 | 153 | private void Dispose(bool disposing) 154 | { 155 | if (disposing) { 156 | ext.agent.KeyAdded -= Agent_KeyAddedOrRemoved; 157 | ext.agent.KeyRemoved -= Agent_KeyAddedOrRemoved; 158 | var agentModeAgent = ext.agent as Agent; 159 | if (agentModeAgent != null) { 160 | agentModeAgent.Locked -= Agent_Locked; 161 | } 162 | } 163 | } 164 | 165 | public void Dispose() 166 | { 167 | GC.SuppressFinalize(this); 168 | Dispose(true); 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /KeeAgentTestProject/OptionsTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // OptionsTest.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2012-2013 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System; 23 | using System.IO; 24 | using System.Reflection; 25 | using System.Windows.Forms; 26 | using KeeAgent; 27 | using KeePass.Plugins; 28 | using KeePassPluginDevTools.Control; 29 | using NUnit.Framework; 30 | 31 | namespace KeeAgentTestProject 32 | { 33 | [TestFixture] 34 | public class OptionsTest 35 | { 36 | [TestFixtureTearDown()] 37 | public static void MyClassCleanup() 38 | { 39 | KeePassControl.ExitAll(); 40 | } 41 | 42 | /// 43 | /// Tests if options are saved when KeePass is closed and reopened 44 | /// 45 | [Test] 46 | public void TestOptionsPersistance() 47 | { 48 | // used for passing Options objects to/from AppDomain 49 | const string optionsPropertyName = "KEEAGENT_OPTIONS"; 50 | 51 | /* test case options */ 52 | 53 | bool requestedLoggingEnabled = true; 54 | string requestedLogFileName = 55 | Environment.GetEnvironmentVariable("TEMP"); 56 | if (string.IsNullOrEmpty(requestedLogFileName)) { 57 | requestedLogFileName = 58 | Environment.GetEnvironmentVariable("TMP"); 59 | } 60 | if (string.IsNullOrEmpty(requestedLogFileName)) { 61 | requestedLogFileName = "/tmp"; 62 | } 63 | Assert.That (Directory.Exists (requestedLogFileName)); 64 | 65 | // verify that requested options are not default to ensure a 66 | // valid test 67 | Options requestedOptions = new Options(); 68 | Assert.AreNotEqual(requestedOptions.LoggingEnabled, 69 | requestedLoggingEnabled); 70 | Assert.AreNotEqual(requestedOptions.LogFileName, 71 | requestedLogFileName); 72 | 73 | requestedOptions.LoggingEnabled = requestedLoggingEnabled; 74 | requestedOptions.LogFileName = requestedLogFileName; 75 | 76 | 77 | /* first instance of KeePass is used to set options to 78 | * requested values */ 79 | 80 | using (KeePassAppDomain testDomain1 = new KeePassAppDomain()) { 81 | testDomain1.StartKeePass(true, false, 1, true); 82 | testDomain1.SetData(optionsPropertyName, requestedOptions); 83 | testDomain1.DoCallBack(delegate() 84 | { 85 | KeePass.Program.MainForm.Invoke((MethodInvoker)delegate() 86 | { 87 | KeeAgentExt td1KeeAgentExt = new KeeAgentExt(); 88 | IPluginHost td1PluginHost = 89 | KeePass.Program.MainForm.PluginHost; 90 | Options td1RequestedOptions = (Options)AppDomain 91 | .CurrentDomain.GetData(optionsPropertyName); 92 | td1KeeAgentExt.Initialize(td1PluginHost); 93 | td1KeeAgentExt.Options.Notification = 94 | td1RequestedOptions.Notification; 95 | td1KeeAgentExt.Options.LoggingEnabled = 96 | td1RequestedOptions.LoggingEnabled; 97 | td1KeeAgentExt.Options.LogFileName = 98 | td1RequestedOptions.LogFileName; 99 | var extType = td1KeeAgentExt.GetType (); 100 | var saveGlobalOptionsMethod = 101 | extType.GetMethod ("SaveGlobalOptions", 102 | BindingFlags.Instance | BindingFlags.NonPublic); 103 | saveGlobalOptionsMethod.Invoke (td1KeeAgentExt, null); 104 | td1PluginHost.MainWindow.SaveConfig(); 105 | AppDomain.CurrentDomain.SetData(optionsPropertyName, 106 | td1KeeAgentExt.Options); 107 | }); 108 | }); 109 | } 110 | 111 | /* second instance of KeePass reads options to verify that they 112 | * were saved in the .config file */ 113 | 114 | using (KeePassAppDomain testDomain2 = new KeePassAppDomain()) { 115 | testDomain2.StartKeePass(true, false, 1, false); 116 | testDomain2.DoCallBack(delegate() 117 | { 118 | KeePass.Program.MainForm.Invoke((MethodInvoker)delegate() 119 | { 120 | KeeAgentExt td2KeeAgentExt = new KeeAgentExt(); 121 | IPluginHost td2PluginHost = 122 | KeePass.Program.MainForm.PluginHost; 123 | td2KeeAgentExt.Initialize(td2PluginHost); 124 | AppDomain.CurrentDomain.SetData(optionsPropertyName, 125 | td2KeeAgentExt.Options); 126 | }); 127 | }); 128 | Options actual = (Options)testDomain2.GetData(optionsPropertyName); 129 | Assert.AreEqual(requestedLoggingEnabled, actual.LoggingEnabled); 130 | Assert.AreEqual(requestedLogFileName, actual.LogFileName); 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /KeeAgent/UI/ManageDialog.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ManageDialog.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2012-2014 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System; 23 | using System.ComponentModel; 24 | using System.Diagnostics; 25 | using System.Drawing; 26 | using System.Windows.Forms; 27 | using dlech.SshAgentLib; 28 | using KeePassLib.Utility; 29 | 30 | namespace KeeAgent.UI 31 | { 32 | public partial class ManageDialog : Form 33 | { 34 | private KeeAgentExt mExt; 35 | 36 | public ManageDialog(KeeAgentExt aExt) 37 | { 38 | InitializeComponent(); 39 | 40 | if (Type.GetType("Mono.Runtime") == null) { 41 | Icon = Properties.Resources.KeeAgent_icon; 42 | } 43 | else { 44 | Icon = Properties.Resources.KeeAgent_icon_mono; 45 | 46 | // on windows, help button is displayed in the title bar 47 | // on mono, we need to add one in the window 48 | var helpButton = new Button(); 49 | helpButton.Size = new Size(25, 25); 50 | helpButton.Image = Properties.Resources.Help_png; 51 | helpButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; 52 | helpButton.Location = new Point(10, Height - 10); 53 | helpButton.Click += (sender, e) => OnHelpRequested(); 54 | var foundControls = 55 | keyInfoView.Controls.Find("buttonTableLayoutPanel", true); 56 | if (foundControls.Length > 0) { 57 | var buttonTableLayout = foundControls[0]; 58 | var buttonTableLayoutParent = buttonTableLayout.Parent; 59 | buttonTableLayoutParent.Controls.Remove(buttonTableLayout); 60 | var buttonTableLayoutWrapper = new TableLayoutPanel(); 61 | buttonTableLayoutWrapper.RowCount = 1; 62 | buttonTableLayoutWrapper.ColumnCount = 2; 63 | buttonTableLayoutWrapper.Anchor = 64 | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom; 65 | buttonTableLayoutWrapper.Width = keyInfoView.dataGridView.Width; 66 | buttonTableLayoutWrapper.Height = helpButton.Height + 8; 67 | buttonTableLayoutWrapper.Controls.Add(helpButton); 68 | buttonTableLayoutWrapper.Controls.Add(buttonTableLayout); 69 | buttonTableLayoutParent.Controls.Add(buttonTableLayoutWrapper); 70 | } 71 | } 72 | 73 | // update title depending on Agent Mode 74 | mExt = aExt; 75 | if (mExt.agent is Agent) { 76 | Text += Translatable.TitleSuffixAgentMode; 77 | } 78 | else { 79 | Text += Translatable.TitleSuffixClientMode; 80 | } 81 | keyInfoView.SetAgent(mExt.agent); 82 | } 83 | 84 | protected override void OnShown(EventArgs e) 85 | { 86 | base.OnShown(e); 87 | keyInfoView.dataGridView.ClearSelection(); 88 | } 89 | 90 | private void addButtonFromFileMenuItem_Click(object sender, EventArgs e) 91 | { 92 | keyInfoView.ShowFileOpenDialog(); 93 | } 94 | 95 | private void addButtonFromKeePassMenuItem_Click(object sender, EventArgs e) 96 | { 97 | var openDatabaseCount = 98 | mExt.pluginHost.MainWindow.DocumentManager.GetOpenDatabases().Count; 99 | if (openDatabaseCount == 0) { 100 | MessageService.ShowWarning("No open databases found.", 101 | "Please open or unlock a database and then try again."); 102 | return; 103 | } 104 | 105 | var showConstraintControls = !(mExt.agent is PageantClient); 106 | var entryPicker = 107 | new EntryPickerDialog(mExt, showConstraintControls); 108 | var result = entryPicker.ShowDialog(ParentForm); 109 | if (result == DialogResult.OK) { 110 | try { 111 | mExt.AddEntry(entryPicker.SelectedEntry, entryPicker.Constraints); 112 | } 113 | catch (Exception) { 114 | // error message already shown 115 | } 116 | } 117 | if (mExt.agent is AgentClient) { 118 | keyInfoView.ReloadKeyListView(); 119 | } 120 | } 121 | 122 | private void keyInfoView_AddFromFileHelpRequested(object sender, EventArgs e) 123 | { 124 | Process.Start(Properties.Resources.WebHelpAddFromFile); 125 | } 126 | 127 | private void ManageDialog_HelpRequested(object sender, HelpEventArgs hlpevent) 128 | { 129 | OnHelpRequested(); 130 | } 131 | 132 | private void ManageDialog_HelpButtonClicked(object sender, CancelEventArgs e) 133 | { 134 | OnHelpRequested(); 135 | e.Cancel = true; 136 | } 137 | 138 | private void OnHelpRequested() 139 | { 140 | Process.Start(Properties.Resources.WebHelpKeeAgentManager); 141 | } 142 | 143 | private void ManageDialog_KeyDown(object sender, KeyEventArgs e) 144 | { 145 | if (e.KeyCode == Keys.Escape) { 146 | e.Handled = true; 147 | Close(); 148 | } 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /KeeAgent/UI/EntryPickerDialog.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /KeeAgent/UI/ManageKeyFileDialog.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # To learn more about .editorconfig see https://aka.ms/editorconfigdocs 2 | ############################### 3 | # Core EditorConfig Options # 4 | ############################### 5 | 6 | root = true 7 | 8 | # All files 9 | [*] 10 | indent_style = space 11 | 12 | # Code files 13 | [*.{cs,csx,vb,vbx}] 14 | indent_size = 2 15 | insert_final_newline = true 16 | trim_trailing_whitespace = true 17 | charset = utf-8-bom 18 | 19 | ############################### 20 | # .NET Coding Conventions # 21 | ############################### 22 | 23 | [*.{cs,vb}] 24 | # Organize usings 25 | dotnet_sort_system_directives_first = true 26 | dotnet_separate_import_directive_groups = false 27 | 28 | # this. preferences 29 | dotnet_style_qualification_for_field = false:silent 30 | dotnet_style_qualification_for_property = false:silent 31 | dotnet_style_qualification_for_method = false:silent 32 | dotnet_style_qualification_for_event = false:silent 33 | 34 | # Language keywords vs BCL types preferences 35 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 36 | dotnet_style_predefined_type_for_member_access = true:silent 37 | 38 | # Parentheses preferences 39 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 40 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 41 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 42 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 43 | 44 | # Modifier preferences 45 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 46 | dotnet_style_readonly_field = true:suggestion 47 | 48 | # Expression-level preferences 49 | dotnet_style_object_initializer = true:suggestion 50 | dotnet_style_collection_initializer = true:suggestion 51 | dotnet_style_explicit_tuple_names = true:suggestion 52 | dotnet_style_null_propagation = true:suggestion 53 | dotnet_style_coalesce_expression = true:suggestion 54 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent 55 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 56 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 57 | dotnet_style_prefer_auto_properties = true:silent 58 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 59 | dotnet_style_prefer_conditional_expression_over_return = true:silent 60 | 61 | ############################### 62 | # Naming Conventions # 63 | ############################### 64 | 65 | # Style Definitions 66 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 67 | 68 | # Use PascalCase for constant fields 69 | dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion 70 | dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields 71 | dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style 72 | dotnet_naming_symbols.constant_fields.applicable_kinds = field 73 | dotnet_naming_symbols.constant_fields.applicable_accessibilities = * 74 | dotnet_naming_symbols.constant_fields.required_modifiers = const 75 | 76 | ############################### 77 | # C# Code Style Rules # 78 | ############################### 79 | 80 | [*.cs] 81 | # var preferences 82 | csharp_style_var_for_built_in_types = true:silent 83 | csharp_style_var_when_type_is_apparent = true:silent 84 | csharp_style_var_elsewhere = true:silent 85 | 86 | # Expression-bodied members 87 | csharp_style_expression_bodied_methods = false:silent 88 | csharp_style_expression_bodied_constructors = false:silent 89 | csharp_style_expression_bodied_operators = false:silent 90 | csharp_style_expression_bodied_properties = true:silent 91 | csharp_style_expression_bodied_indexers = true:silent 92 | csharp_style_expression_bodied_accessors = true:silent 93 | 94 | # Pattern-matching preferences 95 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 96 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 97 | 98 | # Null-checking preferences 99 | csharp_style_throw_expression = true:suggestion 100 | csharp_style_conditional_delegate_call = true:suggestion 101 | 102 | # Modifier preferences 103 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion 104 | 105 | # Expression-level preferences 106 | csharp_prefer_braces = true:silent 107 | csharp_style_deconstructed_variable_declaration = true:suggestion 108 | csharp_prefer_simple_default_expression = true:suggestion 109 | csharp_style_pattern_local_over_anonymous_function = true:suggestion 110 | csharp_style_inlined_variable_declaration = true:suggestion 111 | 112 | ############################### 113 | # C# Formatting Rules # 114 | ############################### 115 | 116 | # New line preferences 117 | csharp_new_line_before_open_brace = methods, types 118 | csharp_new_line_before_else = true 119 | csharp_new_line_before_catch = true 120 | csharp_new_line_before_finally = true 121 | csharp_new_line_before_members_in_object_initializers = true 122 | csharp_new_line_before_members_in_anonymous_types = true 123 | csharp_new_line_between_query_expression_clauses = true 124 | 125 | # Indentation preferences 126 | csharp_indent_case_contents = true 127 | csharp_indent_switch_labels = true 128 | csharp_indent_labels = flush_left 129 | 130 | # Space preferences 131 | csharp_space_after_cast = false 132 | csharp_space_after_keywords_in_control_flow_statements = true 133 | csharp_space_between_method_call_parameter_list_parentheses = false 134 | csharp_space_between_method_declaration_parameter_list_parentheses = false 135 | csharp_space_between_parentheses = false 136 | csharp_space_before_colon_in_inheritance_clause = true 137 | csharp_space_after_colon_in_inheritance_clause = true 138 | csharp_space_around_binary_operators = before_and_after 139 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 140 | csharp_space_between_method_call_name_and_opening_parenthesis = false 141 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 142 | csharp_space_after_comma = true 143 | csharp_space_after_dot = false 144 | 145 | # Wrapping preferences 146 | csharp_preserve_single_line_statements = true 147 | csharp_preserve_single_line_blocks = true 148 | -------------------------------------------------------------------------------- /KeeAgent/UI/DecryptProgressDialog.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | -------------------------------------------------------------------------------- /KeeAgent/UI/HostKeysDialog.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 335, 17 122 | 123 | 124 | 17, 17 125 | 126 | -------------------------------------------------------------------------------- /KeeAgentTestProject/IOProtocolExtTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // OptionsTest.cs 3 | // 4 | // Author(s): 5 | // David Lechner 6 | // 7 | // Copyright (C) 2012-2013 David Lechner 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, see 21 | 22 | using System; 23 | using System.Collections.Generic; 24 | using System.IO; 25 | using System.Reflection; 26 | using System.Security; 27 | using System.Threading; 28 | using System.Windows.Forms; 29 | using dlech.SshAgentLib; 30 | using IOProtocolExt; 31 | using KeeAgent; 32 | using KeePass.Plugins; 33 | using KeePassLib.Serialization; 34 | using KeePassPluginDevTools.Control; 35 | using NUnit.Framework; 36 | 37 | namespace KeeAgentTestProject 38 | { 39 | [TestFixture] 40 | public class IOProtocolExtTest 41 | { 42 | 43 | [TestFixtureSetUp()] 44 | public static void Setup() 45 | { 46 | // copy WinSCP to working directory 47 | 48 | string solutionDir = Path.GetFullPath( 49 | Path.Combine(Environment.CurrentDirectory, "..", "..", "..")); 50 | string winSCPSourceDir = Path.Combine(solutionDir, "lib", "IOProtocolExt", 51 | "WinSCP"); 52 | 53 | Assert.IsTrue(File.Exists(Path.Combine(winSCPSourceDir, "WinSCP.exe"))); 54 | Assert.IsTrue(File.Exists(Path.Combine(winSCPSourceDir, "WinSCP.com"))); 55 | 56 | Assembly assembly = Assembly.GetAssembly(typeof(KeePass.Program)); 57 | string keepassDir = Path.GetDirectoryName(assembly.Location); 58 | 59 | string winSCPDestDir = Path.Combine(keepassDir, "IOProtocolExt_WinSCP"); 60 | if (Directory.Exists(winSCPDestDir)) { 61 | Directory.Delete(winSCPDestDir, true); 62 | int count = 0; 63 | while (Directory.Exists(winSCPDestDir)) { 64 | // wait for directory to delete 65 | count++; 66 | Assert.IsTrue(count < 20, 67 | "Failed to delete IOProtocolExt_WinSCP folder."); 68 | Thread.Sleep(100); 69 | } 70 | } 71 | Directory.CreateDirectory(winSCPDestDir); 72 | foreach (string filePath in Directory.GetFiles(winSCPSourceDir)) { 73 | string fileName = Path.GetFileName(filePath); 74 | string sourceFile = Path.Combine(winSCPSourceDir, fileName); 75 | string destFile = Path.Combine(winSCPDestDir, fileName); 76 | File.Copy(sourceFile, destFile); 77 | } 78 | } 79 | 80 | [TestFixtureTearDown()] 81 | public static void TearDown() 82 | { 83 | KeePassControl.ExitAll(); 84 | } 85 | 86 | /// 87 | /// Tests interaction of KeeAgent with IOProtocolExt 88 | /// 89 | [Test] 90 | public void TestIOProtocolExt() 91 | { 92 | using (KeePassAppDomain testDomain1 = new KeePassAppDomain()) { 93 | testDomain1.StartKeePass(true, false, 1, true); 94 | testDomain1.DoCallBack(delegate() 95 | { 96 | KeePass.Program.MainForm.Invoke((MethodInvoker)delegate() 97 | { 98 | /* initialize plugins */ 99 | 100 | KeeAgentExt td1KeeAgentExt = new KeeAgentExt(); 101 | IOProtocolExtExt td1IOProtocolExt = new IOProtocolExtExt(); 102 | 103 | IPluginHost td1PluginHost = KeePass.Program.MainForm.PluginHost; 104 | td1KeeAgentExt.Initialize(td1PluginHost); 105 | td1IOProtocolExt.Initialize(td1PluginHost); 106 | KeePass.Program.MainForm.FormClosing += delegate( 107 | Object source, FormClosingEventArgs args) 108 | { 109 | td1KeeAgentExt.Terminate(); 110 | td1IOProtocolExt.Terminate(); 111 | }; 112 | 113 | var extType = td1KeeAgentExt.GetType (); 114 | var mAgentField = extType.GetField ("mAgent", 115 | BindingFlags.Instance | BindingFlags.NonPublic); 116 | var agent = mAgentField.GetValue (td1KeeAgentExt) as IAgent; 117 | 118 | // test not valid in client mode 119 | Assert.That(agent, Is.AssignableTo()); 120 | 121 | // override confirm callback so we don't have to click OK 122 | (agent as Agent).ConfirmUserPermissionCallback = 123 | delegate(ISshKey aKey) 124 | { 125 | return true; 126 | }; 127 | 128 | /* load ssh key */ 129 | var keyFileDir = Path.GetFullPath (Path.Combine ( 130 | "..", "..", "..", "SshAgentLib", "SshAgentLibTests", "Resources")); 131 | var keyFilePath = Path.Combine(keyFileDir, "rsa_with_passphrase"); 132 | Assert.That(File.Exists(keyFilePath), "Cannot locate key file: " + keyFilePath); 133 | 134 | KeyFormatter.GetPassphraseCallback getPassphraseCallback = 135 | delegate() 136 | { 137 | var passphrase = "passphrase"; 138 | var securePassphrase = new SecureString(); 139 | foreach (char c in passphrase) { 140 | securePassphrase.AppendChar(c); 141 | } 142 | return securePassphrase; 143 | }; 144 | var constraints = new List(); 145 | constraints.addConfirmConstraint(); 146 | agent.AddKeyFromFile(keyFilePath, getPassphraseCallback, constraints); 147 | 148 | /* run test */ 149 | IOConnectionInfo ioConnectionInfo = new IOConnectionInfo(); 150 | ioConnectionInfo.Path = "sftp://satest/test.kdbx"; 151 | ioConnectionInfo.UserName = "tc"; 152 | bool fileExists = IOConnection.FileExists(ioConnectionInfo); 153 | Assert.IsTrue(fileExists, "Is satest VM running?"); 154 | 155 | /* the problem we are checking for is that IOConnection.FileExists 156 | * does not lock up. Originally, in KeeAgent, WinPageant ran on main 157 | * thread and caused lock-up here. So, we are looking to see if the 158 | * test times out or not. */ 159 | }); 160 | }); 161 | } 162 | } 163 | 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /KeeAgent/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace KeeAgent.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("KeeAgent.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap Help_png { 67 | get { 68 | object obj = ResourceManager.GetObject("Help_png", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). 75 | /// 76 | internal static System.Drawing.Icon KeeAgent_icon { 77 | get { 78 | object obj = ResourceManager.GetObject("KeeAgent_icon", resourceCulture); 79 | return ((System.Drawing.Icon)(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). 85 | /// 86 | internal static System.Drawing.Icon KeeAgent_icon_mono { 87 | get { 88 | object obj = ResourceManager.GetObject("KeeAgent_icon_mono", resourceCulture); 89 | return ((System.Drawing.Icon)(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// Looks up a localized resource of type System.Drawing.Bitmap. 95 | /// 96 | internal static System.Drawing.Bitmap KeeAgentIcon_png { 97 | get { 98 | object obj = ResourceManager.GetObject("KeeAgentIcon_png", resourceCulture); 99 | return ((System.Drawing.Bitmap)(obj)); 100 | } 101 | } 102 | 103 | /// 104 | /// Looks up a localized string similar to https://keeagent.readthedocs.io/en/v0.12.1/usage/keeagent-manager.html. 105 | /// 106 | internal static string WebHelpAddFromFile { 107 | get { 108 | return ResourceManager.GetString("WebHelpAddFromFile", resourceCulture); 109 | } 110 | } 111 | 112 | /// 113 | /// Looks up a localized string similar to https://keeagent.readthedocs.io/en/v0.12.1/usage/options.html. 114 | /// 115 | internal static string WebHelpDatabaseSettings { 116 | get { 117 | return ResourceManager.GetString("WebHelpDatabaseSettings", resourceCulture); 118 | } 119 | } 120 | 121 | /// 122 | /// Looks up a localized string similar to https://keeagent.readthedocs.io/en/v0.12.1/usage/options.html#entry-settings. 123 | /// 124 | internal static string WebHelpEntryOptions { 125 | get { 126 | return ResourceManager.GetString("WebHelpEntryOptions", resourceCulture); 127 | } 128 | } 129 | 130 | /// 131 | /// Looks up a localized string similar to https://keeagent.readthedocs.io/en/v0.12.1/usage/keeagent-manager.html. 132 | /// 133 | internal static string WebHelpEntryPicker { 134 | get { 135 | return ResourceManager.GetString("WebHelpEntryPicker", resourceCulture); 136 | } 137 | } 138 | 139 | /// 140 | /// Looks up a localized string similar to https://keeagent.readthedocs.io/en/v0.12.1/usage/options.html#global-options. 141 | /// 142 | internal static string WebHelpGlobalOptions { 143 | get { 144 | return ResourceManager.GetString("WebHelpGlobalOptions", resourceCulture); 145 | } 146 | } 147 | 148 | /// 149 | /// Looks up a localized string similar to https://keeagent.readthedocs.io. 150 | /// 151 | internal static string WebHelpHome { 152 | get { 153 | return ResourceManager.GetString("WebHelpHome", resourceCulture); 154 | } 155 | } 156 | 157 | /// 158 | /// Looks up a localized string similar to https://keeagent.readthedocs.io/en/v0.12.1/usage/keeagent-manager.html. 159 | /// 160 | internal static string WebHelpKeeAgentManager { 161 | get { 162 | return ResourceManager.GetString("WebHelpKeeAgentManager", resourceCulture); 163 | } 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /KeeAgentTestProject/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\withoutPassphrase.ppk;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 123 | 124 | 125 | ..\Resources\withPassphrase.ppk;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 126 | 127 | 128 | ..\Resources\dsa.ppk;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 129 | 130 | 131 | ..\Resources\4095-bits.ppk;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 132 | 133 | 134 | ..\Resources\ssh2-rsa-non-ascii-passphrase.ppk;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 135 | 136 | --------------------------------------------------------------------------------