diff -Nru keepasshttp-1.8.4.1/debian/changelog keepasshttp-1.8.4.2/debian/changelog --- keepasshttp-1.8.4.1/debian/changelog 2016-12-22 19:43:07.000000000 +0000 +++ keepasshttp-1.8.4.2/debian/changelog 2017-04-27 16:13:21.000000000 +0000 @@ -1,3 +1,36 @@ +keepasshttp (1.8.4.2) trusty; urgency=medium + + [ iamquan ] + * Tips to run KeePassHttp on lastest KeePass 2.31 + + [ Perry Nguyen ] + * Update update-version.txt + + [ Ken Dale ] + * Add logo to match keepasshttp\KeePassHttp\Resources\earth_lock.png + + [ Vladimir Serykh ] + * Fixed exception System.ArgumentOutOfRangeException: Index was out of range + + [ Václav Valíček ] + * Firts steps in docs + * Another example json requests and responses + * added set-login and get-logins-count json examples + * get-logins-count: no SortSelection + + [ Stephen Schrauger ] + * adds feature to prevent returning expired entries + * fixes expire handler + * plugin compiled with new expire check feature + * removes plgx from branch + * fixes indent (change tab to space) + + [ Perry Nguyen ] + * 1.8.4.2 + + + -- David Lechner Thu, 27 Apr 2017 11:12:31 -0500 + keepasshttp (1.8.4.1) trusty; urgency=medium [ frankhommers ] diff -Nru keepasshttp-1.8.4.1/KeePassHttp/ConfigOpt.cs keepasshttp-1.8.4.2/KeePassHttp/ConfigOpt.cs --- keepasshttp-1.8.4.1/KeePassHttp/ConfigOpt.cs 2016-12-22 18:46:57.000000000 +0000 +++ keepasshttp-1.8.4.2/KeePassHttp/ConfigOpt.cs 2017-04-27 16:10:08.000000000 +0000 @@ -11,6 +11,7 @@ const string AlwaysAllowAccessKey = "KeePassHttp_AlwaysAllowAccess"; const string AlwaysAllowUpdatesKey = "KeePassHttp_AlwaysAllowUpdates"; const string SearchInAllOpenedDatabasesKey = "KeePassHttp_SearchInAllOpenedDatabases"; + const string HideExpiredKey = "KeePassHttp_HideExpired"; const string MatchSchemesKey = "KeePassHttp_MatchSchemes"; const string ReturnStringFieldsKey = "KeePassHttp_ReturnStringFields"; const string ReturnStringFieldsWithKphOnlyKey = "KeePassHttp_ReturnStringFieldsWithKphOnly"; @@ -59,6 +60,11 @@ set { _config.SetBool(SearchInAllOpenedDatabasesKey, value); } } + public bool HideExpired + { + get { return _config.GetBool(HideExpiredKey, false); } + set { _config.SetBool(HideExpiredKey, value); } + } public bool MatchSchemes { get { return _config.GetBool(MatchSchemesKey, false); } diff -Nru keepasshttp-1.8.4.1/KeePassHttp/Handlers.cs keepasshttp-1.8.4.2/KeePassHttp/Handlers.cs --- keepasshttp-1.8.4.1/KeePassHttp/Handlers.cs 2016-12-22 18:46:57.000000000 +0000 +++ keepasshttp-1.8.4.2/KeePassHttp/Handlers.cs 2017-04-27 16:10:08.000000000 +0000 @@ -234,6 +234,23 @@ result = from e in result where filterSchemes(e.entry) select e; } + Func hideExpired = delegate(PwEntry e) + { + DateTime dtNow = DateTime.UtcNow; + + if(e.Expires && (e.ExpiryTime <= dtNow)) + { + return false; + } + + return true; + }; + + if (configOpt.HideExpired) + { + result = from e in result where hideExpired(e.entry) select e; + } + return result; } @@ -350,7 +367,9 @@ orderby e.entry.UsageCount ascending select e).ToList(); - ulong lowestDistance = itemsList[0].entry.UsageCount; + ulong lowestDistance = itemsList.Count > 0 ? + itemsList[0].entry.UsageCount : + 0; itemsList = (from e in itemsList where e.entry.UsageCount == lowestDistance diff -Nru keepasshttp-1.8.4.1/KeePassHttp/OptionsForm.cs keepasshttp-1.8.4.2/KeePassHttp/OptionsForm.cs --- keepasshttp-1.8.4.1/KeePassHttp/OptionsForm.cs 2016-12-22 18:46:57.000000000 +0000 +++ keepasshttp-1.8.4.2/KeePassHttp/OptionsForm.cs 2017-04-27 16:10:08.000000000 +0000 @@ -41,6 +41,7 @@ credAllowAccessCheckbox.Checked = _config.AlwaysAllowAccess; credAllowUpdatesCheckbox.Checked = _config.AlwaysAllowUpdates; credSearchInAllOpenedDatabases.Checked = _config.SearchInAllOpenedDatabases; + hideExpiredCheckbox.Checked = _config.HideExpired; matchSchemesCheckbox.Checked = _config.MatchSchemes; returnStringFieldsCheckbox.Checked = _config.ReturnStringFields; returnStringFieldsWithKphOnlyCheckBox.Checked = _config.ReturnStringFieldsWithKphOnly; @@ -60,6 +61,7 @@ _config.AlwaysAllowAccess = credAllowAccessCheckbox.Checked; _config.AlwaysAllowUpdates = credAllowUpdatesCheckbox.Checked; _config.SearchInAllOpenedDatabases = credSearchInAllOpenedDatabases.Checked; + _config.HideExpired = hideExpiredCheckbox.Checked; _config.MatchSchemes = matchSchemesCheckbox.Checked; _config.ReturnStringFields = returnStringFieldsCheckbox.Checked; _config.ReturnStringFieldsWithKphOnly = returnStringFieldsWithKphOnlyCheckBox.Checked; diff -Nru keepasshttp-1.8.4.1/KeePassHttp/OptionsForm.Designer.cs keepasshttp-1.8.4.2/KeePassHttp/OptionsForm.Designer.cs --- keepasshttp-1.8.4.1/KeePassHttp/OptionsForm.Designer.cs 2016-12-22 18:46:57.000000000 +0000 +++ keepasshttp-1.8.4.2/KeePassHttp/OptionsForm.Designer.cs 2017-04-27 16:10:08.000000000 +0000 @@ -34,6 +34,7 @@ this.tabPage1 = new System.Windows.Forms.TabPage(); this.SortByUsernameRadioButton = new System.Windows.Forms.RadioButton(); this.SortByTitleRadioButton = new System.Windows.Forms.RadioButton(); + this.hideExpiredCheckbox = new System.Windows.Forms.CheckBox(); this.matchSchemesCheckbox = new System.Windows.Forms.CheckBox(); this.removePermissionsButton = new System.Windows.Forms.Button(); this.unlockDatabaseCheckbox = new System.Windows.Forms.CheckBox(); @@ -105,6 +106,7 @@ // this.tabPage1.Controls.Add(this.SortByUsernameRadioButton); this.tabPage1.Controls.Add(this.SortByTitleRadioButton); + this.tabPage1.Controls.Add(this.hideExpiredCheckbox); this.tabPage1.Controls.Add(this.matchSchemesCheckbox); this.tabPage1.Controls.Add(this.removePermissionsButton); this.tabPage1.Controls.Add(this.unlockDatabaseCheckbox); @@ -122,7 +124,7 @@ // SortByUsernameRadioButton // this.SortByUsernameRadioButton.AutoSize = true; - this.SortByUsernameRadioButton.Location = new System.Drawing.Point(7, 124); + this.SortByUsernameRadioButton.Location = new System.Drawing.Point(7, 147); this.SortByUsernameRadioButton.Name = "SortByUsernameRadioButton"; this.SortByUsernameRadioButton.Size = new System.Drawing.Size(171, 17); this.SortByUsernameRadioButton.TabIndex = 19; @@ -133,18 +135,28 @@ // SortByTitleRadioButton // this.SortByTitleRadioButton.AutoSize = true; - this.SortByTitleRadioButton.Location = new System.Drawing.Point(7, 147); + this.SortByTitleRadioButton.Location = new System.Drawing.Point(7, 170); this.SortByTitleRadioButton.Name = "SortByTitleRadioButton"; this.SortByTitleRadioButton.Size = new System.Drawing.Size(141, 17); this.SortByTitleRadioButton.TabIndex = 18; this.SortByTitleRadioButton.TabStop = true; this.SortByTitleRadioButton.Text = "Sort found entries by &title"; this.SortByTitleRadioButton.UseVisualStyleBackColor = true; - // + // + // hideExpiredCheckbox + // + this.hideExpiredCheckbox.AutoSize = true; + this.hideExpiredCheckbox.Location = new System.Drawing.Point(7, 88); + this.hideExpiredCheckbox.Name = "hideExpiredCheckbox"; + this.hideExpiredCheckbox.Size = new System.Drawing.Size(256, 17); + this.hideExpiredCheckbox.TabIndex = 17; + this.hideExpiredCheckbox.Text = "Don't return e&xpired entries"; + this.hideExpiredCheckbox.UseVisualStyleBackColor = true; + // // matchSchemesCheckbox - // + // this.matchSchemesCheckbox.AutoSize = true; - this.matchSchemesCheckbox.Location = new System.Drawing.Point(7, 88); + this.matchSchemesCheckbox.Location = new System.Drawing.Point(7, 111); this.matchSchemesCheckbox.Name = "matchSchemesCheckbox"; this.matchSchemesCheckbox.Size = new System.Drawing.Size(375, 30); this.matchSchemesCheckbox.TabIndex = 17; @@ -157,7 +169,7 @@ this.removePermissionsButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.removePermissionsButton.ImageAlign = System.Drawing.ContentAlignment.TopLeft; - this.removePermissionsButton.Location = new System.Drawing.Point(14, 216); + this.removePermissionsButton.Location = new System.Drawing.Point(14, 239); this.removePermissionsButton.Name = "removePermissionsButton"; this.removePermissionsButton.Size = new System.Drawing.Size(372, 28); this.removePermissionsButton.TabIndex = 16; @@ -179,7 +191,7 @@ // this.removeButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.removeButton.Location = new System.Drawing.Point(14, 182); + this.removeButton.Location = new System.Drawing.Point(14, 205); this.removeButton.Name = "removeButton"; this.removeButton.Size = new System.Drawing.Size(372, 28); this.removeButton.TabIndex = 11; @@ -451,6 +463,7 @@ private System.Windows.Forms.Button okButton; private System.Windows.Forms.TabControl tabControl1; private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.CheckBox hideExpiredCheckbox; private System.Windows.Forms.CheckBox matchSchemesCheckbox; private System.Windows.Forms.Button removePermissionsButton; private System.Windows.Forms.CheckBox unlockDatabaseCheckbox; diff -Nru keepasshttp-1.8.4.1/KeePassHttp/Properties/AssemblyInfo.cs keepasshttp-1.8.4.2/KeePassHttp/Properties/AssemblyInfo.cs --- keepasshttp-1.8.4.1/KeePassHttp/Properties/AssemblyInfo.cs 2016-12-22 18:46:57.000000000 +0000 +++ keepasshttp-1.8.4.2/KeePassHttp/Properties/AssemblyInfo.cs 2017-04-27 16:10:08.000000000 +0000 @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.21.0.0")] -[assembly: AssemblyFileVersion("1.8.4.1")] +[assembly: AssemblyVersion("2.34.0.0")] +[assembly: AssemblyFileVersion("1.8.4.2")] Binary files /tmp/tmpmMMZuR/Zk0iAsrC6V/keepasshttp-1.8.4.1/KeePassHttp.plgx and /tmp/tmpmMMZuR/juCRyqLG4C/keepasshttp-1.8.4.2/KeePassHttp.plgx differ Binary files /tmp/tmpmMMZuR/Zk0iAsrC6V/keepasshttp-1.8.4.1/logo.png and /tmp/tmpmMMZuR/juCRyqLG4C/keepasshttp-1.8.4.2/logo.png differ diff -Nru keepasshttp-1.8.4.1/README.md keepasshttp-1.8.4.2/README.md --- keepasshttp-1.8.4.1/README.md 2016-12-22 18:46:57.000000000 +0000 +++ keepasshttp-1.8.4.2/README.md 2017-04-27 16:10:08.000000000 +0000 @@ -35,6 +35,8 @@ * default directory in Arch: /usr/share/keepass 3. Set chmod 644 on file `KeePassHttp.plgx` 4. On linux systems you maybe need to install mono-complete: `$ apt-get install mono-complete` (in Debian it should be enough to install the packages libmono-system-runtime-serialization4.0-cil and libmono-posix2.0-cil) + * Tips to run KeePassHttp on lastest KeePass 2.31: install packages + `sudo apt-get install libmono-system-xml-linq4.0-cil libmono-system-data-datasetextensions4.0-cil libmono-system-runtime-serialization4.0-cil mono-mcs` 5. Restart KeePass ### KeePassHttp on Linux and Mac @@ -219,3 +221,206 @@ 2. server verifies payload and responds with success to client 3. client sends any of "get-logins-count", "get-logins", "set-login" using the previously negotiated key in (A) 4. if any subsequent request fails, it is necessary to "test-associate" again + +## A little deeper into protocol + +### Generic HTTP request +(based on packet sniffing and code analyssis) +Generic HTTP request is json sent in POST message. Cipher, by means of OpenSSL library is `AES-256-CBC`, so key is 32 byte long. + +``` +Host: localhost:19455 +Connection: keep-alive +Content-Length: 54 +Content-Type: application/json +Accept: */* +Accept-Encoding: gzip, deflate, br + +{"RequestType":"test-associate","TriggerUnlock":false} + +``` + +Also, minimal JSON request (except that one without key set up) consists of four main parameters: + - RequestType - `test-associate`, `associate`, `get-logins`, `get-logins-count`, `set-login`, ... + - TriggerUnlock - TODO: what is this good for? seems always false + - Nonce - 128 bit (16 bytes) long random vector, base64 encoded, used as IV for aes encryption + - Verifier - verifier, base64 encoded AES encrypted data: `encrypt(base64_encode($nonce), $key, $nonce);` + - Id - Key id entered into KeePass GUI while `associate`, not used during `associate` + +### test-associate +Request, without key, seems like initialization of every key assignation session: +```javascript +{ + "RequestType":"test-associate", + "TriggerUnlock":false +} +``` + +Response: (without success) +```javascript +{ + "Count":null, + "Entries":null, + "Error":"", + "Hash":"d8312a59523d3c37d6a5401d3cfddd077e194680", + "Id":"", + "Nonce":"", + "RequestType":"test-associate", + "Success":false, + "Verifier":"", + "Version":"1.8.4.1", + "objectName":"" +} +``` + +If you have key, you can test with request like this: +```javascript +{ + "Nonce":"+bG+EpbCR4jSnjROKAAw4A==", // random 128bit vector, base64 encoded + "Verifier":"2nVUxyddGpe62WGx5cm3hcb604Xn8AXrYxUK2WP9dU0=", // Nonce in base64 form, encoded with aes + "RequestType":"test-associate", + "TriggerUnlock":false, + "Id":"PHP" +} +``` + +### associate +Request: +```javascript +{ + "RequestType":"associate", + "Key":"CRyXRbH9vBkdPrkdm52S3bTG2rGtnYuyJttk/mlJ15g=", // Base64 encoded 256 bit key + "Nonce":"epIt2nuAZbHt5JgEsxolWg==", + "Verifier":"Lj+3N58jkjoxS2zNRmTpeQ4g065OlFfJsHNQWYaOJto=" +} +``` + +Response: +```javascript +{ + "Count":null, + "Entries":null, + "Error":"", + "Hash":"d8312a59523d3c37d6a5401d3cfddd077e194680", + "Id":"PHP", // You need to save this - to use in future + "Nonce":"cJUFe18NSThQ/0yAqZMaDA==", + "RequestType":"associate", + "Success":true, + "Verifier":"ChH0PtuQWP4UKTPhdP3XSgwFyVdekHmHT7YdL1EKA+A=", + "Version":"1.8.4.1", + "objectName":"" +} +``` + +### get-logins + +Request: +```javascript +{ + "RequestType":"get-logins", + "SortSelection":"true", + "TriggerUnlock":"false", + "Id":"PHP", + "Nonce":"vCysO8UwsWyE2b+nMzE3/Q==", + "Verifier":"5Nyi5973GawqdP3qF9QlAF/KlZAyvb6c5Smhun8n9wA=", + "Url":"Gz+ZCSjHAGmeYdrtS78hSxH3yD5LiYidSq9n+8TdQXc=", // Encrypted URL + "SubmitUrl":"" // Encrypted submit URL +} +``` + +Response: +```javascript +{ + "Count":3, + "Entries":[ + { + "Login":"{encrypted login base64}", + "Name":"{encrypted item name}", + "Password":"{encrypted Password}", + "StringFields":null, + "Uuid":"{encrypted UUID}" + }, + { + + }, + { + + } + ], + "Error":"", + "Hash":"d8312a59523d3c37d6a5401d3cfddd077e194680", + "Id":"PHP", + "Nonce":"Aeh9maerCjE5v5V8Tz2YxA==", + "RequestType":"get-logins", + "Success":true, + "Verifier":"F87c4ggkMTSEptJT8/FypBH491kRexTAiEZxovLMvD8=", + "Version":"1.8.4.1", + "objectName":"" +} + +``` + +### get-logins-count + +Request: +```javascript +{ + "RequestType":"get-logins-count", + "TriggerUnlock":"false", + "Id":"PHP", + "Nonce":"vCysO8UwsWyE2b+nMzE3/Q==", + "Verifier":"5Nyi5973GawqdP3qF9QlAF/KlZAyvb6c5Smhun8n9wA=", + "Url":"Gz+ZCSjHAGmeYdrtS78hSxH3yD5LiYidSq9n+8TdQXc=", // Encrypted URL + "SubmitUrl":"" // Encrypted submit URL +} +``` + +Response: +```javascript +{ + "Count":3, + "Entries":null, + "Error":"", + "Hash":"d8312a59523d3c37d6a5401d3cfddd077e194680", + "Id":"PHP", + "Nonce":"Aeh9maerCjE5v5V8Tz2YxA==", + "RequestType":"get-logins", + "Success":true, + "Verifier":"F87c4ggkMTSEptJT8/FypBH491kRexTAiEZxovLMvD8=", + "Version":"1.8.4.1", + "objectName":"" +} +``` + +### set-login + +Request: +```javascript +{ + "RequestType":"set-login", + "Id":"PHP", + "Nonce":"VBrPACEOQGxIBkq58/5Xig==", + "Verifier":"1dT0gnw6I1emxDzhtYn1Ecn1sobLG98GfTf7Z/Ma0R0=", + "Login":"lm9qo5HcAYEIaHsCdSsYHQ==", // encrypted username + "Password":"EZLtRxFgZVqIwv5xI9tfvA==", // encrypted password + "Url":"", + "SubmitUrl":"" +} +``` + +Response: +```javascript +{ + "Count":null, + "Entries":null, + "Error":"", + "Hash":"d8312a59523d3c37d6a5401d3cfddd077e194680", + "Id":"PHP", + "Nonce":"uofAcMtnPQo5TOdI21VjBw==", + "RequestType":"set-login", + "Success":true, + "Verifier":"4u8OINVGBtlCCPY7OnW5T616iPlzvf56LzPtPAwZIs0=", + "Version":"1.8.4.1", + "objectName":"" +} +``` diff -Nru keepasshttp-1.8.4.1/update-version.txt keepasshttp-1.8.4.2/update-version.txt --- keepasshttp-1.8.4.1/update-version.txt 2015-02-22 20:13:10.000000000 +0000 +++ keepasshttp-1.8.4.2/update-version.txt 2017-04-27 16:10:08.000000000 +0000 @@ -1,3 +1,3 @@ : -KeePassHttp:1.8.4.0 +KeePassHttp:1.8.4.1 :