├── .gitattributes ├── .gitignore ├── CHANGES.md ├── LICENSE.md ├── Libraries ├── PasswordSafe │ ├── .gitattributes │ ├── .gitignore │ ├── .vscode │ │ └── settings.json │ ├── ICON.png │ ├── LICENSE.md │ ├── README.md │ ├── Resources │ │ └── formatV3.txt │ ├── Setup │ │ └── Pack.cmd │ └── Source │ │ ├── .editorconfig │ │ ├── PasswordSafe.Example │ │ ├── App.cs │ │ ├── PasswordSafe.Example.csproj │ │ └── Resources │ │ │ └── Simple.psafe3 │ │ ├── PasswordSafe.Test │ │ ├── DocumentTests.cs │ │ ├── EntryCollectionTests.cs │ │ ├── EntryTests.cs │ │ ├── GroupPathTests.cs │ │ ├── HeaderCollectionTests.cs │ │ ├── HeaderTests.cs │ │ ├── NamedPasswordPolicyTests.cs │ │ ├── PasswordPolicyTests.cs │ │ ├── PasswordSafe.Test.csproj │ │ ├── Properties │ │ │ └── App.snk │ │ ├── RecordCollectionTests.cs │ │ ├── RecordTests.cs │ │ └── Resources │ │ │ ├── PasswordHistory.psafe3 │ │ │ ├── Policies.psafe3 │ │ │ ├── Simple.bimil │ │ │ ├── Simple.psafe3 │ │ │ ├── SimpleTree.psafe3 │ │ │ ├── Test10.psafe3 │ │ │ ├── Test11.psafe3 │ │ │ └── empty.psafe3 │ │ ├── PasswordSafe.sln │ │ ├── PasswordSafe │ │ ├── (Medo) │ │ │ └── Twofish [003].cs │ │ ├── AutoTypeToken.cs │ │ ├── AutoTypeTokenKind.cs │ │ ├── Document.cs │ │ ├── Entry.cs │ │ ├── EntryCollection.cs │ │ ├── Field.cs │ │ ├── GroupPath.cs │ │ ├── Header.cs │ │ ├── HeaderCollection.cs │ │ ├── HeaderType.cs │ │ ├── Helpers.cs │ │ ├── NamedPasswordPolicy.cs │ │ ├── NamedPasswordPolicyCollection.cs │ │ ├── PasswordHistoryCollection.cs │ │ ├── PasswordHistoryItem.cs │ │ ├── PasswordPolicy.cs │ │ ├── PasswordPolicyStyle.cs │ │ ├── PasswordSafe.csproj │ │ ├── Properties │ │ │ ├── App.snk │ │ │ └── AssemblyInfo.cs │ │ ├── Record.cs │ │ ├── RecordCollection.cs │ │ └── RecordType.cs │ │ └── omnisharp.json └── subtree-pull-command-example.txt ├── README.md ├── Setup ├── Bimil.iss ├── License.rtf ├── Publish-GitHub.sh ├── Publish.cmd ├── deb │ ├── DEBIAN │ │ ├── config │ │ ├── control │ │ ├── postinst │ │ ├── postrm │ │ └── templates │ ├── copyright │ └── usr │ │ └── share │ │ ├── applications │ │ └── bimil.desktop │ │ ├── icons │ │ └── hicolor │ │ │ ├── 128x128 │ │ │ └── apps │ │ │ │ └── bimil.png │ │ │ ├── 16x16 │ │ │ └── apps │ │ │ │ └── bimil.png │ │ │ ├── 192x192 │ │ │ └── apps │ │ │ │ └── bimil.png │ │ │ ├── 24x24 │ │ │ └── apps │ │ │ │ └── bimil.png │ │ │ ├── 256x256 │ │ │ └── apps │ │ │ │ └── bimil.png │ │ │ ├── 32x32 │ │ │ └── apps │ │ │ │ └── bimil.png │ │ │ ├── 48x48 │ │ │ └── apps │ │ │ │ └── bimil.png │ │ │ ├── 64x64 │ │ │ └── apps │ │ │ │ └── bimil.png │ │ │ └── 96x96 │ │ │ └── apps │ │ │ └── bimil.png │ │ └── mime │ │ └── packages │ │ └── bimil.xml └── package.sh ├── Source ├── .editorconfig ├── Bimil.sln └── Bimil │ ├── (Medo) │ ├── AboutBox [013].cs │ ├── Base58 [001].cs │ ├── Config [006].cs │ ├── EntryAssembly [003].cs │ ├── ErrorReport [020].cs │ ├── InputBox [002].cs │ ├── LifetimeWatch [001].cs │ ├── MessageBox [007].cs │ ├── OneTimePassword [002+].cs │ ├── RecentFiles [---].cs │ ├── RecentlyUsed [001].cs │ ├── Settings [---].cs │ ├── State [017].cs │ ├── TrivialNtpClient [001].cs │ ├── UnhandledCatch [008].cs │ └── Upgrade [005].cs │ ├── App.cs │ ├── AutotypeConfigureForm.Designer.cs │ ├── AutotypeConfigureForm.cs │ ├── AutotypeConfigureForm.resx │ ├── AutotypeForm.Designer.cs │ ├── AutotypeForm.cs │ ├── AutotypeForm.resx │ ├── AutotypeHelpForm.Designer.cs │ ├── AutotypeHelpForm.cs │ ├── AutotypeHelpForm.resx │ ├── BadPasswords.cs │ ├── Bimil.csproj │ ├── BimilDocument │ ├── BimilDocument.cs │ ├── BimilItem.cs │ ├── BimilRecord.cs │ ├── BimilValue.cs │ └── DocumentConversion.cs │ ├── ClipboardHelper.cs │ ├── ClipboardMonitor.cs │ ├── DocumentInfoForm.Designer.cs │ ├── DocumentInfoForm.cs │ ├── DocumentInfoForm.resx │ ├── EntryCache.cs │ ├── Execute.cs │ ├── Helpers.cs │ ├── Hibp.cs │ ├── ItemForm.Designer.cs │ ├── ItemForm.cs │ ├── ItemForm.resx │ ├── MainForm.Designer.cs │ ├── MainForm.cs │ ├── MainForm.resx │ ├── NewPasswordForm.Designer.cs │ ├── NewPasswordForm.cs │ ├── NewPasswordForm.resx │ ├── NewRecordForm.Designer.cs │ ├── NewRecordForm.cs │ ├── NewRecordForm.resx │ ├── PasswordDetailsForm.Designer.cs │ ├── PasswordDetailsForm.cs │ ├── PasswordDetailsForm.resx │ ├── PasswordForm.Designer.cs │ ├── PasswordForm.cs │ ├── PasswordForm.resx │ ├── PasswordGeneratorForm.Designer.cs │ ├── PasswordGeneratorForm.cs │ ├── PasswordGeneratorForm.resx │ ├── Properties │ ├── App.ico │ ├── App.manifest │ ├── App.snk │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ └── SolutionInfo.cs │ ├── QRCode.cs │ ├── QRCodeForm.Designer.cs │ ├── QRCodeForm.cs │ ├── QRCodeForm.resx │ ├── RecordEditorForm.Designer.cs │ ├── RecordEditorForm.cs │ ├── RecordEditorForm.resx │ ├── Resources │ ├── Bible.words │ ├── Common.passwords │ ├── English.words │ ├── GeoFeatures.words │ ├── JaneAusten.words │ ├── Names.words │ └── WilliamShakespeare.words │ ├── SearchForm.Designer.cs │ ├── SearchForm.cs │ ├── SearchForm.resx │ ├── SearchWeakForm.Designer.cs │ ├── SearchWeakForm.cs │ ├── SearchWeakForm.resx │ ├── SelectTemplateForm.Designer.cs │ ├── SelectTemplateForm.cs │ ├── SelectTemplateForm.resx │ ├── Settings.cs │ ├── SettingsForm.Designer.cs │ ├── SettingsForm.cs │ ├── SettingsForm.resx │ ├── StartForm.Designer.cs │ ├── StartForm.cs │ ├── StartForm.resx │ ├── Templates.cs │ └── TextBoxEx.cs └── WORDS.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.bat text eol=crlf 4 | *.cmd text eol=crlf 5 | *.cs text diff=csharp 6 | *.csproj text 7 | *.md text 8 | *.sln text 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/bin 2 | **/obj 3 | **/.vs 4 | **/*.csproj.user 5 | 6 | Binaries/** 7 | Releases/** 8 | Research/** 9 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | ## Release Notes ## 2 | 3 | 4 | ### 2.86 [2021-02-15] ### 5 | 6 | * Improved monotype font selection 7 | * Fixed special character handling for Linux' auto-type 8 | * Windows/Linux compatibility improvement for Notes field 9 | 10 | 11 | ### 2.85 [2021-02-07] ### 12 | 13 | * Improved monotype font selection 14 | * Implemented auto-type on Linux 15 | 16 | 17 | ### 2.84 [2020-02-27] ### 18 | 19 | * Removed item deletion on Delete key from search box 20 | 21 | 22 | ### 2.83 [2019-11-26] ### 23 | 24 | * Removed Have I Been Pwned code 25 | * Upgrade and ErrorReport to work with TLS 1.3 26 | * Fixed NTP adjustment bug 27 | 28 | 29 | ### 2.82 [2019-06-10] ### 30 | 31 | * Workaround for disabled combobox being selected 32 | 33 | 34 | ### 2.81 [2019-04-19] ### 35 | 36 | * Various Linux-related fixes 37 | * Clipboard refactoring 38 | 39 | 40 | ### 2.80 [] ### 41 | 42 | * Added static key option to document properties 43 | * Allowing Base58 key instead of password 44 | * Various fixes 45 | 46 | 47 | ### 2.70 [2019-02-21] ### 48 | 49 | * Monospace font for passwords 50 | * Improved Linux package 51 | * New icon 52 | * Bug-fixing 53 | * Added triplet password generation 54 | 55 | 56 | ### 2.61 [2018-07-14] ### 57 | 58 | * Fixed crash during clipboard clear 59 | * Fixed package to work on Linux Mint 19 60 | 61 | 62 | ### 2.60 [2018-06-09] ### 63 | 64 | * Updated Have I Been Pwned code 65 | * Minor bug-fixes 66 | 67 | 68 | ### 2.50 [2018-02-26] ### 69 | 70 | * Minor UI updates 71 | * Load last option 72 | * Updated password generator word list 73 | * Window state is saved also in portable version 74 | 75 | 76 | ### 2.40 [2018-01-12] ### 77 | 78 | * Auto-clear clipboard 79 | * Linux package improvements 80 | * Tooltip is shown when upgrade is ready 81 | 82 | 83 | ### 2.31 [2017-12-16] ### 84 | 85 | * Fixed entry title editing from main window list view 86 | * Fixed http prefix for URL entries 87 | 88 | 89 | ### 2.30 [2017-11-05] ### 90 | 91 | * Integration with Have I been Pwned? 92 | * Added search for weak passwords 93 | 94 | 95 | ### 2.20 [2017-10-09] ### 96 | 97 | * Debian package available 98 | * NTP check before creating two-factor code 99 | * Including two-factor in auto-type 100 | * Editable document information 101 | 102 | 103 | ### 2.10 [2017-08-25] ### 104 | 105 | * Auto-type improvements 106 | * Various minor bug-fixing 107 | 108 | 109 | ### 2.00 [2017-05-06] ### 110 | 111 | * Copy/paste support 112 | * Context menu for entries 113 | * Entry filtering improvements 114 | * Common password warnings 115 | * Password details form 116 | * Using text file for configuration settings 117 | * Uses .NET Framework 4 118 | 119 | 120 | ### 1.70 [2017-01-16] ### 121 | 122 | * Auto-type improvements 123 | * Start dialog improvements 124 | * Added Run Command field 125 | 126 | 127 | ### [] ### 128 | 129 | * 130 | 131 | 132 | ### 1.60 [2016-09-27] ### 133 | 134 | * Added support for auto-fill 135 | * Expanded dictionary words 136 | * Added generic QR code field 137 | * Added read-only option 138 | 139 | 140 | ### 1.51 [2016-08-07] ### 141 | 142 | * Ensures classic password has at least 1 character of each selected type 143 | 144 | 145 | ### 1.50 [2016-08-07] ### 146 | 147 | * Added password generator 148 | * Added search functionality 149 | * Added password history field 150 | * Various minor changes 151 | 152 | 153 | ### 1.30 [2016-06-22] ### 154 | 155 | * Added local QR code generation 156 | * Configurable auto-close timeout 157 | * PasswordSafe compatibility warnings option 158 | 159 | 160 | ### 1.20 [2016-06-10] ### 161 | 162 | * Added auto-close 163 | * Bug fixes 164 | 165 | 166 | ### 1.10 [2016-04-03] ### 167 | 168 | * Added open as read-only 169 | * Added start screen. 170 | * Minor bug fixes 171 | 172 | 173 | ### 1.00 [2016-03-13] ### 174 | 175 | * Initial release 176 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ## The MIT License 2 | 3 | Copyright 2010 Josip Medved 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | * The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | 23 | 24 | 25 | ## QR Coder (https://github.com/codebude/QRCoder) 26 | 27 | To generate QR codes Bimil uses modified version of QRCoder. 28 | 29 | 30 | ### The MIT License (MIT) 31 | 32 | Copyright (c) 2013-2015 Raffael Herrmann 33 | 34 | Permission is hereby granted, free of charge, to any person obtaining a copy of 35 | this software and associated documentation files (the "Software"), to deal in 36 | the Software without restriction, including without limitation the rights to 37 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 38 | the Software, and to permit persons to whom the Software is furnished to do so, 39 | subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in all 42 | copies or substantial portions of the Software. 43 | 44 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 45 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 46 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 47 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 48 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 49 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 50 | 51 | 52 | 53 | ## WordNet (https://wordnet.princeton.edu) 54 | 55 | Bimil uses WordNet database as a source of words for its word-based password 56 | generator. 57 | 58 | 59 | ### WordNet 3.0 License 60 | 61 | This software and database is being provided to you, the LICENSEE, by Princeton 62 | University under the following license. By obtaining, using and/or copying this 63 | software and database, you agree that you have read, understood, and will comply 64 | with these terms and conditions: 65 | 66 | Permission to use, copy, modify and distribute this software and database and 67 | its documentation for any purpose and without fee or royalty is hereby granted, 68 | provided that you agree to comply with the following copyright notice and 69 | statements, including the disclaimer, and that the same appear on ALL copies of 70 | the software, database and documentation, including modifications that you make 71 | for internal use or for distribution. 72 | 73 | WordNet 3.0 Copyright 2006 by Princeton University. All rights reserved. 74 | 75 | THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND PRINCETON UNIVERSITY MAKES NO 76 | REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT 77 | LIMITATION, PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES OF 78 | MERCHANT- ABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE 79 | LICENSED SOFTWARE, DATABASE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 80 | PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. 81 | 82 | The name of Princeton University or Princeton may not be used in advertising or 83 | publicity pertaining to distribution of the software and/or database. Title to 84 | copyright in this software, database and any associated documentation shall at 85 | all times remain with Princeton University and LICENSEE agrees to preserve same. 86 | 87 | 88 | 89 | ## Popular Baby Names (United States Social Security Administration) 90 | 91 | Public Domain 92 | 93 | 94 | 95 | ## US Board On Geographic Names (States, Territories, Associated Areas of the United States) 96 | 97 | Public Domain 98 | 99 | 100 | 101 | ## The Bible, King James Version, Complete (Project Gutenberg) 102 | 103 | Public Domain, The Project Gutenberg License 104 | 105 | 106 | 107 | ## The Complete Works of William Shakespeare (Project Gutenberg) 108 | 109 | Public Domain, The Project Gutenberg License, Produced by World Library, Inc., from their Library of the Future 110 | 111 | 112 | 113 | ## The Complete Works of Jane Austen (Project Gutenberg): 114 | 115 | Public Domain, The Project Gutenberg License 116 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.bat text eol=crlf 4 | *.cmd text eol=crlf 5 | *.cs text diff=csharp 6 | *.csproj text merge=union 7 | *.md text 8 | *.sln text merge=union 9 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/.gitignore: -------------------------------------------------------------------------------- 1 | **/bin 2 | **/obj 3 | **/.vs 4 | **/*.csproj.user 5 | 6 | Binaries/** 7 | Releases/** 8 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | ".git": true, 4 | ".gitattributes": true, 5 | ".gitconfig": true, 6 | ".gitignore": true, 7 | "**/.vs": true, 8 | "**/.vscode": true, 9 | "**/bin": true, 10 | "**/obj": true, 11 | "src/.editorconfig": true, 12 | "src/omnisharp.json": true 13 | }, 14 | "omnisharp.useEditorFormattingSettings": false 15 | } 16 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/ICON.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/ICON.png -------------------------------------------------------------------------------- /Libraries/PasswordSafe/LICENSE.md: -------------------------------------------------------------------------------- 1 | ### The MIT License ### 2 | 3 | Copyright 2015 Josip Medved 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | * The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/README.md: -------------------------------------------------------------------------------- 1 | This library allows for reading and writing Password Safe version 3 files. 2 | 3 | For example usage do check [Bimil](https://www.medo64.com/bimil). 4 | 5 | 6 | 7 | #### Auto-type #### 8 | 9 | Auto-type functionality will simulate keyboard presses. Following escape 10 | characters are supported: 11 | 12 | \u User name field. 13 | \p Password field. 14 | \2 Two-factor authentication code. 15 | \cn Credit card number. 16 | \ct Credit card number (tab separated). 17 | \ce Credit card expiration. 18 | \cv Credit card security code. 19 | \cp Credit card pin number. 20 | \g Group field. 21 | \i Title field. 22 | \l URL field. 23 | \m E-mail field. 24 | \o Notes field. 25 | \o### Nth line of Notes field. If line doesn't exist, it has no effect. 26 | \b Backpace key. 27 | \t Tab key. 28 | \s Shift+Tab key. 29 | \n Enter key. 30 | \\ Backslash (\) key. 31 | \d### Delay between characters in milliseconds, instead of 10 (default). 32 | \w### Wait in milliseconds. 33 | \W### Wait in seconds. 34 | \z Invokes the alternative SendKeys method. 35 | All other text is typed as-is. 36 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Setup/Pack.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | SETLOCAL EnableDelayedExpansion 3 | 4 | SET TOOLS_MSBUILD="%PROGRAMFILES(X86)%\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\amd64\msbuild.exe" 5 | SET TOOLS_NUGET="%USERPROFILE%\Downloads\nuget.exe" 6 | 7 | 8 | ECHO --- DISCOVER TOOLS 9 | ECHO: 10 | 11 | FOR %%I IN (%TOOLS_MSBUILD%) DO ( 12 | IF EXIST %%I IF NOT DEFINED TOOL_MSBUILD SET TOOL_MSBUILD=%%I 13 | ) 14 | ECHO MSBuild: %TOOL_MSBUILD% 15 | IF [%TOOL_MSBUILD%]==[] ECHO Not found^^! & GOTO Error 16 | 17 | FOR %%I IN (%TOOLS_NUGET%) DO ( 18 | IF EXIST %%I IF NOT DEFINED TOOL_NUGET SET TOOL_NUGET=%%I 19 | ) 20 | ECHO NuGet: %TOOL_NUGET% 21 | IF [%TOOL_NUGET%]==[] ECHO Not found^^! & GOTO Error 22 | 23 | ECHO: 24 | ECHO: 25 | 26 | 27 | ECHO --- PACK 28 | ECHO: 29 | 30 | RMDIR /Q /S ".\Temp" 2> NUL 31 | MKDIR ".\Temp" 32 | 33 | DEL "..\Binaries\*.0.0.0.nupkg" 2> NUL 34 | 35 | %TOOL_MSBUILD% ..\Source\PasswordSafe\PasswordSafe.csproj /t:pack /p:IncludeSymbols=true /p:IncludeSource=true /p:Configuration=Release /p:OutputPath=..\..\Setup\Temp\ 36 | 37 | ECHO: 38 | ECHO: 39 | 40 | 41 | IF NOT [%TOOL_NUGET%]==[] ( 42 | ECHO --- PUSH 43 | ECHO: 44 | 45 | ECHO Set API key if needed 46 | ECHO %TOOL_NUGET% SetApiKey ^ 47 | ECHO: 48 | IF EXIST ".\Temp\*.0.0.0.nupkg" ( 49 | ECHO "Not pushing unversioned package." 50 | ) ELSE ( 51 | ECHO Proceed with pushing packaged to Internet^? 52 | PAUSE 53 | IF EXIST ".\Temp\*.nupkg" ( 54 | MKDIR "..\Releases" 2> NUL 55 | FOR %%I IN (".\Temp\*.nupkg") DO ( 56 | ECHO: 57 | SET FILE_NAME=%%~nI%%~xI 58 | IF [!FILE_NAME:~-14!]==[.symbols.nupkg] ( 59 | ECHO Pushing symbols in !FILE_NAME! 60 | %TOOL_NUGET% push .\Temp\!FILE_NAME! -source https://nuget.smbsrc.net/ 61 | ) ELSE ( 62 | ECHO Pushing package in !FILE_NAME! 63 | %TOOL_NUGET% push .\Temp\!FILE_NAME! -source https://nuget.org/ 64 | ) 65 | MOVE .\Temp\!FILE_NAME! ..\Releases\!FILE_NAME! > NUL 66 | ) 67 | RMDIR /Q /S ".\Temp" 2> NUL 68 | ) ELSE ( 69 | ECHO "No packages found." 70 | ) 71 | ) 72 | ) 73 | 74 | 75 | ENDLOCAL 76 | EXIT /B 0 77 | 78 | 79 | :Error 80 | ENDLOCAL 81 | PAUSE 82 | EXIT /B 1 83 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Example/App.cs: -------------------------------------------------------------------------------- 1 | using PwSafe = Medo.Security.Cryptography.PasswordSafe; 2 | using System; 3 | using System.IO; 4 | 5 | namespace Example { 6 | internal class App { 7 | private static void Main() { 8 | var existingFile = @"Resources\Simple.psafe3"; 9 | var newFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), @"NewExample.psafe3"); 10 | 11 | //Load 12 | var doc = PwSafe.Document.Load(existingFile, "123"); 13 | Show(doc, ConsoleColor.Gray); 14 | 15 | //modify 16 | doc.Entries["A"].Title = "Ax"; 17 | doc.Entries["Ax"].Password = "A123x"; 18 | 19 | //remove 20 | doc.Entries["B"] = null; 21 | 22 | //create new 23 | doc.Entries["C"].UserName = "Cuser"; 24 | doc.Entries["C"].Password = "C123"; 25 | doc.Entries["C"].Group = "Test"; 26 | doc.Entries["C", PwSafe.RecordType.Group] = null; 27 | 28 | Show(doc, ConsoleColor.White); 29 | 30 | //save 31 | doc.Save(newFile); 32 | 33 | //load again 34 | var doc2 = PwSafe.Document.Load(newFile, "123"); 35 | Show(doc2, ConsoleColor.Yellow); 36 | 37 | Console.ReadKey(); 38 | } 39 | 40 | 41 | private static void Show(PwSafe.Document doc, ConsoleColor color) { 42 | Console.ForegroundColor = color; 43 | 44 | Console.WriteLine("Headers"); 45 | foreach (var field in doc.Headers) { 46 | Console.WriteLine(" {0}: {1}", field.HeaderType, field.ToString()); 47 | } 48 | Console.WriteLine(); 49 | 50 | Console.WriteLine("Entries"); 51 | foreach (var entry in doc.Entries) { 52 | Console.WriteLine(" {0}:", entry.ToString()); 53 | foreach (var field in entry.Records) { 54 | Console.WriteLine(" {0}: {1}", field.RecordType, field.ToString()); 55 | } 56 | Console.WriteLine(); 57 | } 58 | 59 | Console.ResetColor(); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Example/PasswordSafe.Example.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | Example 7 | Example 8 | 9 | 10 | 11 | 12 | PreserveNewest 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Example/Resources/Simple.psafe3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/Source/PasswordSafe.Example/Resources/Simple.psafe3 -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/GroupPathTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | using PwSafe = Medo.Security.Cryptography.PasswordSafe; 4 | 5 | namespace PasswordSafe.Test { 6 | public class GroupPathTests { 7 | 8 | [Fact(DisplayName = "PasswordSafe: GroupPath: New")] 9 | public void GroupPath_New() { 10 | PwSafe.GroupPath path = "A"; 11 | Assert.Equal("A", path.ToString()); 12 | 13 | var segments = path.GetSegments(); 14 | Assert.Equal(1, segments.Length); 15 | Assert.Equal("A", segments[0]); 16 | } 17 | 18 | [Fact(DisplayName = "PasswordSafe: GroupPath: New (via components)")] 19 | public void GroupPath_NewViaComponents() { 20 | var path = new PwSafe.GroupPath("A", "B"); 21 | Assert.Equal("A.B", path.ToString()); 22 | 23 | var segments = path.GetSegments(); 24 | Assert.Equal(2, segments.Length); 25 | Assert.Equal("A", segments[0]); 26 | Assert.Equal("B", segments[1]); 27 | } 28 | 29 | [Fact(DisplayName = "PasswordSafe: GroupPath: New (via escaped components)")] 30 | public void GroupPath_NewViaComponentsEscaped() { 31 | var path = new PwSafe.GroupPath("A", "B.com"); 32 | Assert.Equal(@"A.B\.com", path.ToString()); 33 | 34 | var segments = path.GetSegments(); 35 | Assert.Equal(2, segments.Length); 36 | Assert.Equal("A", segments[0]); 37 | Assert.Equal("B.com", segments[1]); 38 | } 39 | 40 | [Fact(DisplayName = "PasswordSafe: GroupPath: New (via escaped components 1)")] 41 | public void GroupPath_NewViaComponentsEscaped2() { 42 | var path = new PwSafe.GroupPath("A", @"B\.com"); 43 | Assert.Equal(@"A.B\\.com", path.ToString()); 44 | 45 | var segments = path.GetSegments(); 46 | Assert.Equal(2, segments.Length); 47 | Assert.Equal("A", segments[0]); 48 | Assert.Equal(@"B\.com", segments[1]); 49 | } 50 | 51 | [Fact(DisplayName = "PasswordSafe: GroupPath: New (null)")] 52 | public void GroupPath_NewNull() { 53 | PwSafe.GroupPath path = default(string); 54 | Assert.Equal("", path.ToString()); 55 | 56 | var segments = path.GetSegments(); 57 | Assert.Equal(1, segments.Length); 58 | Assert.Equal("", segments[0]); 59 | } 60 | 61 | [Fact(DisplayName = "PasswordSafe: GroupPath: New tree")] 62 | public void GroupPath_NewTree() { 63 | PwSafe.GroupPath path = "A.B"; 64 | Assert.Equal("A.B", path.ToString()); 65 | 66 | var segments = path.GetSegments(); 67 | Assert.Equal(2, segments.Length); 68 | Assert.Equal("A", segments[0]); 69 | Assert.Equal("B", segments[1]); 70 | } 71 | 72 | 73 | [Fact(DisplayName = "PasswordSafe: GroupPath: Up")] 74 | public void GroupPath_Up() { 75 | PwSafe.GroupPath path = @"A.B.C\.d"; 76 | 77 | Assert.Equal(@"A.B.C\.d", path.ToString()); 78 | Assert.Equal("A.B", path.Up().ToString()); 79 | Assert.Equal("A", path.Up().Up().ToString()); 80 | Assert.Equal("", path.Up().Up().Up().ToString()); 81 | Assert.Equal("", path.Up().Up().Up().Up().ToString()); 82 | } 83 | 84 | [Fact(DisplayName = "PasswordSafe: GroupPath: Append")] 85 | public void GroupPath_Append() { 86 | PwSafe.GroupPath path = ""; 87 | 88 | Assert.Equal("", path.ToString()); 89 | Assert.Equal("", path.Append(null).ToString()); 90 | Assert.Equal("", path.Append("").ToString()); 91 | Assert.Equal("A", path.Append("A").ToString()); 92 | Assert.Equal("A.B", path.Append("A").Append("B").ToString()); 93 | Assert.Equal(@"A.B.C\.d", path.Append("A").Append("B").Append("C.d").ToString()); 94 | Assert.Equal(@"A.B.C\.d", path.Append("A").Append("B").Append("").Append("C.d").Append("").ToString()); //Empty elements are not appended. 95 | } 96 | 97 | 98 | [Fact(DisplayName = "PasswordSafe: GroupPath: Indexer Get")] 99 | public void GroupPath_Indexed() { 100 | PwSafe.GroupPath path = @"A.B.C\.d"; 101 | 102 | Assert.Equal(null, path[-1]); 103 | Assert.Equal("A", path[0]); 104 | Assert.Equal("B", path[1]); 105 | Assert.Equal("C.d", path[2]); 106 | Assert.Equal(null, path[3]); 107 | } 108 | 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/HeaderCollectionTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | using PwSafe = Medo.Security.Cryptography.PasswordSafe; 4 | 5 | namespace PasswordSafe.Test { 6 | public class HeaderCollectionTests { 7 | 8 | [Fact(DisplayName = "PasswordSafe: HeaderCollection: Add")] 9 | public void HeaderCollection_New() { 10 | var doc = new PwSafe.Document("Password"); 11 | doc.Headers.Add(new PwSafe.Header(PwSafe.HeaderType.DatabaseName) { Text = "Test" }); 12 | 13 | Assert.Equal("Test", doc.Name); 14 | } 15 | 16 | 17 | [Fact(DisplayName = "PasswordSafe: HeaderCollection: Add (read-only document)")] 18 | public void HeaderCollection_ReadOnly() { 19 | Assert.Throws(() => { 20 | var doc = new PwSafe.Document("Password") { IsReadOnly = true }; 21 | doc.Headers.Add(new PwSafe.Header(PwSafe.HeaderType.DatabaseName) { Text = "Test" }); 22 | }); 23 | } 24 | 25 | [Fact(DisplayName = "PasswordSafe: HeaderCollection: Indexer Get")] 26 | public void HeaderCollection_ReadOnly_IndexerRead() { 27 | var doc = new PwSafe.Document("Password") { IsReadOnly = true }; 28 | Assert.NotNull(doc.Headers[PwSafe.HeaderType.DatabaseName]); 29 | Assert.Equal("", doc.Headers[PwSafe.HeaderType.DatabaseName].Text); 30 | } 31 | 32 | [Fact(DisplayName = "PasswordSafe: HeaderCollection: Indexer Set")] 33 | public void HeaderCollection_ReadOnly_IndexerWrite() { 34 | Assert.Throws(() => { 35 | var doc = new PwSafe.Document("Password") { IsReadOnly = true }; 36 | doc.Headers[PwSafe.HeaderType.DatabaseName] = null; 37 | }); 38 | } 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/HeaderTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | using PwSafe = Medo.Security.Cryptography.PasswordSafe; 4 | 5 | namespace PasswordSafe.Test { 6 | public class HeaderTests { 7 | 8 | [Fact(DisplayName = "PasswordSafe: Header: New")] 9 | public void Header_New() { 10 | var field = new PwSafe.Header(PwSafe.HeaderType.DatabaseName) { Text = "Test" }; 11 | Assert.Equal("Test", field.Text); 12 | } 13 | 14 | [Fact(DisplayName = "PasswordSafe: Header: New (wrong type)")] 15 | public void Header_New_WrongType() { 16 | Assert.Throws(() => { 17 | var field = new PwSafe.Header(PwSafe.HeaderType.DatabaseName) { Uuid = new Guid() }; 18 | }); 19 | } 20 | 21 | 22 | [Fact(DisplayName = "PasswordSafe: Header: Add (read-only document)")] 23 | public void Header_ReadOnly() { 24 | Assert.Throws(() => { 25 | var doc = new PwSafe.Document("Password"); 26 | doc.Headers.Add(new PwSafe.Header(PwSafe.HeaderType.DatabaseName) { Text = "Test" }); 27 | 28 | doc.IsReadOnly = true; 29 | doc.Headers[PwSafe.HeaderType.DatabaseName].Text = "NewName"; 30 | }); 31 | } 32 | 33 | [Fact(DisplayName = "PasswordSafe: Header: Indexer Get")] 34 | public void Header_ReadOnly_IndexerRead() { 35 | var doc = new PwSafe.Document("Password") { IsReadOnly = true }; 36 | Assert.NotNull(doc.Headers[PwSafe.HeaderType.DatabaseName]); 37 | Assert.Equal("", doc.Headers[PwSafe.HeaderType.DatabaseName].Text); 38 | } 39 | 40 | [Fact(DisplayName = "PasswordSafe: Header: Indexer Set")] 41 | public void Header_ReadOnly_IndexerWrite() { 42 | Assert.Throws(() => { 43 | var doc = new PwSafe.Document("Password") { IsReadOnly = true }; 44 | doc.Headers[PwSafe.HeaderType.DatabaseName] = null; 45 | }); 46 | } 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/NamedPasswordPolicyTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | using PwSafe = Medo.Security.Cryptography.PasswordSafe; 3 | 4 | namespace PasswordSafe.Test { 5 | public class NamedPasswordPolicyTests { 6 | 7 | [Fact(DisplayName = "PasswordSafe: NamedPasswordPolicy: New")] 8 | public void Policy_New() { 9 | var policy = new PwSafe.NamedPasswordPolicy("Test", 10) { 10 | Style = PwSafe.PasswordPolicyStyle.MakePronounceable, 11 | MinimumLowercaseCount = 1, 12 | MinimumUppercaseCount = 2, 13 | MinimumDigitCount = 3, 14 | MinimumSymbolCount = 4 15 | }; 16 | 17 | Assert.Equal("Test", policy.Name); 18 | Assert.Equal(0x0200, (int)policy.Style); 19 | Assert.Equal(10, policy.TotalPasswordLength); 20 | Assert.Equal(1, policy.MinimumLowercaseCount); 21 | Assert.Equal(2, policy.MinimumUppercaseCount); 22 | Assert.Equal(3, policy.MinimumDigitCount); 23 | Assert.Equal(4, policy.MinimumSymbolCount); 24 | Assert.Equal("", new string(policy.GetSpecialSymbolSet())); 25 | Assert.Equal("Test", policy.ToString()); 26 | } 27 | 28 | 29 | [Fact(DisplayName = "PasswordSafe: NamedPasswordPolicy: Single special symbols")] 30 | public void Policy_SingleSymbol() { 31 | var policy = new PwSafe.NamedPasswordPolicy("Test", 10); 32 | policy.SetSpecialSymbolSet(new char[] { '!' }); 33 | Assert.Equal("!", new string(policy.GetSpecialSymbolSet())); 34 | } 35 | 36 | [Fact(DisplayName = "PasswordSafe: NamedPasswordPolicy: Filter duplicate symbols")] 37 | public void Policy_DuplicateSymbols() { 38 | var policy = new PwSafe.NamedPasswordPolicy("Test", 10); 39 | policy.SetSpecialSymbolSet(new char[] { 'A', 'B', 'B', 'A', 'a', 'b', 'b', 'a' }); 40 | Assert.Equal("ABab", new string(policy.GetSpecialSymbolSet())); 41 | } 42 | 43 | [Fact(DisplayName = "PasswordSafe: NamedPasswordPolicy: Empty special symbols")] 44 | public void Policy_EmptySymbols() { 45 | var policy = new PwSafe.NamedPasswordPolicy("Test", 10); 46 | policy.SetSpecialSymbolSet(new char[] { '!' }); 47 | policy.SetSpecialSymbolSet(); 48 | Assert.Equal("", new string(policy.GetSpecialSymbolSet())); 49 | } 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/PasswordPolicyTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | using PwSafe = Medo.Security.Cryptography.PasswordSafe; 3 | 4 | namespace PasswordSafe.Test { 5 | public class PasswordPolicyTests { 6 | 7 | [Fact(DisplayName = "PasswordSafe: PasswordPolicy: New")] 8 | public void Policy_New() { 9 | var policy = new PwSafe.PasswordPolicy(10) { 10 | Style = PwSafe.PasswordPolicyStyle.MakePronounceable, 11 | MinimumLowercaseCount = 1, 12 | MinimumUppercaseCount = 2, 13 | MinimumDigitCount = 3, 14 | MinimumSymbolCount = 4 15 | }; 16 | 17 | Assert.Equal(0x0200, (int)policy.Style); 18 | Assert.Equal(10, policy.TotalPasswordLength); 19 | Assert.Equal(1, policy.MinimumLowercaseCount); 20 | Assert.Equal(2, policy.MinimumUppercaseCount); 21 | Assert.Equal(3, policy.MinimumDigitCount); 22 | Assert.Equal(4, policy.MinimumSymbolCount); 23 | Assert.Equal("", new string(policy.GetSpecialSymbolSet())); 24 | } 25 | 26 | 27 | [Fact(DisplayName = "PasswordSafe: PasswordPolicy: Single special symbols")] 28 | public void Policy_SingleSymbol() { 29 | var policy = new PwSafe.PasswordPolicy(10); 30 | policy.SetSpecialSymbolSet(new char[] { '!' }); 31 | Assert.Equal("!", new string(policy.GetSpecialSymbolSet())); 32 | } 33 | 34 | [Fact(DisplayName = "PasswordSafe: PasswordPolicy: Filter duplicate symbols")] 35 | public void Policy_DuplicateSymbols() { 36 | var policy = new PwSafe.PasswordPolicy(10); 37 | policy.SetSpecialSymbolSet(new char[] { 'A', 'B', 'B', 'A', 'a', 'b', 'b', 'a' }); 38 | Assert.Equal("ABab", new string(policy.GetSpecialSymbolSet())); 39 | } 40 | 41 | [Fact(DisplayName = "PasswordSafe: PasswordPolicy: Empty special symbols")] 42 | public void Policy_EmptySymbols() { 43 | var policy = new PwSafe.PasswordPolicy(10); 44 | policy.SetSpecialSymbolSet(new char[] { '!' }); 45 | policy.SetSpecialSymbolSet(); 46 | Assert.Equal("", new string(policy.GetSpecialSymbolSet())); 47 | } 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/PasswordSafe.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | false 6 | true 7 | Properties\App.snk 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/Properties/App.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/Source/PasswordSafe.Test/Properties/App.snk -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/RecordCollectionTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | using PwSafe = Medo.Security.Cryptography.PasswordSafe; 4 | 5 | namespace PasswordSafe.Test { 6 | public class RecordCollectionTests { 7 | 8 | [Fact(DisplayName = "PasswordSafe: RecordCollection: Add")] 9 | public void RecordCollection_New() { 10 | var doc = new PwSafe.Document("Password"); 11 | doc.Entries.Add(new PwSafe.Entry()); 12 | doc.Entries[0].Records.Add(new PwSafe.Record(PwSafe.RecordType.Group) { Text = "Test" }); 13 | 14 | Assert.True(string.Equals("Test", doc.Entries[0].Group, StringComparison.Ordinal)); 15 | } 16 | 17 | 18 | [Fact(DisplayName = "PasswordSafe: RecordCollection: Add (read-only document)")] 19 | public void RecordCollection_ReadOnly() { 20 | Assert.Throws(() => { 21 | var doc = new PwSafe.Document("Password"); 22 | doc.Entries.Add(new PwSafe.Entry()); 23 | doc.IsReadOnly = true; 24 | doc.Entries[0].Records.Add(new PwSafe.Record(PwSafe.RecordType.Group)); 25 | }); 26 | } 27 | 28 | [Fact(DisplayName = "PasswordSafe: RecordCollection: Indexer Get")] 29 | public void RecordCollection_ReadOnly_IndexerRead() { 30 | var doc = new PwSafe.Document("Password"); 31 | doc.Entries.Add(new PwSafe.Entry()); 32 | doc.IsReadOnly = true; 33 | Assert.Equal("", doc.Entries[0].Records[PwSafe.RecordType.Title].Text); 34 | } 35 | 36 | [Fact(DisplayName = "PasswordSafe: RecordCollection: Indexer Set")] 37 | public void RecordCollection_ReadOnly_IndexerWrite() { 38 | Assert.Throws(() => { 39 | var doc = new PwSafe.Document("Password"); 40 | doc.Entries.Add(new PwSafe.Entry()); 41 | doc.IsReadOnly = true; 42 | doc.Entries[0].Records[PwSafe.RecordType.Title] = null; 43 | }); 44 | } 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/RecordTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | using PwSafe = Medo.Security.Cryptography.PasswordSafe; 4 | 5 | namespace PasswordSafe.Test { 6 | public class RecordTests { 7 | 8 | [Fact(DisplayName = "PasswordSafe: Record: New")] 9 | public void Record_New() { 10 | var field = new PwSafe.Record(PwSafe.RecordType.Title) { Text = "Test" }; 11 | Assert.Equal("Test", field.Text); 12 | } 13 | 14 | [Fact(DisplayName = "PasswordSafe: Record: New (wrong type)")] 15 | public void Record_New_WrongType() { 16 | Assert.Throws(() => { 17 | var field = new PwSafe.Record(PwSafe.RecordType.Title) { Time = DateTime.Now }; 18 | }); 19 | } 20 | 21 | [Fact(DisplayName = "PasswordSafe: Record: New (auto-type)")] 22 | public void Record_New_Autotype() { 23 | var field = new PwSafe.Record(PwSafe.RecordType.Autotype); 24 | Assert.Equal(@"\u\t\p\n", field.Text); 25 | } 26 | 27 | 28 | [Fact(DisplayName = "PasswordSafe: Record: Change (read-only document)")] 29 | public void Record_ReadOnly() { 30 | Assert.Throws(() => { 31 | var doc = new PwSafe.Document("Password"); 32 | doc.Entries["Test"].Password = "Old"; 33 | 34 | doc.IsReadOnly = true; 35 | doc.Entries[0].Records[PwSafe.RecordType.Password].Text = "New"; 36 | }); 37 | } 38 | 39 | 40 | [Fact(DisplayName = "PasswordSafe: Record: SetBytes")] 41 | public void Record_SetBytes() { 42 | var field = new PwSafe.Record(PwSafe.RecordType.Title); 43 | field.SetBytes(new byte[] { 0x00, 0xFF }); 44 | Assert.Equal("00-FF", BitConverter.ToString(field.GetBytes())); 45 | } 46 | 47 | [Fact(DisplayName = "PasswordSafe: Record: SetBytes (null)")] 48 | public void Record_SetBytes_Null() { 49 | Assert.Throws(() => { 50 | var field = new PwSafe.Record(PwSafe.RecordType.Title); 51 | field.SetBytes(null); 52 | }); 53 | } 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/PasswordHistory.psafe3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/PasswordHistory.psafe3 -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/Policies.psafe3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/Policies.psafe3 -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/Simple.bimil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/Simple.bimil -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/Simple.psafe3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/Simple.psafe3 -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/SimpleTree.psafe3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/SimpleTree.psafe3 -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/Test10.psafe3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/Test10.psafe3 -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/Test11.psafe3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/Test11.psafe3 -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/empty.psafe3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/Source/PasswordSafe.Test/Resources/empty.psafe3 -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.3 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PasswordSafe", "PasswordSafe\PasswordSafe.csproj", "{6626919D-0285-4F7C-818D-B3B2FD8D3268}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PasswordSafe.Example", "PasswordSafe.Example\PasswordSafe.Example.csproj", "{DF18DE1F-724E-4719-BA0E-C1DC459667C2}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PasswordSafe.Test", "PasswordSafe.Test\PasswordSafe.Test.csproj", "{3F881E25-F55B-40B2-A4A9-FC3A4C4F70B5}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {6626919D-0285-4F7C-818D-B3B2FD8D3268}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {6626919D-0285-4F7C-818D-B3B2FD8D3268}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {6626919D-0285-4F7C-818D-B3B2FD8D3268}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {6626919D-0285-4F7C-818D-B3B2FD8D3268}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {DF18DE1F-724E-4719-BA0E-C1DC459667C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {DF18DE1F-724E-4719-BA0E-C1DC459667C2}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {DF18DE1F-724E-4719-BA0E-C1DC459667C2}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {DF18DE1F-724E-4719-BA0E-C1DC459667C2}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {3F881E25-F55B-40B2-A4A9-FC3A4C4F70B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {3F881E25-F55B-40B2-A4A9-FC3A4C4F70B5}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {3F881E25-F55B-40B2-A4A9-FC3A4C4F70B5}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {3F881E25-F55B-40B2-A4A9-FC3A4C4F70B5}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {56B539EF-AA00-47CB-9614-1541515BBAB5} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/AutoTypeTokenKind.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Medo.Security.Cryptography.PasswordSafe { 4 | /// 5 | /// Auto-type token kind. 6 | /// 7 | public enum AutotypeTokenKind { 8 | /// 9 | /// Token is command. 10 | /// 11 | Command, 12 | /// 13 | /// Token is a key. 14 | /// 15 | Key, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/GroupPath.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Medo.Security.Cryptography.PasswordSafe { 6 | /// 7 | /// Group path. 8 | /// Separate components are separated by dot (.) character. 9 | /// Class is immutable. 10 | /// 11 | public class GroupPath { 12 | 13 | /// 14 | /// Create a new instance. 15 | /// 16 | /// Path segments. Null or empty components are ignored. 17 | public GroupPath(params string[] segments) { 18 | var sb = new StringBuilder(); 19 | if (segments != null) { 20 | foreach (var component in segments) { 21 | if (!string.IsNullOrEmpty(component)) { 22 | if (sb.Length > 0) { sb.Append("."); } 23 | sb.Append(component.Replace(".", @"\.")); 24 | } 25 | } 26 | } 27 | Group = sb.ToString(); 28 | } 29 | 30 | private GroupPath(string group) { 31 | Group = group; 32 | } 33 | 34 | 35 | private readonly string Group; 36 | 37 | 38 | /// 39 | /// Returns array of all segments. 40 | /// 41 | public string[] GetSegments() { 42 | var escaped = false; 43 | var segmentList = new List(); 44 | var segment = new StringBuilder(); 45 | foreach (var ch in Group) { 46 | if (ch == '.') { 47 | if (escaped) { 48 | segment[segment.Length - 1] = '.'; 49 | escaped = false; 50 | } else { 51 | segmentList.Add(segment.ToString()); 52 | segment.Length = 0; 53 | } 54 | } else { 55 | if (ch == '\\') { escaped = true; } 56 | segment.Append(ch); 57 | } 58 | } 59 | segmentList.Add(segment.ToString()); 60 | return segmentList.ToArray(); 61 | } 62 | 63 | 64 | /// 65 | /// Appends a new segment. 66 | /// 67 | /// Segment to append. 68 | public GroupPath Append(string segment) { 69 | if (string.IsNullOrEmpty(segment)) { return this; } //ok since class is immutable; 70 | if (string.IsNullOrEmpty(Group)) { return new GroupPath(segment); } 71 | 72 | var segments = GetSegments(); 73 | var newSegments = new string[segments.Length + 1]; 74 | Array.Copy(segments, 0, newSegments, 0, segments.Length); 75 | newSegments[newSegments.Length - 1] = segment; 76 | return new GroupPath(newSegments); 77 | } 78 | 79 | /// 80 | /// Returns path one level up the hierarchy. 81 | /// 82 | public GroupPath Up() { 83 | var segments = GetSegments(); 84 | if (segments.Length <= 1) { return new GroupPath(""); } 85 | 86 | var newSegments = new string[segments.Length - 1]; 87 | Array.Copy(segments, 0, newSegments, 0, newSegments.Length); 88 | return new GroupPath(newSegments); 89 | } 90 | 91 | 92 | /// 93 | /// Gets a segment of the path or null if segment doesn't exist. 94 | /// 95 | /// The zero-based index of the element to get. 96 | public string this[int index] { 97 | get { 98 | var segements = GetSegments(); 99 | if ((index < 0) || (index >= segements.Length)) { return null; } 100 | return segements[index]; 101 | } 102 | } 103 | 104 | 105 | #region Overrides 106 | 107 | /// 108 | /// Determines whether the specified object is equal to the current object. 109 | /// 110 | /// The object to compare with the current object. 111 | public override bool Equals(object obj) { 112 | if (obj is GroupPath path) { return Group.Equals(path.Group, StringComparison.OrdinalIgnoreCase); } 113 | 114 | var group = obj as string; 115 | return Group.Equals(group, StringComparison.OrdinalIgnoreCase); 116 | } 117 | 118 | /// 119 | /// A hash code for the current object. 120 | /// 121 | public override int GetHashCode() { 122 | return Group.GetHashCode(); 123 | } 124 | 125 | /// 126 | /// Returns a string that represents the current object. 127 | /// 128 | /// 129 | public override string ToString() { 130 | return Group; 131 | } 132 | 133 | #endregion 134 | 135 | 136 | #region Operators 137 | 138 | /// 139 | /// Returns group from path. 140 | /// If path is null, empty string is assumed. 141 | /// 142 | /// Path expression. 143 | public static implicit operator string(GroupPath groupPath) { 144 | return groupPath?.Group ?? ""; 145 | } 146 | 147 | /// 148 | /// Returns path from group. 149 | /// If group is null, empty group is assumed. 150 | /// 151 | /// Group value. 152 | public static implicit operator GroupPath(string group) { 153 | return new GroupPath(group ?? ""); 154 | } 155 | 156 | #endregion 157 | 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/Header.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace Medo.Security.Cryptography.PasswordSafe { 5 | /// 6 | /// Header field. 7 | /// 8 | [DebuggerDisplay("{HeaderType}: {ToString(),nq}")] 9 | public class Header : Field { 10 | 11 | /// 12 | /// Create a new instance. 13 | /// 14 | /// Header type. 15 | public Header(HeaderType type) 16 | : base() { 17 | HeaderType = type; 18 | } 19 | 20 | 21 | internal Header(HeaderCollection owner, HeaderType type) 22 | : this(type) { 23 | Owner = owner; 24 | } 25 | 26 | internal Header(HeaderType type, byte[] rawData) 27 | : base() { 28 | if ((type < 0) || (type >= HeaderType.EndOfEntry)) { throw new ArgumentOutOfRangeException(nameof(type), "Type not supported."); } 29 | HeaderType = type; 30 | RawData = rawData; 31 | } 32 | 33 | 34 | internal HeaderCollection Owner { get; set; } 35 | 36 | 37 | /// 38 | /// Used to mark document as changed. 39 | /// 40 | protected override void MarkAsChanged() { 41 | if (Owner != null) { Owner.MarkAsChanged(); } 42 | } 43 | 44 | /// 45 | /// Used to mark document as accessed. 46 | /// 47 | protected override void MarkAsAccessed() { } //nobody cares 48 | 49 | /// 50 | /// Gets if object is read-only. 51 | /// 52 | protected override bool IsReadOnly { 53 | get { return Owner?.IsReadOnly ?? false; } 54 | } 55 | 56 | 57 | /// 58 | /// Gets field type. 59 | /// 60 | public HeaderType HeaderType { get; } 61 | 62 | 63 | /// 64 | /// Gets underlying data type for field. 65 | /// 66 | protected override PasswordSafeFieldDataType DataType { 67 | get { 68 | switch (HeaderType) { 69 | case HeaderType.Version: 70 | return PasswordSafeFieldDataType.Version; 71 | 72 | case HeaderType.Uuid: 73 | return PasswordSafeFieldDataType.Uuid; 74 | 75 | case HeaderType.NonDefaultPreferences: 76 | case HeaderType.TreeDisplayStatus: 77 | case HeaderType.WhoPerformedLastSave: 78 | case HeaderType.WhatPerformedLastSave: 79 | case HeaderType.LastSavedByUser: 80 | case HeaderType.LastSavedOnHost: 81 | case HeaderType.DatabaseName: 82 | case HeaderType.DatabaseDescription: 83 | case HeaderType.DatabaseFilters: 84 | case HeaderType.RecentlyUsedEntries: 85 | case HeaderType.NamedPasswordPolicies: 86 | case HeaderType.EmptyGroups: 87 | case HeaderType.Yubico: 88 | return PasswordSafeFieldDataType.Text; 89 | 90 | case HeaderType.TimestampOfLastSave: 91 | return PasswordSafeFieldDataType.Time; 92 | 93 | default: return PasswordSafeFieldDataType.Unknown; 94 | } 95 | } 96 | } 97 | 98 | 99 | internal static ushort DefaultVersion = 0x030D; 100 | 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/HeaderType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Medo.Security.Cryptography.PasswordSafe { 4 | /// 5 | /// Header field types. 6 | /// 7 | public enum HeaderType { 8 | /// 9 | /// Version. 10 | /// 11 | Version = 0x00, 12 | /// 13 | /// UUID. 14 | /// 15 | Uuid = 0x01, 16 | /// 17 | /// Non-default preferences. 18 | /// 19 | NonDefaultPreferences = 0x02, 20 | /// 21 | /// Tree display status. 22 | /// 23 | TreeDisplayStatus = 0x03, 24 | /// 25 | /// Timestamp of last save. 26 | /// 27 | TimestampOfLastSave = 0x04, 28 | /// 29 | /// Who performed last save. 30 | /// 31 | WhoPerformedLastSave = 0x05, 32 | /// 33 | /// What performed last save. 34 | /// 35 | WhatPerformedLastSave = 0x06, 36 | /// 37 | /// Last saved by user. 38 | /// 39 | LastSavedByUser = 0x07, 40 | /// 41 | /// Last saved on host. 42 | /// 43 | LastSavedOnHost = 0x08, 44 | /// 45 | /// Database name. 46 | /// 47 | DatabaseName = 0x09, 48 | /// 49 | /// Database description. 50 | /// 51 | DatabaseDescription = 0x0A, 52 | /// 53 | /// Database filters. 54 | /// 55 | DatabaseFilters = 0x0B, 56 | /// 57 | /// Recently used entries. 58 | /// 59 | RecentlyUsedEntries = 0x0F, 60 | /// 61 | /// Named password policies. 62 | /// 63 | NamedPasswordPolicies = 0x10, 64 | /// 65 | /// Empty groups. 66 | /// 67 | EmptyGroups = 0x11, 68 | /// 69 | /// Yubico. 70 | /// 71 | Yubico = 0x12, 72 | /// 73 | /// End of entries. 74 | /// 75 | EndOfEntry = 0xFF, 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/Helpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Security.Cryptography; 4 | 5 | namespace PasswordSafe { 6 | internal static class Helpers { 7 | 8 | private static readonly Lazy lazyRandomKey = new Lazy(() => { 9 | var buffer = new byte[16]; 10 | RandomNumberGenerator.Create().GetBytes(buffer); 11 | return buffer; 12 | }); 13 | private static readonly Lazy aes = new Lazy(() => Aes.Create()); 14 | 15 | //.NET Standard compatible replacement for ProtectedData.Unprotect(encryptedData, optionalEntropy, DataProtectionScope.CurrentUser); 16 | public static byte[] UnprotectData(byte[] encryptedData, byte[] optionalEntropy) { 17 | if (encryptedData == null) { throw new ArgumentNullException(nameof(encryptedData), "Data cannot be null."); } 18 | var iv = new byte[16]; //all 0s by default 19 | if (optionalEntropy != null) { Buffer.BlockCopy(optionalEntropy, 0, iv, 0, (optionalEntropy.Length < 16) ? optionalEntropy.Length : 16); } //just copy first 16 bytes of entropy to IV 20 | using (var ms = new MemoryStream(encryptedData)) { 21 | using (var decryptor = aes.Value.CreateDecryptor(lazyRandomKey.Value, iv)) 22 | using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read)) { 23 | var decryptedBuffer = new byte[encryptedData.Length]; 24 | var decryptedLength = cs.Read(decryptedBuffer, 0, decryptedBuffer.Length); 25 | 26 | var newBuffer = new byte[decryptedLength]; 27 | Buffer.BlockCopy(decryptedBuffer, 0, newBuffer, 0, newBuffer.Length); 28 | Array.Clear(decryptedBuffer, 0, decryptedBuffer.Length); 29 | return newBuffer; 30 | } 31 | } 32 | } 33 | 34 | //.NET Standard compatible replacement for ProtectedData.Protect(userData, optionalEntropy, DataProtectionScope.CurrentUser); 35 | public static byte[] ProtectData(byte[] userData, byte[] optionalEntropy) { 36 | if (userData == null) { throw new ArgumentNullException(nameof(userData), "Data cannot be null."); } 37 | var iv = new byte[16]; //all 0s by default 38 | if (optionalEntropy != null) { Buffer.BlockCopy(optionalEntropy, 0, iv, 0, (optionalEntropy.Length < 16) ? optionalEntropy.Length : 16); } //just copy first 16 bytes of entropy to IV 39 | using (var ms = new MemoryStream()) { 40 | using (var encryptor = aes.Value.CreateEncryptor(lazyRandomKey.Value, iv)) 41 | using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) { 42 | cs.Write(userData, 0, userData.Length); 43 | } 44 | return ms.ToArray(); 45 | } 46 | } 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/PasswordHistoryItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Security.Cryptography; 4 | using System.Text; 5 | using static PasswordSafe.Helpers; 6 | 7 | namespace Medo.Security.Cryptography.PasswordSafe { 8 | /// 9 | /// One entry in password history. 10 | /// 11 | [DebuggerDisplay("{Password}")] 12 | public class PasswordHistoryItem { 13 | 14 | internal PasswordHistoryItem(PasswordHistoryCollection owner, DateTime firstTimeUsed, string historicalPassword) { 15 | Owner = owner; 16 | TimeFirstUsed = firstTimeUsed; 17 | 18 | byte[] historicalPasswordBytes = null; 19 | try { 20 | historicalPasswordBytes = Utf8Encoding.GetBytes(historicalPassword); 21 | RawHistoricalPasswordData = historicalPasswordBytes; 22 | } finally { 23 | if (historicalPasswordBytes != null) { Array.Clear(historicalPasswordBytes, 0, historicalPasswordBytes.Length); } 24 | } 25 | } 26 | 27 | 28 | private readonly PasswordHistoryCollection Owner; 29 | 30 | 31 | /// 32 | /// Used to mark document as changed. 33 | /// 34 | protected void MarkAsChanged() { 35 | if (Owner != null) { Owner.MarkAsChanged(); } 36 | } 37 | 38 | 39 | /// 40 | /// Gets time when password was first used. 41 | /// 42 | public DateTime TimeFirstUsed { get; } 43 | 44 | /// 45 | /// Gets historical password. 46 | /// 47 | public string HistoricalPassword { 48 | get { 49 | var data = RawHistoricalPasswordData; 50 | try { 51 | return Utf8Encoding.GetString(data); 52 | } finally { 53 | Array.Clear(data, 0, data.Length); 54 | } 55 | } 56 | } 57 | 58 | 59 | private static readonly Encoding Utf8Encoding = new UTF8Encoding(false); 60 | private static readonly RandomNumberGenerator Rnd = RandomNumberGenerator.Create(); 61 | private readonly byte[] RawHistoricalPasswordDataEntropy = new byte[16]; 62 | 63 | private byte[] _rawHistoricalPasswordData = null; 64 | /// 65 | /// Gets/sets raw data. 66 | /// Bytes are kept encrypted in memory until accessed. 67 | /// 68 | private byte[] RawHistoricalPasswordData { 69 | get { 70 | if (_rawHistoricalPasswordData == null) { return new byte[0]; } //return empty array if no value has been set so far 71 | return UnprotectData(_rawHistoricalPasswordData, RawHistoricalPasswordDataEntropy); 72 | } 73 | set { 74 | Rnd.GetBytes(RawHistoricalPasswordDataEntropy); //new entropy every save 75 | _rawHistoricalPasswordData = ProtectData(value, RawHistoricalPasswordDataEntropy); 76 | Array.Clear(value, 0, value.Length); 77 | } 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/PasswordPolicyStyle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Medo.Security.Cryptography.PasswordSafe { 4 | /// 5 | /// Password policy flags. 6 | /// 7 | public enum PasswordPolicyStyle { 8 | /// 9 | /// Lowercase characters are to be used. 10 | /// 11 | UseLowercase = 0x8000, 12 | /// 13 | /// Uppercase characters are to be used. 14 | /// 15 | UseUppercase = 0x4000, 16 | /// 17 | /// Digits are to be used. 18 | /// 19 | UseDigits = 0x2000, 20 | /// 21 | /// Symbols are to be used. 22 | /// 23 | UseSymbols = 0x1000, 24 | /// 25 | /// Hexadecimal digits are to be used. If set, no other flags can be set. 26 | /// 27 | UseHexDigits = 0x0800, 28 | /// 29 | /// Easy-vision is to be used. 30 | /// 31 | UseEasyVision = 0x0400, 32 | /// 33 | /// Resulting password should be adjusted to be more pronounceable. 34 | /// 35 | MakePronounceable = 0x0200, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/PasswordSafe.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | true 6 | Properties/App.snk 7 | false 8 | Medo.Security.Cryptography.PasswordSafe 9 | Josip Medved 10 | Reading and writing Password Safe v3 files. 11 | Copyright 2015 Josip Medved <jmedved@jmedved.com> 12 | https://github.com/medo64/PasswordSafe/blob/master/LICENSE.md 13 | https://www.medo64.com/passwordsafe/ 14 | https://raw.githubusercontent.com/medo64/PasswordSafe/master/ICON.png 15 | https://github.com/medo64/passwordsafe 16 | Git 17 | 0.0.0.0 18 | 0.0.0.0 19 | 0.0.0 20 | 21 | 22 | 23 | ..\..\Binaries\netstandard2.0\PasswordSafe.xml 24 | ..\..\Binaries\ 25 | 26 | 27 | 28 | ..\..\Binaries\netstandard2.0\PasswordSafe.xml 29 | ..\..\Binaries\ 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/Properties/App.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Libraries/PasswordSafe/Source/PasswordSafe/Properties/App.snk -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("PasswordSafe.Test, PublicKey=002400000480000094000000060200000024000052534131000400000100010041eaa8a4e78da38a3b7887dcb17b1a41b228908cd2d322565596db4cdd66074bfe15f9f676daa9306b555cbaed26a5a044d0b9906ee7775c1588c0422ad3fc0ea1ae668fd842afda5466c9431e0a0fe57ac16c006db91ed50d23ede170abe1f41ed62dd5751c317daca5e0ba03ca6ea080a37370144c16a3786ac0b4f3ae3696")] 4 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/Record.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace Medo.Security.Cryptography.PasswordSafe { 5 | /// 6 | /// Record field. 7 | /// 8 | [DebuggerDisplay("{RecordType}: {ToString(),nq}")] 9 | public class Record : Field { 10 | 11 | /// 12 | /// Create a new instance. 13 | /// 14 | /// Record type. 15 | public Record(RecordType type) 16 | : base() { 17 | RecordType = type; 18 | if (RecordType == RecordType.Autotype) { Text = @"\u\t\p\n"; } //to have default value 19 | } 20 | 21 | internal Record(RecordType type, byte[] rawData) : base() { 22 | if ((type < 0) || (type >= RecordType.EndOfEntry)) { throw new ArgumentOutOfRangeException(nameof(type), "Type not supported."); } 23 | RecordType = type; 24 | RawData = rawData; 25 | } 26 | 27 | internal Record(RecordCollection owner, RecordType type) 28 | : this(type) { 29 | Owner = owner; 30 | } 31 | 32 | 33 | internal RecordCollection Owner { get; set; } 34 | 35 | 36 | /// 37 | /// Gets field type. 38 | /// 39 | public RecordType RecordType { get; set; } 40 | 41 | /// 42 | /// Gets/sets text data. 43 | /// Null will be returned if conversion cannot be performed. 44 | /// For unknown field types, conversion will always be attempted. 45 | /// 46 | public override string Text { 47 | get { return base.Text; } 48 | set { 49 | if (RecordType == RecordType.Password) { //only for password change update history 50 | if ((Owner != null) && Owner.Contains(RecordType.PasswordHistory) && Owner.Contains(RecordType.Password)) { 51 | var history = new PasswordHistoryCollection(Owner); 52 | if (history.Enabled) { 53 | var time = Owner.Contains(RecordType.PasswordModificationTime) ? Owner[RecordType.PasswordModificationTime].Time : DateTime.UtcNow; 54 | history.AddPasswordToHistory(time, Text); //save current password 55 | } 56 | } 57 | } 58 | base.Text = value; 59 | } 60 | } 61 | 62 | 63 | /// 64 | /// Used to mark document as changed. 65 | /// 66 | protected override void MarkAsChanged() { 67 | if (Owner != null) { Owner.MarkAsChanged(RecordType); } 68 | } 69 | 70 | /// 71 | /// Used to mark document as accessed. 72 | /// 73 | protected override void MarkAsAccessed() { 74 | if (Owner != null) { Owner.MarkAsAccessed(RecordType); } 75 | } 76 | 77 | /// 78 | /// Gets if object is read-only. 79 | /// 80 | protected override bool IsReadOnly { 81 | get { return Owner?.IsReadOnly ?? false; } 82 | } 83 | 84 | 85 | /// 86 | /// Gets underlying data type for field. 87 | /// 88 | protected override PasswordSafeFieldDataType DataType { 89 | get { 90 | switch (RecordType) { 91 | case RecordType.Uuid: 92 | return PasswordSafeFieldDataType.Uuid; 93 | 94 | case RecordType.Group: 95 | case RecordType.Title: 96 | case RecordType.UserName: 97 | case RecordType.Notes: 98 | case RecordType.Password: 99 | case RecordType.Url: 100 | case RecordType.Autotype: 101 | case RecordType.PasswordHistory: 102 | case RecordType.PasswordPolicy: 103 | case RecordType.RunCommand: 104 | case RecordType.EmailAddress: 105 | case RecordType.OwnSymbolsForPassword: 106 | case RecordType.PasswordPolicyName: 107 | case RecordType.CreditCardNumber: 108 | case RecordType.CreditCardExpiration: 109 | case RecordType.CreditCardVerificationValue: 110 | case RecordType.CreditCardPin: 111 | case RecordType.QRCode: 112 | return PasswordSafeFieldDataType.Text; 113 | 114 | case RecordType.CreationTime: 115 | case RecordType.PasswordModificationTime: 116 | case RecordType.LastAccessTime: 117 | case RecordType.PasswordExpiryTime: 118 | case RecordType.LastModificationTime: 119 | return PasswordSafeFieldDataType.Time; 120 | 121 | case RecordType.TwoFactorKey: 122 | return PasswordSafeFieldDataType.Binary; 123 | 124 | default: return PasswordSafeFieldDataType.Unknown; 125 | } 126 | } 127 | } 128 | 129 | 130 | #region Clone 131 | 132 | /// 133 | /// Returns the exact copy of the record. 134 | /// 135 | public Record Clone() { 136 | return new Record(RecordType, base.RawDataDirect); 137 | } 138 | 139 | #endregion 140 | 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/PasswordSafe/RecordType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Medo.Security.Cryptography.PasswordSafe { 4 | /// 5 | /// Record field types. 6 | /// 7 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "This values map directly into the Password Safe type and there is no record type with value 0.")] 8 | public enum RecordType { 9 | /// 10 | /// UUID. 11 | /// 12 | Uuid = 0x01, 13 | /// 14 | /// Group. 15 | /// 16 | Group = 0x02, 17 | /// 18 | /// Title. 19 | /// 20 | Title = 0x03, 21 | /// 22 | /// User name. 23 | /// 24 | UserName = 0x04, 25 | /// 26 | /// Notes. 27 | /// 28 | Notes = 0x05, 29 | /// 30 | /// Password. 31 | /// 32 | Password = 0x06, 33 | /// 34 | /// Creation time. 35 | /// 36 | CreationTime = 0x07, 37 | /// 38 | /// Password modification time. 39 | /// 40 | PasswordModificationTime = 0x08, 41 | /// 42 | /// Last access time. 43 | /// 44 | LastAccessTime = 0x09, 45 | /// 46 | /// Password expiry time. 47 | /// 48 | PasswordExpiryTime = 0x0a, 49 | /// 50 | /// Last modification time. 51 | /// 52 | LastModificationTime = 0x0c, 53 | /// 54 | /// URL. 55 | /// 56 | Url = 0x0d, 57 | /// 58 | /// Autotype. 59 | /// 60 | Autotype = 0x0e, 61 | /// 62 | /// Password history. 63 | /// 64 | PasswordHistory = 0x0f, 65 | /// 66 | /// Password policy. 67 | /// 68 | PasswordPolicy = 0x10, 69 | /// 70 | /// Password expiry interval. 71 | /// 72 | PasswordExpiryInterval = 0x11, 73 | /// 74 | /// Run command. 75 | /// 76 | RunCommand = 0x12, 77 | /// 78 | /// Double-click action. 79 | /// 80 | DoubleClickAction = 0x13, 81 | /// 82 | /// E-mail address. 83 | /// 84 | EmailAddress = 0x14, 85 | /// 86 | /// Protected entry. 87 | /// 88 | ProtectedEntry = 0x15, 89 | /// 90 | /// Own symbols for password. 91 | /// 92 | OwnSymbolsForPassword = 0x16, 93 | /// 94 | /// Shift double-click action. 95 | /// 96 | ShiftDoubleClickAction = 0x17, 97 | /// 98 | /// Password policy name. 99 | /// 100 | PasswordPolicyName = 0x18, 101 | /// 102 | /// Entry keyboard shortcut. 103 | /// 104 | EntryKeyboardShortcut = 0x19, 105 | 106 | /// 107 | /// Two-factor authentication key. 108 | /// This is the shared secret for sites using Time-Based One-Time Password Algorithm (per RFC6238) such as Google Authenticator. At least 10 bytes. 109 | /// 110 | TwoFactorKey = 0x1b, 111 | /// 112 | /// Credit card number. 113 | /// Number should consist of digits and spaces. 114 | /// 115 | CreditCardNumber = 0x1c, 116 | /// 117 | /// Credit card expiration. 118 | /// Expiration should be MM/YY, where MM is 01-12, and YY 00-99. 119 | /// 120 | CreditCardExpiration = 0x1d, 121 | /// 122 | /// Credit card verification value. 123 | /// CVV (CVV2) is three or four digits. 124 | /// 125 | CreditCardVerificationValue = 0x1e, 126 | /// 127 | /// Credit card PIN. 128 | /// PIN is four to twelve digits long (ISO-9564). 129 | /// 130 | CreditCardPin = 0x1f, 131 | 132 | /// 133 | /// UTF-8 encoded text used for QR code generation. 134 | /// 135 | QRCode = 0x20, 136 | 137 | /// 138 | /// End of entries. 139 | /// 140 | EndOfEntry = 0xFF, 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Libraries/PasswordSafe/Source/omnisharp.json: -------------------------------------------------------------------------------- 1 | { 2 | "FormattingOptions": { 3 | "useTabs": false, 4 | "indentationSize": 4, 5 | "tabSize": 4, 6 | "newLine": "\n", 7 | 8 | "SpacingAfterMethodDeclarationName": false, 9 | "SpaceWithinMethodDeclarationParenthesis": false, 10 | "SpaceBetweenEmptyMethodDeclarationParentheses": false, 11 | "SpaceAfterMethodCallName": false, 12 | "SpaceWithinMethodCallParentheses": false, 13 | "SpaceBetweenEmptyMethodCallParentheses": false, 14 | "SpaceAfterControlFlowStatementKeyword": true, 15 | "SpaceWithinExpressionParentheses": false, 16 | "SpaceWithinCastParentheses": false, 17 | "SpaceWithinOtherParentheses": false, 18 | "SpaceAfterCast": false, 19 | "SpacesIgnoreAroundVariableDeclaration": false, 20 | "SpaceBeforeOpenSquareBracket": false, 21 | "SpaceBetweenEmptySquareBrackets": false, 22 | "SpaceWithinSquareBrackets": false, 23 | "SpaceAfterColonInBaseTypeDeclaration": true, 24 | "SpaceAfterComma": true, 25 | "SpaceAfterDot": false, 26 | "SpaceAfterSemicolonsInForStatement": true, 27 | "SpaceBeforeColonInBaseTypeDeclaration": true, 28 | "SpaceBeforeComma": false, 29 | "SpaceBeforeDot": false, 30 | "SpaceBeforeSemicolonsInForStatement": false, 31 | "SpacingAroundBinaryOperator": "single", 32 | 33 | "IndentBraces": false, 34 | "IndentBlock": true, 35 | "IndentSwitchSection": true, 36 | "IndentSwitchCaseSection": true, 37 | "LabelPositioning": "flushLeft", 38 | "WrappingPreserveSingleLine": true, 39 | "WrappingKeepStatementsOnSingleLine": true, 40 | 41 | "NewLinesForBracesInTypes": false, 42 | "NewLinesForBracesInMethods": false, 43 | "NewLinesForBracesInProperties": false, 44 | "NewLinesForBracesInAccessors": false, 45 | "NewLinesForBracesInAnonymousMethods": false, 46 | "NewLinesForBracesInControlBlocks": false, 47 | "NewLinesForBracesInAnonymousTypes": false, 48 | "NewLinesForBracesInObjectCollectionArrayInitializers": false, 49 | "NewLinesForBracesInLambdaExpressionBody": false, 50 | "NewLineForElse": false, 51 | "NewLineForCatch": false, 52 | "NewLineForFinally": false, 53 | "NewLineForMembersInObjectInit": false, 54 | "NewLineForMembersInAnonymousTypes": false, 55 | "NewLineForClausesInQuery": false 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Libraries/subtree-pull-command-example.txt: -------------------------------------------------------------------------------- 1 | git subtree pull --prefix Libraries/PasswordSafe https://github.com/medo64/PasswordSafe.git main --squash -m"PasswordSafe: Pull latest" 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [Bimil](https://medo64.com/bimil/) 2 | ================================== 3 | 4 | Small password manager. 5 | 6 | Saved files are based on Password Safe file format with a few custom fields. 7 | 8 | 9 | 10 | ## Auto-type 11 | 12 | Auto-type functionality will simulate keyboard presses. Following escape 13 | characters are supported: 14 | 15 | \u User name field. 16 | \p Password field. 17 | \2 Two-factor authentication code. 18 | \cn Credit card number. 19 | \ct Credit card number (tab separated). 20 | \ce Credit card expiration. 21 | \cv Credit card security code. 22 | \cp Credit card pin number. 23 | \g Group field. 24 | \i Title field. 25 | \l URL field. 26 | \m E-mail field. 27 | \o Notes field. 28 | \o### Nth line of Notes field. If line doesn't exist, it has no effect. 29 | \b Backpace key. 30 | \t Tab key. 31 | \s Shift+Tab key. 32 | \n Enter key. 33 | \\ Backslash (\) key. 34 | \d### Delay between characters in milliseconds, instead of 10 (default). 35 | \w### Wait in milliseconds. 36 | \W### Wait in seconds. 37 | \z Invokes the alternative SendKeys method. 38 | All other text is typed as-is. 39 | -------------------------------------------------------------------------------- /Setup/Bimil.iss: -------------------------------------------------------------------------------- 1 | #define AppName GetStringFileInfo('..\Binaries\Bimil.exe', 'ProductName') 2 | #define AppVersion GetStringFileInfo('..\Binaries\Bimil.exe', 'ProductVersion') 3 | #define AppFileVersion GetStringFileInfo('..\Binaries\Bimil.exe', 'FileVersion') 4 | #define AppCompany GetStringFileInfo('..\Binaries\Bimil.exe', 'CompanyName') 5 | #define AppCopyright GetStringFileInfo('..\Binaries\Bimil.exe', 'LegalCopyright') 6 | #define AppBase LowerCase(StringChange(AppName, ' ', '')) 7 | #define AppSetupFile AppBase + StringChange(AppVersion, '.', '') 8 | 9 | #define AppVersionEx StringChange(AppVersion, '0.00', '') 10 | #ifdef VersionHash 11 | # if "" != VersionHash 12 | # define AppVersionEx AppVersionEx + " (" + VersionHash + ")" 13 | # endif 14 | #endif 15 | 16 | 17 | [Setup] 18 | AppName={#AppName} 19 | AppVersion={#AppVersion} 20 | AppVerName={#AppName} {#AppVersion} 21 | AppPublisher={#AppCompany} 22 | AppPublisherURL=https://medo64.com/{#AppBase}/ 23 | AppCopyright={#AppCopyright} 24 | VersionInfoProductVersion={#AppVersion} 25 | VersionInfoProductTextVersion={#AppVersionEx} 26 | VersionInfoVersion={#AppFileVersion} 27 | DefaultDirName={commonpf}\{#AppCompany}\{#AppName} 28 | OutputBaseFilename={#AppSetupFile} 29 | OutputDir=..\Releases 30 | SourceDir=..\Binaries 31 | AppId=JosipMedved_Bimil 32 | CloseApplications="yes" 33 | RestartApplications="no" 34 | AppMutex=Global\JosipMedved_Bimil 35 | UninstallDisplayIcon={app}\Bimil.exe 36 | AlwaysShowComponentsList=no 37 | ArchitecturesInstallIn64BitMode=x64 38 | DisableProgramGroupPage=yes 39 | MergeDuplicateFiles=yes 40 | MinVersion=0,6.0 41 | PrivilegesRequired=admin 42 | ShowLanguageDialog=no 43 | SolidCompression=yes 44 | ChangesAssociations=yes 45 | DisableWelcomePage=yes 46 | LicenseFile=..\Setup\License.rtf 47 | 48 | 49 | [Messages] 50 | SetupAppTitle=Setup {#AppName} {#AppVersionEx} 51 | SetupWindowTitle=Setup {#AppName} {#AppVersionEx} 52 | BeveledLabel=medo64.com 53 | 54 | 55 | [Tasks] 56 | Name: extension_psafe3; GroupDescription: "Associate additional extension:"; Description: "Password Safe 3.x (.psafe3)"; Flags: unchecked; 57 | 58 | 59 | [Files] 60 | Source: "Bimil.exe"; DestDir: "{app}"; Flags: ignoreversion; 61 | Source: "Bimil.pdb"; DestDir: "{app}"; Flags: ignoreversion; 62 | Source: "..\README.md"; DestDir: "{app}"; DestName: "ReadMe.txt"; Flags: overwritereadonly uninsremovereadonly; Attribs: readonly; 63 | Source: "..\LICENSE.md"; DestDir: "{app}"; DestName: "License.txt"; Flags: overwritereadonly uninsremovereadonly; Attribs: readonly; 64 | Source: "..\WORDS.md"; DestDir: "{app}"; DestName: "Words.txt"; Flags: overwritereadonly uninsremovereadonly; Attribs: readonly; 65 | 66 | 67 | [Icons] 68 | Name: "{userstartmenu}\Bimil"; Filename: "{app}\Bimil.exe" 69 | 70 | 71 | [Registry] 72 | Root: HKCU; Subkey: "Software\Josip Medved\Bimil"; ValueType: dword; ValueName: "Installed"; ValueData: "1"; Flags: uninsdeletekey 73 | Root: HKCU; Subkey: "Software\Josip Medved"; Flags: uninsdeletekeyifempty 74 | 75 | Root: HKCR; Subkey: ".bimil"; ValueType: string; ValueName: ""; ValueData: "BimilFile"; Flags: uninsclearvalue; 76 | Root: HKCR; Subkey: ".psafe3"; ValueType: string; ValueName: ""; ValueData: "BimilFile"; Flags: uninsclearvalue; Tasks: extension_psafe3; 77 | 78 | Root: HKCR; Subkey: "BimilFile"; ValueType: none; Flags: uninsdeletekey; 79 | Root: HKCR; Subkey: "BimilFile"; ValueType: string; ValueName: ""; ValueData: "Bimil"; 80 | Root: HKCR; Subkey: "BimilFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\Bimil.exe"; 81 | Root: HKCR; Subkey: "BimilFile\shell\Open"; ValueType: string; ValueName: "MultiSelectModel"; ValueData: "Player"; 82 | Root: HKCR; Subkey: "BimilFile\shell\Open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\Bimil.exe"" ""%1"""; 83 | 84 | [Run] 85 | Filename: "{app}\Bimil.exe"; Flags: postinstall nowait skipifsilent runasoriginaluser; Description: "Launch application now"; 86 | Filename: "{app}\ReadMe.txt"; Flags: postinstall nowait skipifsilent runasoriginaluser unchecked shellexec; Description: "View ReadMe.txt"; 87 | 88 | 89 | [Code] 90 | 91 | procedure InitializeWizard; 92 | begin 93 | WizardForm.LicenseAcceptedRadio.Checked := True; 94 | end; 95 | -------------------------------------------------------------------------------- /Setup/License.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033\deflangfe1033{\fonttbl{\f0\fswiss\fprq2\fcharset0 Calibri;}{\f1\fnil\fcharset2 Symbol;}} 2 | {\*\generator Riched20 10.0.17134}{\*\mmathPr\mnaryLim0\mdispDef1\mwrapIndent1440 }\viewkind4\uc1 3 | \pard\nowidctlpar\sa200\sl276\slmult1\b\f0\fs22\lang9 The MIT License\par 4 | \b0 Copyright 2014 Josip Medved \par 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\par 6 | 7 | \pard{\pntext\f1\'B7\tab}{\*\pn\pnlvlblt\pnf1\pnindent0{\pntxtb\'B7}}\nowidctlpar\fi-360\li720\sa200\sl276\slmult1 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\par 8 | {\pntext\f1\'B7\tab}THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\par 9 | } 10 | -------------------------------------------------------------------------------- /Setup/Publish-GitHub.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OWNER=medo64 4 | REPOSITORY=bimil 5 | TOKEN=`cat ~/GitHub.token 2> /dev/null` 6 | 7 | if [[ "$TOKEN" == "" ]]; then 8 | echo "No GitHub token found." >&2 9 | exit 1 10 | fi 11 | 12 | VERSION_HASH=`git log -n 1 --format=%h` 13 | VERSION_NUMBER=`git rev-list --count HEAD` 14 | FILE_PREFIX=$REPOSITORY-rev$VERSION_NUMBER-$VERSION_HASH 15 | 16 | 17 | BRANCH=`git rev-parse --abbrev-ref HEAD` 18 | 19 | if [[ "$BRANCH" == "master" ]]; then 20 | UNCOMMITED_FILE_COUNT=`git ls | sed 1d | wc -l` 21 | if [[ $UNCOMMITED_FILE_COUNT == 0 ]]; then 22 | git push --dry-run 2>&1 | grep --quiet "Everything up-to-date" 23 | if [[ $? == 0 ]]; then 24 | ./Publish.cmd 25 | 26 | for FILE_EXTENSION in "exe" "zip"; do 27 | if [ ! -e ../Releases/$FILE_PREFIX.$FILE_EXTENSION ]; then 28 | echo "Executables cannot be found." >&2 29 | exit 1 30 | fi 31 | done 32 | 33 | RELEASE_URL=`curl -s -H "Authorization: token $TOKEN" https://api.github.com/repos/$OWNER/$REPOSITORY/releases/tags/latest | grep "\"url\"" | head -1 | cut -d\" -f4` 34 | if [[ "$RELEASE_URL" != "" ]]; then 35 | curl -s -H "Authorization: token $TOKEN" -X DELETE $RELEASE_URL 36 | fi 37 | 38 | git push origin :refs/tags/latest 2> /dev/null 39 | 40 | ASSET_UPLOAD_URL=`curl -s -H "Authorization: token $TOKEN" --data "{\"tag_name\": \"latest\", \"target_commitish\": \"master\", \"name\": \"Most recent build\", \"body\": \"This is the most recent automated build (#$VERSION_HASH, revision $VERSION_NUMBER).\n\nFor the latest stable release go to https://www.medo64.com/$REPOSITORY/.\", \"draft\": false, \"prerelease\": true}" -X POST https://api.github.com/repos/$OWNER/$REPOSITORY/releases | grep "\"upload_url\"" | cut -d\" -f4 | cut -d{ -f1` 41 | for FILE_EXTENSION in "exe" "zip"; do 42 | UPLOAD_RESULT=`curl -s -H "Authorization: token $TOKEN" -H "Content-Type: application/octet-stream" --data-binary @../Releases/$FILE_PREFIX.$FILE_EXTENSION -X POST $ASSET_UPLOAD_URL?name=$FILE_PREFIX.$FILE_EXTENSION` 43 | echo $UPLOAD_RESULT | grep --quiet "browser_download_url" 44 | if [[ $? == 0 ]]; then 45 | echo "$FILE_PREFIX.$FILE_EXTENSION" 46 | else 47 | echo "Failed upload for $FILE_PREFIX.$FILE_EXTENSION" >&2 48 | 49 | RELEASE_URL=`curl -s -H "Authorization: token $TOKEN" https://api.github.com/repos/$OWNER/$REPOSITORY/releases/tags/latest | grep "\"url\"" | head -1 | cut -d\" -f4` 50 | curl -s -H "Authorization: token $TOKEN" -X DELETE $RELEASE_URL 51 | 52 | exit 1; 53 | fi 54 | done 55 | echo 56 | echo "https://github.com/medo64/$REPOSITORY/releases/tag/latest" 57 | else 58 | echo "Not all changes have been pushed to origin." >&2 59 | exit 1 60 | fi 61 | else 62 | echo "Not all modified files are commited." >&2 63 | exit 1 64 | fi 65 | else 66 | echo "Not in master branch." >&2 67 | exit 1 68 | fi 69 | -------------------------------------------------------------------------------- /Setup/deb/DEBIAN/config: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | # Show dialog if repository is not there 4 | SOURCE_FILE="/etc/apt/sources.list.d/medo64.list" 5 | if ! [ -f "$SOURCE_FILE" ] && [ "$DEBIAN_FRONTEND" != "noninteractive" ]; then 6 | . /usr/share/debconf/confmodule 7 | 8 | db_input high bimil/add_repository 9 | db_go 10 | db_get bimil/add_repository 11 | case "$RET" in 12 | n*|N*|f*|F*) DO_ADD_REPO=0 ;; 13 | esac 14 | fi 15 | 16 | DO_ADD_REPO=0 17 | SOURCE_FILE="/etc/apt/sources.list.d/medo64.list" 18 | if ! [ -f "$SOURCE_FILE" ] && [ "$DEBIAN_FRONTEND" != "noninteractive" ]; then 19 | . /usr/share/debconf/confmodule 20 | db_get bimil/add_repository 21 | case "$RET" in 22 | y*|Y*|T*|t*) DO_ADD_REPO=1 ;; 23 | esac 24 | fi 25 | 26 | if [ "$DO_ADD_REPO" -ne 0 ]; then 27 | echo "deb http://packages.medo64.com/deb stable main" > "$SOURCE_FILE" 28 | if [ -d "/etc/apt/trusted.gpg.d/" ]; then 29 | echo "-----BEGIN PGP PUBLIC KEY BLOCK----- 30 | Version: GnuPG v1 31 | 32 | mQENBFqxbGoBCACnavHwueNmk947TOkLDsnay/4uQIan79YFyHnv2zTFRuszuwFw 33 | 65sbflaBTjR57CZRzNyXHEcPb/NrxxuhXKHOXzbURy6FBv0CQZVjf9bm0Lroq5Ab 34 | oZ9v0UZukpLoAyHkNca/zyHJoHtAq2Deq5X44dPRsCALn2zWJKya+hyA8ZYnGlcG 35 | hERdnR8mMB+i0xb44rnDNY7GwdRykSialn3WopSFBrHv9pYOd2wtnrb3H9pFjT3H 36 | jNp1+3/4mW6WDdVzC7mkJk9ia8mHqAw0IgtE7fP7HYcJnmdqCqgI3sZBR+D1VpyM 37 | CgNGK6DrGD5IUp1ktZe2wAL8Jig2/Xmk02g7ABEBAAG0L0pvc2lwIE1lZHZlZCAo 38 | UmVwb3NpdG9yeSkgPGptZWR2ZWRAam1lZHZlZC5jb20+iQE4BBMBCAAiBQJasWxq 39 | AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRA4LnS5Ecf8hgj0B/0XeXn8 40 | aPkDLwHJzLbily9SUxn3WYcZhXEE1JSXtDHWI1owS/TT7kZxswHRh1DyZDQJSK0B 41 | LCsHx1zoIVIvlkGz8PNfN+G/E+2CAI8/cdDBa5z8DM+w8wpQ02NZjWnS5pmpr3MT 42 | sP7hLlyEeq/ErtKmZMlquDtTR7lUjundgtUIgofiSDiri/1xNynUmPgykkKR/vR2 43 | mrPHCxIqiEEq5RkFvIDpH6zltld97AeNP2vEcmkpyS9npFRkHgPNjxZhvHhhjbHP 44 | pXF542bTCX+bXOfPWbdl/mnIBRKdsNGNu/FbXTQ4gEmXQwmki5YL8kRwbBloxuH2 45 | 5VcfjRkkgrnxUy4S 46 | =gY4j 47 | -----END PGP PUBLIC KEY BLOCK-----" > /etc/apt/trusted.gpg.d/medo64.asc 48 | else # add it using deprecated apt-key 49 | echo "-----BEGIN PGP PUBLIC KEY BLOCK----- 50 | Version: GnuPG v1 51 | 52 | mQENBFqxbGoBCACnavHwueNmk947TOkLDsnay/4uQIan79YFyHnv2zTFRuszuwFw 53 | 65sbflaBTjR57CZRzNyXHEcPb/NrxxuhXKHOXzbURy6FBv0CQZVjf9bm0Lroq5Ab 54 | oZ9v0UZukpLoAyHkNca/zyHJoHtAq2Deq5X44dPRsCALn2zWJKya+hyA8ZYnGlcG 55 | hERdnR8mMB+i0xb44rnDNY7GwdRykSialn3WopSFBrHv9pYOd2wtnrb3H9pFjT3H 56 | jNp1+3/4mW6WDdVzC7mkJk9ia8mHqAw0IgtE7fP7HYcJnmdqCqgI3sZBR+D1VpyM 57 | CgNGK6DrGD5IUp1ktZe2wAL8Jig2/Xmk02g7ABEBAAG0L0pvc2lwIE1lZHZlZCAo 58 | UmVwb3NpdG9yeSkgPGptZWR2ZWRAam1lZHZlZC5jb20+iQE4BBMBCAAiBQJasWxq 59 | AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRA4LnS5Ecf8hgj0B/0XeXn8 60 | aPkDLwHJzLbily9SUxn3WYcZhXEE1JSXtDHWI1owS/TT7kZxswHRh1DyZDQJSK0B 61 | LCsHx1zoIVIvlkGz8PNfN+G/E+2CAI8/cdDBa5z8DM+w8wpQ02NZjWnS5pmpr3MT 62 | sP7hLlyEeq/ErtKmZMlquDtTR7lUjundgtUIgofiSDiri/1xNynUmPgykkKR/vR2 63 | mrPHCxIqiEEq5RkFvIDpH6zltld97AeNP2vEcmkpyS9npFRkHgPNjxZhvHhhjbHP 64 | pXF542bTCX+bXOfPWbdl/mnIBRKdsNGNu/FbXTQ4gEmXQwmki5YL8kRwbBloxuH2 65 | 5VcfjRkkgrnxUy4S 66 | =gY4j 67 | -----END PGP PUBLIC KEY BLOCK-----" | apt-key add - 68 | fi 69 | fi 70 | 71 | # Done 72 | exit 0 73 | -------------------------------------------------------------------------------- /Setup/deb/DEBIAN/control: -------------------------------------------------------------------------------- 1 | Package: bimil 2 | Version: MAJOR.MINOR 3 | Architecture: all 4 | Maintainer: Josip Medved 5 | Homepage: https://www.medo64.com/bimil/ 6 | Description: Password manager. 7 | A small password manager compatible with Password Safe file format. 8 | Section: misc 9 | Priority: optional 10 | Depends: debconf, gnupg2, mono-complete (>=4.2), xdotool 11 | Build-Depends: mono-complete (>=4.2) 12 | -------------------------------------------------------------------------------- /Setup/deb/DEBIAN/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | chmod +x /opt/bimil/bimil 5 | rm "/usr/bin/bimil" 2>/dev/null || true 6 | ln -s /opt/bimil/bimil /usr/bin/bimil 7 | 8 | # Just loading to suppress warning 9 | . /usr/share/debconf/confmodule || true 10 | 11 | # Done 12 | exit 0 13 | -------------------------------------------------------------------------------- /Setup/deb/DEBIAN/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Remove link 5 | if [ "$1" == "remove" ]; then 6 | if [ -f "/usr/bin/bimil" ]; then 7 | rm "/usr/bin/bimil" 8 | fi 9 | 10 | if [ -f "$HOME/.bimil" ]; then 11 | rm "$HOME/.bimil" 12 | fi 13 | fi 14 | 15 | # Purge debconf 16 | if [ "$1" = "purge" -a -e /usr/share/debconf/confmodule ]; then 17 | . /usr/share/debconf/confmodule 18 | db_purge 19 | fi 20 | 21 | # Done 22 | exit 0 23 | -------------------------------------------------------------------------------- /Setup/deb/DEBIAN/templates: -------------------------------------------------------------------------------- 1 | Template: bimil/add_repository 2 | Type: boolean 3 | Default: true 4 | Description: Should the repository be added to the system? 5 | If selected, the repository for the package will be added for the purpose 6 | of simplifying the future upgrades. If not added, each update will have to 7 | be manually installed. 8 | -------------------------------------------------------------------------------- /Setup/deb/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: bimil 3 | Upstream-Contact: Josip Medved 4 | Source: https://www.medo64.com/bimil/ 5 | 6 | Files: * 7 | Copyright: 2010 Josip Medved 8 | License: MIT 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | this software and associated documentation files (the "Software"), to deal in 11 | the Software without restriction, including without limitation the rights to 12 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 13 | of the Software, and to permit persons to whom the Software is furnished to do 14 | so, subject to the following conditions: 15 | . 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | . 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /Setup/deb/usr/share/applications/bimil.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Bimil 3 | GenericName=Password Manager 4 | Comment=A small password manager. 5 | TryExec=/opt/bimil/bimil 6 | Exec=/opt/bimil/bimil %f 7 | Icon=bimil 8 | Type=Application 9 | Categories=GTK;GNOME;Utility; 10 | MimeType=application/x-bimil 11 | -------------------------------------------------------------------------------- /Setup/deb/usr/share/icons/hicolor/128x128/apps/bimil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Setup/deb/usr/share/icons/hicolor/128x128/apps/bimil.png -------------------------------------------------------------------------------- /Setup/deb/usr/share/icons/hicolor/16x16/apps/bimil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Setup/deb/usr/share/icons/hicolor/16x16/apps/bimil.png -------------------------------------------------------------------------------- /Setup/deb/usr/share/icons/hicolor/192x192/apps/bimil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Setup/deb/usr/share/icons/hicolor/192x192/apps/bimil.png -------------------------------------------------------------------------------- /Setup/deb/usr/share/icons/hicolor/24x24/apps/bimil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Setup/deb/usr/share/icons/hicolor/24x24/apps/bimil.png -------------------------------------------------------------------------------- /Setup/deb/usr/share/icons/hicolor/256x256/apps/bimil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Setup/deb/usr/share/icons/hicolor/256x256/apps/bimil.png -------------------------------------------------------------------------------- /Setup/deb/usr/share/icons/hicolor/32x32/apps/bimil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Setup/deb/usr/share/icons/hicolor/32x32/apps/bimil.png -------------------------------------------------------------------------------- /Setup/deb/usr/share/icons/hicolor/48x48/apps/bimil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Setup/deb/usr/share/icons/hicolor/48x48/apps/bimil.png -------------------------------------------------------------------------------- /Setup/deb/usr/share/icons/hicolor/64x64/apps/bimil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Setup/deb/usr/share/icons/hicolor/64x64/apps/bimil.png -------------------------------------------------------------------------------- /Setup/deb/usr/share/icons/hicolor/96x96/apps/bimil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Setup/deb/usr/share/icons/hicolor/96x96/apps/bimil.png -------------------------------------------------------------------------------- /Setup/deb/usr/share/mime/packages/bimil.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Bimil password file 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Setup/package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while getopts ":h" OPT 4 | do 5 | case $OPT in 6 | h) 7 | echo 8 | echo " SYNOPSIS" 9 | echo -e " `echo $0 | xargs basename` \033[4mfile\033[0m" | fmt 10 | echo 11 | echo -e " \033[4mfile\033[0m" 12 | echo " File from release directory." | fmt 13 | echo 14 | echo " DESCRIPTION" 15 | echo " Creates debian package based on zipped release file." | fmt 16 | echo 17 | echo " SAMPLES" 18 | echo " $0 bimil210.zip" | fmt 19 | echo 20 | exit 0 21 | ;; 22 | 23 | \?) 24 | echo "Invalid option: -$OPTARG!" >&2 25 | exit 1 26 | ;; 27 | 28 | :) 29 | echo "Option -$OPTARG requires an argument!" >&2 30 | exit 1 31 | ;; 32 | esac 33 | done 34 | 35 | shift $(( OPTIND - 1 )) 36 | 37 | if [[ "$2" != "" ]] 38 | then 39 | echo "Too many arguments!" >&2 40 | exit 1 41 | fi 42 | 43 | 44 | if [[ ! "$(uname -a)" =~ "GNU/Linux" ]] 45 | then 46 | echo "Must run under Linux!" >&2 47 | exit 1 48 | fi 49 | 50 | which dpkg-deb &> /dev/null 51 | if [ ! $? -eq 0 ] 52 | then 53 | echo "Package dpkg-deb not installed!" >&2 54 | exit 1 55 | fi 56 | 57 | 58 | DIRECTORY_ROOT=`mktemp -d` 59 | 60 | terminate() { 61 | rm -R $DIRECTORY_ROOT 2> /dev/null 62 | } 63 | trap terminate INT EXIT 64 | 65 | 66 | if [ "$EUID" -ne 0 ] 67 | then 68 | echo "Must run as root (try sudo)!" >&2 69 | exit 1 70 | fi 71 | 72 | 73 | DIRECTORY_RELEASE="../Releases" 74 | FILE_RELEASE="$1" 75 | PATH_RELEASE="$DIRECTORY_RELEASE/$FILE_RELEASE" 76 | 77 | if [[ ! $PATH_RELEASE =~ \.zip$ ]] 78 | then 79 | echo "Release file $FILE_RELEASE does not end in .zip!" >&2 80 | exit 1 81 | fi 82 | 83 | if [ ! -e "$PATH_RELEASE" ] 84 | then 85 | echo "Cannot find release file $FILE_RELEASE!" >&2 86 | exit 1 87 | fi 88 | 89 | 90 | RELEASE_VERSION=`echo $FILE_RELEASE | sed -e s/[^0-9]//g` 91 | 92 | if (( ${#RELEASE_VERSION} != 3 )) 93 | then 94 | echo "Cannot extract version from $FILE_RELEASE!" >&2 95 | exit 1 96 | fi 97 | 98 | RELEASE_VERSION_MAJOR=`echo -n $RELEASE_VERSION | head -c 1` 99 | RELEASE_VERSION_MINOR=`echo -n $RELEASE_VERSION | tail -c 2` 100 | RELEASE_ARCHITECTURE=`grep "Architecture:" ./deb/DEBIAN/control | sed "s/Architecture://" | sed "s/[^a-z]//g"` 101 | 102 | PACKAGE_NAME="bimil_${RELEASE_VERSION_MAJOR}.${RELEASE_VERSION_MINOR}_${RELEASE_ARCHITECTURE}" 103 | DIRECTORY_PACKAGE="$DIRECTORY_ROOT/$PACKAGE_NAME" 104 | 105 | mkdir $DIRECTORY_PACKAGE 106 | cp -R ./deb/DEBIAN $DIRECTORY_PACKAGE/ 107 | cp -R ./deb/usr $DIRECTORY_PACKAGE/ 108 | 109 | find $DIRECTORY_PACKAGE -type d -exec chmod 755 {} + 110 | find $DIRECTORY_PACKAGE -type f -exec chmod 644 {} + 111 | chmod 755 $DIRECTORY_PACKAGE/DEBIAN/config 112 | chmod 755 $DIRECTORY_PACKAGE/DEBIAN/*inst 113 | chmod 755 $DIRECTORY_PACKAGE/DEBIAN/*rm 114 | 115 | sed -i "s/MAJOR/$RELEASE_VERSION_MAJOR/" $DIRECTORY_PACKAGE/DEBIAN/control 116 | sed -i "s/MINOR/$RELEASE_VERSION_MINOR/" $DIRECTORY_PACKAGE/DEBIAN/control 117 | 118 | mkdir -p "$DIRECTORY_PACKAGE/usr/share/doc/bimil/" 119 | cp ./deb/copyright "$DIRECTORY_PACKAGE/usr/share/doc/bimil/copyright" 120 | chmod 644 "$DIRECTORY_PACKAGE/usr/share/doc/bimil/copyright" 121 | 122 | mkdir -p "$DIRECTORY_PACKAGE/opt/bimil" 123 | unzip -LL "$PATH_RELEASE" -d "$DIRECTORY_PACKAGE/opt/bimil" > /dev/null 124 | if [ ! $? -eq 0 ] 125 | then 126 | echo "Cannot extract archive!" >&2 127 | exit 1 128 | fi 129 | 130 | cat << 'EOF' > "$DIRECTORY_PACKAGE/opt/bimil/bimil" 131 | #!/bin/bash 132 | TERM=xterm 133 | /usr/bin/mono /opt/bimil/bimil.exe "$@" 134 | EOF 135 | chmod 755 "$DIRECTORY_PACKAGE/opt/bimil/bimil" 136 | 137 | dpkg-deb --build $DIRECTORY_PACKAGE > /dev/null 138 | 139 | cp "$DIRECTORY_ROOT/$PACKAGE_NAME.deb" $DIRECTORY_RELEASE 140 | if [ $? -eq 0 ]; then 141 | echo "Package $DIRECTORY_RELEASE/$PACKAGE_NAME.deb successfully created." >&2 142 | else 143 | echo "Didn't find output Debian package!" >&2 144 | exit 1 145 | fi 146 | -------------------------------------------------------------------------------- /Source/Bimil.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.26730.12 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bimil", "Bimil\Bimil.csproj", "{A0726ACD-6850-4C24-86D8-EAFF2574F866}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Debug|x86 = Debug|x86 11 | Release|Any CPU = Release|Any CPU 12 | Release|x86 = Release|x86 13 | WindowsStore|Any CPU = WindowsStore|Any CPU 14 | WindowsStore|x86 = WindowsStore|x86 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {A0726ACD-6850-4C24-86D8-EAFF2574F866}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {A0726ACD-6850-4C24-86D8-EAFF2574F866}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {A0726ACD-6850-4C24-86D8-EAFF2574F866}.Debug|x86.ActiveCfg = Debug|Any CPU 20 | {A0726ACD-6850-4C24-86D8-EAFF2574F866}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {A0726ACD-6850-4C24-86D8-EAFF2574F866}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {A0726ACD-6850-4C24-86D8-EAFF2574F866}.Release|x86.ActiveCfg = Release|Any CPU 23 | {A0726ACD-6850-4C24-86D8-EAFF2574F866}.WindowsStore|Any CPU.ActiveCfg = WindowsStore|Any CPU 24 | {A0726ACD-6850-4C24-86D8-EAFF2574F866}.WindowsStore|Any CPU.Build.0 = WindowsStore|Any CPU 25 | {A0726ACD-6850-4C24-86D8-EAFF2574F866}.WindowsStore|x86.ActiveCfg = WindowsStore|Any CPU 26 | {A0726ACD-6850-4C24-86D8-EAFF2574F866}.WindowsStore|x86.Build.0 = WindowsStore|Any CPU 27 | EndGlobalSection 28 | GlobalSection(SolutionProperties) = preSolution 29 | HideSolutionNode = FALSE 30 | EndGlobalSection 31 | GlobalSection(ExtensibilityGlobals) = postSolution 32 | SolutionGuid = {AA892B6D-D3D7-45B5-BDC8-5769577D8185} 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /Source/Bimil/(Medo)/EntryAssembly [003].cs: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | 3 | //2008-06-06: Added Copyright. 4 | //2008-05-22: Added Description. 5 | //2007-12-31: New version. 6 | 7 | 8 | using System.Reflection; 9 | 10 | namespace Medo.Reflection { 11 | 12 | /// 13 | /// Returns various info about assembly that started process. 14 | /// 15 | public static class EntryAssembly { 16 | 17 | private readonly static Assembly Assembly = System.Reflection.Assembly.GetEntryAssembly(); 18 | //private readonly static AssemblyName AssemblyName = Assembly.GetName(); 19 | 20 | /// 21 | /// Gets entry assembly's full name. 22 | /// 23 | public static string FullName { 24 | get { return System.Reflection.Assembly.GetEntryAssembly().GetName().FullName; } 25 | } 26 | 27 | /// 28 | /// Gets entry assembly's application name. 29 | /// 30 | public static string Name { 31 | get { return System.Reflection.Assembly.GetEntryAssembly().GetName().Name; } 32 | } 33 | 34 | /// 35 | /// Gets entry assembly's version. 36 | /// 37 | public static System.Version Version { 38 | get { return System.Reflection.Assembly.GetEntryAssembly().GetName().Version; } 39 | } 40 | 41 | /// 42 | /// Returns entry assembly's version in x.xx format. 43 | /// 44 | public static string ShortVersionString { 45 | get { 46 | System.Version version = EntryAssembly.Version; 47 | return version.Major.ToString("0", System.Globalization.CultureInfo.InvariantCulture) + "." + version.Minor.ToString("00", System.Globalization.CultureInfo.InvariantCulture); 48 | } 49 | } 50 | 51 | /// 52 | /// Returns entry assembly's version in x.xx.xxx.xxxx format. 53 | /// 54 | public static string LongVersionString { 55 | get { 56 | System.Version version = EntryAssembly.Version; 57 | return version.Major.ToString("0", System.Globalization.CultureInfo.CurrentCulture) + "." + version.Minor.ToString("00", System.Globalization.CultureInfo.CurrentCulture) + "." + version.Build.ToString("000", System.Globalization.CultureInfo.CurrentCulture) + "." + version.Revision.ToString("0000", System.Globalization.CultureInfo.CurrentCulture); 58 | } 59 | } 60 | 61 | /// 62 | /// Returns entry assembly's company or null if not found. 63 | /// 64 | public static string Company { 65 | get{ 66 | object[] companyAttributes = System.Reflection.Assembly.GetEntryAssembly().GetCustomAttributes(typeof(System.Reflection.AssemblyCompanyAttribute), true); 67 | if ((companyAttributes != null) && (companyAttributes.Length >= 1)) { 68 | return ((System.Reflection.AssemblyCompanyAttribute)companyAttributes[companyAttributes.Length - 1]).Company; 69 | } 70 | return null; 71 | } 72 | } 73 | 74 | /// 75 | /// Returns entry assembly's title or name if title is not found. 76 | /// 77 | public static string Title { 78 | get{ 79 | object[] titleAttributes = System.Reflection.Assembly.GetEntryAssembly().GetCustomAttributes(typeof(System.Reflection.AssemblyTitleAttribute), true); 80 | if ((titleAttributes != null) && (titleAttributes.Length >= 1)) { 81 | return ((System.Reflection.AssemblyTitleAttribute)titleAttributes[titleAttributes.Length - 1]).Title; 82 | } else { 83 | return Name; 84 | } 85 | } 86 | } 87 | 88 | /// 89 | /// Retuns entry's assembly product. If product is not found, title is returned. 90 | /// 91 | public static string Product { 92 | get{ 93 | object[] productAttributes = System.Reflection.Assembly.GetEntryAssembly().GetCustomAttributes(typeof(System.Reflection.AssemblyProductAttribute), true); 94 | if ((productAttributes != null) && (productAttributes.Length >= 1)) { 95 | return ((System.Reflection.AssemblyProductAttribute)productAttributes[productAttributes.Length - 1]).Product; 96 | } else { 97 | return Title; 98 | } 99 | } 100 | } 101 | 102 | /// 103 | /// Retuns entry's assembly description. If description is not found, empty string is returned. 104 | /// 105 | public static string Description { 106 | get { 107 | object[] descriptionAttributes = System.Reflection.Assembly.GetEntryAssembly().GetCustomAttributes(typeof(System.Reflection.AssemblyDescriptionAttribute), true); 108 | if ((descriptionAttributes != null) && (descriptionAttributes.Length >= 1)) { 109 | return ((System.Reflection.AssemblyDescriptionAttribute)descriptionAttributes[descriptionAttributes.Length - 1]).Description; 110 | } else { 111 | return string.Empty; 112 | } 113 | } 114 | } 115 | 116 | /// 117 | /// Retuns entry's assembly copyright. If copyright is not found, empty string is returned. 118 | /// 119 | public static string Copyright { 120 | get { 121 | object[] copyrightAttributes = Assembly.GetCustomAttributes(typeof(System.Reflection.AssemblyCopyrightAttribute), true); 122 | if ((copyrightAttributes != null) && (copyrightAttributes.Length >= 1)) { 123 | return ((System.Reflection.AssemblyCopyrightAttribute)copyrightAttributes[copyrightAttributes.Length - 1]).Copyright; 124 | } else { 125 | return string.Empty; 126 | } 127 | } 128 | } 129 | 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /Source/Bimil/(Medo)/LifetimeWatch [001].cs: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | 3 | //2010-08-29: Initial version. 4 | 5 | 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Reflection; 9 | using System.Text; 10 | using System.Diagnostics; 11 | 12 | namespace Medo.Diagnostics { 13 | 14 | /// 15 | /// Timer that fires upon creation of object and stops with it's disposal. 16 | /// 17 | public class LifetimeWatch : IDisposable { 18 | 19 | private readonly string Name; 20 | private readonly Stopwatch Stopwatch; 21 | 22 | /// 23 | /// Initializes new instance. 24 | /// 25 | public LifetimeWatch() 26 | : this(null) { 27 | } 28 | 29 | /// 30 | /// Initializes new instance. 31 | /// 32 | /// Custom name for action. 33 | public LifetimeWatch(string name) { 34 | Stopwatch = Stopwatch.StartNew(); 35 | Name = name; 36 | } 37 | 38 | /// 39 | /// Gets the total elapsed time measured by the current instance. 40 | /// 41 | public TimeSpan Elapsed { 42 | get { return Stopwatch.Elapsed; } 43 | } 44 | 45 | /// 46 | /// Gets the total elapsed time measured by the current instance, in milliseconds. 47 | /// 48 | public long ElapsedMilliseconds { 49 | get { return Stopwatch.ElapsedMilliseconds; } 50 | } 51 | 52 | /// 53 | /// Gets the total elapsed time measured by the current instance, in timer ticks. 54 | /// 55 | public long ElapsedTicks { 56 | get { return Stopwatch.ElapsedTicks; } 57 | } 58 | 59 | 60 | #region IDisposable Members 61 | 62 | /// 63 | /// Clean up any resources being used. 64 | /// 65 | public void Dispose() { 66 | Dispose(true); 67 | System.GC.SuppressFinalize(this); 68 | } 69 | 70 | /// 71 | /// Clean up any resources being used. 72 | /// 73 | /// True if managed resources should be disposed; otherwise, false. 74 | protected virtual void Dispose(bool disposing) { 75 | if (disposing) { 76 | Stopwatch.Stop(); 77 | if (Name != null) { 78 | Debug.WriteLine(string.Format("{1} completed in {0} milliseconds.", Stopwatch.ElapsedMilliseconds, Name)); 79 | } else { 80 | Debug.WriteLine(string.Format("Completed in {0} milliseconds.", Stopwatch.ElapsedMilliseconds)); 81 | } 82 | } 83 | } 84 | 85 | #endregion 86 | 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /Source/Bimil/(Medo)/UnhandledCatch [008].cs: -------------------------------------------------------------------------------- 1 | /* Josip Medved * www.medo64.com * MIT License */ 2 | 3 | //2010-11-22: Changed default exception mode to CatchException. 4 | //2010-11-07: Compatible with Mono (ignoring FailFast). 5 | //2009-03-31: Changed FailFast to optional in order to avoid WER messages. 6 | //2008-01-13: Changed default mode to ThrowException. 7 | // Uses FailFast to exit application. 8 | //2008-01-06: System.Environment.Exit returns E_UNEXPECTED (0x8000ffff). 9 | //2008-01-03: Added Resources. 10 | //2008-01-02: Added support for inner exceptions. 11 | // Added thread-safe locking. 12 | //2007-12-30: New version. 13 | 14 | 15 | using System; 16 | using System.Threading; 17 | 18 | namespace Medo.Application { 19 | 20 | /// 21 | /// Handling of unhandled errors. 22 | /// This class is thread-safe. 23 | /// 24 | public static class UnhandledCatch { 25 | 26 | /// 27 | /// Occurs when an exception is not caught. 28 | /// 29 | public static event EventHandler ThreadException; 30 | 31 | private static readonly object SyncRoot = new object(); 32 | 33 | /// 34 | /// Initializes handlers for unhandled exception. 35 | /// 36 | public static void Attach() { 37 | lock (SyncRoot) { 38 | Attach(System.Windows.Forms.UnhandledExceptionMode.CatchException, true); 39 | } 40 | } 41 | 42 | /// 43 | /// Initializes handlers for unhandled exception. 44 | /// 45 | /// Defines where a Windows Forms application should send unhandled exceptions. 46 | public static void Attach(System.Windows.Forms.UnhandledExceptionMode mode) { 47 | lock (SyncRoot) { 48 | Attach(mode, true); 49 | } 50 | } 51 | 52 | /// 53 | /// Initializes handlers for unhandled exception. 54 | /// 55 | /// Defines where a Windows Forms application should send unhandled exceptions. 56 | /// True to set the thread exception mode. 57 | public static void Attach(System.Windows.Forms.UnhandledExceptionMode mode, bool threadScope) { 58 | lock (SyncRoot) { 59 | System.Windows.Forms.Application.SetUnhandledExceptionMode(mode, threadScope); 60 | System.Windows.Forms.Application.ThreadException += Application_ThreadException; 61 | System.AppDomain.CurrentDomain.UnhandledException += AppDomain_UnhandledException; 62 | } 63 | } 64 | 65 | /// 66 | /// Initializes handlers for unhandled exception. 67 | /// 68 | /// Defines where a Windows Forms application should send unhandled exceptions. 69 | /// True to set the thread exception mode. 70 | /// When true, FailFast will be used to stop application. If false, standard Environment.Exit will be used instead. 71 | [Obsolete("Use UseFailFast property instead.")] 72 | public static void Attach(System.Windows.Forms.UnhandledExceptionMode mode, bool threadScope, bool useFailFast) { 73 | lock (SyncRoot) { 74 | UnhandledCatch.UseFailFast = useFailFast; 75 | System.Windows.Forms.Application.SetUnhandledExceptionMode(mode, threadScope); 76 | System.Windows.Forms.Application.ThreadException += Application_ThreadException; 77 | System.AppDomain.CurrentDomain.UnhandledException += AppDomain_UnhandledException; 78 | } 79 | } 80 | 81 | private static bool _useFailFast; 82 | /// 83 | /// Gets/sets whether to use FailFast terminating application. 84 | /// Under Mono this property always remains false. 85 | /// 86 | public static bool UseFailFast { 87 | get { lock (SyncRoot) { return _useFailFast; } } 88 | set { lock (SyncRoot) { _useFailFast = value && !IsRunningOnMono; } } 89 | } 90 | 91 | private static void AppDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e) { 92 | lock (SyncRoot) { 93 | Process(e.ExceptionObject as System.Exception); 94 | } 95 | } 96 | 97 | private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { 98 | lock (SyncRoot) { 99 | Process(e.Exception); 100 | } 101 | } 102 | 103 | 104 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "General exceptions are catched on purpose because this is handler for unhandled exceptions.")] 105 | private static void Process(System.Exception exception) { 106 | lock (SyncRoot) { 107 | System.Environment.ExitCode = unchecked((int)0x8000ffff); //E_UNEXPECTED(0x8000ffff) 108 | 109 | if (exception != null) { 110 | System.Diagnostics.Trace.TraceError(exception.ToString() + " {Medo.Application.UnhandledCatch}"); 111 | 112 | System.Windows.Forms.Application.ThreadException -= Application_ThreadException; 113 | System.AppDomain.CurrentDomain.UnhandledException -= AppDomain_UnhandledException; 114 | 115 | ThreadException?.Invoke(null, new ThreadExceptionEventArgs(exception)); 116 | } 117 | 118 | System.Diagnostics.Trace.TraceError("Exit(E_UNEXPECTED): Unhandled exception has occurred. {Medo.Application.UnhandledCatch}"); 119 | 120 | if (UnhandledCatch.UseFailFast) { 121 | System.Environment.FailFast(exception.Message); 122 | } else { 123 | System.Environment.Exit(unchecked((int)0x8000ffff)); //E_UNEXPECTED(0x8000ffff) 124 | } 125 | } 126 | } 127 | 128 | private static bool IsRunningOnMono { 129 | get { 130 | return (Type.GetType("Mono.Runtime") != null); 131 | } 132 | } 133 | 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /Source/Bimil/App.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Windows.Forms; 5 | using Medo.Configuration; 6 | 7 | namespace Bimil { 8 | internal static class App { 9 | 10 | private static readonly Mutex SetupMutex = new Mutex(false, @"Global\JosipMedved_Bimil"); 11 | internal static RecentlyUsed Recent; 12 | internal static TimeSpan? LastNtpDrift; 13 | internal static DateTime? LastNtpCheck; 14 | internal static MainForm MainForm; 15 | 16 | [STAThread] 17 | internal static void Main() { 18 | Application.EnableVisualStyles(); 19 | Application.SetCompatibleTextRenderingDefault(false); 20 | Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US"); 21 | 22 | Medo.Application.UnhandledCatch.ThreadException += new EventHandler(UnhandledCatch_ThreadException); 23 | Medo.Application.UnhandledCatch.Attach(); 24 | 25 | 26 | var recentLegacy = new RecentFiles(); 27 | if (recentLegacy.Count > 0) { 28 | var fileList = new List(); 29 | foreach (var item in recentLegacy.Items) { 30 | fileList.Add(item.FileName); 31 | } 32 | Recent = new RecentlyUsed(fileList); 33 | Config.Write("RecentFile", Recent.FileNames); 34 | recentLegacy.Clear(); 35 | } else { 36 | Recent = new RecentlyUsed(Config.Read("RecentFile")); 37 | } 38 | Recent.Changed += (o, i) => { 39 | Config.Write("RecentFile", Recent.FileNames); 40 | }; 41 | 42 | if (!Config.IsAssumedInstalled) { 43 | Medo.Windows.Forms.State.ReadState += delegate (object sender, Medo.Windows.Forms.StateReadEventArgs e) { 44 | e.Value = Config.Read("State!" + e.Name.Replace("Bimil.", ""), e.DefaultValue); 45 | }; 46 | Medo.Windows.Forms.State.WriteState += delegate (object sender, Medo.Windows.Forms.StateWriteEventArgs e) { 47 | Config.Write("State!" + e.Name.Replace("Bimil.", ""), e.Value); 48 | }; 49 | } 50 | 51 | App.MainForm = new MainForm(); 52 | Application.Run(App.MainForm); 53 | 54 | SetupMutex.Close(); 55 | } 56 | 57 | 58 | 59 | private static void UnhandledCatch_ThreadException(object sender, ThreadExceptionEventArgs e) { 60 | #if !DEBUG 61 | Medo.Diagnostics.ErrorReport.ShowDialog(null, e.Exception, new Uri("https://medo64.com/feedback/")); 62 | #else 63 | throw e.Exception; 64 | #endif 65 | } 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Source/Bimil/AutotypeForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Bimil { 2 | partial class AutotypeForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose(bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose(); 15 | } 16 | base.Dispose(disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent() { 26 | this.components = new System.ComponentModel.Container(); 27 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AutotypeForm)); 28 | this.tmrRestore = new System.Windows.Forms.Timer(this.components); 29 | this.bwType = new System.ComponentModel.BackgroundWorker(); 30 | this.tryProgress = new System.Windows.Forms.NotifyIcon(this.components); 31 | this.tip = new System.Windows.Forms.ToolTip(this.components); 32 | this.SuspendLayout(); 33 | // 34 | // tmrRestore 35 | // 36 | this.tmrRestore.Interval = 500; 37 | this.tmrRestore.Tick += new System.EventHandler(this.tmrRestore_Tick); 38 | // 39 | // bwType 40 | // 41 | this.bwType.WorkerReportsProgress = true; 42 | this.bwType.WorkerSupportsCancellation = true; 43 | this.bwType.DoWork += new System.ComponentModel.DoWorkEventHandler(this.bwType_DoWork); 44 | this.bwType.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.bwType_ProgressChanged); 45 | this.bwType.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.bwType_RunWorkerCompleted); 46 | // 47 | // tryProgress 48 | // 49 | this.tryProgress.Text = "Bimil auto-type"; 50 | // 51 | // AutotypeForm 52 | // 53 | this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); 54 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 55 | this.ClientSize = new System.Drawing.Size(222, 253); 56 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 57 | this.MaximizeBox = false; 58 | this.MinimizeBox = false; 59 | this.Name = "AutotypeForm"; 60 | this.Text = "Bimil auto-type"; 61 | this.TopMost = true; 62 | this.ResumeLayout(false); 63 | 64 | } 65 | 66 | #endregion 67 | 68 | private System.Windows.Forms.Timer tmrRestore; 69 | private System.ComponentModel.BackgroundWorker bwType; 70 | private System.Windows.Forms.NotifyIcon tryProgress; 71 | private System.Windows.Forms.ToolTip tip; 72 | } 73 | } -------------------------------------------------------------------------------- /Source/Bimil/AutotypeHelpForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | 6 | namespace Bimil { 7 | internal partial class AutotypeHelpForm : Form { 8 | public AutotypeHelpForm(string autotypeText, bool isReadOnly) { 9 | InitializeComponent(); 10 | Font = SystemFonts.MessageBoxFont; 11 | Medo.Windows.Forms.State.Attach(this); 12 | 13 | if (string.IsNullOrEmpty(autotypeText)) { 14 | txtAutotype.Text = @"\u\t\p\n"; 15 | } else { 16 | txtAutotype.Text = autotypeText; 17 | } 18 | 19 | if (isReadOnly) { 20 | lsvHelp.BackColor = SystemColors.Control; 21 | txtAutotype.ReadOnly = isReadOnly; 22 | txtAutotype.Width += btnOK.Width + (btnCancel.Left - btnOK.Right); 23 | btnOK.Visible = false; 24 | } 25 | } 26 | 27 | 28 | #region Disable minimize 29 | 30 | protected override void WndProc(ref Message m) { 31 | if ((Environment.OSVersion.Platform == PlatformID.Win32NT) && (Environment.OSVersion.Version.Major < 10) 32 | && (m != null) && (m.Msg == NativeMethods.WM_SYSCOMMAND) && (m.WParam == NativeMethods.SC_MINIMIZE)) { 33 | m.Result = IntPtr.Zero; 34 | } else if (m != null) { 35 | base.WndProc(ref m); 36 | } 37 | } 38 | 39 | 40 | private class NativeMethods { 41 | internal const int WM_SYSCOMMAND = 0x0112; 42 | internal static readonly IntPtr SC_MINIMIZE = new IntPtr(0xF020); 43 | } 44 | 45 | #endregion 46 | 47 | 48 | private void Form_Load(object sender, System.EventArgs e) { 49 | AddItem("Fields", @"\u", "User name"); 50 | AddItem("Fields", @"\p", "Password"); 51 | AddItem("Fields", @"\2", "Two-factor authentication code"); 52 | AddItem("Fields", @"\cn", "Credit card number"); 53 | AddItem("Fields", @"\ct", "Credit card number (tab separated)"); 54 | AddItem("Fields", @"\ce", "Credit card expiration"); 55 | AddItem("Fields", @"\cv", "Credit card security code"); 56 | AddItem("Fields", @"\cp", "Credit card pin number"); 57 | AddItem("Fields", @"\g", "Group field"); 58 | AddItem("Fields", @"\i", "Title field"); 59 | AddItem("Fields", @"\l", "URL"); 60 | AddItem("Fields", @"\m", "E-mail"); 61 | AddItem("Fields", @"\o", "Notes"); 62 | AddItem("Fields", @"\o###", "Nth line of Notes field (if line doesn't exist, it has no effect)"); 63 | 64 | AddItem("Keys", @"\b", "Backpace"); 65 | AddItem("Keys", @"\t", "Tab"); 66 | AddItem("Keys", @"\s", "Shift+Tab"); 67 | AddItem("Keys", @"\n", "Enter"); 68 | AddItem("Keys", @"\\", "Backslash (\\)"); 69 | 70 | AddItem("Time", @"\d###", "Delay between characters in milliseconds, instead of 10 (default)"); 71 | AddItem("Time", @"\w###", "Wait in milliseconds"); 72 | AddItem("Time", @"\W###", "Wait in seconds"); 73 | } 74 | 75 | private void Form_Resize(object sender, System.EventArgs e) { 76 | lsvHelp_colHelp.Width = lsvHelp.ClientRectangle.Width - lsvHelp_colEscape.Width - SystemInformation.VerticalScrollBarWidth; 77 | } 78 | 79 | private void Form_Shown(object sender, System.EventArgs e) { 80 | Medo.Windows.Forms.State.Load(this); //workaround for Mono form resize 81 | txtAutotype.SelectionStart = txtAutotype.Text.Length; 82 | } 83 | 84 | 85 | public string AutotypeText { get; private set; } 86 | 87 | private void btnOK_Click(object sender, System.EventArgs e) { 88 | AutotypeText = txtAutotype.Text; 89 | } 90 | 91 | 92 | private void lsvHelp_ItemActivate(object sender, System.EventArgs e) { 93 | if (!txtAutotype.ReadOnly && (lsvHelp.SelectedItems.Count == 1)) { 94 | txtAutotype.SelectedText = lsvHelp.SelectedItems[0].Text; 95 | } 96 | } 97 | 98 | private void txtAutotype_TextChanged(object sender, EventArgs e) { 99 | var caption = Helpers.GetAutotypeDescription(txtAutotype.Text); 100 | lblDescription.Text = caption; 101 | tip.SetToolTip(lblDescription, caption); 102 | } 103 | 104 | 105 | private readonly Dictionary Groups = new Dictionary(); 106 | 107 | private void AddItem(string group, string escapeSequence, string helpText) { 108 | var lvi = new ListViewItem(escapeSequence); 109 | lvi.SubItems.Add(helpText); 110 | 111 | if (Groups.ContainsKey(group)) { 112 | lvi.Group = Groups[group]; 113 | } else { 114 | lvi.Group = new ListViewGroup(group); 115 | Groups.Add(group, lvi.Group); 116 | lsvHelp.Groups.Add(lvi.Group); 117 | } 118 | 119 | lsvHelp.Items.Add(lvi); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Source/Bimil/BadPasswords.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Reflection; 6 | 7 | namespace Bimil { 8 | internal static class BadPasswords { 9 | 10 | public static IEnumerable Passwords; 11 | 12 | public static bool IsCommon(string password, out string matchedPassword) { 13 | if (Settings.ShowCommonPasswordWarnings) { 14 | if (Passwords == null) { 15 | var sw = Stopwatch.StartNew(); 16 | 17 | var passwords = new List(); 18 | using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Bimil.Resources.Common.passwords")) 19 | using (var textStream = new StreamReader(stream)) { 20 | var items = textStream.ReadToEnd().Split(new string[] { "\r\n", "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries); 21 | foreach (var item in items) { 22 | if (item.StartsWith("#", StringComparison.Ordinal)) { continue; } //omit comments 23 | passwords.Add(item); 24 | } 25 | } 26 | Passwords = passwords; 27 | 28 | Debug.WriteLine($"Loaded {passwords.Count} common passwords in {sw.ElapsedMilliseconds} ms."); 29 | } 30 | 31 | var swVerify = Stopwatch.StartNew(); 32 | try { 33 | foreach (var commonPassword in Passwords) { 34 | if (commonPassword.Length * 3 > password.Length) { //only check passwords over minimum length 35 | if (password.IndexOf(commonPassword, StringComparison.OrdinalIgnoreCase) >= 0) { 36 | matchedPassword = commonPassword; 37 | return true; 38 | } 39 | } 40 | } 41 | } finally { 42 | Debug.WriteLine($"Common password search done in {swVerify.ElapsedMilliseconds} ms."); 43 | } 44 | } 45 | 46 | matchedPassword = null; 47 | return false; 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/Bimil/BimilDocument/BimilRecord.cs: -------------------------------------------------------------------------------- 1 | namespace Medo.Security.Cryptography.Bimil { 2 | public class BimilRecord { 3 | 4 | private readonly BimilDocument Document; 5 | 6 | internal BimilRecord(BimilDocument document, string key, string value, BimilRecordFormat format) { 7 | Document = document; 8 | Key = new BimilValue(document) { Text = key }; 9 | Value = new BimilValue(document) { Text = value }; 10 | Format = format; 11 | } 12 | 13 | 14 | /// 15 | /// Gets key. 16 | /// 17 | public BimilValue Key { get; private set; } 18 | 19 | /// 20 | /// Gets value. 21 | /// 22 | public BimilValue Value { get; private set; } 23 | 24 | /// 25 | /// Gets/sets type. 26 | /// 27 | public BimilRecordFormat Format { get; set; } 28 | 29 | 30 | /// 31 | /// Returns key. 32 | /// 33 | public override string ToString() { 34 | return Key.ToString(); 35 | } 36 | 37 | } 38 | 39 | 40 | 41 | /// 42 | /// Bimil record formats. 43 | /// 44 | public enum BimilRecordFormat : int { 45 | /// 46 | /// System parameter. 47 | /// 48 | System = 0, 49 | /// 50 | /// One-line text. 51 | /// 52 | Text = 10, 53 | /// 54 | /// Multiline text. 55 | /// 56 | MultilineText = 11, 57 | /// 58 | /// Fixed-font text. 59 | /// 60 | MonospacedText = 12, 61 | /// 62 | /// URL. 63 | /// 64 | Url = 20, 65 | /// 66 | /// Password text. 67 | /// 68 | Password = 30, 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /Source/Bimil/BimilDocument/BimilValue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace Medo.Security.Cryptography.Bimil { 5 | 6 | /// 7 | /// Encrypted value. 8 | /// 9 | public class BimilValue { 10 | 11 | private readonly BimilDocument Document; 12 | 13 | internal BimilValue(BimilDocument document) { 14 | Document = document; 15 | Text = ""; 16 | } 17 | 18 | 19 | /// 20 | /// Gets/sets text. 21 | /// 22 | public string Text { 23 | get { 24 | if (Bytes == null) { return null; } 25 | byte[] decBuffer; 26 | using (var dec = Document.Crypto.CreateDecryptor()) { 27 | decBuffer = dec.TransformFinalBlock(Bytes, 0, Bytes.Length); 28 | } 29 | return UTF8Encoding.UTF8.GetString(decBuffer, 16, decBuffer.Length - 16); 30 | } 31 | set { 32 | if (value == null) { throw new ArgumentNullException("value", "Value cannot be null."); } 33 | 34 | var bufferSalt = new byte[16]; 35 | Document.Rng.GetBytes(bufferSalt); 36 | var bufferText = UTF8Encoding.UTF8.GetBytes(value); 37 | var buffer = new byte[16 + bufferText.Length]; 38 | 39 | Buffer.BlockCopy(bufferSalt, 0, buffer, 0, 16); 40 | Buffer.BlockCopy(bufferText, 0, buffer, 16, bufferText.Length); 41 | 42 | byte[] encBuffer; 43 | using (var enc = Document.Crypto.CreateEncryptor()) { 44 | encBuffer = enc.TransformFinalBlock(buffer, 0, buffer.Length); 45 | } 46 | Bytes = encBuffer; 47 | } 48 | } 49 | 50 | internal byte[] Bytes { get; private set; } 51 | 52 | 53 | internal static BimilValue Parse(BimilDocument document, byte[] buffer, int offset, int count) { 54 | var encBuffer = new byte[count]; 55 | Buffer.BlockCopy(buffer, offset, encBuffer, 0, count); 56 | 57 | return new BimilValue(document) { Bytes = encBuffer }; 58 | } 59 | 60 | 61 | /// 62 | /// Returns text. 63 | /// 64 | /// Encrypted text. 65 | public static implicit operator string(BimilValue value) { 66 | return value.Text; 67 | } 68 | 69 | 70 | /// 71 | /// Returns text. 72 | /// 73 | public override string ToString() { 74 | return Text; 75 | } 76 | 77 | } 78 | } 79 | 80 | 81 | 82 | // FORMAT 83 | //-------- 84 | // 16x Salt 85 | // ?x Text 86 | // 87 | // * Salt is there so we do not leak key with common text. 88 | // * Data is double-encrypted because it needs to stay as such once document is decrypted. 89 | -------------------------------------------------------------------------------- /Source/Bimil/BimilDocument/DocumentConversion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using Medo.Security.Cryptography.PasswordSafe; 4 | using BimilDocument = Medo.Security.Cryptography.Bimil; 5 | 6 | namespace Bimil { 7 | internal static class DocumentConversion { 8 | 9 | internal static Document ConvertFromBimil(BimilDocument.BimilDocument legacyDoc, byte[] passphraseBytes) { 10 | var doc = new Document(passphraseBytes); 11 | 12 | foreach (var item in legacyDoc.Items) { 13 | var entry = new Entry { 14 | Title = item.Name, 15 | Group = item.CategoryRecord.Value.Text 16 | }; 17 | entry[RecordType.Password] = null; 18 | 19 | foreach (var record in item.Records) { 20 | if (record.Format == BimilDocument.BimilRecordFormat.System) { continue; } 21 | var newRecord = ConvertBimilRecord(record); 22 | if (newRecord != null) { 23 | if ((newRecord.RecordType == 0) || entry.Records.Contains(newRecord.RecordType)) { 24 | if (entry.Notes.Length > 0) { entry.Notes += "\r\n"; } 25 | entry.Notes += newRecord.Text; 26 | } else { 27 | entry.Records.Add(newRecord); 28 | } 29 | } 30 | } 31 | 32 | if (entry.Records.Contains(RecordType.Notes)) { 33 | var notes = entry.Records[RecordType.Notes]; 34 | entry.Records[RecordType.Notes] = null; 35 | entry.Records.Add(notes); 36 | } 37 | 38 | doc.Entries.Add(entry); 39 | } 40 | 41 | return doc; 42 | } 43 | 44 | private static Record ConvertBimilRecord(BimilDocument.BimilRecord record) { 45 | if (record.Key.Text.Equals("User name", StringComparison.OrdinalIgnoreCase) 46 | || record.Key.Text.Equals("Username", StringComparison.OrdinalIgnoreCase) 47 | || record.Key.Text.Equals("User", StringComparison.OrdinalIgnoreCase)) { 48 | return new Record(RecordType.UserName) { Text = record.Value.Text }; 49 | } else if (record.Key.Text.Equals("Password", StringComparison.OrdinalIgnoreCase)) { 50 | return new Record(RecordType.Password) { Text = record.Value.Text }; 51 | } else if (record.Key.Text.Equals("Notes", StringComparison.OrdinalIgnoreCase)) { 52 | return new Record(RecordType.Notes) { Text = record.Value.Text }; 53 | } else if (record.Key.Text.Equals("URL", StringComparison.OrdinalIgnoreCase) 54 | || record.Key.Text.Equals("Web address", StringComparison.OrdinalIgnoreCase)) { 55 | return new Record(RecordType.Url) { Text = record.Value.Text }; 56 | } else if (record.Key.Text.Equals("Key", StringComparison.OrdinalIgnoreCase)) { 57 | return new Record(RecordType.TwoFactorKey) { Text = record.Value.Text }; 58 | } else if (record.Key.Text.Equals("Card number", StringComparison.OrdinalIgnoreCase)) { 59 | return new Record(RecordType.CreditCardNumber) { Text = record.Value.Text }; 60 | } else if (record.Key.Text.Equals("Expiration date", StringComparison.OrdinalIgnoreCase)) { 61 | return new Record(RecordType.CreditCardExpiration) { Text = record.Value.Text }; 62 | } else if (record.Key.Text.Equals("Security code", StringComparison.OrdinalIgnoreCase) 63 | || record.Key.Text.Equals("CVV", StringComparison.OrdinalIgnoreCase) 64 | || record.Key.Text.Equals("CVV2", StringComparison.OrdinalIgnoreCase) 65 | || record.Key.Text.Equals("CID", StringComparison.OrdinalIgnoreCase) 66 | || record.Key.Text.Equals("CSC", StringComparison.OrdinalIgnoreCase)) { 67 | return new Record(RecordType.CreditCardVerificationValue) { Text = record.Value.Text }; 68 | } else if (record.Key.Text.Equals("PIN", StringComparison.OrdinalIgnoreCase)) { 69 | return new Record(RecordType.CreditCardPin) { Text = record.Value.Text }; 70 | } else { 71 | Debug.WriteLine("Not auto-converting field \"" + record.Key.Text + "\""); 72 | if (record.Value.Text.Length > 0) { 73 | return new Record(0) { Text = record.Key.Text + ": " + record.Value.Text }; 74 | } else { 75 | return null; 76 | } 77 | } 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Source/Bimil/ClipboardMonitor.cs: -------------------------------------------------------------------------------- 1 | //https://stackoverflow.com/questions/621577/clipboard-event-c-sharp/#1394225 2 | 3 | using System; 4 | using System.ComponentModel; 5 | using System.Diagnostics; 6 | using System.Runtime.InteropServices; 7 | using System.Windows.Forms; 8 | 9 | namespace Bimil { 10 | 11 | [DefaultEvent("ClipboardChanged")] 12 | internal class ClipboardMonitor : Control { 13 | public ClipboardMonitor() { 14 | CreateHandle(); 15 | try { 16 | NextViewerPtr = NativeMethods.SetClipboardViewer(Handle); 17 | } catch (EntryPointNotFoundException) { } //happens on Linux 18 | } 19 | 20 | ~ClipboardMonitor() { 21 | Dispose(disposing: false); 22 | } 23 | 24 | private IntPtr NextViewerPtr; 25 | 26 | 27 | /// 28 | /// Clipboard contents changed. 29 | /// 30 | public event EventHandler ClipboardChanged; 31 | 32 | 33 | protected override void Dispose(bool disposing) { 34 | if (NextViewerPtr != IntPtr.Zero) { 35 | NativeMethods.ChangeClipboardChain(Handle, NextViewerPtr); 36 | NextViewerPtr = IntPtr.Zero; 37 | } 38 | } 39 | 40 | 41 | protected override void WndProc(ref Message m) { 42 | if (m != null) { 43 | switch (m.Msg) { 44 | case NativeMethods.WM_DRAWCLIPBOARD: 45 | Debug.WriteLine("ClipboardMonitor WndProc: WM_DRAWCLIPBOARD"); 46 | NativeMethods.SendMessage(NextViewerPtr, m.Msg, m.WParam, m.LParam); 47 | OnClipboardChanged(); 48 | break; 49 | 50 | case NativeMethods.WM_CHANGECBCHAIN: 51 | Debug.WriteLine("ClipboardMonitor WndProc: WM_CHANGECBCHAIN"); 52 | if (m.WParam == NextViewerPtr) { 53 | NextViewerPtr = m.LParam; 54 | } else { 55 | NativeMethods.SendMessage(NextViewerPtr, m.Msg, m.WParam, m.LParam); 56 | } 57 | break; 58 | 59 | default: 60 | Debug.WriteLine("ClipboardMonitor WndProc: 0x" + m.Msg.ToString("X4")); 61 | base.WndProc(ref m); 62 | break; 63 | } 64 | } 65 | } 66 | 67 | 68 | private void OnClipboardChanged() { 69 | try { 70 | var dataObject = Clipboard.GetDataObject(); 71 | if (dataObject != null) { 72 | ClipboardChanged?.Invoke(this, new ClipboardChangedEventArgs(dataObject)); 73 | } 74 | } catch (ExternalException) { } 75 | } 76 | 77 | 78 | 79 | private static class NativeMethods { 80 | 81 | internal const int WM_DRAWCLIPBOARD = 0x0308; 82 | internal const int WM_CHANGECBCHAIN = 0x030D; 83 | 84 | 85 | [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 86 | internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer); 87 | 88 | [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 89 | [return: MarshalAs(UnmanagedType.Bool)] 90 | internal static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext); 91 | 92 | [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 93 | internal static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); 94 | 95 | } 96 | } 97 | 98 | 99 | internal class ClipboardChangedEventArgs : EventArgs { 100 | public ClipboardChangedEventArgs(IDataObject dataObject) { 101 | DataObject = dataObject; 102 | } 103 | 104 | public IDataObject DataObject { get; } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Source/Bimil/DocumentInfoForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Security.Cryptography; 4 | using System.Windows.Forms; 5 | using Medo.Convert; 6 | using Medo.Security.Cryptography.PasswordSafe; 7 | 8 | namespace Bimil { 9 | internal partial class DocumentInfoForm : Form { 10 | public DocumentInfoForm(Document document) { 11 | InitializeComponent(); 12 | Font = SystemFonts.MessageBoxFont; 13 | 14 | Document = document; 15 | 16 | txtName.ReadOnly = document.IsReadOnly; 17 | txtDescription.ReadOnly = document.IsReadOnly; 18 | btnOK.Enabled = !document.IsReadOnly; 19 | } 20 | 21 | 22 | private readonly Document Document; 23 | 24 | 25 | private void Form_Load(object sender, EventArgs e) { 26 | txtName.Text = Document.Name; 27 | txtDescription.Text = Document.Description; 28 | 29 | txtUuid.Text = Document.Uuid.ToString(); 30 | 31 | txtLastSaveApplication.Text = Document.LastSaveApplication; 32 | txtLastSaveUser.Text = Document.LastSaveUser + " (" + Document.LastSaveHost + ")"; 33 | txtLastSaveTime.Text = Document.LastSaveTime.ToString("f"); 34 | 35 | foreach (var header in Document.Headers) { 36 | if (header.HeaderType == Helpers.HeaderConstants.StaticKey) { 37 | var bytes = header.GetBytes(); 38 | try { 39 | if (bytes.Length == 64) { 40 | chbStaticKey.Checked = true; 41 | txtStaticKey.Text = Base58.ToString(bytes); 42 | break; 43 | } else { 44 | Array.Clear(bytes, 0, bytes.Length); 45 | } 46 | } finally { 47 | Array.Clear(bytes, 0, bytes.Length); 48 | } 49 | } 50 | } 51 | chbStaticKey_CheckedChanged(null, null); //to sort out size diffs 52 | if (Document.IsReadOnly) { chbStaticKey.Enabled = false; } 53 | } 54 | 55 | 56 | private void chbStaticKey_CheckedChanged(object sender, EventArgs e) { 57 | if (chbStaticKey.Checked && !grpStaticKey.Enabled) { 58 | grpStaticKey.Enabled = true; 59 | 60 | //make a new key 61 | var keyBytes = new byte[64]; 62 | try { 63 | var random = RandomNumberGenerator.Create(); 64 | random.GetBytes(keyBytes); 65 | txtStaticKey.Text = Base58.ToString(keyBytes); 66 | } finally { 67 | Array.Clear(keyBytes, 0, keyBytes.Length); 68 | } 69 | } else if (!chbStaticKey.Checked && grpStaticKey.Enabled) { 70 | grpStaticKey.Enabled = false; 71 | } 72 | } 73 | 74 | 75 | private void btnOK_Click(object sender, EventArgs e) { 76 | Document.Name = txtName.Text; 77 | Document.Description = txtDescription.Text; 78 | 79 | if (chbStaticKey.Enabled) { //just if document is not read-only 80 | //first remove old static key header - if any 81 | for (var i = Document.Headers.Count - 1; i >= 0; i--) { 82 | var header = Document.Headers[i]; 83 | if (header.HeaderType == Helpers.HeaderConstants.StaticKey) { 84 | var bytes = header.GetBytes(); 85 | try { 86 | if (bytes.Length == 64) { 87 | Document.Headers.RemoveAt(i); 88 | } 89 | } finally { 90 | Array.Clear(bytes, 0, bytes.Length); 91 | } 92 | } 93 | } 94 | 95 | //add new static key header 96 | if (chbStaticKey.Checked) { 97 | var bytes = Base58.AsBytes(txtStaticKey.Text); 98 | try { 99 | var header = new Header(Helpers.HeaderConstants.StaticKey, bytes); 100 | Document.Headers.Add(header); 101 | } finally { 102 | Array.Clear(bytes, 0, bytes.Length); 103 | txtStaticKey.Text = ""; 104 | GC.Collect(); 105 | } 106 | } 107 | } 108 | } 109 | 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Source/Bimil/EntryCache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text; 3 | using Medo.Security.Cryptography.PasswordSafe; 4 | 5 | namespace Bimil { 6 | internal class EntryCache { 7 | 8 | public EntryCache(Entry entry) { 9 | Entry = entry; 10 | 11 | Title = entry.Title; 12 | Group = entry.Group; 13 | } 14 | 15 | public Entry Entry { get; } 16 | public string Title { get; } 17 | public string Group { get; } 18 | 19 | public string MatchedText { 20 | get { 21 | if (_matchList != null) { 22 | var sb = new StringBuilder(); 23 | foreach (var text in _matchList) { 24 | if (sb.Length > 0) { sb.Append(", "); } 25 | sb.Append(text); 26 | } 27 | return sb.ToString(); 28 | } else { 29 | return null; 30 | } 31 | } 32 | } 33 | 34 | private List _matchList; 35 | 36 | public void AddMatch(string text) { 37 | if (_matchList == null) { _matchList = new List(); } 38 | if (!_matchList.Contains(text)) { 39 | _matchList.Add(text); 40 | } 41 | } 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Source/Bimil/Execute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | 7 | namespace Bimil { 8 | internal static class Execute { 9 | 10 | public static void StartCommand(string commandText, IWin32Window owner) { 11 | var startInfo = GetStartInfo(commandText); 12 | 13 | try { 14 | Process.Start(startInfo); 15 | } catch (InvalidOperationException ex) { //inproper call 16 | if (owner != null) { 17 | Medo.MessageBox.ShowError(owner, "Cannot parse command.\n\n" + ex.Message); 18 | } else { 19 | throw; 20 | } 21 | } catch (SystemException ex) { 22 | if (owner != null) { 23 | Medo.MessageBox.ShowError(owner, ex.Message); 24 | } else { 25 | throw; 26 | } 27 | } 28 | } 29 | 30 | public static ProcessStartInfo GetStartInfo(string commandText) { 31 | var sbFileName = new StringBuilder(); 32 | var sbArguments = new StringBuilder(); 33 | 34 | var state = StartInfoState.Default; 35 | foreach (var ch in commandText.Trim()) { 36 | switch (state) { 37 | case StartInfoState.Default: 38 | if (ch == '\"') { 39 | state = StartInfoState.QuotedFileName; 40 | } else { 41 | sbFileName.Append(ch); 42 | state = StartInfoState.FileName; 43 | } 44 | break; 45 | 46 | case StartInfoState.FileName: 47 | if ((ch == ' ') || (ch == '\"')) { 48 | state = StartInfoState.Arguments; 49 | } else { 50 | sbFileName.Append(ch); 51 | } 52 | break; 53 | 54 | case StartInfoState.QuotedFileName: 55 | if (ch == '\"') { 56 | state = StartInfoState.Arguments; 57 | } else { 58 | sbFileName.Append(ch); 59 | } 60 | break; 61 | 62 | case StartInfoState.Arguments: 63 | sbArguments.Append(ch); 64 | break; 65 | } 66 | } 67 | 68 | var fileName = FillEnvironment(sbFileName.ToString().Trim()); 69 | var arguments = FillEnvironment(sbArguments.ToString().Trim()); 70 | 71 | return new ProcessStartInfo(fileName, arguments); 72 | } 73 | 74 | private enum StartInfoState { 75 | Default, 76 | FileName, 77 | QuotedFileName, 78 | Arguments, 79 | } 80 | 81 | private static string FillEnvironment(string text) { 82 | var sb = new StringBuilder(); 83 | var sbVariable = new StringBuilder(); 84 | 85 | var state = EnvironmentState.Default; 86 | foreach (var ch in text) { 87 | switch (state) { 88 | case EnvironmentState.Default: 89 | if (ch == '%') { 90 | state = EnvironmentState.PercentVariable; 91 | } else { 92 | sb.Append(ch); 93 | } 94 | break; 95 | 96 | case EnvironmentState.PercentVariable: 97 | if (ch == '%') { 98 | if (sbVariable.Length == 0) { //just double percent 99 | sb.Append("%"); 100 | } else { 101 | var value = Environment.GetEnvironmentVariable(sbVariable.ToString().Trim()); 102 | if (value != null) { 103 | sb.Append(value); 104 | } else { //just copy it all if environment variable is not found 105 | sb.Append("%" + sbVariable.ToString() + "%"); 106 | } 107 | sbVariable.Length = 0; 108 | } 109 | state = EnvironmentState.Default; 110 | } else { 111 | sbVariable.Append(ch); 112 | } 113 | break; 114 | } 115 | } 116 | 117 | return sb.ToString(); 118 | } 119 | 120 | private enum EnvironmentState { 121 | Default, 122 | PercentVariable, 123 | } 124 | 125 | public static void StartUrl(string urlText) { 126 | var url = NormalizeUrl(urlText); 127 | if (!string.IsNullOrEmpty(url)) { 128 | try { 129 | Process.Start(url); 130 | } catch (Win32Exception) { // to avoid crash on Linux 131 | if (Helpers.IsRunningOnLinux) { 132 | try { 133 | Process.Start("xdg-open", url); // try using xdg-open 134 | } catch (Win32Exception) { } // ok, just give up 135 | } 136 | } 137 | } 138 | } 139 | 140 | public static string NormalizeUrl(string urlText) { 141 | var url = urlText.Trim(); 142 | if (url.Length > 0) { 143 | return (url.IndexOf("://", StringComparison.OrdinalIgnoreCase) > 0) ? url : ("http://" + url); 144 | } else { 145 | return ""; 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /Source/Bimil/Hibp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace Bimil { 5 | internal static class Hibp { 6 | 7 | public static bool IsPassworPwned(string passwordHash) { 8 | var sha1Prefix = passwordHash.Substring(0, 5); 9 | var url = "https://pwned.medo64.com/range/" + System.Web.HttpUtility.UrlEncode(sha1Prefix); 10 | try { 11 | ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; //TLS 1.2 - works only if .NET framework 4.5 is installed 12 | using (var client = new WebClient()) { 13 | client.Headers["User-Agent"] = Medo.Reflection.EntryAssembly.Product + "/" + Medo.Reflection.EntryAssembly.Version.ToString(); 14 | var response = client.DownloadString(url); 15 | var lines = response.Split(new string[] { "\n", "\r\n", "\r" }, StringSplitOptions.RemoveEmptyEntries); 16 | foreach (var line in lines) { 17 | if (line.StartsWith(passwordHash, StringComparison.OrdinalIgnoreCase)) { // to ignore : if one is present 18 | return true; 19 | } 20 | } 21 | return false; 22 | } 23 | } catch (WebException ex) { 24 | if ((ex.Response is HttpWebResponse response) && (response.StatusCode == HttpStatusCode.NotFound)) { 25 | return false; 26 | } else { 27 | throw; 28 | } 29 | } 30 | } 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/Bimil/NewPasswordForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | 5 | namespace Bimil { 6 | internal partial class NewPasswordForm : Form { 7 | 8 | private static readonly Font FixedFont = Settings.MonotypeFont; 9 | 10 | public NewPasswordForm() { 11 | InitializeComponent(); 12 | Font = SystemFonts.MessageBoxFont; 13 | txtPassword.Font = FixedFont; 14 | txtPassword2.Font = FixedFont; 15 | 16 | foreach (var control in new Control[] { txtPassword, txtPassword2 }) { 17 | erp.SetIconAlignment(control, ErrorIconAlignment.MiddleLeft); 18 | erp.SetIconPadding(control, SystemInformation.Border3DSize.Width); 19 | } 20 | } 21 | 22 | 23 | #region Disable minimize 24 | 25 | protected override void WndProc(ref Message m) { 26 | if ((Environment.OSVersion.Platform == PlatformID.Win32NT) && (Environment.OSVersion.Version.Major < 10) 27 | && (m != null) && (m.Msg == NativeMethods.WM_SYSCOMMAND) && (m.WParam == NativeMethods.SC_MINIMIZE)) { 28 | m.Result = IntPtr.Zero; 29 | } else if (m != null) { 30 | base.WndProc(ref m); 31 | } 32 | } 33 | 34 | 35 | private class NativeMethods { 36 | internal const int WM_SYSCOMMAND = 0x0112; 37 | internal static readonly IntPtr SC_MINIMIZE = new IntPtr(0xF020); 38 | } 39 | 40 | #endregion 41 | 42 | 43 | private void txtPassword_KeyDown(object sender, KeyEventArgs e) { 44 | if (e.KeyData == Keys.Enter) { 45 | txtPassword2.Select(); 46 | } 47 | } 48 | 49 | private void txtPassword2_KeyDown(object sender, KeyEventArgs e) { 50 | if (e.KeyData == Keys.Enter) { 51 | if (btnOK.Enabled) { 52 | btnOK_Click(null, null); 53 | DialogResult = DialogResult.OK; 54 | } 55 | } 56 | } 57 | 58 | private void txtPassword_TextChanged(object sender, EventArgs e) { 59 | if (txtPassword.TextLength <= 12) { 60 | erp.SetError(txtPassword, "You should really have a longer master password."); 61 | } else { 62 | erp.SetError(txtPassword, null); 63 | } 64 | if (string.Equals(txtPassword.Text, txtPassword2.Text, StringComparison.Ordinal)) { 65 | btnOK.Enabled = true; 66 | erp.SetError(txtPassword2, null); 67 | } else { 68 | erp.SetError(txtPassword2, "Passwords don't match."); 69 | btnOK.Enabled = false; 70 | } 71 | AcceptButton = btnOK.Enabled ? btnOK : null; 72 | } 73 | 74 | 75 | private void btnOK_Click(object sender, EventArgs e) { 76 | Password = txtPassword.Text; 77 | } 78 | 79 | public string Password { get; private set; } 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Source/Bimil/NewRecordForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Bimil { 2 | partial class NewRecordForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose(bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose(); 15 | } 16 | base.Dispose(disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent() { 26 | this.components = new System.ComponentModel.Container(); 27 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(NewRecordForm)); 28 | this.btnCancel = new System.Windows.Forms.Button(); 29 | this.btnOK = new System.Windows.Forms.Button(); 30 | this.lblRecordType = new System.Windows.Forms.Label(); 31 | this.cmbRecordType = new System.Windows.Forms.ComboBox(); 32 | this.erp = new System.Windows.Forms.ErrorProvider(this.components); 33 | this.tip = new System.Windows.Forms.ToolTip(this.components); 34 | ((System.ComponentModel.ISupportInitialize)(this.erp)).BeginInit(); 35 | this.SuspendLayout(); 36 | // 37 | // btnCancel 38 | // 39 | this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 40 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; 41 | this.btnCancel.Location = new System.Drawing.Point(252, 54); 42 | this.btnCancel.Margin = new System.Windows.Forms.Padding(3, 15, 3, 3); 43 | this.btnCancel.Name = "btnCancel"; 44 | this.btnCancel.Size = new System.Drawing.Size(90, 28); 45 | this.btnCancel.TabIndex = 5; 46 | this.btnCancel.Text = "Cancel"; 47 | this.tip.SetToolTip(this.btnCancel, "Close without changes."); 48 | this.btnCancel.UseVisualStyleBackColor = true; 49 | // 50 | // btnOK 51 | // 52 | this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 53 | this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; 54 | this.btnOK.Location = new System.Drawing.Point(156, 54); 55 | this.btnOK.Margin = new System.Windows.Forms.Padding(3, 15, 3, 3); 56 | this.btnOK.Name = "btnOK"; 57 | this.btnOK.Size = new System.Drawing.Size(90, 28); 58 | this.btnOK.TabIndex = 4; 59 | this.btnOK.Text = "OK"; 60 | this.tip.SetToolTip(this.btnOK, "Insert record type."); 61 | this.btnOK.UseVisualStyleBackColor = true; 62 | this.btnOK.Click += new System.EventHandler(this.btnOK_Click); 63 | // 64 | // lblRecordType 65 | // 66 | this.lblRecordType.AutoSize = true; 67 | this.lblRecordType.Location = new System.Drawing.Point(12, 15); 68 | this.lblRecordType.Name = "lblRecordType"; 69 | this.lblRecordType.Size = new System.Drawing.Size(44, 17); 70 | this.lblRecordType.TabIndex = 2; 71 | this.lblRecordType.Text = "Type:"; 72 | // 73 | // cmbRecordType 74 | // 75 | this.cmbRecordType.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 76 | | System.Windows.Forms.AnchorStyles.Right))); 77 | this.cmbRecordType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 78 | this.cmbRecordType.FormattingEnabled = true; 79 | this.cmbRecordType.Location = new System.Drawing.Point(92, 12); 80 | this.cmbRecordType.Name = "cmbRecordType"; 81 | this.cmbRecordType.Size = new System.Drawing.Size(250, 24); 82 | this.cmbRecordType.TabIndex = 3; 83 | this.tip.SetToolTip(this.cmbRecordType, "Record type."); 84 | this.cmbRecordType.SelectedIndexChanged += new System.EventHandler(this.cmbRecordType_SelectedIndexChanged); 85 | // 86 | // erp 87 | // 88 | this.erp.ContainerControl = this; 89 | this.erp.Icon = ((System.Drawing.Icon)(resources.GetObject("erp.Icon"))); 90 | // 91 | // NewRecordForm 92 | // 93 | this.AcceptButton = this.btnOK; 94 | this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); 95 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 96 | this.CancelButton = this.btnCancel; 97 | this.ClientSize = new System.Drawing.Size(354, 94); 98 | this.Controls.Add(this.btnCancel); 99 | this.Controls.Add(this.btnOK); 100 | this.Controls.Add(this.lblRecordType); 101 | this.Controls.Add(this.cmbRecordType); 102 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 103 | this.MaximizeBox = false; 104 | this.MinimizeBox = false; 105 | this.Name = "NewRecordForm"; 106 | this.ShowIcon = false; 107 | this.ShowInTaskbar = false; 108 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 109 | this.Text = "New record"; 110 | this.Load += new System.EventHandler(this.Form_Load); 111 | ((System.ComponentModel.ISupportInitialize)(this.erp)).EndInit(); 112 | this.ResumeLayout(false); 113 | this.PerformLayout(); 114 | 115 | } 116 | 117 | #endregion 118 | 119 | private System.Windows.Forms.Button btnCancel; 120 | private System.Windows.Forms.Button btnOK; 121 | private System.Windows.Forms.Label lblRecordType; 122 | private System.Windows.Forms.ComboBox cmbRecordType; 123 | private System.Windows.Forms.ErrorProvider erp; 124 | private System.Windows.Forms.ToolTip tip; 125 | } 126 | } -------------------------------------------------------------------------------- /Source/Bimil/NewRecordForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | using Medo.Security.Cryptography.PasswordSafe; 6 | 7 | namespace Bimil { 8 | internal partial class NewRecordForm : Form { 9 | public NewRecordForm(Document document, IEnumerable recordsInUse) { 10 | InitializeComponent(); 11 | Font = SystemFonts.MessageBoxFont; 12 | 13 | erp.SetIconAlignment(cmbRecordType, ErrorIconAlignment.MiddleLeft); 14 | erp.SetIconPadding(cmbRecordType, cmbRecordType.Height / 6); 15 | 16 | Document = document; 17 | RecordsInUse = recordsInUse; 18 | } 19 | 20 | private readonly Document Document; 21 | private readonly IEnumerable RecordsInUse; 22 | 23 | 24 | private void Form_Load(object sender, EventArgs e) { 25 | foreach (var recordType in Helpers.GetUsableRecordTypes()) { 26 | cmbRecordType.Items.Add(new BimilFormatWrapper(Helpers.GetRecordCaption(recordType), recordType)); 27 | } 28 | 29 | if (Record != null) { 30 | cmbRecordType.SelectedItem = Record.RecordType; 31 | } else { 32 | foreach (BimilFormatWrapper item in cmbRecordType.Items) { 33 | var isAlreadyUsed = false; 34 | foreach (var record in RecordsInUse) { 35 | if (item.Format == record.RecordType) { 36 | isAlreadyUsed = true; 37 | break; 38 | } 39 | } 40 | if (isAlreadyUsed == false) { 41 | cmbRecordType.SelectedItem = item; 42 | break; 43 | } 44 | } 45 | if (cmbRecordType.SelectedItem == null) { 46 | cmbRecordType.SelectedIndex = 0; 47 | } 48 | } 49 | } 50 | 51 | 52 | public Record Record { get; private set; } 53 | 54 | private void btnOK_Click(object sender, EventArgs e) { 55 | Record = new Record(((BimilFormatWrapper)cmbRecordType.SelectedItem).Format); 56 | if (Record.RecordType == RecordType.PasswordHistory) { Record.Text = "10300"; } //enable by default 57 | } 58 | 59 | 60 | #region Private 61 | 62 | private class BimilFormatWrapper { 63 | public BimilFormatWrapper(string text, RecordType format) { 64 | Text = text; 65 | Format = format; 66 | } 67 | public string Text { get; private set; } 68 | public RecordType Format { get; private set; } 69 | public override bool Equals(object obj) { 70 | if (obj is RecordType otherFormat) { 71 | return (Format == otherFormat); 72 | } 73 | return base.Equals(obj); 74 | } 75 | public override int GetHashCode() { 76 | return Format.GetHashCode(); 77 | } 78 | public override string ToString() { 79 | return Text; 80 | } 81 | } 82 | 83 | #endregion 84 | 85 | private void cmbRecordType_SelectedIndexChanged(object sender, EventArgs e) { 86 | if (!Settings.ShowPasswordSafeWarnings) { return; } 87 | 88 | var wrap = (BimilFormatWrapper)cmbRecordType.SelectedItem; 89 | erp.SetError(cmbRecordType, null); 90 | 91 | switch (wrap.Format) { 92 | case RecordType.TwoFactorKey: 93 | case RecordType.CreditCardNumber: 94 | case RecordType.CreditCardExpiration: 95 | case RecordType.CreditCardVerificationValue: 96 | case RecordType.CreditCardPin: 97 | case RecordType.QRCode: 98 | erp.SetError(cmbRecordType, "This record type is not supported by PasswordSafe."); 99 | break; 100 | 101 | default: 102 | var recordTypeCount = 0; 103 | foreach (var item in RecordsInUse) { 104 | if (item.RecordType == wrap.Format) { recordTypeCount++; } 105 | } 106 | if (recordTypeCount >= 1) { 107 | erp.SetError(cmbRecordType, "Repeating record type is not supported by PasswordSafe."); 108 | } 109 | break; 110 | } 111 | } 112 | 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Source/Bimil/PasswordForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | 5 | namespace Bimil { 6 | internal partial class PasswordForm : Form { 7 | 8 | private static readonly Font FixedFont = Settings.MonotypeFont; 9 | 10 | public PasswordForm(string extraTitle = null) { 11 | InitializeComponent(); 12 | Font = SystemFonts.MessageBoxFont; 13 | txtPassword.Font = FixedFont; 14 | 15 | erp.SetIconAlignment(txtPassword, ErrorIconAlignment.MiddleLeft); 16 | erp.SetIconPadding(txtPassword, SystemInformation.Border3DSize.Width); 17 | 18 | if (extraTitle != null) { Text += " (" + extraTitle + ")"; } 19 | } 20 | 21 | 22 | #region Disable minimize 23 | 24 | protected override void WndProc(ref Message m) { 25 | if ((Environment.OSVersion.Platform == PlatformID.Win32NT) && (Environment.OSVersion.Version.Major < 10) 26 | && (m != null) && (m.Msg == NativeMethods.WM_SYSCOMMAND) && (m.WParam == NativeMethods.SC_MINIMIZE)) { 27 | m.Result = IntPtr.Zero; 28 | } else if (m != null) { 29 | base.WndProc(ref m); 30 | } 31 | } 32 | 33 | 34 | private class NativeMethods { 35 | internal const int WM_SYSCOMMAND = 0x0112; 36 | internal static readonly IntPtr SC_MINIMIZE = new IntPtr(0xF020); 37 | } 38 | 39 | #endregion 40 | 41 | 42 | private void chbShowPassword_CheckedChanged(object sender, EventArgs e) { 43 | txtPassword.UseSystemPasswordChar = !txtPassword.UseSystemPasswordChar; 44 | } 45 | 46 | private void btnOK_Click(object sender, EventArgs e) { 47 | Password = txtPassword.Text; 48 | } 49 | 50 | public string Password { get; private set; } 51 | 52 | private void tmrCapsLock_Tick(object sender, EventArgs e) { 53 | var isCapsLock = Control.IsKeyLocked(Keys.CapsLock); 54 | var wasCapsLock = !string.IsNullOrEmpty(erp.GetError(txtPassword)); 55 | if (isCapsLock && !wasCapsLock) { 56 | erp.SetError(txtPassword, "CapsLock is on."); 57 | } else if (!isCapsLock && wasCapsLock) { 58 | erp.SetError(txtPassword, null); 59 | } 60 | } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Source/Bimil/Properties/App.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Source/Bimil/Properties/App.ico -------------------------------------------------------------------------------- /Source/Bimil/Properties/App.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | true 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Source/Bimil/Properties/App.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/medo64/Bimil/5539a063911597364ab8a4b039ea0b06fe3ec108/Source/Bimil/Properties/App.snk -------------------------------------------------------------------------------- /Source/Bimil/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Resources; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | 7 | 8 | [assembly: AssemblyTitle("Bimil")] 9 | [assembly: AssemblyDescription("Password manager.")] 10 | 11 | [assembly: CLSCompliant(true)] 12 | [assembly: ComVisible(false)] 13 | [assembly: NeutralResourcesLanguage("en-US")] 14 | 15 | [assembly: InternalsVisibleTo("Bimil.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100dd86a004339478cde1e8293deea855a5282b4bc1fa5783f852719ae6c8ab0a3db047b94e6fb2619d976891dae70b86b67471398f86fddc7c6bd93a169a2dee4c17a57a5e34114aa4de938c369149645033f926e527b4e7206bc080ec09c27c2d8ed83d270f17773ca82fa0f212be721cf6a1b2d9c568c9134717ed6ad38042ac")] 16 | -------------------------------------------------------------------------------- /Source/Bimil/Properties/SolutionInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | 4 | [assembly: AssemblyProduct("Bimil")] //"Password" in Korean is "bimil beonho" (phonetically). 5 | [assembly: AssemblyCompany("Josip Medved")] 6 | [assembly: AssemblyCopyright("Copyright 2010 Josip Medved ")] 7 | 8 | [assembly: AssemblyVersion("0.00.*")] 9 | [assembly: AssemblyInformationalVersion("0.00")] 10 | -------------------------------------------------------------------------------- /Source/Bimil/QRCodeForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Bimil { 2 | partial class QRCodeForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose(bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose(); 15 | } 16 | base.Dispose(disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent() { 26 | this.SuspendLayout(); 27 | // 28 | // QRCodeForm 29 | // 30 | this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); 31 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 32 | this.BackColor = System.Drawing.Color.White; 33 | this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; 34 | this.ClientSize = new System.Drawing.Size(282, 253); 35 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 36 | this.MaximizeBox = false; 37 | this.MinimizeBox = false; 38 | this.Name = "QRCodeForm"; 39 | this.ShowIcon = false; 40 | this.ShowInTaskbar = false; 41 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 42 | this.Text = "QR code"; 43 | this.ResumeLayout(false); 44 | 45 | } 46 | 47 | #endregion 48 | } 49 | } -------------------------------------------------------------------------------- /Source/Bimil/QRCodeForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | 5 | namespace Bimil { 6 | internal partial class QRCodeForm : Form { 7 | public QRCodeForm(string text) { 8 | InitializeComponent(); 9 | Font = SystemFonts.MessageBoxFont; 10 | 11 | Coder = new QRCoder.QRCode(text); 12 | 13 | int qrSize; 14 | using (var bmp = Coder.GetBitmap()) { 15 | qrSize = Math.Max(bmp.Width, bmp.Height); 16 | } 17 | 18 | var screen = Screen.GetWorkingArea(this); 19 | var factor = Math.Min(screen.Width, screen.Height) / qrSize / 2; 20 | 21 | var scaledBitmap = Coder.GetBitmap(factor); 22 | ClientSize = scaledBitmap.Size; 23 | BackgroundImage = scaledBitmap; 24 | } 25 | 26 | private readonly QRCoder.QRCode Coder; 27 | 28 | 29 | #region Disable minimize 30 | 31 | protected override void WndProc(ref Message m) { 32 | if ((Environment.OSVersion.Platform == PlatformID.Win32NT) && (Environment.OSVersion.Version.Major < 10) 33 | && (m != null) && (m.Msg == NativeMethods.WM_SYSCOMMAND) && (m.WParam == NativeMethods.SC_MINIMIZE)) { 34 | m.Result = IntPtr.Zero; 35 | } else if (m != null) { 36 | base.WndProc(ref m); 37 | } 38 | } 39 | 40 | 41 | private class NativeMethods { 42 | internal const int WM_SYSCOMMAND = 0x0112; 43 | internal static readonly IntPtr SC_MINIMIZE = new IntPtr(0xF020); 44 | } 45 | 46 | #endregion 47 | 48 | 49 | protected override void OnKeyDown(KeyEventArgs e) { 50 | base.OnKeyDown(e); 51 | if ((e.KeyData == Keys.Escape) || (e.KeyData == Keys.Return)) { DialogResult = DialogResult.Cancel; } 52 | } 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Source/Bimil/QRCodeForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Source/Bimil/RecordEditorForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | using Medo.Security.Cryptography.PasswordSafe; 6 | 7 | namespace Bimil { 8 | internal partial class RecordEditorForm : Form { 9 | 10 | private readonly Document Document; 11 | private readonly Entry Item; 12 | 13 | public RecordEditorForm(Document document, Entry item) { 14 | InitializeComponent(); 15 | Font = SystemFonts.MessageBoxFont; 16 | 17 | Document = document; 18 | Item = item; 19 | } 20 | 21 | 22 | #region Disable minimize 23 | 24 | protected override void WndProc(ref Message m) { 25 | if ((Environment.OSVersion.Platform == PlatformID.Win32NT) && (Environment.OSVersion.Version.Major < 10) 26 | && (m != null) && (m.Msg == NativeMethods.WM_SYSCOMMAND) && (m.WParam == NativeMethods.SC_MINIMIZE)) { 27 | m.Result = IntPtr.Zero; 28 | } else if (m != null) { 29 | base.WndProc(ref m); 30 | } 31 | } 32 | 33 | 34 | private class NativeMethods { 35 | internal const int WM_SYSCOMMAND = 0x0112; 36 | internal static readonly IntPtr SC_MINIMIZE = new IntPtr(0xF020); 37 | } 38 | 39 | #endregion 40 | 41 | 42 | private void Form_Load(object sender, EventArgs e) { 43 | lsvFields.Columns[0].Width = lsvFields.Width - SystemInformation.VerticalScrollBarWidth; 44 | 45 | foreach (var record in Item.Records) { 46 | var caption = Helpers.GetRecordCaption(record); 47 | if (caption != null) { 48 | var lvi = new ListViewItem(caption) { Tag = record }; 49 | lsvFields.Items.Add(lvi); 50 | } 51 | } 52 | } 53 | 54 | private void lsvFields_KeyDown(object sender, KeyEventArgs e) { 55 | switch (e.KeyData) { 56 | case Keys.Insert: { 57 | btnAdd_Click(null, null); 58 | } 59 | break; 60 | case Keys.Delete: { 61 | btnRemove_Click(null, null); 62 | } 63 | break; 64 | } 65 | } 66 | 67 | private void lsvFields_SelectedIndexChanged(object sender, EventArgs e) { 68 | btnRemove.Enabled = (lsvFields.SelectedItems.Count > 0); 69 | } 70 | 71 | private void lsvFields_ItemDrag(object sender, ItemDragEventArgs e) { 72 | lsvFields.DoDragDrop(lsvFields.SelectedItems, DragDropEffects.Move); 73 | } 74 | 75 | private void lsvFields_DragEnter(object sender, DragEventArgs e) { 76 | for (var i = 0; i < e.Data.GetFormats().Length; i++) { 77 | if (e.Data.GetFormats()[i].Equals("System.Windows.Forms.ListView+SelectedListViewItemCollection")) { 78 | e.Effect = DragDropEffects.Move; 79 | break; 80 | } 81 | } 82 | } 83 | 84 | private void lsvFields_DragDrop(object sender, DragEventArgs e) { 85 | if (lsvFields.SelectedItems.Count == 0) { return; } 86 | 87 | var cp = lsvFields.PointToClient(new Point(e.X, e.Y)); 88 | var dragToItem = lsvFields.GetItemAt(cp.X, cp.Y); 89 | if (dragToItem == null) { return; } 90 | 91 | var dragIndex = dragToItem.Index; 92 | var sel = new ListViewItem[lsvFields.SelectedItems.Count]; 93 | for (var i = 0; i < lsvFields.SelectedItems.Count; i++) { 94 | sel[i] = lsvFields.SelectedItems[i]; 95 | } 96 | 97 | for (var i = 0; i < sel.Length; i++) { 98 | var dragItem = sel[i]; 99 | var itemIndex = dragIndex; 100 | if (itemIndex == dragItem.Index) { return; } 101 | 102 | if (dragItem.Index < itemIndex) { 103 | itemIndex++; 104 | } else { 105 | itemIndex = dragIndex + i; 106 | } 107 | 108 | var insertItem = (ListViewItem)dragItem.Clone(); 109 | lsvFields.Items.Insert(itemIndex, insertItem); 110 | lsvFields.Items.Remove(dragItem); 111 | } 112 | } 113 | 114 | 115 | private void btnAdd_Click(object sender, EventArgs e) { 116 | var records = new List(); 117 | foreach (ListViewItem item in lsvFields.Items) { 118 | records.Add((Record)item.Tag); 119 | } 120 | using (var frm = new NewRecordForm(Document, records.AsReadOnly())) { 121 | if (frm.ShowDialog(this) == DialogResult.OK) { 122 | var lvi = new ListViewItem(Helpers.GetRecordCaption(frm.Record)) { Tag = frm.Record }; 123 | lsvFields.Items.Add(lvi); 124 | } 125 | } 126 | } 127 | 128 | private readonly List RecordsToRemove = new List(); 129 | 130 | private void btnRemove_Click(object sender, EventArgs e) { 131 | if (lsvFields.SelectedItems.Count == 1) { 132 | RecordsToRemove.Add(lsvFields.SelectedItems[0].Tag as Record); 133 | lsvFields.Items.RemoveAt(lsvFields.SelectedItems[0].Index); 134 | } 135 | } 136 | 137 | private void btnOK_Click(object sender, EventArgs e) { 138 | foreach (var record in RecordsToRemove) { 139 | Item.Records.Remove(record); 140 | } 141 | foreach (ListViewItem lvi in lsvFields.Items) { 142 | var record = (Record)lvi.Tag; 143 | if (Item.Records.Contains(record)) { 144 | Item.Records.Remove(record); 145 | Item.Records.Add(record); 146 | } else { 147 | Item.Records.Add(record); 148 | } 149 | } 150 | } 151 | 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Source/Bimil/SearchForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | using Medo.Security.Cryptography.PasswordSafe; 6 | 7 | namespace Bimil { 8 | internal partial class SearchForm : Form { 9 | public SearchForm(Document document, IList categories, string defaultText) { 10 | InitializeComponent(); 11 | Font = SystemFonts.MessageBoxFont; 12 | Medo.Windows.Forms.State.Attach(this); 13 | 14 | Document = document; 15 | Categories = categories; 16 | DefaultText = defaultText; 17 | 18 | erp.SetIconAlignment(chbIncludeHiddenFields, ErrorIconAlignment.MiddleRight); 19 | erp.SetIconPadding(chbIncludeHiddenFields, chbIncludeHiddenFields.Height / 6); 20 | } 21 | 22 | private readonly Document Document; 23 | private readonly IList Categories; 24 | private readonly string DefaultText; 25 | 26 | 27 | #region Disable minimize 28 | 29 | protected override void WndProc(ref Message m) { 30 | if ((Environment.OSVersion.Platform == PlatformID.Win32NT) && (Environment.OSVersion.Version.Major < 10) 31 | && (m != null) && (m.Msg == NativeMethods.WM_SYSCOMMAND) && (m.WParam == NativeMethods.SC_MINIMIZE)) { 32 | m.Result = IntPtr.Zero; 33 | } else if (m != null) { 34 | base.WndProc(ref m); 35 | } 36 | } 37 | 38 | 39 | private class NativeMethods { 40 | internal const int WM_SYSCOMMAND = 0x0112; 41 | internal static readonly IntPtr SC_MINIMIZE = new IntPtr(0xF020); 42 | } 43 | 44 | #endregion 45 | 46 | 47 | private void Form_KeyDown(object sender, KeyEventArgs e) { 48 | if (e.KeyData == Keys.Escape) { 49 | Close(); 50 | } 51 | } 52 | 53 | private void Form_Shown(object sender, EventArgs e) { 54 | Medo.Windows.Forms.State.Load(this); //workaround for Mono form resize 55 | cmbSearch.Text = DefaultText; 56 | cmbSearch.SelectAll(); 57 | } 58 | 59 | private void Form_Resize(object sender, EventArgs e) { 60 | lsvEntries.Columns[0].Width = lsvEntries.ClientSize.Width; 61 | } 62 | 63 | 64 | private void cmbSearch_KeyDown(object sender, KeyEventArgs e) { 65 | if (!Helpers.HandleSearchKeyDown(e, lsvEntries, processPageUpDown: true)) { 66 | if (e.KeyData == (Keys.Control | Keys.F)) { 67 | cmbSearch.SelectAll(); 68 | cmbSearch.Select(); 69 | e.SuppressKeyPress = true; 70 | e.Handled = true; 71 | } 72 | } 73 | } 74 | 75 | private void cmbText_TextChanged(object sender, System.EventArgs e) { 76 | Helpers.PerformEntrySearch(Document, lsvEntries, cmbSearch.Text, extendedSearch: true, addMatchDescription: true, includeHidden: chbIncludeHiddenFields.Checked); 77 | Form_Resize(null, null); //to support both ListView full row with and without scrollbar 78 | } 79 | 80 | 81 | private void lsvEntries_ItemActivate(object sender, EventArgs e) { 82 | if ((Document == null) || (lsvEntries.SelectedItems.Count != 1)) { return; } 83 | 84 | var item = (Entry)(lsvEntries.SelectedItems[0].Tag); 85 | using (var frm2 = new ItemForm(Document, item, Categories, startsAsEditable: Settings.EditableByDefault, hideAutotype: true)) { 86 | if (frm2.ShowDialog(this) == DialogResult.OK) { 87 | Helpers.PerformEntrySearch(Document, lsvEntries, cmbSearch.Text, entriesToSelect: new Entry[] { item }, extendedSearch: true, addMatchDescription: true); 88 | Form_Resize(null, null); //to support both ListView full row with and without scrollbar 89 | } 90 | } 91 | } 92 | 93 | private void lsvEntries_KeyDown(object sender, KeyEventArgs e) { 94 | if (e.KeyData == (Keys.Control | Keys.F)) { 95 | cmbSearch.SelectAll(); 96 | cmbSearch.Select(); 97 | e.SuppressKeyPress = true; 98 | e.Handled = true; 99 | } 100 | } 101 | 102 | private void chbIncludeHiddenFields_CheckedChanged(object sender, EventArgs e) { 103 | if (chbIncludeHiddenFields.Checked) { 104 | erp.SetError(chbIncludeHiddenFields, "Search will include password and key fields."); 105 | } else { 106 | erp.SetError(chbIncludeHiddenFields, null); 107 | } 108 | cmbText_TextChanged(null, null); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Source/Bimil/SelectTemplateForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Bimil { 2 | partial class SelectTemplateForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose(bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose(); 15 | } 16 | base.Dispose(disposing); 17 | } 18 | 19 | #region Windows Form Designer generated code 20 | 21 | /// 22 | /// Required method for Designer support - do not modify 23 | /// the contents of this method with the code editor. 24 | /// 25 | private void InitializeComponent() { 26 | this.cmbTemplate = new System.Windows.Forms.ComboBox(); 27 | this.lblTemplate = new System.Windows.Forms.Label(); 28 | this.btnCancel = new System.Windows.Forms.Button(); 29 | this.btnOK = new System.Windows.Forms.Button(); 30 | this.SuspendLayout(); 31 | // 32 | // cmbTemplate 33 | // 34 | this.cmbTemplate.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 35 | | System.Windows.Forms.AnchorStyles.Right))); 36 | this.cmbTemplate.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 37 | this.cmbTemplate.FormattingEnabled = true; 38 | this.cmbTemplate.Location = new System.Drawing.Point(92, 12); 39 | this.cmbTemplate.Name = "cmbTemplate"; 40 | this.cmbTemplate.Size = new System.Drawing.Size(250, 24); 41 | this.cmbTemplate.TabIndex = 3; 42 | // 43 | // lblTemplate 44 | // 45 | this.lblTemplate.AutoSize = true; 46 | this.lblTemplate.Location = new System.Drawing.Point(12, 15); 47 | this.lblTemplate.Name = "lblTemplate"; 48 | this.lblTemplate.Size = new System.Drawing.Size(71, 17); 49 | this.lblTemplate.TabIndex = 2; 50 | this.lblTemplate.Text = "Template:"; 51 | // 52 | // btnCancel 53 | // 54 | this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 55 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; 56 | this.btnCancel.Location = new System.Drawing.Point(252, 54); 57 | this.btnCancel.Margin = new System.Windows.Forms.Padding(3, 15, 3, 3); 58 | this.btnCancel.Name = "btnCancel"; 59 | this.btnCancel.Size = new System.Drawing.Size(90, 28); 60 | this.btnCancel.TabIndex = 5; 61 | this.btnCancel.Text = "Cancel"; 62 | this.btnCancel.UseVisualStyleBackColor = true; 63 | // 64 | // btnOK 65 | // 66 | this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 67 | this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; 68 | this.btnOK.Location = new System.Drawing.Point(156, 54); 69 | this.btnOK.Margin = new System.Windows.Forms.Padding(3, 15, 3, 3); 70 | this.btnOK.Name = "btnOK"; 71 | this.btnOK.Size = new System.Drawing.Size(90, 28); 72 | this.btnOK.TabIndex = 4; 73 | this.btnOK.Text = "OK"; 74 | this.btnOK.UseVisualStyleBackColor = true; 75 | this.btnOK.Click += new System.EventHandler(this.btnOK_Click); 76 | // 77 | // SelectTemplateForm 78 | // 79 | this.AcceptButton = this.btnOK; 80 | this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); 81 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 82 | this.CancelButton = this.btnCancel; 83 | this.ClientSize = new System.Drawing.Size(354, 94); 84 | this.Controls.Add(this.btnCancel); 85 | this.Controls.Add(this.btnOK); 86 | this.Controls.Add(this.lblTemplate); 87 | this.Controls.Add(this.cmbTemplate); 88 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 89 | this.MaximizeBox = false; 90 | this.MinimizeBox = false; 91 | this.Name = "SelectTemplateForm"; 92 | this.ShowIcon = false; 93 | this.ShowInTaskbar = false; 94 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 95 | this.Text = "Select template"; 96 | this.ResumeLayout(false); 97 | this.PerformLayout(); 98 | 99 | } 100 | 101 | #endregion 102 | 103 | private System.Windows.Forms.ComboBox cmbTemplate; 104 | private System.Windows.Forms.Label lblTemplate; 105 | private System.Windows.Forms.Button btnCancel; 106 | private System.Windows.Forms.Button btnOK; 107 | } 108 | } -------------------------------------------------------------------------------- /Source/Bimil/SelectTemplateForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | 5 | namespace Bimil { 6 | internal partial class SelectTemplateForm : Form { 7 | public SelectTemplateForm() { 8 | InitializeComponent(); 9 | Font = SystemFonts.MessageBoxFont; 10 | 11 | cmbTemplate.Items.AddRange(Templates.GetTemplates()); 12 | cmbTemplate.SelectedIndex = 0; 13 | } 14 | 15 | 16 | #region Disable minimize 17 | 18 | protected override void WndProc(ref Message m) { 19 | if ((Environment.OSVersion.Platform == PlatformID.Win32NT) && (Environment.OSVersion.Version.Major < 10) 20 | && (m != null) && (m.Msg == NativeMethods.WM_SYSCOMMAND) && (m.WParam == NativeMethods.SC_MINIMIZE)) { 21 | m.Result = IntPtr.Zero; 22 | } else if (m != null) { 23 | base.WndProc(ref m); 24 | } 25 | } 26 | 27 | 28 | private class NativeMethods { 29 | internal const int WM_SYSCOMMAND = 0x0112; 30 | internal static readonly IntPtr SC_MINIMIZE = new IntPtr(0xF020); 31 | } 32 | 33 | #endregion 34 | 35 | 36 | private void btnOK_Click(object sender, EventArgs e) { 37 | Template = (Template)cmbTemplate.SelectedItem; 38 | } 39 | 40 | public Template Template { get; private set; } 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Source/Bimil/SelectTemplateForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Source/Bimil/Templates.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Medo.Security.Cryptography.PasswordSafe; 3 | 4 | namespace Bimil { 5 | internal static class Templates { 6 | 7 | private static Template[] TemplatesCache = null; 8 | 9 | public static Template[] GetTemplates() { 10 | if (Templates.TemplatesCache == null) { 11 | var list = new List