First draft of the development version
780
chromeKeePassXC/background/aes.js
Normal file
|
|
@ -0,0 +1,780 @@
|
|||
/*
|
||||
* aes.js: implements AES - Advanced Encryption Standard
|
||||
* from the SlowAES project, http://code.google.com/p/slowaes/
|
||||
*
|
||||
* Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ),
|
||||
* Mark Percival ( http://mpercival.com ),
|
||||
*
|
||||
* Ported from C code written by Laurent Haan ( http://www.progressive-coding.com )
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0
|
||||
* http://www.apache.org/licenses/
|
||||
*/
|
||||
|
||||
var slowAES = {
|
||||
/*
|
||||
* START AES SECTION
|
||||
*/
|
||||
aes:{
|
||||
// structure of valid key sizes
|
||||
keySize:{
|
||||
SIZE_128:16,
|
||||
SIZE_192:24,
|
||||
SIZE_256:32
|
||||
},
|
||||
|
||||
// Rijndael S-box
|
||||
sbox:[
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ],
|
||||
|
||||
// Rijndael Inverted S-box
|
||||
rsbox:
|
||||
[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
|
||||
, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
|
||||
, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
|
||||
, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
|
||||
, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
|
||||
, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
|
||||
, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
|
||||
, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
|
||||
, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
|
||||
, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
|
||||
, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
|
||||
, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
|
||||
, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
|
||||
, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
|
||||
, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
|
||||
, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ],
|
||||
|
||||
/* rotate the word eight bits to the left */
|
||||
rotate:function(word)
|
||||
{
|
||||
var c = word[0];
|
||||
for (var i = 0; i < 3; i++)
|
||||
word[i] = word[i+1];
|
||||
word[3] = c;
|
||||
|
||||
return word;
|
||||
},
|
||||
|
||||
// Rijndael Rcon
|
||||
Rcon:[
|
||||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
|
||||
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
|
||||
0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
|
||||
0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d,
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab,
|
||||
0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
|
||||
0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25,
|
||||
0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01,
|
||||
0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
|
||||
0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa,
|
||||
0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a,
|
||||
0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,
|
||||
0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
|
||||
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
|
||||
0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
|
||||
0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
|
||||
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f,
|
||||
0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
|
||||
0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33,
|
||||
0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb ],
|
||||
|
||||
G2X: [
|
||||
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16,
|
||||
0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e,
|
||||
0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46,
|
||||
0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
|
||||
0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76,
|
||||
0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e,
|
||||
0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6,
|
||||
0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
|
||||
0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6,
|
||||
0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee,
|
||||
0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d,
|
||||
0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
|
||||
0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d,
|
||||
0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55,
|
||||
0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 0x7b, 0x79, 0x7f, 0x7d,
|
||||
0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
|
||||
0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d,
|
||||
0x83, 0x81, 0x87, 0x85, 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5,
|
||||
0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd,
|
||||
0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
|
||||
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed,
|
||||
0xe3, 0xe1, 0xe7, 0xe5
|
||||
],
|
||||
|
||||
G3X: [
|
||||
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d,
|
||||
0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39,
|
||||
0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65,
|
||||
0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
|
||||
0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d,
|
||||
0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9,
|
||||
0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5,
|
||||
0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
|
||||
0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd,
|
||||
0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99,
|
||||
0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e,
|
||||
0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
|
||||
0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6,
|
||||
0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2,
|
||||
0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, 0xcb, 0xc8, 0xcd, 0xce,
|
||||
0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
|
||||
0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46,
|
||||
0x4f, 0x4c, 0x49, 0x4a, 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62,
|
||||
0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e,
|
||||
0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
|
||||
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16,
|
||||
0x1f, 0x1c, 0x19, 0x1a
|
||||
],
|
||||
|
||||
G9X: [
|
||||
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53,
|
||||
0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf,
|
||||
0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b, 0x32, 0x29, 0x20,
|
||||
0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
|
||||
0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8,
|
||||
0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49,
|
||||
0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd,
|
||||
0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,
|
||||
0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e,
|
||||
0x21, 0x28, 0x33, 0x3a, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2,
|
||||
0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7,
|
||||
0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,
|
||||
0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f,
|
||||
0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8,
|
||||
0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 0x47, 0x4e, 0x55, 0x5c,
|
||||
0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,
|
||||
0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9,
|
||||
0xf6, 0xff, 0xe4, 0xed, 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35,
|
||||
0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba,
|
||||
0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,
|
||||
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62,
|
||||
0x5d, 0x54, 0x4f, 0x46
|
||||
],
|
||||
|
||||
GBX: [
|
||||
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45,
|
||||
0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81,
|
||||
0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b, 0x70, 0x6d, 0x66,
|
||||
0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,
|
||||
0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e,
|
||||
0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7,
|
||||
0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b,
|
||||
0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,
|
||||
0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8,
|
||||
0xf9, 0xf2, 0xef, 0xe4, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c,
|
||||
0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea,
|
||||
0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,
|
||||
0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02,
|
||||
0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd,
|
||||
0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 0x3c, 0x37, 0x2a, 0x21,
|
||||
0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,
|
||||
0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44,
|
||||
0x75, 0x7e, 0x63, 0x68, 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80,
|
||||
0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67,
|
||||
0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,
|
||||
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f,
|
||||
0xbe, 0xb5, 0xa8, 0xa3
|
||||
],
|
||||
|
||||
GDX: [
|
||||
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f,
|
||||
0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3,
|
||||
0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb, 0xb6, 0xa1, 0xac,
|
||||
0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,
|
||||
0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14,
|
||||
0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e,
|
||||
0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa,
|
||||
0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,
|
||||
0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9,
|
||||
0x8a, 0x87, 0x90, 0x9d, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25,
|
||||
0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd,
|
||||
0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,
|
||||
0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75,
|
||||
0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42,
|
||||
0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 0xb1, 0xbc, 0xab, 0xa6,
|
||||
0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,
|
||||
0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8,
|
||||
0xeb, 0xe6, 0xf1, 0xfc, 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44,
|
||||
0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b,
|
||||
0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,
|
||||
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3,
|
||||
0x80, 0x8d, 0x9a, 0x97
|
||||
],
|
||||
|
||||
GEX: [
|
||||
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62,
|
||||
0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca,
|
||||
0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb, 0xd5, 0xc7, 0xc9,
|
||||
0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,
|
||||
0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59,
|
||||
0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87,
|
||||
0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f,
|
||||
0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,
|
||||
0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14,
|
||||
0x3e, 0x30, 0x22, 0x2c, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc,
|
||||
0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53,
|
||||
0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,
|
||||
0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3,
|
||||
0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0,
|
||||
0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 0x7a, 0x74, 0x66, 0x68,
|
||||
0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,
|
||||
0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e,
|
||||
0xa4, 0xaa, 0xb8, 0xb6, 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26,
|
||||
0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25,
|
||||
0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,
|
||||
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5,
|
||||
0x9f, 0x91, 0x83, 0x8d
|
||||
],
|
||||
|
||||
// Key Schedule Core
|
||||
core:function(word,iteration)
|
||||
{
|
||||
/* rotate the 32-bit word 8 bits to the left */
|
||||
word = this.rotate(word);
|
||||
/* apply S-Box substitution on all 4 parts of the 32-bit word */
|
||||
for (var i = 0; i < 4; ++i)
|
||||
word[i] = this.sbox[word[i]];
|
||||
/* XOR the output of the rcon operation with i to the first part (leftmost) only */
|
||||
word[0] = word[0]^this.Rcon[iteration];
|
||||
return word;
|
||||
},
|
||||
|
||||
/* Rijndael's key expansion
|
||||
* expands an 128,192,256 key into an 176,208,240 bytes key
|
||||
*
|
||||
* expandedKey is a pointer to an char array of large enough size
|
||||
* key is a pointer to a non-expanded key
|
||||
*/
|
||||
expandKey:function(key,size)
|
||||
{
|
||||
var expandedKeySize = (16*(this.numberOfRounds(size)+1));
|
||||
|
||||
/* current expanded keySize, in bytes */
|
||||
var currentSize = 0;
|
||||
var rconIteration = 1;
|
||||
var t = []; // temporary 4-byte variable
|
||||
|
||||
var expandedKey = [];
|
||||
for(var i = 0;i < expandedKeySize;i++)
|
||||
expandedKey[i] = 0;
|
||||
|
||||
/* set the 16,24,32 bytes of the expanded key to the input key */
|
||||
for (var j = 0; j < size; j++)
|
||||
expandedKey[j] = key[j];
|
||||
currentSize += size;
|
||||
|
||||
while (currentSize < expandedKeySize)
|
||||
{
|
||||
/* assign the previous 4 bytes to the temporary value t */
|
||||
for (var k = 0; k < 4; k++)
|
||||
t[k] = expandedKey[(currentSize - 4) + k];
|
||||
|
||||
/* every 16,24,32 bytes we apply the core schedule to t
|
||||
* and increment rconIteration afterwards
|
||||
*/
|
||||
if(currentSize % size == 0)
|
||||
t = this.core(t, rconIteration++);
|
||||
|
||||
/* For 256-bit keys, we add an extra sbox to the calculation */
|
||||
if(size == this.keySize.SIZE_256 && ((currentSize % size) == 16))
|
||||
for(var l = 0; l < 4; l++)
|
||||
t[l] = this.sbox[t[l]];
|
||||
|
||||
/* We XOR t with the four-byte block 16,24,32 bytes before the new expanded key.
|
||||
* This becomes the next four bytes in the expanded key.
|
||||
*/
|
||||
for(var m = 0; m < 4; m++) {
|
||||
expandedKey[currentSize] = expandedKey[currentSize - size] ^ t[m];
|
||||
currentSize++;
|
||||
}
|
||||
}
|
||||
return expandedKey;
|
||||
},
|
||||
|
||||
// Adds (XORs) the round key to the state
|
||||
addRoundKey:function(state,roundKey)
|
||||
{
|
||||
for (var i = 0; i < 16; i++)
|
||||
state[i] ^= roundKey[i];
|
||||
return state;
|
||||
},
|
||||
|
||||
// Creates a round key from the given expanded key and the
|
||||
// position within the expanded key.
|
||||
createRoundKey:function(expandedKey,roundKeyPointer)
|
||||
{
|
||||
var roundKey = [];
|
||||
for (var i = 0; i < 4; i++)
|
||||
for (var j = 0; j < 4; j++)
|
||||
roundKey[j*4+i] = expandedKey[roundKeyPointer + i*4 + j];
|
||||
return roundKey;
|
||||
},
|
||||
|
||||
/* substitute all the values from the state with the value in the SBox
|
||||
* using the state value as index for the SBox
|
||||
*/
|
||||
subBytes:function(state,isInv)
|
||||
{
|
||||
for (var i = 0; i < 16; i++)
|
||||
state[i] = isInv?this.rsbox[state[i]]:this.sbox[state[i]];
|
||||
return state;
|
||||
},
|
||||
|
||||
/* iterate over the 4 rows and call shiftRow() with that row */
|
||||
shiftRows:function(state,isInv)
|
||||
{
|
||||
for (var i = 0; i < 4; i++)
|
||||
state = this.shiftRow(state,i*4, i,isInv);
|
||||
return state;
|
||||
},
|
||||
|
||||
/* each iteration shifts the row to the left by 1 */
|
||||
shiftRow:function(state,statePointer,nbr,isInv)
|
||||
{
|
||||
for (var i = 0; i < nbr; i++)
|
||||
{
|
||||
if(isInv)
|
||||
{
|
||||
var tmp = state[statePointer + 3];
|
||||
for (var j = 3; j > 0; j--)
|
||||
state[statePointer + j] = state[statePointer + j-1];
|
||||
state[statePointer] = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
var tmp = state[statePointer];
|
||||
for (var j = 0; j < 3; j++)
|
||||
state[statePointer + j] = state[statePointer + j+1];
|
||||
state[statePointer + 3] = tmp;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
},
|
||||
|
||||
// galois multiplication of 8 bit characters a and b
|
||||
galois_multiplication:function(a,b)
|
||||
{
|
||||
var p = 0;
|
||||
for(var counter = 0; counter < 8; counter++)
|
||||
{
|
||||
if((b & 1) == 1)
|
||||
p ^= a;
|
||||
if(p > 0x100) p ^= 0x100;
|
||||
var hi_bit_set = (a & 0x80); //keep p 8 bit
|
||||
a <<= 1;
|
||||
if(a > 0x100) a ^= 0x100; //keep a 8 bit
|
||||
if(hi_bit_set == 0x80)
|
||||
a ^= 0x1b;
|
||||
if(a > 0x100) a ^= 0x100; //keep a 8 bit
|
||||
b >>= 1;
|
||||
if(b > 0x100) b ^= 0x100; //keep b 8 bit
|
||||
}
|
||||
return p;
|
||||
},
|
||||
|
||||
// galois multipication of the 4x4 matrix
|
||||
mixColumns:function(state,isInv)
|
||||
{
|
||||
var column = [];
|
||||
/* iterate over the 4 columns */
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
/* construct one column by iterating over the 4 rows */
|
||||
for (var j = 0; j < 4; j++)
|
||||
column[j] = state[(j*4)+i];
|
||||
/* apply the mixColumn on one column */
|
||||
column = this.mixColumn(column,isInv);
|
||||
/* put the values back into the state */
|
||||
for (var k = 0; k < 4; k++)
|
||||
state[(k*4)+i] = column[k];
|
||||
}
|
||||
return state;
|
||||
},
|
||||
|
||||
// galois multipication of 1 column of the 4x4 matrix
|
||||
mixColumn:function(column,isInv)
|
||||
{
|
||||
var mult = [];
|
||||
if(isInv)
|
||||
mult = [14,9,13,11];
|
||||
else
|
||||
mult = [2,1,1,3];
|
||||
var cpy = [];
|
||||
for(var i = 0; i < 4; i++)
|
||||
cpy[i] = column[i];
|
||||
|
||||
column[0] = this.galois_multiplication(cpy[0],mult[0]) ^
|
||||
this.galois_multiplication(cpy[3],mult[1]) ^
|
||||
this.galois_multiplication(cpy[2],mult[2]) ^
|
||||
this.galois_multiplication(cpy[1],mult[3]);
|
||||
column[1] = this.galois_multiplication(cpy[1],mult[0]) ^
|
||||
this.galois_multiplication(cpy[0],mult[1]) ^
|
||||
this.galois_multiplication(cpy[3],mult[2]) ^
|
||||
this.galois_multiplication(cpy[2],mult[3]);
|
||||
column[2] = this.galois_multiplication(cpy[2],mult[0]) ^
|
||||
this.galois_multiplication(cpy[1],mult[1]) ^
|
||||
this.galois_multiplication(cpy[0],mult[2]) ^
|
||||
this.galois_multiplication(cpy[3],mult[3]);
|
||||
column[3] = this.galois_multiplication(cpy[3],mult[0]) ^
|
||||
this.galois_multiplication(cpy[2],mult[1]) ^
|
||||
this.galois_multiplication(cpy[1],mult[2]) ^
|
||||
this.galois_multiplication(cpy[0],mult[3]);
|
||||
return column;
|
||||
},
|
||||
|
||||
// applies the 4 operations of the forward round in sequence
|
||||
round:function(state, roundKey)
|
||||
{
|
||||
state = this.subBytes(state,false);
|
||||
state = this.shiftRows(state,false);
|
||||
state = this.mixColumns(state,false);
|
||||
state = this.addRoundKey(state, roundKey);
|
||||
return state;
|
||||
},
|
||||
|
||||
// applies the 4 operations of the inverse round in sequence
|
||||
invRound:function(state,roundKey)
|
||||
{
|
||||
state = this.shiftRows(state,true);
|
||||
state = this.subBytes(state,true);
|
||||
state = this.addRoundKey(state, roundKey);
|
||||
state = this.mixColumns(state,true);
|
||||
return state;
|
||||
},
|
||||
|
||||
/*
|
||||
* Perform the initial operations, the standard round, and the final operations
|
||||
* of the forward aes, creating a round key for each round
|
||||
*/
|
||||
main:function(state,expandedKey,nbrRounds)
|
||||
{
|
||||
state = this.addRoundKey(state, this.createRoundKey(expandedKey,0));
|
||||
for (var i = 1; i < nbrRounds; i++)
|
||||
state = this.round(state, this.createRoundKey(expandedKey,16*i));
|
||||
state = this.subBytes(state,false);
|
||||
state = this.shiftRows(state,false);
|
||||
state = this.addRoundKey(state, this.createRoundKey(expandedKey,16*nbrRounds));
|
||||
return state;
|
||||
},
|
||||
|
||||
/*
|
||||
* Perform the initial operations, the standard round, and the final operations
|
||||
* of the inverse aes, creating a round key for each round
|
||||
*/
|
||||
invMain:function(state, expandedKey, nbrRounds)
|
||||
{
|
||||
state = this.addRoundKey(state, this.createRoundKey(expandedKey,16*nbrRounds));
|
||||
for (var i = nbrRounds-1; i > 0; i--)
|
||||
state = this.invRound(state, this.createRoundKey(expandedKey,16*i));
|
||||
state = this.shiftRows(state,true);
|
||||
state = this.subBytes(state,true);
|
||||
state = this.addRoundKey(state, this.createRoundKey(expandedKey,0));
|
||||
return state;
|
||||
},
|
||||
|
||||
numberOfRounds:function(size)
|
||||
{
|
||||
var nbrRounds;
|
||||
switch (size) /* set the number of rounds */
|
||||
{
|
||||
case this.keySize.SIZE_128:
|
||||
nbrRounds = 10;
|
||||
break;
|
||||
case this.keySize.SIZE_192:
|
||||
nbrRounds = 12;
|
||||
break;
|
||||
case this.keySize.SIZE_256:
|
||||
nbrRounds = 14;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
return nbrRounds;
|
||||
},
|
||||
|
||||
// encrypts a 128 bit input block against the given key of size specified
|
||||
encrypt:function(input,key,size)
|
||||
{
|
||||
var output = [];
|
||||
var block = []; /* the 128 bit block to encode */
|
||||
var nbrRounds = this.numberOfRounds(size);
|
||||
/* Set the block values, for the block:
|
||||
* a0,0 a0,1 a0,2 a0,3
|
||||
* a1,0 a1,1 a1,2 a1,3
|
||||
* a2,0 a2,1 a2,2 a2,3
|
||||
* a3,0 a3,1 a3,2 a3,3
|
||||
* the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3
|
||||
*/
|
||||
for (var i = 0; i < 4; i++) /* iterate over the columns */
|
||||
for (var j = 0; j < 4; j++) /* iterate over the rows */
|
||||
block[(i+(j*4))] = input[(i*4)+j];
|
||||
|
||||
/* expand the key into an 176, 208, 240 bytes key */
|
||||
var expandedKey = this.expandKey(key, size); /* the expanded key */
|
||||
/* encrypt the block using the expandedKey */
|
||||
block = this.main(block, expandedKey, nbrRounds);
|
||||
for (var k = 0; k < 4; k++) /* unmap the block again into the output */
|
||||
for (var l = 0; l < 4; l++) /* iterate over the rows */
|
||||
output[(k*4)+l] = block[(k+(l*4))];
|
||||
return output;
|
||||
},
|
||||
|
||||
// decrypts a 128 bit input block against the given key of size specified
|
||||
decrypt:function(input, key, size)
|
||||
{
|
||||
var output = [];
|
||||
var block = []; /* the 128 bit block to decode */
|
||||
var nbrRounds = this.numberOfRounds(size);
|
||||
/* Set the block values, for the block:
|
||||
* a0,0 a0,1 a0,2 a0,3
|
||||
* a1,0 a1,1 a1,2 a1,3
|
||||
* a2,0 a2,1 a2,2 a2,3
|
||||
* a3,0 a3,1 a3,2 a3,3
|
||||
* the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3
|
||||
*/
|
||||
for (var i = 0; i < 4; i++) /* iterate over the columns */
|
||||
for (var j = 0; j < 4; j++) /* iterate over the rows */
|
||||
block[(i+(j*4))] = input[(i*4)+j];
|
||||
/* expand the key into an 176, 208, 240 bytes key */
|
||||
var expandedKey = this.expandKey(key, size);
|
||||
/* decrypt the block using the expandedKey */
|
||||
block = this.invMain(block, expandedKey, nbrRounds);
|
||||
for (var k = 0; k < 4; k++)/* unmap the block again into the output */
|
||||
for (var l = 0; l < 4; l++)/* iterate over the rows */
|
||||
output[(k*4)+l] = block[(k+(l*4))];
|
||||
return output;
|
||||
}
|
||||
},
|
||||
/*
|
||||
* END AES SECTION
|
||||
*/
|
||||
|
||||
/*
|
||||
* START MODE OF OPERATION SECTION
|
||||
*/
|
||||
//structure of supported modes of operation
|
||||
modeOfOperation:{
|
||||
OFB:0,
|
||||
CFB:1,
|
||||
CBC:2
|
||||
},
|
||||
|
||||
// get the next block of 16 bytes (aes operates on 128bits)
|
||||
getNextBlock: function(bytesIn,start,end,mode)
|
||||
{
|
||||
if(end - start > 16)
|
||||
end = start + 16;
|
||||
|
||||
return bytesIn.slice(start, end);
|
||||
},
|
||||
|
||||
/*
|
||||
* Mode of Operation Encryption
|
||||
* bytesIn - Input String as array of bytes
|
||||
* mode - mode of type modeOfOperation
|
||||
* key - a number array of length 'size'
|
||||
* size - the bit length of the key
|
||||
* iv - the 128 bit number array Initialization Vector
|
||||
*/
|
||||
encrypt: function (bytesIn, mode, key, iv)
|
||||
{
|
||||
var size = key.length;
|
||||
if(iv.length%16)
|
||||
{
|
||||
throw 'iv length must be 128 bits.';
|
||||
}
|
||||
// the AES input/output
|
||||
var byteArray = [];
|
||||
var input = [];
|
||||
var output = [];
|
||||
var ciphertext = [];
|
||||
var cipherOut = [];
|
||||
// char firstRound
|
||||
var firstRound = true;
|
||||
if (mode == this.modeOfOperation.CBC)
|
||||
this.padBytesIn(bytesIn);
|
||||
if (bytesIn !== null)
|
||||
{
|
||||
for (var j = 0;j < Math.ceil(bytesIn.length/16); j++)
|
||||
{
|
||||
var start = j*16;
|
||||
var end = j*16+16;
|
||||
if(j*16+16 > bytesIn.length)
|
||||
end = bytesIn.length;
|
||||
byteArray = this.getNextBlock(bytesIn,start,end,mode);
|
||||
if (mode == this.modeOfOperation.CFB)
|
||||
{
|
||||
if (firstRound)
|
||||
{
|
||||
output = this.aes.encrypt(iv, key, size);
|
||||
firstRound = false;
|
||||
}
|
||||
else
|
||||
output = this.aes.encrypt(input, key, size);
|
||||
for (var i = 0; i < 16; i++)
|
||||
ciphertext[i] = byteArray[i] ^ output[i];
|
||||
for(var k = 0;k < end-start;k++)
|
||||
cipherOut.push(ciphertext[k]);
|
||||
input = ciphertext;
|
||||
}
|
||||
else if (mode == this.modeOfOperation.OFB)
|
||||
{
|
||||
if (firstRound)
|
||||
{
|
||||
output = this.aes.encrypt(iv, key, size);
|
||||
firstRound = false;
|
||||
}
|
||||
else
|
||||
output = this.aes.encrypt(input, key, size);
|
||||
for (var i = 0; i < 16; i++)
|
||||
ciphertext[i] = byteArray[i] ^ output[i];
|
||||
for(var k = 0;k < end-start;k++)
|
||||
cipherOut.push(ciphertext[k]);
|
||||
input = output;
|
||||
}
|
||||
else if (mode == this.modeOfOperation.CBC)
|
||||
{
|
||||
for (var i = 0; i < 16; i++)
|
||||
input[i] = byteArray[i] ^ ((firstRound) ? iv[i] : ciphertext[i]);
|
||||
firstRound = false;
|
||||
ciphertext = this.aes.encrypt(input, key, size);
|
||||
// always 16 bytes because of the padding for CBC
|
||||
for(var k = 0;k < 16;k++)
|
||||
cipherOut.push(ciphertext[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cipherOut;
|
||||
},
|
||||
|
||||
/*
|
||||
* Mode of Operation Decryption
|
||||
* cipherIn - Encrypted String as array of bytes
|
||||
* originalsize - The unencrypted string length - required for CBC
|
||||
* mode - mode of type modeOfOperation
|
||||
* key - a number array of length 'size'
|
||||
* size - the bit length of the key
|
||||
* iv - the 128 bit number array Initialization Vector
|
||||
*/
|
||||
decrypt:function(cipherIn,mode,key,iv)
|
||||
{
|
||||
var size = key.length;
|
||||
if(iv.length%16)
|
||||
{
|
||||
throw 'iv length must be 128 bits.';
|
||||
}
|
||||
// the AES input/output
|
||||
var ciphertext = [];
|
||||
var input = [];
|
||||
var output = [];
|
||||
var byteArray = [];
|
||||
var bytesOut = [];
|
||||
// char firstRound
|
||||
var firstRound = true;
|
||||
if (cipherIn !== null)
|
||||
{
|
||||
for (var j = 0;j < Math.ceil(cipherIn.length/16); j++)
|
||||
{
|
||||
var start = j*16;
|
||||
var end = j*16+16;
|
||||
if(j*16+16 > cipherIn.length)
|
||||
end = cipherIn.length;
|
||||
ciphertext = this.getNextBlock(cipherIn,start,end,mode);
|
||||
if (mode == this.modeOfOperation.CFB)
|
||||
{
|
||||
if (firstRound)
|
||||
{
|
||||
output = this.aes.encrypt(iv, key, size);
|
||||
firstRound = false;
|
||||
}
|
||||
else
|
||||
output = this.aes.encrypt(input, key, size);
|
||||
for (i = 0; i < 16; i++)
|
||||
byteArray[i] = output[i] ^ ciphertext[i];
|
||||
for(var k = 0;k < end-start;k++)
|
||||
bytesOut.push(byteArray[k]);
|
||||
input = ciphertext;
|
||||
}
|
||||
else if (mode == this.modeOfOperation.OFB)
|
||||
{
|
||||
if (firstRound)
|
||||
{
|
||||
output = this.aes.encrypt(iv, key, size);
|
||||
firstRound = false;
|
||||
}
|
||||
else
|
||||
output = this.aes.encrypt(input, key, size);
|
||||
for (i = 0; i < 16; i++)
|
||||
byteArray[i] = output[i] ^ ciphertext[i];
|
||||
for(var k = 0;k < end-start;k++)
|
||||
bytesOut.push(byteArray[k]);
|
||||
input = output;
|
||||
}
|
||||
else if(mode == this.modeOfOperation.CBC)
|
||||
{
|
||||
output = this.aes.decrypt(ciphertext, key, size);
|
||||
for (i = 0; i < 16; i++)
|
||||
byteArray[i] = ((firstRound) ? iv[i] : input[i]) ^ output[i];
|
||||
firstRound = false;
|
||||
for(var k = 0;k < end-start;k++)
|
||||
bytesOut.push(byteArray[k]);
|
||||
input = ciphertext;
|
||||
}
|
||||
}
|
||||
if(mode == this.modeOfOperation.CBC)
|
||||
this.unpadBytesOut(bytesOut);
|
||||
}
|
||||
return bytesOut;
|
||||
},
|
||||
padBytesIn: function(data) {
|
||||
var len = data.length;
|
||||
var padByte = 16 - (len % 16);
|
||||
for (var i = 0; i < padByte; i++) {
|
||||
data.push(padByte);
|
||||
}
|
||||
},
|
||||
unpadBytesOut: function(data) {
|
||||
var padCount = 0;
|
||||
var padByte = -1;
|
||||
var blockSize = 16;
|
||||
for (var i = data.length - 1; i >= data.length-1 - blockSize; i--) {
|
||||
if (data[i] <= blockSize) {
|
||||
if (padByte == -1)
|
||||
padByte = data[i];
|
||||
if (data[i] != padByte) {
|
||||
padCount = 0;
|
||||
break;
|
||||
}
|
||||
padCount++;
|
||||
} else
|
||||
break;
|
||||
if (padCount == padByte)
|
||||
break;
|
||||
}
|
||||
if (padCount > 0)
|
||||
data.splice(data.length - padCount, padCount);
|
||||
}
|
||||
/*
|
||||
* END MODE OF OPERATION SECTION
|
||||
*/
|
||||
};
|
||||
266
chromeKeePassXC/background/browserAction.js
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
var browserAction = {};
|
||||
|
||||
var BLINK_TIMEOUT_DEFAULT = 7500;
|
||||
var BLINK_TIMEOUT_REDIRECT_THRESHOLD_TIME_DEFAULT = -1;
|
||||
var BLINK_TIMEOUT_REDIRECT_COUNT_DEFAULT = 1;
|
||||
|
||||
browserAction.show = function(callback, tab) {
|
||||
var data = {};
|
||||
if(!page.tabs[tab.id] || page.tabs[tab.id].stack.length == 0) {
|
||||
browserAction.showDefault(callback, tab);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
data = page.tabs[tab.id].stack[page.tabs[tab.id].stack.length - 1];
|
||||
}
|
||||
|
||||
chrome.browserAction.setIcon({
|
||||
tabId: tab.id,
|
||||
path: "/icons/19x19/" + browserAction.generateIconName(data.iconType, data.icon)
|
||||
});
|
||||
|
||||
if(data.popup) {
|
||||
chrome.browserAction.setPopup({
|
||||
tabId: tab.id,
|
||||
popup: "popups/" + data.popup
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
browserAction.update = function(interval) {
|
||||
if(!page.tabs[page.currentTabId] || page.tabs[page.currentTabId].stack.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var data = page.tabs[page.currentTabId].stack[page.tabs[page.currentTabId].stack.length - 1];
|
||||
|
||||
if(typeof data.visibleForMilliSeconds != "undefined") {
|
||||
if(data.visibleForMilliSeconds <= 0) {
|
||||
browserAction.stackPop(page.currentTabId);
|
||||
browserAction.show(null, {"id": page.currentTabId});
|
||||
page.clearCredentials(page.currentTabId);
|
||||
return;
|
||||
}
|
||||
data.visibleForMilliSeconds -= interval;
|
||||
}
|
||||
|
||||
if(data.intervalIcon) {
|
||||
data.intervalIcon.counter += 1;
|
||||
if(data.intervalIcon.counter < data.intervalIcon.max) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.intervalIcon.counter = 0;
|
||||
data.intervalIcon.index += 1;
|
||||
|
||||
if(data.intervalIcon.index > data.intervalIcon.icons.length - 1) {
|
||||
data.intervalIcon.index = 0;
|
||||
}
|
||||
|
||||
chrome.browserAction.setIcon({
|
||||
tabId: page.currentTabId,
|
||||
path: "/icons/19x19/" + browserAction.generateIconName(null, data.intervalIcon.icons[data.intervalIcon.index])
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
browserAction.showDefault = function(callback, tab) {
|
||||
var stackData = {
|
||||
level: 1,
|
||||
iconType: "normal",
|
||||
popup: "popup.html"
|
||||
}
|
||||
if(!keepass.isConfigured() || keepass.isDatabaseClosed || !keepass.isKeePassXCAvailable || page.tabs[tab.id].errorMessage) {
|
||||
stackData.iconType = "cross";
|
||||
}
|
||||
|
||||
if(page.tabs[tab.id].loginList.length > 0) {
|
||||
stackData.iconType = "questionmark";
|
||||
stackData.popup = "popup_login.html";
|
||||
}
|
||||
|
||||
browserAction.stackUnshift(stackData, tab.id);
|
||||
|
||||
browserAction.show(null, tab);
|
||||
}
|
||||
|
||||
browserAction.stackAdd = function(callback, tab, icon, popup, level, push, visibleForMilliSeconds, visibleForPageUpdates, redirectOffset, dontShow) {
|
||||
var id = tab.id || page.currentTabId;
|
||||
|
||||
if(!level) {
|
||||
level = 1;
|
||||
}
|
||||
|
||||
var stackData = {
|
||||
"level": level,
|
||||
"icon": icon
|
||||
}
|
||||
|
||||
if(popup) {
|
||||
stackData.popup = popup;
|
||||
}
|
||||
|
||||
if(visibleForMilliSeconds) {
|
||||
stackData.visibleForMilliSeconds = visibleForMilliSeconds;
|
||||
}
|
||||
|
||||
if(visibleForPageUpdates) {
|
||||
stackData.visibleForPageUpdates = visibleForPageUpdates;
|
||||
}
|
||||
|
||||
if(redirectOffset) {
|
||||
stackData.redirectOffset = redirectOffset;
|
||||
}
|
||||
|
||||
if(push) {
|
||||
browserAction.stackPush(stackData, id);
|
||||
}
|
||||
else {
|
||||
browserAction.stackUnshift(stackData, id);
|
||||
}
|
||||
|
||||
if(!dontShow) {
|
||||
browserAction.show(null, {"id": id});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
browserAction.removeLevelFromStack = function(callback, tab, level, type, dontShow) {
|
||||
if(!page.tabs[tab.id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!type) {
|
||||
type = "<=";
|
||||
}
|
||||
|
||||
var newStack = [];
|
||||
for(var i = 0; i < page.tabs[tab.id].stack.length; i++) {
|
||||
if(
|
||||
(type == "<" && page.tabs[tab.id].stack[i].level >= level) ||
|
||||
(type == "<=" && page.tabs[tab.id].stack[i].level > level) ||
|
||||
(type == "=" && page.tabs[tab.id].stack[i].level != level) ||
|
||||
(type == "==" && page.tabs[tab.id].stack[i].level != level) ||
|
||||
(type == "!=" && page.tabs[tab.id].stack[i].level == level) ||
|
||||
(type == ">" && page.tabs[tab.id].stack[i].level <= level) ||
|
||||
(type == ">=" && page.tabs[tab.id].stack[i].level < level)
|
||||
) {
|
||||
newStack.push(page.tabs[tab.id].stack[i]);
|
||||
}
|
||||
}
|
||||
|
||||
page.tabs[tab.id].stack = newStack;
|
||||
|
||||
if(!dontShow) {
|
||||
browserAction.show(callback, tab);
|
||||
}
|
||||
}
|
||||
|
||||
browserAction.stackPop = function(tabId) {
|
||||
var id = tabId || page.currentTabId;
|
||||
|
||||
page.tabs[id].stack.pop();
|
||||
};
|
||||
|
||||
browserAction.stackPush = function(data, tabId) {
|
||||
var id = tabId || page.currentTabId;
|
||||
|
||||
browserAction.removeLevelFromStack(null, {"id": id}, data.level, "<=", true);
|
||||
page.tabs[id].stack.push(data);
|
||||
};
|
||||
|
||||
browserAction.stackUnshift = function(data, tabId) {
|
||||
var id = tabId || page.currentTabId;
|
||||
|
||||
browserAction.removeLevelFromStack(null, {"id": id}, data.level, "<=", true);
|
||||
page.tabs[id].stack.unshift(data);
|
||||
};
|
||||
|
||||
|
||||
browserAction.removeRememberPopup = function(callback, tab, removeImmediately) {
|
||||
if(!page.tabs[tab.id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(page.tabs[tab.id].stack.length == 0) {
|
||||
page.clearCredentials(tab.id);
|
||||
return;
|
||||
}
|
||||
var data = page.tabs[tab.id].stack[page.tabs[tab.id].stack.length - 1];
|
||||
|
||||
if(removeImmediately || !isNaN(data.visibleForPageUpdates)) {
|
||||
var currentMS = Date.now();
|
||||
if( removeImmediately || (data.visibleForPageUpdates <= 0 && data.redirectOffset > 0)) {
|
||||
browserAction.stackPop(tab.id);
|
||||
browserAction.show(null, {"id": tab.id});
|
||||
page.clearCredentials(tab.id);
|
||||
return;
|
||||
}
|
||||
else if (!isNaN(data.visibleForPageUpdates) && data.redirectOffset > 0 && currentMS >= data.redirectOffset) {
|
||||
data.visibleForPageUpdates = data.visibleForPageUpdates - 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
browserAction.setRememberPopup = function(tabId, username, password, url, usernameExists, credentialsList) {
|
||||
var settings = typeof(localStorage.settings)=='undefined' ? {} : JSON.parse(localStorage.settings);
|
||||
|
||||
var id = tabId || page.currentTabId;
|
||||
|
||||
var timeoutMinMillis = parseInt(getValueOrDefault(settings, "blinkMinTimeout", BLINK_TIMEOUT_REDIRECT_THRESHOLD_TIME_DEFAULT, 0)) ;
|
||||
if (timeoutMinMillis > 0) {
|
||||
timeoutMinMillis += Date.now();
|
||||
}
|
||||
var blinkTimeout = getValueOrDefault(settings, "blinkTimeout", BLINK_TIMEOUT_DEFAULT, 0);
|
||||
var pageUpdateAllowance = getValueOrDefault(settings, "allowedRedirect", BLINK_TIMEOUT_REDIRECT_COUNT_DEFAULT, 0);
|
||||
|
||||
var stackData = {
|
||||
visibleForMilliSeconds: blinkTimeout,
|
||||
visibleForPageUpdates: pageUpdateAllowance,
|
||||
redirectOffset: timeoutMinMillis,
|
||||
level: 10,
|
||||
intervalIcon: {
|
||||
index: 0,
|
||||
counter: 0,
|
||||
max: 2,
|
||||
icons: ["icon_remember_red_background_19x19.png", "icon_remember_red_lock_19x19.png"]
|
||||
},
|
||||
icon: "icon_remember_red_background_19x19.png",
|
||||
popup: "popup_remember.html"
|
||||
}
|
||||
|
||||
browserAction.stackPush(stackData, id);
|
||||
|
||||
page.tabs[id].credentials = {
|
||||
"username": username,
|
||||
"password": password,
|
||||
"url": url,
|
||||
"usernameExists": usernameExists,
|
||||
"list": credentialsList
|
||||
};
|
||||
|
||||
browserAction.show(null, {"id": id});
|
||||
}
|
||||
|
||||
function getValueOrDefault(settings, key, defaultVal, min) {
|
||||
try {
|
||||
var val = settings[key];
|
||||
if (isNaN(val) || val < min) {
|
||||
val = defaultVal;
|
||||
}
|
||||
return val;
|
||||
} catch(e) { return defaultVal; }
|
||||
}
|
||||
|
||||
browserAction.generateIconName = function(iconType, icon) {
|
||||
if(icon) {
|
||||
return icon;
|
||||
}
|
||||
|
||||
var name = "icon_";
|
||||
name += (keepass.keePassXCUpdateAvailable()) ? "new_" : "";
|
||||
name += (!iconType || iconType == "normal") ? "normal" : iconType;
|
||||
name += "_19x19.png";
|
||||
|
||||
return name;
|
||||
}
|
||||
181
chromeKeePassXC/background/cryptoHelpers.js
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* cryptoHelpers.js: implements AES - Advanced Encryption Standard
|
||||
* from the SlowAES project, http://code.google.com/p/slowaes/
|
||||
*
|
||||
* Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ),
|
||||
* Mark Percival ( http://mpercival.com ),
|
||||
* Johan Sundstrom ( http://ecmanaut.blogspot.com ),
|
||||
* John Resig ( http://ejohn.org )
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0
|
||||
* http://www.apache.org/licenses/
|
||||
*/
|
||||
|
||||
var cryptoHelpers = {
|
||||
// encodes a unicode string to UTF8 (8 bit characters are critical to AES functioning properly)
|
||||
encode_utf8:function(s)
|
||||
{
|
||||
try{return unescape(encodeURIComponent(s));}
|
||||
catch(e){throw 'error during utf8 encoding: cryptoHelpers.encode_utf8.';}
|
||||
},
|
||||
|
||||
// decodes a UTF8 string back to unicode
|
||||
decode_utf8:function(s)
|
||||
{
|
||||
try{return decodeURIComponent(escape(s));}
|
||||
catch(e){throw('error during utf8 decoding: cryptoHelpers.decode_utf8.');}
|
||||
},
|
||||
|
||||
//convert a number array to a hex string
|
||||
toHex:function()
|
||||
{
|
||||
var array = [];
|
||||
if(arguments.length == 1 && arguments[0].constructor == Array)
|
||||
array = arguments[0];
|
||||
else
|
||||
array = arguments;
|
||||
var ret = '';
|
||||
for(var i = 0;i < array.length;i++)
|
||||
ret += (array[i] < 16 ? '0' : '') + array[i].toString(16);
|
||||
return ret.toLowerCase();
|
||||
},
|
||||
|
||||
//convert a hex string to a number array
|
||||
toNumbers:function(s)
|
||||
{
|
||||
var ret = [];
|
||||
s.replace(/(..)/g,function(s){
|
||||
ret.push(parseInt(s,16));
|
||||
});
|
||||
return ret;
|
||||
},
|
||||
|
||||
// get a random number in the range [min,max]
|
||||
getRandom:function(min,max)
|
||||
{
|
||||
if(min === null)
|
||||
min = 0;
|
||||
if(max === null)
|
||||
max = 1;
|
||||
return Math.floor(Math.random()*(max+1)) + min;
|
||||
},
|
||||
|
||||
generateSharedKey:function(len)
|
||||
{
|
||||
if(len === null)
|
||||
len = 16;
|
||||
var key = [];
|
||||
for(var i = 0; i < len*2; i++)
|
||||
key.push(this.getRandom(0,255));
|
||||
return key;
|
||||
},
|
||||
|
||||
generatePrivateKey:function(s,size)
|
||||
{
|
||||
var sha = jsHash.sha2.arr_sha256(s);
|
||||
return sha.slice(0,size);
|
||||
},
|
||||
|
||||
convertStringToByteArray: function(s)
|
||||
{
|
||||
var byteArray = [];
|
||||
for(var i = 0;i < s.length;i++)
|
||||
{
|
||||
byteArray.push(s.charCodeAt(i));
|
||||
}
|
||||
return byteArray;
|
||||
},
|
||||
|
||||
convertByteArrayToString: function(byteArray)
|
||||
{
|
||||
var s = '';
|
||||
for(var i = 0;i < byteArray.length;i++)
|
||||
{
|
||||
s += String.fromCharCode(byteArray[i])
|
||||
}
|
||||
return s;
|
||||
},
|
||||
|
||||
base64: {
|
||||
// Takes a Nx16x1 byte array and converts it to Base64
|
||||
chars: [
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/',
|
||||
'=', // for decoding purposes
|
||||
],
|
||||
|
||||
encode_line: function(flatArr){
|
||||
var b64 = '';
|
||||
|
||||
for (var i = 0; i < flatArr.length; i += 3){
|
||||
b64 += this.chars[flatArr[i] >> 2];
|
||||
b64 += this.chars[((flatArr[i] & 3) << 4) | (flatArr[i + 1] >> 4)];
|
||||
if (!(flatArr[i + 1] == null)){
|
||||
b64 += this.chars[((flatArr[i + 1] & 15) << 2) | (flatArr[i + 2] >> 6)];
|
||||
}else{
|
||||
b64 += '=';
|
||||
}
|
||||
if (!(flatArr[i + 2] == null)){
|
||||
b64 += this.chars[flatArr[i + 2] & 63];
|
||||
}else{
|
||||
b64 += '=';
|
||||
}
|
||||
}
|
||||
return b64;
|
||||
},
|
||||
|
||||
encode: function(flatArr)
|
||||
{
|
||||
var b64 = this.encode_line(flatArr);
|
||||
// OpenSSL is super particular about line breaks
|
||||
var broken_b64 = b64.slice(0, 64) + '\n';
|
||||
for (var i = 1; i < (Math.ceil(b64.length / 64)); i++)
|
||||
{
|
||||
broken_b64 += b64.slice(i * 64, i * 64 + 64) + (Math.ceil(b64.length / 64) == i + 1 ? '': '\n');
|
||||
}
|
||||
return broken_b64;
|
||||
},
|
||||
|
||||
decode: function(string)
|
||||
{
|
||||
string = string.replace(/[\r\n\t ]+/g, '') + '===='; // drop all whitespaces and pad with '=' (end of b64 marker)
|
||||
var flatArr = [];
|
||||
var c = [];
|
||||
var b = [];
|
||||
for (var i = 0; ; i = i + 4){
|
||||
c[0] = this.chars.indexOf(string.charAt(i));
|
||||
if(c[0] == 64){
|
||||
return flatArr;
|
||||
}
|
||||
c[1] = this.chars.indexOf(string.charAt(i + 1));
|
||||
c[2] = this.chars.indexOf(string.charAt(i + 2));
|
||||
c[3] = this.chars.indexOf(string.charAt(i + 3));
|
||||
|
||||
if(
|
||||
(c[0] < 0) || // char1 is wrong
|
||||
(c[1] < 0) || (c[1] == 64) || // char2 is wrong
|
||||
(c[2] < 0) || // char3 is neither an valid char nor '='
|
||||
(c[3] < 0) // char4 is neither an valid char nor '='
|
||||
){
|
||||
throw 'error during base64 decoding at pos '+i+': cryptoHelpers.base64.decode.';
|
||||
}
|
||||
|
||||
flatArr.push((c[0] << 2) | (c[1] >> 4));
|
||||
if(c[2] >= 0 && c[2] < 64){
|
||||
flatArr.push(((c[1] & 15) << 4) | (c[2] >> 2));
|
||||
if(c[3] >= 0 && c[2] < 64){
|
||||
flatArr.push(((c[2] & 3) << 6) | c[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
};
|
||||
245
chromeKeePassXC/background/event.js
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
var event = {};
|
||||
|
||||
|
||||
event.onMessage = function(request, sender, callback) {
|
||||
if (request.action in event.messageHandlers) {
|
||||
//console.log("onMessage(" + request.action + ") for #" + sender.tab.id);
|
||||
|
||||
if(!sender.hasOwnProperty('tab') || sender.tab.id < 1) {
|
||||
sender.tab = {};
|
||||
sender.tab.id = page.currentTabId;
|
||||
}
|
||||
|
||||
event.invoke(event.messageHandlers[request.action], callback, sender.tab.id, request.args);
|
||||
|
||||
// onMessage closes channel for callback automatically
|
||||
// if this method does not return true
|
||||
if(callback) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get interesting information about the given tab.
|
||||
* Function adapted from AdBlock-Plus.
|
||||
*
|
||||
* @param {function} handler to call after invoke
|
||||
* @param {function} callback to call after handler or null
|
||||
* @param {integer} senderTabId
|
||||
* @param {array} args
|
||||
* @param {bool} secondTime
|
||||
* @returns null (asynchronous)
|
||||
*/
|
||||
event.invoke = function(handler, callback, senderTabId, args, secondTime) {
|
||||
if(senderTabId < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!page.tabs[senderTabId]) {
|
||||
page.createTabEntry(senderTabId);
|
||||
}
|
||||
|
||||
// remove information from no longer existing tabs
|
||||
page.removePageInformationFromNotExistingTabs();
|
||||
|
||||
chrome.tabs.get(senderTabId, function(tab) {
|
||||
//chrome.tabs.query({"active": true, "windowId": chrome.windows.WINDOW_ID_CURRENT}, function(tabs) {
|
||||
//if (tabs.length === 0)
|
||||
// return; // For example: only the background devtools or a popup are opened
|
||||
//var tab = tabs[0];
|
||||
|
||||
if(!tab) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tab.url) {
|
||||
// Issue 6877: tab URL is not set directly after you opened a window
|
||||
// using window.open()
|
||||
if (!secondTime) {
|
||||
window.setTimeout(function() {
|
||||
event.invoke(handler, callback, senderTabId, args, true);
|
||||
}, 250);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!page.tabs[tab.id]) {
|
||||
page.createTabEntry(tab.id);
|
||||
}
|
||||
|
||||
args = args || [];
|
||||
|
||||
args.unshift(tab);
|
||||
args.unshift(callback);
|
||||
|
||||
if(handler) {
|
||||
handler.apply(this, args);
|
||||
}
|
||||
else {
|
||||
console.log("undefined handler for tab " + tab.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
event.onShowAlert = function(callback, tab, message) {
|
||||
if( page.settings.supressAlerts ){ console.log(message); }
|
||||
else { alert(message); }
|
||||
}
|
||||
|
||||
event.onLoadSettings = function(callback, tab) {
|
||||
page.settings = (typeof(localStorage.settings) == 'undefined') ? {} : JSON.parse(localStorage.settings);
|
||||
}
|
||||
|
||||
event.onLoadKeyRing = function(callback, tab) {
|
||||
keepass.keyRing = (typeof(localStorage.keyRing) == 'undefined') ? {} : JSON.parse(localStorage.keyRing);
|
||||
if(keepass.isAssociated() && !keepass.keyRing[keepass.associated.hash]) {
|
||||
keepass.associated = {
|
||||
"value": false,
|
||||
"hash": null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
event.onGetSettings = function(callback, tab) {
|
||||
event.onLoadSettings();
|
||||
callback({ data: page.settings });
|
||||
}
|
||||
|
||||
event.onSaveSettings = function(callback, tab, settings) {
|
||||
localStorage.settings = JSON.stringify(settings);
|
||||
event.onLoadSettings();
|
||||
}
|
||||
|
||||
event.onGetStatus = function(callback, tab) {
|
||||
keepass.testAssociation(tab);
|
||||
|
||||
var configured = keepass.isConfigured();
|
||||
var keyId = null;
|
||||
if (configured) {
|
||||
keyId = keepass.keyRing[keepass.databaseHash].id;
|
||||
}
|
||||
|
||||
browserAction.showDefault(null, tab);
|
||||
|
||||
callback({
|
||||
identifier: keyId,
|
||||
configured: configured,
|
||||
databaseClosed: keepass.isDatabaseClosed,
|
||||
keePassXCAvailable: keepass.isKeePassXCAvailable,
|
||||
encryptionKeyUnrecognized: keepass.isEncryptionKeyUnrecognized,
|
||||
associated: keepass.isAssociated(),
|
||||
error: page.tabs[tab.id].errorMessage
|
||||
});
|
||||
}
|
||||
|
||||
event.onPopStack = function(callback, tab) {
|
||||
browserAction.stackPop(tab.id);
|
||||
browserAction.show(null, tab);
|
||||
}
|
||||
|
||||
event.onGetTabInformation = function(callback, tab) {
|
||||
var id = tab.id || page.currentTabId;
|
||||
|
||||
callback(page.tabs[id]);
|
||||
}
|
||||
|
||||
event.onGetConnectedDatabase = function(callback, tab) {
|
||||
callback({
|
||||
"count": Object.keys(keepass.keyRing).length,
|
||||
"identifier": (keepass.keyRing[keepass.associated.hash]) ? keepass.keyRing[keepass.associated.hash].id : null
|
||||
});
|
||||
}
|
||||
|
||||
event.onGetKeePassXCVersions = function(callback, tab) {
|
||||
if(keepass.currentKeePassXC.version == 0) {
|
||||
keepass.getDatabaseHash(tab);
|
||||
}
|
||||
callback({"current": keepass.currentKeePassXC.version, "latest": keepass.latestKeePassXC.version});
|
||||
}
|
||||
|
||||
event.onCheckUpdateKeePassXC = function(callback, tab) {
|
||||
keepass.checkForNewKeePassXCVersion();
|
||||
callback({"current": keepass.currentKeePassXC.version, "latest": keepass.latestKeePassXC.version});
|
||||
}
|
||||
|
||||
event.onUpdateAvailableKeePassXC = function(callback, tab) {
|
||||
callback(keepass.keePassXCUpdateAvailable());
|
||||
}
|
||||
|
||||
event.onRemoveCredentialsFromTabInformation = function(callback, tab) {
|
||||
var id = tab.id || page.currentTabId;
|
||||
|
||||
page.clearCredentials(id);
|
||||
}
|
||||
|
||||
event.onSetRememberPopup = function(callback, tab, username, password, url, usernameExists, credentialsList) {
|
||||
browserAction.setRememberPopup(tab.id, username, password, url, usernameExists, credentialsList);
|
||||
}
|
||||
|
||||
event.onLoginPopup = function(callback, tab, logins) {
|
||||
var stackData = {
|
||||
level: 1,
|
||||
iconType: "questionmark",
|
||||
popup: "popup_login.html"
|
||||
}
|
||||
browserAction.stackUnshift(stackData, tab.id);
|
||||
|
||||
page.tabs[tab.id].loginList = logins;
|
||||
|
||||
browserAction.show(null, tab);
|
||||
}
|
||||
|
||||
event.onHTTPAuthPopup = function(callback, tab, data) {
|
||||
var stackData = {
|
||||
level: 1,
|
||||
iconType: "questionmark",
|
||||
popup: "popup_httpauth.html"
|
||||
}
|
||||
browserAction.stackUnshift(stackData, tab.id);
|
||||
|
||||
page.tabs[tab.id].loginList = data;
|
||||
|
||||
browserAction.show(null, tab);
|
||||
}
|
||||
|
||||
event.onMultipleFieldsPopup = function(callback, tab) {
|
||||
var stackData = {
|
||||
level: 1,
|
||||
iconType: "normal",
|
||||
popup: "popup_multiple-fields.html"
|
||||
}
|
||||
browserAction.stackUnshift(stackData, tab.id);
|
||||
|
||||
browserAction.show(null, tab);
|
||||
}
|
||||
|
||||
|
||||
// all methods named in this object have to be declared BEFORE this!
|
||||
event.messageHandlers = {
|
||||
'add_credentials': keepass.addCredentials,
|
||||
'alert': event.onShowAlert,
|
||||
'associate': keepass.associate,
|
||||
'check_update_keepassxc': event.onCheckUpdateKeePassXC,
|
||||
'get_connected_database': event.onGetConnectedDatabase,
|
||||
'get_keepassxc_versions': event.onGetKeePassXCVersions,
|
||||
'get_settings': event.onGetSettings,
|
||||
'get_status': event.onGetStatus,
|
||||
'get_tab_information': event.onGetTabInformation,
|
||||
'load_keyring': event.onLoadKeyRing,
|
||||
'load_settings': event.onLoadSettings,
|
||||
'pop_stack': event.onPopStack,
|
||||
'popup_login': event.onLoginPopup,
|
||||
'popup_multiple-fields': event.onMultipleFieldsPopup,
|
||||
'remove_credentials_from_tab_information': event.onRemoveCredentialsFromTabInformation,
|
||||
'retrieve_credentials': keepass.retrieveCredentials,
|
||||
'show_default_browseraction': browserAction.showDefault,
|
||||
'update_credentials': keepass.updateCredentials,
|
||||
'save_settings': event.onSaveSettings,
|
||||
'set_remember_credentials': event.onSetRememberPopup,
|
||||
'stack_add': browserAction.stackAdd,
|
||||
'update_available_keepassxc': event.onUpdateAvailableKeePassXC,
|
||||
'generate_password': keepass.generatePassword,
|
||||
'copy_password': keepass.copyPassword
|
||||
};
|
||||
65
chromeKeePassXC/background/httpauth.js
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
var httpAuth = httpAuth || {};
|
||||
|
||||
httpAuth.pendingCallbacks = [];
|
||||
httpAuth.requestId = "";
|
||||
httpAuth.callback = null;
|
||||
httpAuth.tabId = 0;
|
||||
httpAuth.url = null;
|
||||
httpAuth.isProxy = false;
|
||||
httpAuth.proxyUrl = null;
|
||||
|
||||
|
||||
httpAuth.handleRequest = function (details, callback) {
|
||||
if(httpAuth.requestId == details.requestId || !page.tabs[details.tabId]) {
|
||||
callback({});
|
||||
}
|
||||
else {
|
||||
httpAuth.requestId = details.requestId;
|
||||
httpAuth.pendingCallbacks.push(callback);
|
||||
httpAuth.processPendingCallbacks(details);
|
||||
}
|
||||
}
|
||||
|
||||
httpAuth.processPendingCallbacks = function(details) {
|
||||
httpAuth.callback = httpAuth.pendingCallbacks.pop();
|
||||
httpAuth.tabId = details.tabId;
|
||||
httpAuth.url = details.url;
|
||||
httpAuth.isProxy = details.isProxy;
|
||||
|
||||
if(details.challenger){
|
||||
httpAuth.proxyUrl = details.challenger.host;
|
||||
}
|
||||
|
||||
// WORKAROUND: second parameter should be tab, but is an own object with tab-id
|
||||
// but in background.js only tab.id is used. To get tabs we could use
|
||||
// chrome.tabs.get(tabId, callback) <-- but what should callback be?
|
||||
|
||||
var url = (httpAuth.isProxy && httpAuth.proxyUrl) ? httpAuth.proxyUrl : httpAuth.url;
|
||||
|
||||
keepass.retrieveCredentials(httpAuth.loginOrShowCredentials, { "id" : details.tabId }, url, url, true);
|
||||
}
|
||||
|
||||
httpAuth.loginOrShowCredentials = function(logins) {
|
||||
// at least one login found --> use first to login
|
||||
if (logins.length > 0) {
|
||||
var url = (httpAuth.isProxy && httpAuth.proxyUrl) ? httpAuth.proxyUrl : httpAuth.url;
|
||||
event.onHTTPAuthPopup(null, {"id": httpAuth.tabId}, {"logins": logins, "url": url});
|
||||
//generate popup-list for HTTP Auth usernames + descriptions
|
||||
|
||||
if(page.settings.autoFillAndSend) {
|
||||
httpAuth.callback({
|
||||
authCredentials: {
|
||||
username: logins[0].Login,
|
||||
password: logins[0].Password
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
httpAuth.callback({});
|
||||
}
|
||||
}
|
||||
// no logins found
|
||||
else {
|
||||
httpAuth.callback({});
|
||||
}
|
||||
}
|
||||
152
chromeKeePassXC/background/init.js
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
// since version 2.0 the extension is using a keyRing instead of a single key-name-pair
|
||||
keepass.convertKeyToKeyRing();
|
||||
// load settings
|
||||
page.initSettings();
|
||||
// create tab information structure for every opened tab
|
||||
page.initOpenedTabs();
|
||||
// initial connection with KeePassXC
|
||||
keepass.connectToNative();
|
||||
keepass.getDatabaseHash(null);
|
||||
// set initial tab-ID
|
||||
chrome.tabs.query({"active": true, "windowId": chrome.windows.WINDOW_ID_CURRENT}, function(tabs) {
|
||||
if (tabs.length === 0)
|
||||
return; // For example: only the background devtools or a popup are opened
|
||||
page.currentTabId = tabs[0].id;
|
||||
});
|
||||
// Milliseconds for intervall (e.g. to update browserAction)
|
||||
var _interval = 250;
|
||||
|
||||
|
||||
/**
|
||||
* Generate information structure for created tab and invoke all needed
|
||||
* functions if tab is created in foreground
|
||||
* @param {object} tab
|
||||
*/
|
||||
chrome.tabs.onCreated.addListener(function(tab) {
|
||||
if(tab.id > 0) {
|
||||
//console.log("chrome.tabs.onCreated(" + tab.id+ ")");
|
||||
if(tab.selected) {
|
||||
page.currentTabId = tab.id;
|
||||
event.invoke(page.switchTab, null, tab.id, []);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Remove information structure of closed tab for freeing memory
|
||||
* @param {integer} tabId
|
||||
* @param {object} removeInfo
|
||||
*/
|
||||
chrome.tabs.onRemoved.addListener(function(tabId, removeInfo) {
|
||||
delete page.tabs[tabId];
|
||||
if(page.currentTabId == tabId) {
|
||||
page.currentTabId = -1;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Remove stored credentials on switching tabs.
|
||||
* Invoke functions to retrieve credentials for focused tab
|
||||
* @param {object} activeInfo
|
||||
*/
|
||||
chrome.tabs.onActivated.addListener(function(activeInfo) {
|
||||
// remove possible credentials from old tab information
|
||||
page.clearCredentials(page.currentTabId, true);
|
||||
browserAction.removeRememberPopup(null, {"id": page.currentTabId}, true);
|
||||
|
||||
chrome.tabs.get(activeInfo.tabId, function(info) {
|
||||
//console.log(info.id + ": " + info.url);
|
||||
if(info && info.id) {
|
||||
page.currentTabId = info.id;
|
||||
if(info.status == "complete") {
|
||||
//console.log("event.invoke(page.switchTab, null, "+info.id + ", []);");
|
||||
event.invoke(page.switchTab, null, info.id, []);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Update browserAction on every update of the page
|
||||
* @param {integer} tabId
|
||||
* @param {object} changeInfo
|
||||
*/
|
||||
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
|
||||
if(changeInfo.status == "complete") {
|
||||
event.invoke(browserAction.removeRememberPopup, null, tabId, []);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve Credentials and try auto-login for HTTPAuth requests
|
||||
*/
|
||||
chrome.webRequest.onAuthRequired.addListener(httpAuth.handleRequest,
|
||||
{ urls: ["<all_urls>"] }, ["asyncBlocking"]
|
||||
);
|
||||
|
||||
/**
|
||||
* Interaction between background-script and front-script
|
||||
*/
|
||||
chrome.extension.onMessage.addListener(event.onMessage);
|
||||
|
||||
|
||||
/**
|
||||
* Add context menu entry for filling in username + password
|
||||
*/
|
||||
chrome.contextMenus.create({
|
||||
"title": "Fill &User + Pass",
|
||||
"contexts": [ "editable" ],
|
||||
"onclick": function(info, tab) {
|
||||
chrome.tabs.sendMessage(tab.id, {
|
||||
action: "fill_user_pass"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Add context menu entry for filling in only password which matches for given username
|
||||
*/
|
||||
chrome.contextMenus.create({
|
||||
"title": "Fill &Pass Only",
|
||||
"contexts": [ "editable" ],
|
||||
"onclick": function(info, tab) {
|
||||
chrome.tabs.sendMessage(tab.id, {
|
||||
action: "fill_pass_only"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Add context menu entry for creating icon for generate-password dialog
|
||||
*/
|
||||
chrome.contextMenus.create({
|
||||
"title": "Show Password &Generator Icons",
|
||||
"contexts": [ "editable" ],
|
||||
"onclick": function(info, tab) {
|
||||
chrome.tabs.sendMessage(tab.id, {
|
||||
action: "activate_password_generator"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Add context menu entry for creating icon for generate-password dialog
|
||||
*/
|
||||
chrome.contextMenus.create({
|
||||
"title": "&Save credentials",
|
||||
"contexts": [ "editable" ],
|
||||
"onclick": function(info, tab) {
|
||||
chrome.tabs.sendMessage(tab.id, {
|
||||
action: "remember_credentials"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Interval which updates the browserAction (e.g. blinking icon)
|
||||
*/
|
||||
window.setInterval(function() {
|
||||
browserAction.update(_interval);
|
||||
}, _interval);
|
||||
632
chromeKeePassXC/background/keepass original.js
Normal file
|
|
@ -0,0 +1,632 @@
|
|||
var keepass = {};
|
||||
|
||||
keepass.associated = {"value": false, "hash": null};
|
||||
keepass.isDatabaseClosed = false;
|
||||
keepass.isKeePassHttpAvailable = false;
|
||||
keepass.isEncryptionKeyUnrecognized = false;
|
||||
keepass.currentKeePassHttp = {"version": 0, "versionParsed": 0};
|
||||
keepass.latestKeePassHttp = (typeof(localStorage.latestKeePassHttp) == 'undefined') ? {"version": 0, "versionParsed": 0, "lastChecked": null} : JSON.parse(localStorage.latestKeePassHttp);
|
||||
keepass.keySize = 8; // wtf? stupid cryptoHelpers
|
||||
keepass.pluginUrlDefault = "http://localhost:19455/";
|
||||
keepass.latestVersionUrl = "https://passifox.appspot.com/kph/latest-version.txt";
|
||||
keepass.cacheTimeout = 30 * 1000; // milliseconds
|
||||
keepass.databaseHash = "no-hash"; //no-hash = keepasshttp is too old and does not return a hash value
|
||||
keepass.keyRing = (typeof(localStorage.keyRing) == 'undefined') ? {} : JSON.parse(localStorage.keyRing);
|
||||
keepass.keyId = "chromeipass-cryptokey-name";
|
||||
keepass.keyBody = "chromeipass-key";
|
||||
keepass.to_s = cryptoHelpers.convertByteArrayToString;
|
||||
keepass.to_b = cryptoHelpers.convertStringToByteArray;
|
||||
|
||||
|
||||
keepass.addCredentials = function(callback, tab, username, password, url) {
|
||||
keepass.updateCredentials(callback, tab, null, username, password, url);
|
||||
}
|
||||
|
||||
keepass.updateCredentials = function(callback, tab, entryId, username, password, url) {
|
||||
page.debug("keepass.updateCredentials(callback, {1}, {2}, {3}, [password], {4})", tab.id, entryId, username, url);
|
||||
|
||||
// unset error message
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
|
||||
// is browser associated to keepass?
|
||||
if(!keepass.testAssociation(tab)) {
|
||||
browserAction.showDefault(null, tab);
|
||||
callback("error");
|
||||
return;
|
||||
}
|
||||
|
||||
// build request
|
||||
var request = {
|
||||
RequestType: "set-login"
|
||||
};
|
||||
var verifier = keepass.setVerifier(request);
|
||||
var id = verifier[0];
|
||||
var key = verifier[1];
|
||||
var iv = request.Nonce;
|
||||
|
||||
|
||||
request.Login = keepass.encrypt(cryptoHelpers.encode_utf8(username), key, iv);
|
||||
|
||||
request.Password = keepass.encrypt(cryptoHelpers.encode_utf8(password), key, iv);
|
||||
request.Url = keepass.encrypt(url, key, iv);
|
||||
request.SubmitUrl = keepass.encrypt(url, key, iv);
|
||||
|
||||
if(entryId) {
|
||||
request.Uuid = keepass.encrypt(entryId, key, iv);
|
||||
}
|
||||
|
||||
// send request
|
||||
var result = keepass.send(request);
|
||||
var status = result[0];
|
||||
var response = result[1];
|
||||
|
||||
// verify response
|
||||
var code = "error";
|
||||
if(keepass.checkStatus(status, tab)) {
|
||||
var r = JSON.parse(response);
|
||||
if (keepass.verifyResponse(r, key, id)) {
|
||||
code = "success";
|
||||
}
|
||||
else {
|
||||
code = "error";
|
||||
}
|
||||
}
|
||||
|
||||
callback(code);
|
||||
}
|
||||
|
||||
keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCallback, triggerUnlock) {
|
||||
page.debug("keepass.retrieveCredentials(callback, {1}, {2}, {3}, {4})", tab.id, url, submiturl, forceCallback);
|
||||
|
||||
// unset error message
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
|
||||
// is browser associated to keepass?
|
||||
if(!keepass.testAssociation(tab, triggerUnlock)) {
|
||||
browserAction.showDefault(null, tab);
|
||||
if(forceCallback) {
|
||||
callback([]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// build request
|
||||
var request = {
|
||||
"RequestType": "get-logins",
|
||||
"SortSelection": "true",
|
||||
"TriggerUnlock": (triggerUnlock === true) ? "true" : "false"
|
||||
};
|
||||
var verifier = keepass.setVerifier(request);
|
||||
var id = verifier[0];
|
||||
var key = verifier[1];
|
||||
var iv = request.Nonce;
|
||||
request.Url = keepass.encrypt(url, key, iv);
|
||||
|
||||
if(submiturl) {
|
||||
request.SubmitUrl = keepass.encrypt(submiturl, key, iv);
|
||||
}
|
||||
|
||||
// send request
|
||||
var result = keepass.send(request);
|
||||
var status = result[0];
|
||||
var response = result[1];
|
||||
var entries = [];
|
||||
|
||||
// verify response
|
||||
if(keepass.checkStatus(status, tab)) {
|
||||
var r = JSON.parse(response);
|
||||
|
||||
keepass.setCurrentKeePassHttpVersion(r.Version);
|
||||
|
||||
if (keepass.verifyResponse(r, key, id)) {
|
||||
var rIv = r.Nonce;
|
||||
for (var i = 0; i < r.Entries.length; i++) {
|
||||
keepass.decryptEntry(r.Entries[i], key, rIv);
|
||||
}
|
||||
entries = r.Entries;
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
if(entries.length == 0) {
|
||||
//questionmark-icon is not triggered, so we have to trigger for the normal symbol
|
||||
browserAction.showDefault(null, tab);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log("RetrieveCredentials for " + url + " rejected");
|
||||
}
|
||||
}
|
||||
else {
|
||||
browserAction.showDefault(null, tab);
|
||||
}
|
||||
|
||||
page.debug("keepass.retrieveCredentials() => entries.length = {1}", entries.length);
|
||||
|
||||
callback(entries);
|
||||
}
|
||||
|
||||
keepass.generatePassword = function (callback, tab, forceCallback) {
|
||||
// is browser associated to keepass?
|
||||
if(!keepass.testAssociation(tab)) {
|
||||
browserAction.showDefault(null, tab);
|
||||
if(forceCallback) {
|
||||
callback([]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(keepass.currentKeePassHttp.versionParsed < 1400) {
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
|
||||
// build request
|
||||
var request = {
|
||||
RequestType: "generate-password"
|
||||
};
|
||||
var verifier = keepass.setVerifier(request);
|
||||
var id = verifier[0];
|
||||
var key = verifier[1];
|
||||
|
||||
// send request
|
||||
var result = keepass.send(request);
|
||||
var status = result[0];
|
||||
var response = result[1];
|
||||
var passwords = [];
|
||||
|
||||
// verify response
|
||||
if(keepass.checkStatus(status, tab)) {
|
||||
var r = JSON.parse(response);
|
||||
|
||||
keepass.setCurrentKeePassHttpVersion(r.Version);
|
||||
|
||||
if (keepass.verifyResponse(r, key, id)) {
|
||||
var rIv = r.Nonce;
|
||||
|
||||
if(r.Entries) {
|
||||
for (var i = 0; i < r.Entries.length; i++) {
|
||||
keepass.decryptEntry(r.Entries[i], key, rIv);
|
||||
}
|
||||
passwords = r.Entries;
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
}
|
||||
else {
|
||||
console.log("No entries returned. Is KeePassHttp up-to-date?");
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log("GeneratePassword rejected");
|
||||
}
|
||||
}
|
||||
else {
|
||||
browserAction.showDefault(null, tab);
|
||||
}
|
||||
|
||||
callback(passwords);
|
||||
}
|
||||
|
||||
keepass.copyPassword = function(callback, tab, password) {
|
||||
var bg = chrome.extension.getBackgroundPage();
|
||||
var c2c = bg.document.getElementById("copy2clipboard");
|
||||
if(!c2c) {
|
||||
var input = document.createElement('input');
|
||||
input.type = "text";
|
||||
input.id = "copy2clipboard";
|
||||
bg.document.getElementsByTagName('body')[0].appendChild(input);
|
||||
c2c = bg.document.getElementById("copy2clipboard");
|
||||
}
|
||||
|
||||
c2c.value = password;
|
||||
c2c.select();
|
||||
document.execCommand("copy");
|
||||
c2c.value = "";
|
||||
callback(true);
|
||||
}
|
||||
|
||||
keepass.associate = function(callback, tab) {
|
||||
if(keepass.isAssociated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
keepass.getDatabaseHash(tab);
|
||||
|
||||
if(keepass.isDatabaseClosed || !keepass.isKeePassHttpAvailable) {
|
||||
return;
|
||||
}
|
||||
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
|
||||
var rawKey = cryptoHelpers.generateSharedKey(keepass.keySize * 2);
|
||||
var key = keepass.b64e(rawKey);
|
||||
|
||||
var request = {
|
||||
RequestType: "associate",
|
||||
Key: key
|
||||
};
|
||||
|
||||
keepass.setVerifier(request, key);
|
||||
|
||||
var result = keepass.send(request);
|
||||
|
||||
if(keepass.checkStatus(result[0], tab)) {
|
||||
var r = JSON.parse(result[1]);
|
||||
|
||||
if(r.Version) {
|
||||
keepass.currentKeePassHttp = {
|
||||
"version": r.Version,
|
||||
"versionParsed": parseInt(r.Version.replace(/\./g,""))
|
||||
};
|
||||
}
|
||||
|
||||
var id = r.Id;
|
||||
if(!keepass.verifyResponse(r, key)) {
|
||||
page.tabs[tab.id].errorMessage = "KeePass association failed, try again.";
|
||||
}
|
||||
else {
|
||||
keepass.setCryptoKey(id, key);
|
||||
keepass.associated.value = true;
|
||||
keepass.associated.hash = r.Hash || 0;
|
||||
}
|
||||
|
||||
browserAction.show(callback, tab);
|
||||
}
|
||||
}
|
||||
|
||||
keepass.isConfigured = function() {
|
||||
if(typeof(keepass.databaseHash) == "undefined") {
|
||||
keepass.getDatabaseHash();
|
||||
}
|
||||
return (keepass.databaseHash in keepass.keyRing);
|
||||
}
|
||||
|
||||
keepass.isAssociated = function() {
|
||||
return (keepass.associated.value && keepass.associated.hash && keepass.associated.hash == keepass.databaseHash);
|
||||
}
|
||||
|
||||
keepass.send = function(request) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", keepass.getPluginUrl(), false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
try {
|
||||
var r = JSON.stringify(request);
|
||||
page.debug("Request: {1}", r);
|
||||
xhr.send(r);
|
||||
}
|
||||
catch (e) {
|
||||
console.log("KeePassHttp: " + e);
|
||||
}
|
||||
page.debug("Response: {1} => {2}", xhr.status, xhr.responseText);
|
||||
return [xhr.status, xhr.responseText];
|
||||
}
|
||||
|
||||
keepass.checkStatus = function (status, tab) {
|
||||
var success = (status >= 200 && status <= 299);
|
||||
keepass.isDatabaseClosed = false;
|
||||
keepass.isKeePassHttpAvailable = true;
|
||||
|
||||
if(tab && page.tabs[tab.id]) {
|
||||
delete page.tabs[tab.id].errorMessage;
|
||||
}
|
||||
if (!success) {
|
||||
keepass.associated.value = false;
|
||||
keepass.associated.hash = null;
|
||||
if(tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = "Unknown error: " + status;
|
||||
}
|
||||
console.log("Error: "+ status);
|
||||
if (status == 503) {
|
||||
keepass.isDatabaseClosed = true;
|
||||
console.log("KeePass database is not opened");
|
||||
if(tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = "KeePass database is not opened.";
|
||||
}
|
||||
}
|
||||
else if (status == 0) {
|
||||
keepass.isKeePassHttpAvailable = false;
|
||||
console.log("Could not connect to keepass");
|
||||
if(tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = "Is KeePassHttp installed and is KeePass running?";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
page.debug("keepass.checkStatus({1}, [tabID]) => {2}", status, success);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
keepass.convertKeyToKeyRing = function() {
|
||||
if(keepass.keyId in localStorage && keepass.keyBody in localStorage && !("keyRing" in localStorage)) {
|
||||
var hash = keepass.getDatabaseHash(null);
|
||||
keepass.saveKey(hash, localStorage[keepass.keyId], localStorage[keepass.keyBody]);
|
||||
}
|
||||
|
||||
if("keyRing" in localStorage) {
|
||||
delete localStorage[keepass.keyId];
|
||||
delete localStorage[keepass.keyBody];
|
||||
}
|
||||
}
|
||||
|
||||
keepass.saveKey = function(hash, id, key) {
|
||||
if(!(hash in keepass.keyRing)) {
|
||||
keepass.keyRing[hash] = {
|
||||
"id": id,
|
||||
"key": key,
|
||||
"icon": "blue",
|
||||
"created": new Date(),
|
||||
"last-used": new Date()
|
||||
}
|
||||
}
|
||||
else {
|
||||
keepass.keyRing[hash].id = id;
|
||||
keepass.keyRing[hash].key = key;
|
||||
}
|
||||
localStorage.keyRing = JSON.stringify(keepass.keyRing);
|
||||
}
|
||||
|
||||
keepass.updateLastUsed = function(hash) {
|
||||
if((hash in keepass.keyRing)) {
|
||||
keepass.keyRing[hash].lastUsed = new Date();
|
||||
localStorage.keyRing = JSON.stringify(keepass.keyRing);
|
||||
}
|
||||
}
|
||||
|
||||
keepass.deleteKey = function(hash) {
|
||||
delete keepass.keyRing[hash];
|
||||
localStorage.keyRing = JSON.stringify(keepass.keyRing);
|
||||
}
|
||||
|
||||
keepass.getIconColor = function() {
|
||||
return ((keepass.databaseHash in keepass.keyRing) && keepass.keyRing[keepass.databaseHash].icon) ? keepass.keyRing[keepass.databaseHash].icon : "blue";
|
||||
}
|
||||
|
||||
keepass.getPluginUrl = function() {
|
||||
if(page.settings.hostname && page.settings.port) {
|
||||
return "http://" + page.settings.hostname + ":" + page.settings.port;
|
||||
}
|
||||
return keepass.pluginUrlDefault;
|
||||
}
|
||||
|
||||
keepass.setCurrentKeePassHttpVersion = function(version) {
|
||||
if(version) {
|
||||
keepass.currentKeePassHttp = {
|
||||
"version": version,
|
||||
"versionParsed": parseInt(version.replace(/\./g,""))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
keepass.keePassHttpUpdateAvailable = function() {
|
||||
if(page.settings.checkUpdateKeePassHttp && page.settings.checkUpdateKeePassHttp > 0) {
|
||||
var lastChecked = (keepass.latestKeePassHttp.lastChecked) ? new Date(keepass.latestKeePassHttp.lastChecked) : new Date("11/21/1986");
|
||||
var daysSinceLastCheck = Math.floor(((new Date()).getTime()-lastChecked.getTime())/86400000);
|
||||
if(daysSinceLastCheck >= page.settings.checkUpdateKeePassHttp) {
|
||||
keepass.checkForNewKeePassHttpVersion();
|
||||
}
|
||||
}
|
||||
|
||||
return (keepass.currentKeePassHttp.versionParsed > 0 && keepass.currentKeePassHttp.versionParsed < keepass.latestKeePassHttp.versionParsed);
|
||||
}
|
||||
|
||||
keepass.checkForNewKeePassHttpVersion = function() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", keepass.latestVersionUrl, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
try {
|
||||
xhr.send();
|
||||
var $version = xhr.responseText;
|
||||
if($version.substring(0, 1) == ":") {
|
||||
$version = $version.substring(xhr.responseText.indexOf("KeePassHttp") + 12);
|
||||
$version = $version.substring(0, $version.indexOf(":") - 1);
|
||||
keepass.latestKeePassHttp.version = $version;
|
||||
keepass.latestKeePassHttp.versionParsed = parseInt($version.replace(/\./g,""));
|
||||
}
|
||||
else {
|
||||
$version = -1;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
console.log("Error: " + e);
|
||||
}
|
||||
|
||||
if($version != -1) {
|
||||
localStorage.latestKeePassHttp = JSON.stringify(keepass.latestKeePassHttp);
|
||||
}
|
||||
keepass.latestKeePassHttp.lastChecked = new Date();
|
||||
}
|
||||
|
||||
keepass.testAssociation = function (tab, triggerUnlock) {
|
||||
keepass.getDatabaseHash(tab, triggerUnlock);
|
||||
|
||||
if(keepass.isDatabaseClosed || !keepass.isKeePassHttpAvailable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(keepass.isAssociated()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var request = {
|
||||
"RequestType": "test-associate",
|
||||
"TriggerUnlock": (triggerUnlock === true) ? "true" : false
|
||||
};
|
||||
var verifier = keepass.setVerifier(request);
|
||||
|
||||
if(!verifier) {
|
||||
keepass.associated.value = false;
|
||||
keepass.associated.hash = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var result = keepass.send(request);
|
||||
var status = result[0];
|
||||
var response = result[1];
|
||||
|
||||
if(keepass.checkStatus(status, tab)) {
|
||||
var r = JSON.parse(response);
|
||||
var id = verifier[0];
|
||||
var key = verifier[1];
|
||||
|
||||
if(r.Version) {
|
||||
keepass.currentKeePassHttp = {
|
||||
"version": r.Version,
|
||||
"versionParsed": parseInt(r.Version.replace(/\./g,""))
|
||||
};
|
||||
}
|
||||
|
||||
keepass.isEncryptionKeyUnrecognized = false;
|
||||
if(!keepass.verifyResponse(r, key, id)) {
|
||||
var hash = r.Hash || 0;
|
||||
keepass.deleteKey(hash);
|
||||
keepass.isEncryptionKeyUnrecognized = true;
|
||||
console.log("Encryption key is not recognized!");
|
||||
page.tabs[tab.id].errorMessage = "Encryption key is not recognized.";
|
||||
keepass.associated.value = false;
|
||||
keepass.associated.hash = null;
|
||||
}
|
||||
else if(!keepass.isAssociated()) {
|
||||
console.log("Association was not successful");
|
||||
page.tabs[tab.id].errorMessage = "Association was not successful.";
|
||||
}
|
||||
}
|
||||
|
||||
return keepass.isAssociated();
|
||||
}
|
||||
|
||||
keepass.getDatabaseHash = function (tab, triggerUnlock) {
|
||||
var request = {
|
||||
"RequestType": "test-associate",
|
||||
"TriggerUnlock": (triggerUnlock === true) ? "true" : false
|
||||
};
|
||||
|
||||
var oldDatabaseHash = keepass.databaseHash;
|
||||
|
||||
var result = keepass.send(request);
|
||||
if(keepass.checkStatus(result[0], tab)) {
|
||||
var response = JSON.parse(result[1]);
|
||||
keepass.setCurrentKeePassHttpVersion(response.Version);
|
||||
keepass.databaseHash = response.Hash || "no-hash";
|
||||
}
|
||||
else {
|
||||
keepass.databaseHash = "no-hash";
|
||||
}
|
||||
|
||||
if(oldDatabaseHash && oldDatabaseHash != keepass.databaseHash) {
|
||||
//console.log("clear association (old db hash != new db hash ==> " + oldDatabaseHash + " != " + keepass.databaseHash);
|
||||
keepass.associated.value = false;
|
||||
keepass.associated.hash = null;
|
||||
}
|
||||
|
||||
return keepass.databaseHash;
|
||||
}
|
||||
|
||||
keepass.setVerifier = function(request, inputKey) {
|
||||
var key = inputKey || null;
|
||||
var id = null;
|
||||
|
||||
if(!key) {
|
||||
var info = keepass.getCryptoKey();
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
id = info[0];
|
||||
key = info[1];
|
||||
}
|
||||
|
||||
if(id) {
|
||||
request.Id = id;
|
||||
}
|
||||
|
||||
var iv = cryptoHelpers.generateSharedKey(keepass.keySize);
|
||||
request.Nonce = keepass.b64e(iv);
|
||||
|
||||
//var decodedKey = keepass.b64d(key);
|
||||
request.Verifier = keepass.encrypt(request.Nonce, key, request.Nonce);
|
||||
|
||||
return [id, key];
|
||||
}
|
||||
|
||||
keepass.verifyResponse = function(response, key, id) {
|
||||
keepass.associated.value = response.Success;
|
||||
if (!response.Success) {
|
||||
keepass.associated.hash = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
keepass.associated.hash = keepass.databaseHash;
|
||||
|
||||
var iv = response.Nonce;
|
||||
var value = keepass.decrypt(response.Verifier, key, iv, true);
|
||||
|
||||
keepass.associated.value = (value == iv);
|
||||
|
||||
if(id) {
|
||||
keepass.associated.value = (keepass.associated.value && id == response.Id);
|
||||
}
|
||||
|
||||
keepass.associated.hash = (keepass.associated.value) ? keepass.databaseHash : null;
|
||||
|
||||
return keepass.isAssociated();
|
||||
|
||||
}
|
||||
|
||||
keepass.b64e = function(d) {
|
||||
return btoa(keepass.to_s(d));
|
||||
}
|
||||
|
||||
keepass.b64d = function(d) {
|
||||
return keepass.to_b(atob(d));
|
||||
}
|
||||
|
||||
keepass.getCryptoKey = function() {
|
||||
if(!(keepass.databaseHash in keepass.keyRing)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var id = keepass.keyRing[keepass.databaseHash].id;
|
||||
var key = null;
|
||||
|
||||
if(id) {
|
||||
key = keepass.keyRing[keepass.databaseHash].key;
|
||||
}
|
||||
|
||||
return key ? [id, key] : null;
|
||||
}
|
||||
|
||||
keepass.setCryptoKey = function(id, key) {
|
||||
keepass.saveKey(keepass.databaseHash, id, key);
|
||||
}
|
||||
|
||||
keepass.encrypt = function(input, key, iv) {
|
||||
return keepass.b64e(
|
||||
slowAES.encrypt(
|
||||
keepass.to_b(input),
|
||||
slowAES.modeOfOperation.CBC,
|
||||
keepass.b64d(key),
|
||||
keepass.b64d(iv)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
keepass.decrypt = function(input, key, iv, toStr) {
|
||||
var output = slowAES.decrypt(
|
||||
keepass.b64d(input),
|
||||
slowAES.modeOfOperation.CBC,
|
||||
keepass.b64d(key),
|
||||
keepass.b64d(iv)
|
||||
);
|
||||
|
||||
return toStr ? keepass.to_s(output) : output;
|
||||
}
|
||||
|
||||
keepass.decryptEntry = function (e, key, iv) {
|
||||
e.Uuid = keepass.decrypt(e.Uuid, key, iv, true);
|
||||
e.Name = UTF8.decode(keepass.decrypt(e.Name, key, iv, true));
|
||||
e.Login = UTF8.decode(keepass.decrypt(e.Login, key, iv, true));
|
||||
e.Password = UTF8.decode(keepass.decrypt(e.Password, key, iv, true));
|
||||
|
||||
if(e.StringFields) {
|
||||
for(var i = 0; i < e.StringFields.length; i++) {
|
||||
e.StringFields[i].Key = UTF8.decode(keepass.decrypt(e.StringFields[i].Key, key, iv, true))
|
||||
e.StringFields[i].Value = UTF8.decode(keepass.decrypt(e.StringFields[i].Value, key, iv, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
642
chromeKeePassXC/background/keepass.js
Normal file
|
|
@ -0,0 +1,642 @@
|
|||
var keepass = {};
|
||||
|
||||
keepass.associated = {"value": false, "hash": null};
|
||||
keepass.isConnected = false;
|
||||
keepass.isDatabaseClosed = false;
|
||||
keepass.isKeePassXCAvailable = false;
|
||||
keepass.useSecretBox = false;
|
||||
keepass.isEncryptionKeyUnrecognized = false;
|
||||
keepass.currentKeePassXC = {"version": 0, "versionParsed": 0};
|
||||
keepass.latestKeePassXC = (typeof(localStorage.latestKeePassXC) == 'undefined') ? {"version": 0, "versionParsed": 0, "lastChecked": null} : JSON.parse(localStorage.latestKeePassXC);
|
||||
keepass.requiredKeePassXC = 212;
|
||||
keepass.nativeHostName = "com.varjolintu.chromekeepassxc";
|
||||
keepass.nativePort = null;
|
||||
keepass.keySize = 8; // wtf? stupid cryptoHelpers
|
||||
keepass.latestVersionUrl = "https://raw.githubusercontent.com/keepassxreboot/keepassxc/develop/CHANGELOG";
|
||||
keepass.cacheTimeout = 30 * 1000; // milliseconds
|
||||
keepass.databaseHash = "no-hash"; //no-hash = keepasshttp is too old and does not return a hash value
|
||||
keepass.keyRing = (typeof(localStorage.keyRing) == 'undefined') ? {} : JSON.parse(localStorage.keyRing);
|
||||
keepass.keyId = "chromekeepassxc-cryptokey-name";
|
||||
keepass.keyBody = "chromekeepassxc-key";
|
||||
keepass.to_s = cryptoHelpers.convertByteArrayToString;
|
||||
keepass.to_b = cryptoHelpers.convertStringToByteArray;
|
||||
|
||||
|
||||
keepass.addCredentials = function(callback, tab, username, password, url) {
|
||||
keepass.updateCredentials(callback, tab, null, username, password, url);
|
||||
}
|
||||
|
||||
keepass.updateCredentials = function(callback, tab, entryId, username, password, url) {
|
||||
page.debug("keepass.updateCredentials(callback, {1}, {2}, {3}, [password], {4})", tab.id, entryId, username, url);
|
||||
|
||||
// unset error message
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
|
||||
// is browser associated to keepass?
|
||||
if(!keepass.testAssociation(tab)) {
|
||||
browserAction.showDefault(null, tab);
|
||||
callback("error");
|
||||
return;
|
||||
}
|
||||
|
||||
// build request
|
||||
var request = {
|
||||
RequestType: "set-login"
|
||||
};
|
||||
var verifier = keepass.setVerifier(request);
|
||||
var id = verifier[0];
|
||||
var key = verifier[1];
|
||||
var iv = request.Nonce;
|
||||
|
||||
|
||||
request.Login = keepass.encrypt(nacl.util.encode_UTF8(username), key, iv);
|
||||
|
||||
request.Password = keepass.encrypt(nacl.util.encode_UTF8(password), key, iv);
|
||||
request.Url = keepass.encrypt(url, key, iv);
|
||||
request.SubmitUrl = keepass.encrypt(url, key, iv);
|
||||
|
||||
if(entryId) {
|
||||
request.Uuid = keepass.encrypt(entryId, key, iv);
|
||||
}
|
||||
|
||||
// send request
|
||||
var result = keepass.send(request);
|
||||
var status = result[0];
|
||||
var response = result[1];
|
||||
|
||||
// verify response
|
||||
var code = "error";
|
||||
if(keepass.checkStatus(status, tab)) {
|
||||
var r = JSON.parse(response);
|
||||
if (keepass.verifyResponse(r, key, id)) {
|
||||
code = "success";
|
||||
}
|
||||
else {
|
||||
code = "error";
|
||||
}
|
||||
}
|
||||
|
||||
callback(code);
|
||||
}
|
||||
|
||||
keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCallback, triggerUnlock) {
|
||||
page.debug("keepass.retrieveCredentials(callback, {1}, {2}, {3}, {4})", tab.id, url, submiturl, forceCallback);
|
||||
|
||||
// is browser associated to keepass?
|
||||
if(!keepass.testAssociation(tab)) {
|
||||
browserAction.showDefault(null, tab);
|
||||
callback("error");
|
||||
return;
|
||||
}
|
||||
|
||||
// unset error message
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
|
||||
if (!keepass.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
var entries = [];
|
||||
message = {
|
||||
"action": "get-logins",
|
||||
"url": url
|
||||
};
|
||||
|
||||
var verifier = keepass.setVerifier(message);
|
||||
var id = verifier[0];
|
||||
var key = verifier[1];
|
||||
var iv = message.nonce;
|
||||
var entries = [];
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "get-logins-reply", function(response) {
|
||||
if (response) {
|
||||
keepass.setcurrentKeePassXCVersion(response.version);
|
||||
|
||||
if (keepass.verifyResponse(response, key, id)) {
|
||||
var rIv = response.nonce;
|
||||
for (var i = 0; i < response.entries.length; i++) {
|
||||
keepass.decryptEntry(response.entries[i], key, rIv);
|
||||
}
|
||||
entries = response.entries;
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
if(entries.length == 0) {
|
||||
//questionmark-icon is not triggered, so we have to trigger for the normal symbol
|
||||
browserAction.showDefault(null, tab);
|
||||
}
|
||||
callback(entries);
|
||||
}
|
||||
else {
|
||||
console.log("RetrieveCredentials for " + url + " rejected");
|
||||
}
|
||||
}
|
||||
else {
|
||||
browserAction.showDefault(null, tab);
|
||||
}
|
||||
});
|
||||
keepass.nativePort.postMessage(message);
|
||||
page.debug("keepass.retrieveCredentials() => entries.length = {1}", entries.length);
|
||||
}
|
||||
|
||||
// Handles the replies with callback provided
|
||||
keepass.handleReply = function (msg) {
|
||||
var reply;
|
||||
if (msg.action == "generate-reply") {
|
||||
console.log("Handling generate-reply");
|
||||
var a = [];
|
||||
var response = JSON.stringify({ login: (msg.password.length * 8), password: msg.password });
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
a.push(response);
|
||||
reply = a;
|
||||
}
|
||||
/*else if (msg.action == "get-logins-reply") {
|
||||
console.log("Handling get-logins-reply");
|
||||
if (msg.count) {
|
||||
var a = [];
|
||||
for (var i = 0; i < msg.count; i++) {
|
||||
var response = JSON.stringify({ login: msg.entries[i].login, name: msg.entries[i].name, password: msg.entries[i].password });
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
console.log(response);
|
||||
a.push(response);
|
||||
}
|
||||
reply = a;
|
||||
}
|
||||
}*/
|
||||
else {
|
||||
reply = msg;
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
|
||||
// Redirects the callback to a listener (handleReply())
|
||||
keepass.callbackOnId = function (ev, id, callback) {
|
||||
var listener = ( function(port, id) {
|
||||
var handler = function(msg) {
|
||||
if(msg.action == id) {
|
||||
var reply = keepass.handleReply(msg);
|
||||
ev.removeListener(handler);
|
||||
callback(reply);
|
||||
}
|
||||
}
|
||||
return handler;
|
||||
})(ev, id, callback);
|
||||
ev.addListener(listener);
|
||||
}
|
||||
|
||||
|
||||
keepass.generatePassword = function (callback, tab, forceCallback) {
|
||||
if (!keepass.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
// is browser associated to keepass?
|
||||
if(!keepass.testAssociation(tab)) {
|
||||
browserAction.showDefault(null, tab);
|
||||
callback("error");
|
||||
return;
|
||||
}
|
||||
|
||||
if(keepass.currentKeePassXC.versionParsed < keepass.requiredKeePassXC) {
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
|
||||
var passwords = [];
|
||||
message = { "action": "generate-password" };
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "generate-reply", callback);
|
||||
keepass.nativePort.postMessage(message);
|
||||
}
|
||||
|
||||
keepass.copyPassword = function(callback, tab, password) {
|
||||
var bg = chrome.extension.getBackgroundPage();
|
||||
var c2c = bg.document.getElementById("copy2clipboard");
|
||||
if(!c2c) {
|
||||
var input = document.createElement('input');
|
||||
input.type = "text";
|
||||
input.id = "copy2clipboard";
|
||||
bg.document.getElementsByTagName('body')[0].appendChild(input);
|
||||
c2c = bg.document.getElementById("copy2clipboard");
|
||||
}
|
||||
|
||||
c2c.value = password;
|
||||
c2c.select();
|
||||
document.execCommand("copy");
|
||||
c2c.value = "";
|
||||
callback(true);
|
||||
}
|
||||
|
||||
keepass.associate = function(callback, tab) {
|
||||
if(keepass.isAssociated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
keepass.getDatabaseHash(callback, tab);
|
||||
|
||||
if(keepass.isDatabaseClosed || !keepass.isKeePassXCAvailable) {
|
||||
return;
|
||||
}
|
||||
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
|
||||
var rawKey = nacl.randomBytes(keepass.keySize * 2);
|
||||
//var rawKey = [41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56]; // This is just for testing with the test client. KSorLC0uLzAxMjM0NTY3OA== )*+,-./012345678
|
||||
console.log(rawKey);
|
||||
var key = keepass.b64e(rawKey);
|
||||
|
||||
var request = {
|
||||
action: "associate",
|
||||
key: key
|
||||
};
|
||||
|
||||
keepass.setVerifier(request, key);
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "associate-reply", function(response) {
|
||||
if (response.version) {
|
||||
keepass.currentKeePassXC = {
|
||||
"version": response.version,
|
||||
"versionParsed": parseInt(response.version.replace(/\./g,""))}
|
||||
;
|
||||
}
|
||||
|
||||
var id = response.id;
|
||||
if(!keepass.verifyResponse(response, key)) {
|
||||
page.tabs[tab.id].errorMessage = "KeePassXC association failed, try again.";
|
||||
}
|
||||
else {
|
||||
keepass.setCryptoKey(id, key);
|
||||
keepass.associated.value = true;
|
||||
keepass.associated.hash = response.hash || 0;
|
||||
}
|
||||
|
||||
browserAction.show(callback, tab);
|
||||
});
|
||||
|
||||
keepass.nativePort.postMessage(request);
|
||||
}
|
||||
|
||||
keepass.testAssociation = function (tab, triggerUnlock) {
|
||||
keepass.getDatabaseHash(null, tab, triggerUnlock);
|
||||
|
||||
if(keepass.isDatabaseClosed || !keepass.isKeePassXCAvailable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(keepass.isAssociated()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var message = {
|
||||
"action": "test-associate",
|
||||
};
|
||||
var verifier = keepass.setVerifier(message);
|
||||
|
||||
if(!verifier) {
|
||||
keepass.associated.value = false;
|
||||
keepass.associated.hash = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "test-associate-reply", function(response) {
|
||||
if (response) {
|
||||
var id = verifier[0];
|
||||
var key = verifier[1];
|
||||
|
||||
if(response.version) {
|
||||
keepass.currentKeePassXC = {
|
||||
"version": response.version,
|
||||
"versionParsed": parseInt(response.version.replace(/\./g,""))
|
||||
};
|
||||
}
|
||||
|
||||
keepass.isEncryptionKeyUnrecognized = false;
|
||||
if(!keepass.verifyResponse(response, key, id)) {
|
||||
var hash = response.hash || 0;
|
||||
keepass.deleteKey(hash);
|
||||
keepass.isEncryptionKeyUnrecognized = true;
|
||||
console.log("Encryption key is not recognized!");
|
||||
page.tabs[tab.id].errorMessage = "Encryption key is not recognized.";
|
||||
keepass.associated.value = false;
|
||||
keepass.associated.hash = null;
|
||||
}
|
||||
else if(!keepass.isAssociated()) {
|
||||
console.log("Association was not successful");
|
||||
page.tabs[tab.id].errorMessage = "Association was not successful.";
|
||||
}
|
||||
}
|
||||
});
|
||||
keepass.nativePort.postMessage(message);
|
||||
|
||||
return keepass.isAssociated();
|
||||
}
|
||||
|
||||
keepass.getDatabaseHash = function (callback, tab, triggerUnlock) {
|
||||
if (!keepass.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
message = { "action": "get-databasehash" };
|
||||
keepass.callbackOnId(keepass.nativePort.onMessage, "hash-reply", function(response) {
|
||||
console.log("hash-reply received: "+ response.hash);
|
||||
var oldDatabaseHash = keepass.databaseHash;
|
||||
keepass.setcurrentKeePassXCVersion(response.version);
|
||||
keepass.databaseHash = response.hash || "no-hash";
|
||||
|
||||
if(oldDatabaseHash && oldDatabaseHash != keepass.databaseHash) {
|
||||
keepass.associated.value = false;
|
||||
keepass.associated.hash = null;
|
||||
}
|
||||
|
||||
statusOK();
|
||||
return keepass.databaseHash;
|
||||
});
|
||||
keepass.nativePort.postMessage(message);
|
||||
}
|
||||
|
||||
keepass.isConfigured = function() {
|
||||
if(typeof(keepass.databaseHash) == "undefined") {
|
||||
keepass.getDatabaseHash();
|
||||
}
|
||||
return (keepass.databaseHash in keepass.keyRing);
|
||||
}
|
||||
|
||||
keepass.isAssociated = function() {
|
||||
return (keepass.associated.value && keepass.associated.hash && keepass.associated.hash == keepass.databaseHash);
|
||||
}
|
||||
|
||||
// Needed?
|
||||
keepass.checkStatus = function (status, tab) {
|
||||
var success = (status >= 200 && status <= 299);
|
||||
keepass.isDatabaseClosed = false;
|
||||
keepass.isKeePassXCAvailable = true;
|
||||
|
||||
if(tab && page.tabs[tab.id]) {
|
||||
delete page.tabs[tab.id].errorMessage;
|
||||
}
|
||||
if (!success) {
|
||||
keepass.associated.value = false;
|
||||
keepass.associated.hash = null;
|
||||
if(tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = "Unknown error: " + status;
|
||||
}
|
||||
console.log("Error: "+ status);
|
||||
if (status == 503) {
|
||||
keepass.isDatabaseClosed = true;
|
||||
console.log("KeePass database is not opened");
|
||||
if(tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = "KeePass database is not opened.";
|
||||
}
|
||||
}
|
||||
else if (status == 0) {
|
||||
keepass.isKeePassXCAvailable = false;
|
||||
console.log("Could not connect to keepass");
|
||||
if(tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = "Is KeePassXC installed and running?";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
page.debug("keepass.checkStatus({1}, [tabID]) => {2}", status, success);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
keepass.convertKeyToKeyRing = function() {
|
||||
if(keepass.keyId in localStorage && keepass.keyBody in localStorage && !("keyRing" in localStorage)) {
|
||||
//var hash = keepass.getDatabaseHash(null);
|
||||
//keepass.saveKey(hash, localStorage[keepass.keyId], localStorage[keepass.keyBody]);
|
||||
|
||||
keepass.getDatabaseHash(function(hash) {
|
||||
keepass.saveKey(hash, localStorage[keepass.keyId], localStorage[keepass.keyBody]);
|
||||
}, null);
|
||||
}
|
||||
|
||||
if("keyRing" in localStorage) {
|
||||
delete localStorage[keepass.keyId];
|
||||
delete localStorage[keepass.keyBody];
|
||||
}
|
||||
}
|
||||
|
||||
keepass.saveKey = function(hash, id, key) {
|
||||
if(!(hash in keepass.keyRing)) {
|
||||
keepass.keyRing[hash] = {
|
||||
"id": id,
|
||||
"key": key,
|
||||
"icon": "blue",
|
||||
"created": new Date(),
|
||||
"last-used": new Date()
|
||||
}
|
||||
}
|
||||
else {
|
||||
keepass.keyRing[hash].id = id;
|
||||
keepass.keyRing[hash].key = key;
|
||||
}
|
||||
localStorage.keyRing = JSON.stringify(keepass.keyRing);
|
||||
}
|
||||
|
||||
keepass.updateLastUsed = function(hash) {
|
||||
if((hash in keepass.keyRing)) {
|
||||
keepass.keyRing[hash].lastUsed = new Date();
|
||||
localStorage.keyRing = JSON.stringify(keepass.keyRing);
|
||||
}
|
||||
}
|
||||
|
||||
keepass.deleteKey = function(hash) {
|
||||
delete keepass.keyRing[hash];
|
||||
localStorage.keyRing = JSON.stringify(keepass.keyRing);
|
||||
}
|
||||
|
||||
keepass.getIconColor = function() {
|
||||
return ((keepass.databaseHash in keepass.keyRing) && keepass.keyRing[keepass.databaseHash].icon) ? keepass.keyRing[keepass.databaseHash].icon : "blue";
|
||||
}
|
||||
|
||||
keepass.setcurrentKeePassXCVersion = function(version) {
|
||||
if(version) {
|
||||
keepass.currentKeePassXC = {
|
||||
"version": version,
|
||||
"versionParsed": parseInt(version.replace(/\./g,""))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
keepass.keePassXCUpdateAvailable = function() {
|
||||
if(page.settings.checkUpdateKeePassXC && page.settings.checkUpdateKeePassXC > 0) {
|
||||
var lastChecked = (keepass.latestKeePassXC.lastChecked) ? new Date(keepass.latestKeePassXC.lastChecked) : new Date("11/21/1986");
|
||||
var daysSinceLastCheck = Math.floor(((new Date()).getTime()-lastChecked.getTime())/86400000);
|
||||
if(daysSinceLastCheck >= page.settings.checkUpdateKeePassXC) {
|
||||
keepass.checkForNewKeePassXCVersion();
|
||||
}
|
||||
}
|
||||
|
||||
return (keepass.currentKeePassXC.versionParsed > 0 && keepass.currentKeePassXC.versionParsed < keepass.latestKeePassXC.versionParsed);
|
||||
}
|
||||
|
||||
keepass.checkForNewKeePassXCVersion = function() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", keepass.latestVersionUrl, true);
|
||||
xhr.onload = function(e) {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
var $version = xhr.responseText;
|
||||
if($version.substring(0, 1) == "2") {
|
||||
$version = $version.substring(0, $version.indexOf(" "));
|
||||
keepass.latestKeePassXC.version = $version;
|
||||
keepass.latestKeePassXC.versionParsed = parseInt($version.replace(/\./g,""));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$version = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if($version != -1) {
|
||||
localStorage.latestKeePassXC = JSON.stringify(keepass.latestKeePassXC);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = function(e) {
|
||||
console.log("checkForNewKeePassXCVersion error: " + e);
|
||||
}
|
||||
|
||||
xhr.send();
|
||||
keepass.latestKeePassXC.lastChecked = new Date();
|
||||
}
|
||||
|
||||
keepass.connectToNative = function() {
|
||||
if (!keepass.isConnected) {
|
||||
keepass.nativeConnect();
|
||||
}
|
||||
}
|
||||
|
||||
function statusOK() {
|
||||
keepass.isDatabaseClosed = false;
|
||||
keepass.isKeePassXCAvailable = true;
|
||||
}
|
||||
|
||||
keepass.onNativeMessage = function (response) {
|
||||
console.log("Received message: " + JSON.stringify(response));
|
||||
}
|
||||
|
||||
function onDisconnected() {
|
||||
console.log("Failed to connect: " + chrome.runtime.lastError.message);
|
||||
keepass.nativePort = null;
|
||||
keepass.isConnected = false;
|
||||
}
|
||||
|
||||
keepass.nativeConnect = function() {
|
||||
console.log("Connecting to native messaging host " + keepass.nativeHostName)
|
||||
keepass.nativePort = chrome.runtime.connectNative(keepass.nativeHostName);
|
||||
keepass.nativePort.onMessage.addListener(keepass.onNativeMessage);
|
||||
keepass.nativePort.onDisconnect.addListener(onDisconnected);
|
||||
keepass.isConnected = true;
|
||||
}
|
||||
|
||||
keepass.setVerifier = function(request, inputKey) {
|
||||
var key = inputKey || null;
|
||||
var id = null;
|
||||
|
||||
if(!key) {
|
||||
var info = keepass.getCryptoKey();
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
id = info[0];
|
||||
key = info[1];
|
||||
}
|
||||
|
||||
if(id) {
|
||||
request.id = id;
|
||||
}
|
||||
|
||||
//var iv = cryptoHelpers.generateSharedKey(keepass.keySize);
|
||||
var nonce = nacl.randomBytes(keepass.keySize * 2);
|
||||
request.nonce = keepass.b64e(nonce);
|
||||
|
||||
//var decodedKey = keepass.b64d(key);
|
||||
request.verifier = keepass.encrypt(request.nonce, key, request.nonce);
|
||||
|
||||
var test = keepass.encrypt("Aeh9maerCjE5v5V8Tz2YxA==", key, "Aeh9maerCjE5v5V8Tz2YxA==");
|
||||
console.log(test);
|
||||
|
||||
return [id, key];
|
||||
}
|
||||
|
||||
keepass.verifyResponse = function(response, key, id) {
|
||||
keepass.associated.value = response.success;
|
||||
if (!response.success) {
|
||||
keepass.associated.hash = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
keepass.associated.hash = keepass.databaseHash;
|
||||
|
||||
var nonce = response.nonce;
|
||||
var value = keepass.decrypt(response.verifier, key, nonce, true);
|
||||
|
||||
keepass.associated.value = (value == nonce);
|
||||
|
||||
if(id) {
|
||||
keepass.associated.value = (keepass.associated.value && id == response.id);
|
||||
}
|
||||
|
||||
keepass.associated.hash = (keepass.associated.value) ? keepass.databaseHash : null;
|
||||
|
||||
return keepass.isAssociated();
|
||||
|
||||
}
|
||||
|
||||
keepass.b64e = function(d) {
|
||||
//return nacl.util.encodeBase64(d);
|
||||
return btoa(keepass.to_s(d));
|
||||
}
|
||||
|
||||
keepass.b64d = function(d) {
|
||||
//return nacl.util.decodeBase64(d);
|
||||
return keepass.to_b(atob(d));
|
||||
}
|
||||
|
||||
keepass.getCryptoKey = function() {
|
||||
if(!(keepass.databaseHash in keepass.keyRing)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var id = keepass.keyRing[keepass.databaseHash].id;
|
||||
var key = null;
|
||||
|
||||
if(id) {
|
||||
key = keepass.keyRing[keepass.databaseHash].key;
|
||||
}
|
||||
|
||||
return key ? [id, key] : null;
|
||||
}
|
||||
|
||||
keepass.setCryptoKey = function(id, key) {
|
||||
keepass.saveKey(keepass.databaseHash, id, key);
|
||||
}
|
||||
|
||||
keepass.encrypt = function(input, key, nonce) {
|
||||
return keepass.b64e(slowAES.encrypt(keepass.to_b(input), slowAES.modeOfOperation.CBC, keepass.b64d(key), keepass.b64d(nonce)));
|
||||
//return keepass.b64e(nacl.secretbox(keepass.to_b(input), keepass.b64d(nonce), keepass.b64d(key)));
|
||||
}
|
||||
|
||||
keepass.decrypt = function(input, key, nonce, toStr) {
|
||||
var output = slowAES.decrypt(keepass.b64d(input), slowAES.modeOfOperation.CBC, keepass.b64d(key), keepass.b64d(nonce));
|
||||
//var output = nacl.secretbox.open(keepass.b64d(input), keepass.b64d(nonce), keepass.b64d(key));
|
||||
return toStr ? keepass.to_s(output) : output;
|
||||
}
|
||||
|
||||
keepass.decryptEntry = function (box, key, nonce) {
|
||||
var e = keepass.useSecretBox ? nacl.secretbox.open(box, nonce, key) : box;
|
||||
if (e)
|
||||
{
|
||||
e.uuid = keepass.decrypt(e.uuid, key, nonce, true);
|
||||
e.name = UTF8.decode(keepass.decrypt(e.name, key, nonce, true));
|
||||
e.login = UTF8.decode(keepass.decrypt(e.login, key, nonce, true));
|
||||
e.password = UTF8.decode(keepass.decrypt(e.password, key, nonce, true));
|
||||
|
||||
if(e.StringFields) {
|
||||
for(var i = 0; i < e.StringFields.length; i++) {
|
||||
e.StringFields[i].Key = UTF8.decode(keepass.decrypt(e.StringFields[i].Key, key, nonce, true))
|
||||
e.StringFields[i].Value = UTF8.decode(keepass.decrypt(e.StringFields[i].Value, key, nonce, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
chromeKeePassXC/background/nacl-util.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Written in 2014-2016 by Dmitry Chestnykh and Devi Mandiri.
|
||||
// Public domain.
|
||||
(function(root, f) {
|
||||
'use strict';
|
||||
if (typeof module !== 'undefined' && module.exports) module.exports = f();
|
||||
else if (root.nacl) root.nacl.util = f();
|
||||
else {
|
||||
root.nacl = {};
|
||||
root.nacl.util = f();
|
||||
}
|
||||
}(this, function() {
|
||||
'use strict';
|
||||
|
||||
var util = {};
|
||||
|
||||
util.decodeUTF8 = function(s) {
|
||||
if (typeof s !== 'string') throw new TypeError('expected string');
|
||||
var i, d = unescape(encodeURIComponent(s)), b = new Uint8Array(d.length);
|
||||
for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i);
|
||||
return b;
|
||||
};
|
||||
|
||||
util.encodeUTF8 = function(arr) {
|
||||
var i, s = [];
|
||||
for (i = 0; i < arr.length; i++) s.push(String.fromCharCode(arr[i]));
|
||||
return decodeURIComponent(escape(s.join('')));
|
||||
};
|
||||
|
||||
util.encodeBase64 = function(arr) {
|
||||
if (typeof btoa === 'undefined') {
|
||||
return (new Buffer(arr)).toString('base64');
|
||||
} else {
|
||||
var i, s = [], len = arr.length;
|
||||
for (i = 0; i < len; i++) s.push(String.fromCharCode(arr[i]));
|
||||
return btoa(s.join(''));
|
||||
}
|
||||
};
|
||||
|
||||
util.decodeBase64 = function(s) {
|
||||
if (typeof atob === 'undefined') {
|
||||
return new Uint8Array(Array.prototype.slice.call(new Buffer(s, 'base64'), 0));
|
||||
} else {
|
||||
var i, d = atob(s), b = new Uint8Array(d.length);
|
||||
for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i);
|
||||
return b;
|
||||
}
|
||||
};
|
||||
|
||||
return util;
|
||||
|
||||
}));
|
||||
1
chromeKeePassXC/background/nacl.min.js
vendored
Executable file
136
chromeKeePassXC/background/page.js
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
var page = {};
|
||||
|
||||
// special information for every tab
|
||||
page.tabs = {};
|
||||
|
||||
page.currentTabId = -1;
|
||||
page.settings = (typeof(localStorage.settings) == 'undefined') ? {} : JSON.parse(localStorage.settings);
|
||||
page.blockedTabs = {};
|
||||
|
||||
page.initSettings = function() {
|
||||
event.onLoadSettings();
|
||||
if(!("checkUpdateKeePassXC" in page.settings)) {
|
||||
page.settings.checkUpdateKeePassXC = 3;
|
||||
}
|
||||
if(!("autoCompleteUsernames" in page.settings)) {
|
||||
page.settings.autoCompleteUsernames = 1;
|
||||
}
|
||||
if(!("autoFillAndSend" in page.settings)) {
|
||||
page.settings.autoFillAndSend = 1;
|
||||
}
|
||||
if(!("usePasswordGenerator" in page.settings)) {
|
||||
page.settings.usePasswordGenerator = 1;
|
||||
}
|
||||
if(!("autoFillSingleEntry" in page.settings)) {
|
||||
page.settings.autoFillSingleEntry = 1;
|
||||
}
|
||||
if(!("autoRetrieveCredentials" in page.settings)) {
|
||||
page.settings.autoRetrieveCredentials = 1;
|
||||
}
|
||||
if(!("hostname" in page.settings)) {
|
||||
page.settings.hostname = "localhost";
|
||||
}
|
||||
if(!("port" in page.settings)) {
|
||||
page.settings.port = "19455";
|
||||
}
|
||||
localStorage.settings = JSON.stringify(page.settings);
|
||||
}
|
||||
|
||||
page.initOpenedTabs = function() {
|
||||
chrome.tabs.query({}, function(tabs) {
|
||||
for(var i = 0; i < tabs.length; i++) {
|
||||
page.createTabEntry(tabs[i].id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
page.isValidProtocol = function(url) {
|
||||
var protocol = url.substring(0, url.indexOf(":"));
|
||||
protocol = protocol.toLowerCase();
|
||||
return !(url.indexOf(".") == -1 || (protocol != "http" && protocol != "https" && protocol != "ftp" && protocol != "sftp"));
|
||||
}
|
||||
|
||||
page.switchTab = function(callback, tab) {
|
||||
browserAction.showDefault(null, tab);
|
||||
|
||||
chrome.tabs.sendMessage(tab.id, {action: "activated_tab"});
|
||||
}
|
||||
|
||||
page.clearCredentials = function(tabId, complete) {
|
||||
if(!page.tabs[tabId]) {
|
||||
return;
|
||||
}
|
||||
|
||||
page.tabs[tabId].credentials = {};
|
||||
delete page.tabs[tabId].credentials;
|
||||
|
||||
if(complete) {
|
||||
page.tabs[tabId].loginList = [];
|
||||
|
||||
chrome.tabs.sendMessage(tabId, {
|
||||
action: "clear_credentials"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
page.createTabEntry = function(tabId) {
|
||||
//console.log("page.createTabEntry("+tabId+")");
|
||||
page.tabs[tabId] = {
|
||||
"stack": [],
|
||||
"errorMessage": null,
|
||||
"loginList": {}
|
||||
};
|
||||
}
|
||||
|
||||
page.removePageInformationFromNotExistingTabs = function() {
|
||||
var rand = Math.floor(Math.random()*1001);
|
||||
if(rand == 28) {
|
||||
chrome.tabs.query({}, function(tabs) {
|
||||
var $tabIds = {};
|
||||
var $infoIds = Object.keys(page.tabs);
|
||||
|
||||
for(var i = 0; i < tabs.length; i++) {
|
||||
$tabIds[tabs[i].id] = true;
|
||||
}
|
||||
|
||||
for(var i = 0; i < $infoIds.length; i++) {
|
||||
if(!($infoIds[i] in $tabIds)) {
|
||||
delete page.tabs[$infoIds[i]];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
page.debugConsole = function() {
|
||||
if(arguments.length > 1) {
|
||||
console.log(page.sprintf(arguments[0], arguments));
|
||||
}
|
||||
else {
|
||||
console.log(arguments[0]);
|
||||
}
|
||||
};
|
||||
|
||||
page.sprintf = function(input, args) {
|
||||
return input.replace(/{(\d+)}/g, function(match, number) {
|
||||
return typeof args[number] != 'undefined'
|
||||
? (typeof args[number] == 'object' ? JSON.stringify(args[number]) : args[number])
|
||||
: match
|
||||
;
|
||||
});
|
||||
}
|
||||
|
||||
page.debugDummy = function() {};
|
||||
|
||||
page.debug = page.debugDummy;
|
||||
|
||||
page.setDebug = function(bool) {
|
||||
if(bool) {
|
||||
page.debug = page.debugConsole;
|
||||
return "Debug mode enabled";
|
||||
}
|
||||
else {
|
||||
page.debug = page.debugDummy;
|
||||
return "Debug mode disabled";
|
||||
}
|
||||
};
|
||||
573
chromeKeePassXC/background/sjcl.js
Normal file
|
|
@ -0,0 +1,573 @@
|
|||
/** @fileOverview Javascript cryptography implementation.
|
||||
*
|
||||
* Crush to remove comments, shorten variable names and
|
||||
* generally reduce transmission size.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
/*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */
|
||||
/*global document, window, escape, unescape */
|
||||
|
||||
/** @namespace The Stanford Javascript Crypto Library, top-level namespace. */
|
||||
var sjcl = {
|
||||
/** @namespace Symmetric ciphers. */
|
||||
cipher: {},
|
||||
|
||||
/** @namespace Hash functions. Right now only SHA256 is implemented. */
|
||||
hash: {},
|
||||
|
||||
/** @namespace Key exchange functions. Right now only SRP is implemented. */
|
||||
keyexchange: {},
|
||||
|
||||
/** @namespace Block cipher modes of operation. */
|
||||
mode: {},
|
||||
|
||||
/** @namespace Miscellaneous. HMAC and PBKDF2. */
|
||||
misc: {},
|
||||
|
||||
/**
|
||||
* @namespace Bit array encoders and decoders.
|
||||
*
|
||||
* @description
|
||||
* The members of this namespace are functions which translate between
|
||||
* SJCL's bitArrays and other objects (usually strings). Because it
|
||||
* isn't always clear which direction is encoding and which is decoding,
|
||||
* the method names are "fromBits" and "toBits".
|
||||
*/
|
||||
codec: {},
|
||||
|
||||
/** @namespace Exceptions. */
|
||||
exception: {
|
||||
/** @class Ciphertext is corrupt. */
|
||||
corrupt: function(message) {
|
||||
this.toString = function() { return "CORRUPT: "+this.message; };
|
||||
this.message = message;
|
||||
},
|
||||
|
||||
/** @class Invalid parameter. */
|
||||
invalid: function(message) {
|
||||
this.toString = function() { return "INVALID: "+this.message; };
|
||||
this.message = message;
|
||||
},
|
||||
|
||||
/** @class Bug or missing feature in SJCL. */
|
||||
bug: function(message) {
|
||||
this.toString = function() { return "BUG: "+this.message; };
|
||||
this.message = message;
|
||||
},
|
||||
|
||||
/** @class Something isn't ready. */
|
||||
notReady: function(message) {
|
||||
this.toString = function() { return "NOT READY: "+this.message; };
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
};
|
||||
/** @fileOverview Low-level AES implementation.
|
||||
*
|
||||
* This file contains a low-level implementation of AES, optimized for
|
||||
* size and for efficiency on several browsers. It is based on
|
||||
* OpenSSL's aes_core.c, a public-domain implementation by Vincent
|
||||
* Rijmen, Antoon Bosselaers and Paulo Barreto.
|
||||
*
|
||||
* An older version of this implementation is available in the public
|
||||
* domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
|
||||
* Stanford University 2008-2010 and BSD-licensed for liability
|
||||
* reasons.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Schedule out an AES key for both encryption and decryption. This
|
||||
* is a low-level class. Use a cipher mode to do bulk encryption.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Array} key The key as an array of 4, 6 or 8 words.
|
||||
*
|
||||
* @class Advanced Encryption Standard (low-level interface)
|
||||
*/
|
||||
sjcl.cipher.aes = function (key) {
|
||||
if (!this._tables[0][0][0]) {
|
||||
this._precompute();
|
||||
}
|
||||
|
||||
var i, j, tmp,
|
||||
encKey, decKey,
|
||||
sbox = this._tables[0][4], decTable = this._tables[1],
|
||||
keyLen = key.length, rcon = 1;
|
||||
|
||||
if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
|
||||
throw new sjcl.exception.invalid("invalid aes key size");
|
||||
}
|
||||
|
||||
this._key = [encKey = key.slice(0), decKey = []];
|
||||
|
||||
// schedule encryption keys
|
||||
for (i = keyLen; i < 4 * keyLen + 28; i++) {
|
||||
tmp = encKey[i-1];
|
||||
|
||||
// apply sbox
|
||||
if (i%keyLen === 0 || (keyLen === 8 && i%keyLen === 4)) {
|
||||
tmp = sbox[tmp>>>24]<<24 ^ sbox[tmp>>16&255]<<16 ^ sbox[tmp>>8&255]<<8 ^ sbox[tmp&255];
|
||||
|
||||
// shift rows and add rcon
|
||||
if (i%keyLen === 0) {
|
||||
tmp = tmp<<8 ^ tmp>>>24 ^ rcon<<24;
|
||||
rcon = rcon<<1 ^ (rcon>>7)*283;
|
||||
}
|
||||
}
|
||||
|
||||
encKey[i] = encKey[i-keyLen] ^ tmp;
|
||||
}
|
||||
|
||||
// schedule decryption keys
|
||||
for (j = 0; i; j++, i--) {
|
||||
tmp = encKey[j&3 ? i : i - 4];
|
||||
if (i<=4 || j<4) {
|
||||
decKey[j] = tmp;
|
||||
} else {
|
||||
decKey[j] = decTable[0][sbox[tmp>>>24 ]] ^
|
||||
decTable[1][sbox[tmp>>16 & 255]] ^
|
||||
decTable[2][sbox[tmp>>8 & 255]] ^
|
||||
decTable[3][sbox[tmp & 255]];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.cipher.aes.prototype = {
|
||||
// public
|
||||
/* Something like this might appear here eventually
|
||||
name: "AES",
|
||||
blockSize: 4,
|
||||
keySizes: [4,6,8],
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encrypt an array of 4 big-endian words.
|
||||
* @param {Array} data The plaintext.
|
||||
* @return {Array} The ciphertext.
|
||||
*/
|
||||
encrypt:function (data) { return this._crypt(data,0); },
|
||||
|
||||
/**
|
||||
* Decrypt an array of 4 big-endian words.
|
||||
* @param {Array} data The ciphertext.
|
||||
* @return {Array} The plaintext.
|
||||
*/
|
||||
decrypt:function (data) { return this._crypt(data,1); },
|
||||
|
||||
/**
|
||||
* The expanded S-box and inverse S-box tables. These will be computed
|
||||
* on the client so that we don't have to send them down the wire.
|
||||
*
|
||||
* There are two tables, _tables[0] is for encryption and
|
||||
* _tables[1] is for decryption.
|
||||
*
|
||||
* The first 4 sub-tables are the expanded S-box with MixColumns. The
|
||||
* last (_tables[01][4]) is the S-box itself.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_tables: [[[],[],[],[],[]],[[],[],[],[],[]]],
|
||||
|
||||
/**
|
||||
* Expand the S-box tables.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_precompute: function () {
|
||||
var encTable = this._tables[0], decTable = this._tables[1],
|
||||
sbox = encTable[4], sboxInv = decTable[4],
|
||||
i, x, xInv, d=[], th=[], x2, x4, x8, s, tEnc, tDec;
|
||||
|
||||
// Compute double and third tables
|
||||
for (i = 0; i < 256; i++) {
|
||||
th[( d[i] = i<<1 ^ (i>>7)*283 )^i]=i;
|
||||
}
|
||||
|
||||
for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
|
||||
// Compute sbox
|
||||
s = xInv ^ xInv<<1 ^ xInv<<2 ^ xInv<<3 ^ xInv<<4;
|
||||
s = s>>8 ^ s&255 ^ 99;
|
||||
sbox[x] = s;
|
||||
sboxInv[s] = x;
|
||||
|
||||
// Compute MixColumns
|
||||
x8 = d[x4 = d[x2 = d[x]]];
|
||||
tDec = x8*0x1010101 ^ x4*0x10001 ^ x2*0x101 ^ x*0x1010100;
|
||||
tEnc = d[s]*0x101 ^ s*0x1010100;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
encTable[i][x] = tEnc = tEnc<<24 ^ tEnc>>>8;
|
||||
decTable[i][s] = tDec = tDec<<24 ^ tDec>>>8;
|
||||
}
|
||||
}
|
||||
|
||||
// Compactify. Considerable speedup on Firefox.
|
||||
for (i = 0; i < 5; i++) {
|
||||
encTable[i] = encTable[i].slice(0);
|
||||
decTable[i] = decTable[i].slice(0);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Encryption and decryption core.
|
||||
* @param {Array} input Four words to be encrypted or decrypted.
|
||||
* @param dir The direction, 0 for encrypt and 1 for decrypt.
|
||||
* @return {Array} The four encrypted or decrypted words.
|
||||
* @private
|
||||
*/
|
||||
_crypt:function (input, dir) {
|
||||
if (input.length !== 4) {
|
||||
throw new sjcl.exception.invalid("invalid aes block size");
|
||||
}
|
||||
|
||||
var key = this._key[dir],
|
||||
// state variables a,b,c,d are loaded with pre-whitened data
|
||||
a = input[0] ^ key[0],
|
||||
b = input[dir ? 3 : 1] ^ key[1],
|
||||
c = input[2] ^ key[2],
|
||||
d = input[dir ? 1 : 3] ^ key[3],
|
||||
a2, b2, c2,
|
||||
|
||||
nInnerRounds = key.length/4 - 2,
|
||||
i,
|
||||
kIndex = 4,
|
||||
out = [0,0,0,0],
|
||||
table = this._tables[dir],
|
||||
|
||||
// load up the tables
|
||||
t0 = table[0],
|
||||
t1 = table[1],
|
||||
t2 = table[2],
|
||||
t3 = table[3],
|
||||
sbox = table[4];
|
||||
|
||||
// Inner rounds. Cribbed from OpenSSL.
|
||||
for (i = 0; i < nInnerRounds; i++) {
|
||||
a2 = t0[a>>>24] ^ t1[b>>16 & 255] ^ t2[c>>8 & 255] ^ t3[d & 255] ^ key[kIndex];
|
||||
b2 = t0[b>>>24] ^ t1[c>>16 & 255] ^ t2[d>>8 & 255] ^ t3[a & 255] ^ key[kIndex + 1];
|
||||
c2 = t0[c>>>24] ^ t1[d>>16 & 255] ^ t2[a>>8 & 255] ^ t3[b & 255] ^ key[kIndex + 2];
|
||||
d = t0[d>>>24] ^ t1[a>>16 & 255] ^ t2[b>>8 & 255] ^ t3[c & 255] ^ key[kIndex + 3];
|
||||
kIndex += 4;
|
||||
a=a2; b=b2; c=c2;
|
||||
}
|
||||
|
||||
// Last round.
|
||||
for (i = 0; i < 4; i++) {
|
||||
out[dir ? 3&-i : i] =
|
||||
sbox[a>>>24 ]<<24 ^
|
||||
sbox[b>>16 & 255]<<16 ^
|
||||
sbox[c>>8 & 255]<<8 ^
|
||||
sbox[d & 255] ^
|
||||
key[kIndex++];
|
||||
a2=a; a=b; b=c; c=d; d=a2;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/** @fileOverview Arrays of bits, encoded as arrays of Numbers.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace Arrays of bits, encoded as arrays of Numbers.
|
||||
*
|
||||
* @description
|
||||
* <p>
|
||||
* These objects are the currency accepted by SJCL's crypto functions.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Most of our crypto primitives operate on arrays of 4-byte words internally,
|
||||
* but many of them can take arguments that are not a multiple of 4 bytes.
|
||||
* This library encodes arrays of bits (whose size need not be a multiple of 8
|
||||
* bits) as arrays of 32-bit words. The bits are packed, big-endian, into an
|
||||
* array of words, 32 bits at a time. Since the words are double-precision
|
||||
* floating point numbers, they fit some extra data. We use this (in a private,
|
||||
* possibly-changing manner) to encode the number of bits actually present
|
||||
* in the last word of the array.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Because bitwise ops clear this out-of-band data, these arrays can be passed
|
||||
* to ciphers like AES which want arrays of words.
|
||||
* </p>
|
||||
*/
|
||||
sjcl.bitArray = {
|
||||
/**
|
||||
* Array slices in units of bits.
|
||||
* @param {bitArray a} The array to slice.
|
||||
* @param {Number} bstart The offset to the start of the slice, in bits.
|
||||
* @param {Number} bend The offset to the end of the slice, in bits. If this is undefined,
|
||||
* slice until the end of the array.
|
||||
* @return {bitArray} The requested slice.
|
||||
*/
|
||||
bitSlice: function (a, bstart, bend) {
|
||||
a = sjcl.bitArray._shiftRight(a.slice(bstart/32), 32 - (bstart & 31)).slice(1);
|
||||
return (bend === undefined) ? a : sjcl.bitArray.clamp(a, bend-bstart);
|
||||
},
|
||||
|
||||
/**
|
||||
* Extract a number packed into a bit array.
|
||||
* @param {bitArray} a The array to slice.
|
||||
* @param {Number} bstart The offset to the start of the slice, in bits.
|
||||
* @param {Number} length The length of the number to extract.
|
||||
* @return {Number} The requested slice.
|
||||
*/
|
||||
extract: function(a, bstart, blength) {
|
||||
// FIXME: this Math.floor is not necessary at all, but for some reason
|
||||
// seems to suppress a bug in the Chromium JIT.
|
||||
var x, sh = Math.floor((-bstart-blength) & 31);
|
||||
if ((bstart + blength - 1 ^ bstart) & -32) {
|
||||
// it crosses a boundary
|
||||
x = (a[bstart/32|0] << (32 - sh)) ^ (a[bstart/32+1|0] >>> sh);
|
||||
} else {
|
||||
// within a single word
|
||||
x = a[bstart/32|0] >>> sh;
|
||||
}
|
||||
return x & ((1<<blength) - 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Concatenate two bit arrays.
|
||||
* @param {bitArray} a1 The first array.
|
||||
* @param {bitArray} a2 The second array.
|
||||
* @return {bitArray} The concatenation of a1 and a2.
|
||||
*/
|
||||
concat: function (a1, a2) {
|
||||
if (a1.length === 0 || a2.length === 0) {
|
||||
return a1.concat(a2);
|
||||
}
|
||||
|
||||
var out, i, last = a1[a1.length-1], shift = sjcl.bitArray.getPartial(last);
|
||||
if (shift === 32) {
|
||||
return a1.concat(a2);
|
||||
} else {
|
||||
return sjcl.bitArray._shiftRight(a2, shift, last|0, a1.slice(0,a1.length-1));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the length of an array of bits.
|
||||
* @param {bitArray} a The array.
|
||||
* @return {Number} The length of a, in bits.
|
||||
*/
|
||||
bitLength: function (a) {
|
||||
var l = a.length, x;
|
||||
if (l === 0) { return 0; }
|
||||
x = a[l - 1];
|
||||
return (l-1) * 32 + sjcl.bitArray.getPartial(x);
|
||||
},
|
||||
|
||||
/**
|
||||
* Truncate an array.
|
||||
* @param {bitArray} a The array.
|
||||
* @param {Number} len The length to truncate to, in bits.
|
||||
* @return {bitArray} A new array, truncated to len bits.
|
||||
*/
|
||||
clamp: function (a, len) {
|
||||
if (a.length * 32 < len) { return a; }
|
||||
a = a.slice(0, Math.ceil(len / 32));
|
||||
var l = a.length;
|
||||
len = len & 31;
|
||||
if (l > 0 && len) {
|
||||
a[l-1] = sjcl.bitArray.partial(len, a[l-1] & 0x80000000 >> (len-1), 1);
|
||||
}
|
||||
return a;
|
||||
},
|
||||
|
||||
/**
|
||||
* Make a partial word for a bit array.
|
||||
* @param {Number} len The number of bits in the word.
|
||||
* @param {Number} x The bits.
|
||||
* @param {Number} [0] _end Pass 1 if x has already been shifted to the high side.
|
||||
* @return {Number} The partial word.
|
||||
*/
|
||||
partial: function (len, x, _end) {
|
||||
if (len === 32) { return x; }
|
||||
return (_end ? x|0 : x << (32-len)) + len * 0x10000000000;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the number of bits used by a partial word.
|
||||
* @param {Number} x The partial word.
|
||||
* @return {Number} The number of bits used by the partial word.
|
||||
*/
|
||||
getPartial: function (x) {
|
||||
return Math.round(x/0x10000000000) || 32;
|
||||
},
|
||||
|
||||
/**
|
||||
* Compare two arrays for equality in a predictable amount of time.
|
||||
* @param {bitArray} a The first array.
|
||||
* @param {bitArray} b The second array.
|
||||
* @return {boolean} true if a == b; false otherwise.
|
||||
*/
|
||||
equal: function (a, b) {
|
||||
if (sjcl.bitArray.bitLength(a) !== sjcl.bitArray.bitLength(b)) {
|
||||
return false;
|
||||
}
|
||||
var x = 0, i;
|
||||
for (i=0; i<a.length; i++) {
|
||||
x |= a[i]^b[i];
|
||||
}
|
||||
return (x === 0);
|
||||
},
|
||||
|
||||
/** Shift an array right.
|
||||
* @param {bitArray} a The array to shift.
|
||||
* @param {Number} shift The number of bits to shift.
|
||||
* @param {Number} [carry=0] A byte to carry in
|
||||
* @param {bitArray} [out=[]] An array to prepend to the output.
|
||||
* @private
|
||||
*/
|
||||
_shiftRight: function (a, shift, carry, out) {
|
||||
var i, last2=0, shift2;
|
||||
if (out === undefined) { out = []; }
|
||||
|
||||
for (; shift >= 32; shift -= 32) {
|
||||
out.push(carry);
|
||||
carry = 0;
|
||||
}
|
||||
if (shift === 0) {
|
||||
return out.concat(a);
|
||||
}
|
||||
|
||||
for (i=0; i<a.length; i++) {
|
||||
out.push(carry | a[i]>>>shift);
|
||||
carry = a[i] << (32-shift);
|
||||
}
|
||||
last2 = a.length ? a[a.length-1] : 0;
|
||||
shift2 = sjcl.bitArray.getPartial(last2);
|
||||
out.push(sjcl.bitArray.partial(shift+shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(),1));
|
||||
return out;
|
||||
},
|
||||
|
||||
/** xor a block of 4 words together.
|
||||
* @private
|
||||
*/
|
||||
_xor4: function(x,y) {
|
||||
return [x[0]^y[0],x[1]^y[1],x[2]^y[2],x[3]^y[3]];
|
||||
}
|
||||
};
|
||||
/** @fileOverview CBC mode implementation
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace
|
||||
* Dangerous: CBC mode with PKCS#5 padding.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
sjcl.mode.cbc = {
|
||||
/** The name of the mode.
|
||||
* @constant
|
||||
*/
|
||||
name: "cbc",
|
||||
|
||||
/** Encrypt in CBC mode with PKCS#5 padding.
|
||||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} plaintext The plaintext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} [adata=[]] The authenticated data. Must be empty.
|
||||
* @return The encrypted data, an array of bytes.
|
||||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified.
|
||||
*/
|
||||
encrypt: function(prp, plaintext, iv, adata) {
|
||||
if (adata && adata.length) {
|
||||
throw new sjcl.exception.invalid("cbc can't authenticate data");
|
||||
}
|
||||
if (sjcl.bitArray.bitLength(iv) !== 128) {
|
||||
throw new sjcl.exception.invalid("cbc iv must be 128 bits");
|
||||
}
|
||||
var i,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
bl = w.bitLength(plaintext),
|
||||
bp = 0,
|
||||
output = [];
|
||||
|
||||
if (bl&7) {
|
||||
throw new sjcl.exception.invalid("pkcs#5 padding only works for multiples of a byte");
|
||||
}
|
||||
|
||||
for (i=0; bp+128 <= bl; i+=4, bp+=128) {
|
||||
/* Encrypt a non-final block */
|
||||
iv = prp.encrypt(xor(iv, plaintext.slice(i,i+4)));
|
||||
output.splice(i,0,iv[0],iv[1],iv[2],iv[3]);
|
||||
}
|
||||
|
||||
/* Construct the pad. */
|
||||
bl = (16 - ((bl >> 3) & 15)) * 0x1010101;
|
||||
|
||||
/* Pad and encrypt. */
|
||||
iv = prp.encrypt(xor(iv,w.concat(plaintext,[bl,bl,bl,bl]).slice(i,i+4)));
|
||||
output.splice(i,0,iv[0],iv[1],iv[2],iv[3]);
|
||||
return output;
|
||||
},
|
||||
|
||||
/** Decrypt in CBC mode.
|
||||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} ciphertext The ciphertext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} [adata=[]] The authenticated data. It must be empty.
|
||||
* @return The decrypted data, an array of bytes.
|
||||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified.
|
||||
* @throws {sjcl.exception.corrupt} if if the message is corrupt.
|
||||
*/
|
||||
decrypt: function(prp, ciphertext, iv, adata) {
|
||||
if (adata && adata.length) {
|
||||
throw new sjcl.exception.invalid("cbc can't authenticate data");
|
||||
}
|
||||
if (sjcl.bitArray.bitLength(iv) !== 128) {
|
||||
throw new sjcl.exception.invalid("cbc iv must be 128 bits");
|
||||
}
|
||||
if ((sjcl.bitArray.bitLength(ciphertext) & 127) || !ciphertext.length) {
|
||||
throw new sjcl.exception.corrupt("cbc ciphertext must be a positive multiple of the block size");
|
||||
}
|
||||
var i,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
bi, bo,
|
||||
output = [];
|
||||
|
||||
adata = adata || [];
|
||||
|
||||
for (i=0; i<ciphertext.length; i+=4) {
|
||||
bi = ciphertext.slice(i,i+4);
|
||||
bo = xor(iv,prp.decrypt(bi));
|
||||
output.splice(i,0,bo[0],bo[1],bo[2],bo[3]);
|
||||
iv = bi;
|
||||
}
|
||||
|
||||
/* check and remove the pad */
|
||||
bi = output[i-1] & 255;
|
||||
if (bi == 0 || bi > 16) {
|
||||
throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
|
||||
}
|
||||
bo = bi * 0x1010101;
|
||||
if (!w.equal(w.bitSlice([bo,bo,bo,bo], 0, bi*8),
|
||||
w.bitSlice(output, output.length*32 - bi*8, output.length*32))) {
|
||||
throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
|
||||
}
|
||||
|
||||
return w.bitSlice(output, 0, output.length*32 - bi*8);
|
||||
}
|
||||
};
|
||||
28
chromeKeePassXC/background/utf8.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
var UTF8 = {
|
||||
decode : function (utftext) {
|
||||
var string = "";
|
||||
var i = 0;
|
||||
var c = c1 = c2 = 0;
|
||||
|
||||
while (i < utftext.length) {
|
||||
c = utftext.charCodeAt(i);
|
||||
if (c < 128) {
|
||||
string += String.fromCharCode(c);
|
||||
i++;
|
||||
}
|
||||
else if((c > 191) && (c < 224)) {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
|
||||
i += 2;
|
||||
} else {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
c3 = utftext.charCodeAt(i+2);
|
||||
string += String.fromCharCode(
|
||||
((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
|
||||
i += 3;
|
||||
}
|
||||
|
||||
}
|
||||
return string;
|
||||
}
|
||||
}
|
||||
468
chromeKeePassXC/bootstrap-btn.css
vendored
Normal file
|
|
@ -0,0 +1,468 @@
|
|||
.b2c-btn {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
padding: 4px 14px;
|
||||
margin-bottom: 0;
|
||||
*margin-left: .3em;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
*line-height: 20px;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
background-color: #f5f5f5;
|
||||
*background-color: #e6e6e6;
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
|
||||
background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
|
||||
background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
|
||||
background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
|
||||
background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
|
||||
background-repeat: repeat-x;
|
||||
border: 1px solid #bbbbbb;
|
||||
*border: 0;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
border-color: #e6e6e6 #e6e6e6 #bfbfbf;
|
||||
border-bottom-color: #a2a2a2;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
|
||||
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
|
||||
*zoom: 1;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.b2c-btn:hover,
|
||||
.b2c-btn:active,
|
||||
.b2c-btn.active,
|
||||
.b2c-btn.disabled,
|
||||
.b2c-btn[disabled] {
|
||||
color: #333333;
|
||||
background-color: #e6e6e6;
|
||||
*background-color: #d9d9d9;
|
||||
}
|
||||
|
||||
.b2c-btn:active,
|
||||
.b2c-btn.active {
|
||||
background-color: #cccccc \9;
|
||||
}
|
||||
|
||||
.b2c-btn:first-child {
|
||||
*margin-left: 0;
|
||||
}
|
||||
|
||||
.b2c-btn:hover {
|
||||
color: #333333;
|
||||
text-decoration: none;
|
||||
background-color: #e6e6e6;
|
||||
*background-color: #d9d9d9;
|
||||
/* Buttons in IE7 don't get borders, so darken on hover */
|
||||
|
||||
background-position: 0 -15px;
|
||||
-webkit-transition: background-position 0.1s linear;
|
||||
-moz-transition: background-position 0.1s linear;
|
||||
-o-transition: background-position 0.1s linear;
|
||||
transition: background-position 0.1s linear;
|
||||
}
|
||||
|
||||
.b2c-btn:focus {
|
||||
outline: thin dotted #333;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.b2c-btn.active,
|
||||
.b2c-btn:active {
|
||||
background-color: #e6e6e6;
|
||||
background-color: #d9d9d9 \9;
|
||||
background-image: none;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
-moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.b2c-btn.disabled,
|
||||
.b2c-btn[disabled] {
|
||||
cursor: default;
|
||||
background-color: #e6e6e6;
|
||||
background-image: none;
|
||||
opacity: 0.65;
|
||||
filter: alpha(opacity=65);
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.b2c-btn-large {
|
||||
padding: 9px 14px;
|
||||
font-size: 16px;
|
||||
line-height: normal;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.b2c-btn-large [class^="icon-"] {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.b2c-btn-small {
|
||||
padding: 3px 9px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.b2c-btn-small [class^="icon-"] {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.b2c-btn-mini {
|
||||
padding: 2px 6px;
|
||||
font-size: 11px;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
.b2c-btn-block {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.b2c-btn-block + .b2c-btn-block {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
input[type="submit"].b2c-btn-block,
|
||||
input[type="reset"].b2c-btn-block,
|
||||
input[type="button"].b2c-btn-block {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.b2c-btn-primary.active,
|
||||
.b2c-btn-warning.active,
|
||||
.b2c-btn-danger.active,
|
||||
.b2c-btn-success.active,
|
||||
.b2c-btn-info.active,
|
||||
.b2c-btn-inverse.active {
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
|
||||
.b2c-btn {
|
||||
border-color: #c5c5c5;
|
||||
border-color: rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.b2c-btn-primary {
|
||||
color: #ffffff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
background-color: #006dcc;
|
||||
*background-color: #0044cc;
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
|
||||
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: linear-gradient(to bottom, #0088cc, #0044cc);
|
||||
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #0044cc #0044cc #002a80;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
|
||||
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.b2c-btn-primary:hover,
|
||||
.b2c-btn-primary:active,
|
||||
.b2c-btn-primary.active,
|
||||
.b2c-btn-primary.disabled,
|
||||
.b2c-btn-primary[disabled] {
|
||||
color: #ffffff;
|
||||
background-color: #0044cc;
|
||||
*background-color: #003bb3;
|
||||
}
|
||||
|
||||
.b2c-btn-primary:active,
|
||||
.b2c-btn-primary.active {
|
||||
background-color: #003399 \9;
|
||||
}
|
||||
|
||||
.b2c-btn-warning {
|
||||
color: #ffffff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
background-color: #faa732;
|
||||
*background-color: #f89406;
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
|
||||
background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
|
||||
background-image: -o-linear-gradient(top, #fbb450, #f89406);
|
||||
background-image: linear-gradient(to bottom, #fbb450, #f89406);
|
||||
background-image: -moz-linear-gradient(top, #fbb450, #f89406);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #f89406 #f89406 #ad6704;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
|
||||
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.b2c-btn-warning:hover,
|
||||
.b2c-btn-warning:active,
|
||||
.b2c-btn-warning.active,
|
||||
.b2c-btn-warning.disabled,
|
||||
.b2c-btn-warning[disabled] {
|
||||
color: #ffffff;
|
||||
background-color: #f89406;
|
||||
*background-color: #df8505;
|
||||
}
|
||||
|
||||
.b2c-btn-warning:active,
|
||||
.b2c-btn-warning.active {
|
||||
background-color: #c67605 \9;
|
||||
}
|
||||
|
||||
.b2c-btn-danger {
|
||||
color: #ffffff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
background-color: #da4f49;
|
||||
*background-color: #bd362f;
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));
|
||||
background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);
|
||||
background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);
|
||||
background-image: linear-gradient(to bottom, #ee5f5b, #bd362f);
|
||||
background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #bd362f #bd362f #802420;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);
|
||||
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.b2c-btn-danger:hover,
|
||||
.b2c-btn-danger:active,
|
||||
.b2c-btn-danger.active,
|
||||
.b2c-btn-danger.disabled,
|
||||
.b2c-btn-danger[disabled] {
|
||||
color: #ffffff;
|
||||
background-color: #bd362f;
|
||||
*background-color: #a9302a;
|
||||
}
|
||||
|
||||
.b2c-btn-danger:active,
|
||||
.b2c-btn-danger.active {
|
||||
background-color: #942a25 \9;
|
||||
}
|
||||
|
||||
.b2c-btn-success {
|
||||
color: #ffffff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
background-color: #5bb75b;
|
||||
*background-color: #51a351;
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));
|
||||
background-image: -webkit-linear-gradient(top, #62c462, #51a351);
|
||||
background-image: -o-linear-gradient(top, #62c462, #51a351);
|
||||
background-image: linear-gradient(to bottom, #62c462, #51a351);
|
||||
background-image: -moz-linear-gradient(top, #62c462, #51a351);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #51a351 #51a351 #387038;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);
|
||||
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.b2c-btn-success:hover,
|
||||
.b2c-btn-success:active,
|
||||
.b2c-btn-success.active,
|
||||
.b2c-btn-success.disabled,
|
||||
.b2c-btn-success[disabled] {
|
||||
color: #ffffff;
|
||||
background-color: #51a351;
|
||||
*background-color: #499249;
|
||||
}
|
||||
|
||||
.b2c-btn-success:active,
|
||||
.b2c-btn-success.active {
|
||||
background-color: #408140 \9;
|
||||
}
|
||||
|
||||
.b2c-btn-info {
|
||||
color: #ffffff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
background-color: #49afcd;
|
||||
*background-color: #2f96b4;
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);
|
||||
background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);
|
||||
background-image: linear-gradient(to bottom, #5bc0de, #2f96b4);
|
||||
background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #2f96b4 #2f96b4 #1f6377;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);
|
||||
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.b2c-btn-info:hover,
|
||||
.b2c-btn-info:active,
|
||||
.b2c-btn-info.active,
|
||||
.b2c-btn-info.disabled,
|
||||
.b2c-btn-info[disabled] {
|
||||
color: #ffffff;
|
||||
background-color: #2f96b4;
|
||||
*background-color: #2a85a0;
|
||||
}
|
||||
|
||||
.b2c-btn-info:active,
|
||||
.b2c-btn-info.active {
|
||||
background-color: #24748c \9;
|
||||
}
|
||||
|
||||
.b2c-btn-inverse {
|
||||
color: #ffffff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
background-color: #363636;
|
||||
*background-color: #222222;
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));
|
||||
background-image: -webkit-linear-gradient(top, #444444, #222222);
|
||||
background-image: -o-linear-gradient(top, #444444, #222222);
|
||||
background-image: linear-gradient(to bottom, #444444, #222222);
|
||||
background-image: -moz-linear-gradient(top, #444444, #222222);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #222222 #222222 #000000;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);
|
||||
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.b2c-btn-inverse:hover,
|
||||
.b2c-btn-inverse:active,
|
||||
.b2c-btn-inverse.active,
|
||||
.b2c-btn-inverse.disabled,
|
||||
.b2c-btn-inverse[disabled] {
|
||||
color: #ffffff;
|
||||
background-color: #222222;
|
||||
*background-color: #151515;
|
||||
}
|
||||
|
||||
.b2c-btn-inverse:active,
|
||||
.b2c-btn-inverse.active {
|
||||
background-color: #080808 \9;
|
||||
}
|
||||
|
||||
button.b2c-btn,
|
||||
input[type="submit"].b2c-btn {
|
||||
*padding-top: 3px;
|
||||
*padding-bottom: 3px;
|
||||
}
|
||||
|
||||
button.b2c-btn::-moz-focus-inner,
|
||||
input[type="submit"].b2c-btn::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
button.b2c-btn.b2c-btn-large,
|
||||
input[type="submit"].b2c-btn.b2c-btn-large {
|
||||
*padding-top: 7px;
|
||||
*padding-bottom: 7px;
|
||||
}
|
||||
|
||||
button.b2c-btn.b2c-btn-small,
|
||||
input[type="submit"].b2c-btn.b2c-btn-small {
|
||||
*padding-top: 3px;
|
||||
*padding-bottom: 3px;
|
||||
}
|
||||
|
||||
button.b2c-btn.b2c-btn-mini,
|
||||
input[type="submit"].b2c-btn.b2c-btn-mini {
|
||||
*padding-top: 1px;
|
||||
*padding-bottom: 1px;
|
||||
}
|
||||
|
||||
.b2c-input-append {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.b2c-input-append input,
|
||||
.b2c-input-append select,
|
||||
.b2c-input-append .b2c-uneditable-input,
|
||||
.b2c-input-append .b2c-dropdown-menu,
|
||||
.b2c-input-append .b2c-popover {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.b2c-input-append input,
|
||||
.b2c-input-append select,
|
||||
.b2c-input-append .b2c-uneditable-input {
|
||||
position: relative;
|
||||
margin-bottom: 0;
|
||||
*margin-left: 0;
|
||||
vertical-align: top;
|
||||
-webkit-border-radius: 0 4px 4px 0;
|
||||
-moz-border-radius: 0 4px 4px 0;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
.b2c-input-append input:focus,
|
||||
.b2c-input-append select:focus,
|
||||
.b2c-input-append .b2c-b2c-uneditable-input:focus {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.b2c-input-append .b2c-add-on {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
height: 20px;
|
||||
min-width: 16px;
|
||||
padding: 4px 5px;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 0 #ffffff;
|
||||
background-color: #eeeeee;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.b2c-input-append .b2c-add-on,
|
||||
.b2c-input-append .b2c-btn,
|
||||
.b2c-input-append .b2c-btn-group > .b2c-dropdown-toggle {
|
||||
vertical-align: top;
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.b2c-input-append .b2c-active {
|
||||
background-color: #a9dba9;
|
||||
border-color: #46a546;
|
||||
}
|
||||
|
||||
.b2c-input-append input,
|
||||
.b2c-input-append select,
|
||||
.b2c-input-append .b2c-uneditable-input {
|
||||
-webkit-border-radius: 4px 0 0 4px;
|
||||
-moz-border-radius: 4px 0 0 4px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.b2c-input-append .b2c-add-on,
|
||||
.b2c-input-append .b2c-btn,
|
||||
.b2c-input-append .b2c-btn-group {
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
.b2c-input-append .b2c-add-on:last-child,
|
||||
.b2c-input-append .b2c-btn:last-child,
|
||||
.b2c-input-append .b2c-btn-group:last-child > .b2c-dropdown-toggle {
|
||||
-webkit-border-radius: 0 4px 4px 0;
|
||||
-moz-border-radius: 0 4px 4px 0;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
172
chromeKeePassXC/chromekeepassxc.css
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
.cip-ui-autocomplete li.cip-ui-menu-item {
|
||||
text-align: left !important;
|
||||
font-size: 12px !important;
|
||||
font-weight: normal !important;
|
||||
font-style: normal !important;
|
||||
font-family: Verdana, Arial, sans-serif !important;
|
||||
color: #222222 !important;
|
||||
}
|
||||
.cip-ui-dialog-titlebar-close {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
.cip-ui-widget-overlay {
|
||||
background: none !important;
|
||||
z-index: 2147483601 !important;
|
||||
}
|
||||
.cip-ui-dialog {
|
||||
z-index: 2147483602 !important;
|
||||
}
|
||||
.cip-ui-dialog .cip-ui-dialog-title {
|
||||
font-size:.8em !important;
|
||||
}
|
||||
.cip-ui-dialog .cip-ui-dialog-titlebar {
|
||||
padding:.1em .5em !important;
|
||||
}
|
||||
.cip-ui-dialog-content {
|
||||
font-size: .8em !important;
|
||||
}
|
||||
|
||||
#cip-genpw-dialog {
|
||||
text-align: left !important;
|
||||
}
|
||||
#cip-genpw-dialog button {
|
||||
height: 26px !important;
|
||||
}
|
||||
.cip-genpw-clearfix:after {
|
||||
clear: both;
|
||||
line-height: 0;
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
.cip-genpw-icon {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
}
|
||||
.cip-genpw-icon.cip-icon-key-small {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-image: url(chrome-extension://__MSG_@@extension_id__/icons/key_16x16.png);
|
||||
}
|
||||
.cip-genpw-icon.cip-icon-key-big {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-image: url(chrome-extension://__MSG_@@extension_id__/icons/key_24x24.png);
|
||||
}
|
||||
.cip-genpw-password-frame {
|
||||
margin-top: 5px !important;
|
||||
margin-bottom: 5px !important;
|
||||
}
|
||||
.cip-genpw-password-frame > * {
|
||||
height: 20px !important;
|
||||
font-size: 11px !important;
|
||||
}
|
||||
.cip-genpw-textfield {
|
||||
background: none !important;
|
||||
font-size: 11px !important;
|
||||
display: inline !important;
|
||||
border: 1px solid rgb(170, 170, 170) !important;
|
||||
padding: 1px 2px !important;
|
||||
max-width: none !important;
|
||||
min-width: 0 !important;
|
||||
font-size: 1em !important;
|
||||
width: 240px !important;
|
||||
padding-left: 5px !important;
|
||||
}
|
||||
#cip-genpw-quality {
|
||||
width: 50px !important;
|
||||
padding-top: 1px !important;
|
||||
padding-bottom: 1px !important;
|
||||
}
|
||||
.cip-genpw-label {
|
||||
display: block !important;
|
||||
margin: 5px 0 !important;
|
||||
}
|
||||
.cip-genpw-checkbox {
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#cip-genpw-btn-fillin {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.b2c-modal-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 2147483645;
|
||||
}
|
||||
.b2c-modal-backdrop:after {
|
||||
content:'';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: #000000;
|
||||
opacity: 0.8;
|
||||
filter: alpha(opacity=80);
|
||||
}
|
||||
#b2c-cipDefine-fields {
|
||||
z-index: 2147483646;
|
||||
}
|
||||
#b2c-cipDefine-description {
|
||||
z-index: 2147483646;
|
||||
color: #efefef;
|
||||
border: 2px solid #555555;
|
||||
padding: 7px 5px;
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 150px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
background-color:rgba(255,255,255,0.3);
|
||||
font-size: 15px;
|
||||
}
|
||||
#b2c-cipDefine-description div:first-of-type {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
text-align: left;
|
||||
color: #efefef;
|
||||
padding-bottom: 8px;
|
||||
font-weight: bold;
|
||||
font-size: 160%;
|
||||
}
|
||||
#b2c-cipDefine-description p {
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
color: #efefef;
|
||||
border-top: 2px solid #666666;
|
||||
line-height: 110%;
|
||||
}
|
||||
#b2c-help {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.b2c-fixed-field {
|
||||
position: absolute;
|
||||
border: 2px solid #efefef;
|
||||
cursor: pointer;
|
||||
z-index: 2147483646;
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
background-color:rgba(239,239,239,0.4);
|
||||
}
|
||||
.b2c-fixed-hover-field {
|
||||
border: 2px solid orange;
|
||||
background-color:rgba(255,165,239,0.4);
|
||||
}
|
||||
.b2c-fixed-password-field {
|
||||
border: 2px solid red;
|
||||
color: #efefef;
|
||||
background-color:rgba(255,0,0,0.4);
|
||||
}
|
||||
.b2c-fixed-username-field {
|
||||
border: 2px solid limegreen;
|
||||
color: #efefef;
|
||||
background-color:rgba(50,205,50,0.4);
|
||||
}
|
||||
.b2c-fixed-string-field {
|
||||
border: 2px solid deepskyblue;
|
||||
color: #efefef;
|
||||
background-color:rgba(30,144,255,0.4);
|
||||
}
|
||||
1739
chromeKeePassXC/chromekeepassxc.js
Normal file
BIN
chromeKeePassXC/icons/19x19/icon_bang_19x19.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
chromeKeePassXC/icons/19x19/icon_cross_19x19.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
chromeKeePassXC/icons/19x19/icon_new_bang_19x19.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
chromeKeePassXC/icons/19x19/icon_new_cross_19x19.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
chromeKeePassXC/icons/19x19/icon_new_normal_19x19.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
chromeKeePassXC/icons/19x19/icon_new_questionmark_19x19.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
chromeKeePassXC/icons/19x19/icon_new_questionmark_blue_19x19.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
chromeKeePassXC/icons/19x19/icon_normal_19x19.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
chromeKeePassXC/icons/19x19/icon_questionmark_19x19.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
|
After Width: | Height: | Size: 1 KiB |
BIN
chromeKeePassXC/icons/19x19/icon_remember_red_lock_19x19.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
chromeKeePassXC/icons/keepassxc-dark_128x128.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
chromeKeePassXC/icons/keepassxc-dark_16x16.png
Normal file
|
After Width: | Height: | Size: 838 B |
BIN
chromeKeePassXC/icons/keepassxc-dark_32x32.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
chromeKeePassXC/icons/keepassxc-dark_48x48.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
chromeKeePassXC/icons/keepassxc-dark_64x64.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
chromeKeePassXC/icons/keepassxc_128x128.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
chromeKeePassXC/icons/keepassxc_16x16.png
Normal file
|
After Width: | Height: | Size: 880 B |
BIN
chromeKeePassXC/icons/keepassxc_19x19.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
chromeKeePassXC/icons/keepassxc_32x32.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
chromeKeePassXC/icons/keepassxc_38x38.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
chromeKeePassXC/icons/keepassxc_48x48.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
chromeKeePassXC/icons/keepassxc_64x64.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
chromeKeePassXC/icons/key_16x16.png
Normal file
|
After Width: | Height: | Size: 481 B |
BIN
chromeKeePassXC/icons/key_24x24.png
Normal file
|
After Width: | Height: | Size: 1 KiB |
BIN
chromeKeePassXC/images/ui-bg_flat_0_aaaaaa_40x100.png
Normal file
|
After Width: | Height: | Size: 212 B |
BIN
chromeKeePassXC/images/ui-bg_flat_75_ffffff_40x100.png
Normal file
|
After Width: | Height: | Size: 208 B |
BIN
chromeKeePassXC/images/ui-bg_glass_55_fbf9ee_1x400.png
Normal file
|
After Width: | Height: | Size: 335 B |
BIN
chromeKeePassXC/images/ui-bg_glass_65_ffffff_1x400.png
Normal file
|
After Width: | Height: | Size: 207 B |
BIN
chromeKeePassXC/images/ui-bg_glass_75_dadada_1x400.png
Normal file
|
After Width: | Height: | Size: 262 B |
BIN
chromeKeePassXC/images/ui-bg_glass_75_e6e6e6_1x400.png
Normal file
|
After Width: | Height: | Size: 262 B |
BIN
chromeKeePassXC/images/ui-bg_glass_95_fef1ec_1x400.png
Normal file
|
After Width: | Height: | Size: 332 B |
BIN
chromeKeePassXC/images/ui-bg_highlight-soft_75_cccccc_1x100.png
Normal file
|
After Width: | Height: | Size: 280 B |
17
chromeKeePassXC/jquery-1.11.1.min.js
vendored
Normal file
4
chromeKeePassXC/jquery-2.2.3.min.js
vendored
Normal file
4
chromeKeePassXC/jquery-3.2.0.min.js
vendored
Normal file
11
chromeKeePassXC/jquery-ui-1.10.2.custom.min.css
vendored
Normal file
11
chromeKeePassXC/jquery-ui-1.10.2.custom.min.js
vendored
Normal file
85
chromeKeePassXC/manifest.json
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
{
|
||||
"name": "chromeKeePassXC",
|
||||
"version": "0.1.0",
|
||||
"manifest_version": 2,
|
||||
"description": "KeePassXC integration for Chrome",
|
||||
"icons": {
|
||||
"16": "icons/keepassxc_16x16.png",
|
||||
"48": "icons/keepassxc_48x48.png",
|
||||
"128": "icons/keepassxc_128x128.png"
|
||||
},
|
||||
|
||||
"browser_action": {
|
||||
"default_icon": {
|
||||
"19": "icons/keepassxc_19x19.png",
|
||||
"38": "icons/keepassxc_38x38.png"
|
||||
},
|
||||
"default_title": "chromeKeePassXC",
|
||||
"default_popup": "popups/popup.html"
|
||||
},
|
||||
|
||||
"options_page": "options/options.html",
|
||||
"background": {
|
||||
"scripts": [
|
||||
"background/aes.js",
|
||||
"background/cryptoHelpers.js",
|
||||
"background/nacl.min.js",
|
||||
"background/nacl-util.js",
|
||||
"background/utf8.js",
|
||||
"background/keepass.js",
|
||||
"background/httpauth.js",
|
||||
"background/browserAction.js",
|
||||
"background/page.js",
|
||||
"background/event.js",
|
||||
"background/init.js"
|
||||
]
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches":
|
||||
[
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
],
|
||||
"js":
|
||||
[
|
||||
"jquery-1.11.1.min.js",
|
||||
"jquery-ui-1.10.2.custom.min.js",
|
||||
"chromekeepassxc.js"
|
||||
],
|
||||
"css":
|
||||
[
|
||||
"jquery-ui-1.10.2.custom.min.css",
|
||||
"bootstrap-btn.css",
|
||||
"chromekeepassxc.css"
|
||||
],
|
||||
"run_at": "document_idle",
|
||||
"all_frames": true
|
||||
}
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
"jquery.min.map",
|
||||
"icons/key_16x16.png",
|
||||
"icons/key_24x24.png",
|
||||
"images/ui-bg_flat_0_aaaaaa_40x100.png",
|
||||
"images/ui-bg_flat_0_aaaaaa_40x100.png",
|
||||
"images/ui-bg_flat_75_ffffff_40x100.png",
|
||||
"images/ui-bg_glass_55_fbf9ee_1x400.png",
|
||||
"images/ui-bg_glass_65_ffffff_1x400.png",
|
||||
"images/ui-bg_glass_75_dadada_1x400.png",
|
||||
"images/ui-bg_glass_75_e6e6e6_1x400.png",
|
||||
"images/ui-bg_glass_95_fef1ec_1x400.png",
|
||||
"images/ui-bg_highlight-soft_75_cccccc_1x100.png"
|
||||
],
|
||||
"permissions": [
|
||||
"contextMenus",
|
||||
"clipboardWrite",
|
||||
"nativeMessaging",
|
||||
"tabs",
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
"https://*/*",
|
||||
"http://*/*",
|
||||
"https://raw.github.com/"
|
||||
]
|
||||
}
|
||||
9
chromeKeePassXC/options/bootstrap-responsive.min.css
vendored
Normal file
9
chromeKeePassXC/options/bootstrap.min.css
vendored
Normal file
6
chromeKeePassXC/options/bootstrap.min.js
vendored
Normal file
BIN
chromeKeePassXC/options/http-auth-dialog.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
368
chromeKeePassXC/options/options.html
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Settings | chromeKeePassXC</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<link href="bootstrap.min.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="../bootstrap-btn.css" />
|
||||
<link href="bootstrap-responsive.min.css" rel="stylesheet" />
|
||||
<script type="text/javascript" src="../jquery-1.11.1.min.js"></script>
|
||||
<!--<script type="text/javascript" src="../jquery-3.2.0.min.js"></script>-->
|
||||
<script type="text/javascript" src="bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="options.js"></script>
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding-top: 20px;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
/* Custom container */
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
max-width: 1000px;
|
||||
}
|
||||
.container > hr {
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
/* Customize the navbar links to be fill the entire space of the .navbar */
|
||||
.navbar .navbar-inner {
|
||||
padding: 0;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.navbar .nav {
|
||||
margin: 0;
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar .nav li {
|
||||
display: table-cell;
|
||||
width: 1%;
|
||||
float: none;
|
||||
}
|
||||
.navbar .nav li a {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
border-left: 1px solid rgba(255,255,255,.75);
|
||||
border-right: 1px solid rgba(0,0,0,.1);
|
||||
}
|
||||
.navbar .nav li:first-child a {
|
||||
border-left: 0;
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
.navbar .nav li:last-child a {
|
||||
border-right: 0;
|
||||
border-radius: 0 3px 3px 0;
|
||||
}
|
||||
.tab {
|
||||
display: none;
|
||||
}
|
||||
h2+hr {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#tab-connected-databases .color.dropdown .dropdown-menu {
|
||||
width: 180px;
|
||||
padding: 7px 10px;
|
||||
line-height: 175%;
|
||||
}
|
||||
#tab-connected-databases .color.dropdown .dropdown-menu a {
|
||||
margin-right: 3px;
|
||||
}
|
||||
#tab-connected-databases .color.dropdown a.dropdown-toggle img {
|
||||
margin-right: 5px;
|
||||
}
|
||||
tr.clone {
|
||||
display: none;
|
||||
}
|
||||
td.last-used,
|
||||
td.created {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.radio.inline,
|
||||
.checkbox.inline {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.radio.inline + .radio.inline,
|
||||
.checkbox.inline + .checkbox.inline {
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
.checkUpdateKeePassXC {
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
#dangerousSettings {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="masthead">
|
||||
<h3 class="muted"><img src="/icons/keepassxc_48x48.png" alt="logo" /> chromeKeePassXC</h3>
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<ul class="nav">
|
||||
<li class="active"><a href="#general-settings">General</a></li>
|
||||
<li><a href="#connected-databases">Connected Databases</a></li>
|
||||
<li><a href="#specified-fields">Specified credential fields</a></li>
|
||||
<li><a href="#about">About</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.navbar -->
|
||||
</div>
|
||||
|
||||
<!-- General Settings -->
|
||||
<div class="tab" id="tab-general-settings">
|
||||
<h2>General Settings</h2>
|
||||
<hr />
|
||||
<p>
|
||||
If you just want to insert username + password into the fields where your focus is, press Ctrl + Shift + U.
|
||||
<br />
|
||||
If you only want to insert the password, just press Ctrl + Shift + P.
|
||||
</p>
|
||||
<p>
|
||||
<label for="blinkTimeout">Blink Time:</label>
|
||||
<div class="control-group">
|
||||
<div class="input-append">
|
||||
<input type="number" id="blinkTimeout" placeholder="7500" value="7500" />
|
||||
<button class="btn" id="blinkTimeoutButton" type="button">Save</button>
|
||||
</div>
|
||||
<span class="help-inline">
|
||||
What is the maximum time (ms) the icon should blink after detecting new credentials
|
||||
<br />
|
||||
Default: 7500
|
||||
</span>
|
||||
</div>
|
||||
</p>
|
||||
<p>
|
||||
<label for="blinkMinTimeout">Redirect Offset:</label>
|
||||
<div class="control-group">
|
||||
<div class="input-append">
|
||||
<input type="number" id="blinkMinTimeout" placeholder="2000" value="2000" />
|
||||
<button class="btn" id="blinkMinTimeoutButton" type="button">Save</button>
|
||||
</div>
|
||||
<span class="help-inline">
|
||||
What is the minimum time (ms) the icon should blink before deactivating due to page redirects.
|
||||
<br />
|
||||
-1 to only use <i>Blink Time</i> ignoring Redirect Allowance (old behavior)
|
||||
<br />
|
||||
Default: -1, Recommended: 2000
|
||||
</span>
|
||||
</div>
|
||||
</p>
|
||||
<p>
|
||||
<label for="allowedRedirect">Redirect Allowance:</label>
|
||||
<div class="control-group">
|
||||
<div class="input-append">
|
||||
<input type="number" id="allowedRedirect" placeholder="1" value="1" />
|
||||
<button class="btn" id="allowedRedirectButton" type="button">Save</button>
|
||||
</div>
|
||||
<span class="help-inline">
|
||||
How many pages should the tab cycle through after the redirect offset before deactivating the icon
|
||||
<br />
|
||||
Default: 1
|
||||
</span>
|
||||
</div>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="usePasswordGenerator" value="1" /> Activate password generator.
|
||||
</label>
|
||||
<span class="help-block">For all password-fields there will be an icon added to generate a new password.<br />
|
||||
It is generated by KeePassXC with the profile for automatically generated passwords for new entries.</span>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="autoRetrieveCredentials" value="1" /> Automatically retrieve credentials.
|
||||
</label>
|
||||
<span class="help-block">chromeKeePassXC will immediately retrieve the credentials when the tab is activated.</span>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="autoFillSingleEntry" value="1" /> Automatically fill-in single credentials entry.
|
||||
</label>
|
||||
<span class="help-block">If chromeKeePassXC does only receive a single entry from KeePassXC it automatically fills this credentials into the found credential fields.</span>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="autoCompleteUsernames" value="1" /> Activate autocomplete for username fields.
|
||||
</label>
|
||||
<span class="help-block">For all username fields on a page a dropdown list appears which contains all available credentials.</span>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
Check for updates of KeePassXC:
|
||||
<br />
|
||||
<label class="radio inline"><input type="radio" name="checkUpdateKeePassXC" value="3" /> every 3 days</label>
|
||||
<label class="radio inline"><input type="radio" name="checkUpdateKeePassXC" value="7" /> every week</label>
|
||||
<label class="radio inline"><input type="radio" name="checkUpdateKeePassXC" value="30" /> every month</label>
|
||||
<label class="radio inline"><input type="radio" name="checkUpdateKeePassXC" value="0" /> never</label>
|
||||
</p>
|
||||
<div class="help-block kphVersion">
|
||||
chromeKeePassXC needs KeePassXC to retrieve credentials.
|
||||
<br />
|
||||
You can download the latest stable version from here: <a target="_blank" href="https://keepassxc.org/">https://keepassxc.org/</a>
|
||||
<br />
|
||||
<br />
|
||||
<div class="row">
|
||||
<div class="span3">Your running version of KeePassXC:</div>
|
||||
<div class="span6"><em class="yourVersion"></em></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span3">Latest available version of KeePassXC:</div>
|
||||
<div class="span6"><em class="latestVersion"></em><button class="btn btn-mini checkUpdateKeePassXC">Check for updates</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="autoFillAndSend" value="1" /> Auto fill HTTP Auth dialogs and send them.
|
||||
</label>
|
||||
<span class="help-block">
|
||||
If credentials are found for a page and the login-type is an HTTP Auth request, chromeKeePassXC tries to login with the first given credentials.
|
||||
<br />
|
||||
An HTTP Auth dialog looks like this:
|
||||
</span>
|
||||
<img src="/options/http-auth-dialog.png" alt="http-auth-dialog" />
|
||||
</p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<!-- Connected Databases -->
|
||||
<div class="tab" id="tab-connected-databases">
|
||||
<h2>Connected Databases</h2>
|
||||
<hr />
|
||||
<p>
|
||||
If you are using several KeePass databases you can define a specific icon-color to each of them.
|
||||
<br />
|
||||
This will help you to easily determine from which database the credentials are retrieved.
|
||||
</p>
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="span5">Identifier</th>
|
||||
<th class="span2">Icon</th>
|
||||
<th class="span2">Last used</th>
|
||||
<th class="span2">Created</th>
|
||||
<th class="span1">Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="empty">
|
||||
<td colspan="5">No connected databases found.</td>
|
||||
</tr>
|
||||
<tr class="clone">
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="last-used"></td>
|
||||
<td class="created"></td>
|
||||
<td><button class="btn delete btn-danger">Remove</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="text-align: right">
|
||||
<button id="connect-button" class="b2c-btn b2c-btn-primary">Connect</button>
|
||||
</div>
|
||||
<div id="dialogDeleteConnectedDatabase" class="modal hide" tabindex="-1" role="dialog">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Remove identifier from Chrome?</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Do you really want to remove the identifier <span class="bold"></span> from Chrome?</p>
|
||||
<p class="help-block">You can reconnect your database at any time.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
|
||||
<button class="btn yes btn-primary">Yes, remove now</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Specified credential fields -->
|
||||
<div class="tab" id="tab-specified-fields">
|
||||
<h2>Specified credential fields</h2>
|
||||
<hr />
|
||||
<p>
|
||||
If chromeKeePassXC detects the wrong credential fields, you are able to specify the correct fields by yourself.
|
||||
<br />
|
||||
Just go to the page and click on the chromeKeePassXC-Icon, now select <em>Choose own credential fields for this page</em>.
|
||||
<br />
|
||||
On this page you can manage theses specified credential fields.
|
||||
</p>
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="span10">Page URL</th>
|
||||
<th class="span2">Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="empty">
|
||||
<td colspan="2">No specified credential fields found.</td>
|
||||
</tr>
|
||||
<tr class="clone">
|
||||
<td></td>
|
||||
<td><button class="btn delete btn-danger btn">Remove</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="dialogDeleteSpecifiedCredentialFields" class="modal hide" tabindex="-1" role="dialog">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Remove specified credential fields?</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Do you really want to remove the specified credential fields on the page <strong></strong>?</p>
|
||||
<p class="help-block">chromeKeePassXC will automatically detect the credential fields the next time you visit this page.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
|
||||
<button class="btn yes btn-primary">Yes, remove now</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- About -->
|
||||
<div class="tab" id="tab-about">
|
||||
<h2>About</h2>
|
||||
<hr />
|
||||
<p>
|
||||
Developed by <a target="_blank" href="https://github.com/pfn/">Perry Nguyen</a>, <a target="_blank" href="http://lukas-schulze.de">Lukas Schulze</a> and
|
||||
<a target="_blank" href="https://github.com/varjolintu/">Sami Vänttinen</a>
|
||||
</p>
|
||||
<p>
|
||||
<a target="_blank" href="https://chrome.google.com/webstore/detail/chromeipass/ompiailgknfdndiefoaoiligalphfdae">Visit extension's page in Chrome Web store</a>
|
||||
</p>
|
||||
<p>
|
||||
<a target="_blank" href="https://github.com/varjolintu/chromeKeePassXC">Visit project's page in GitHub</a>.
|
||||
</p>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="span2">chromeKeePassXC Version:</div>
|
||||
<div class="span6"><em class="versionCIP"></em></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span2">KeePassXC Version:</div>
|
||||
<div class="span6"><em class="versionKPH"></em></div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="footer">
|
||||
<p>2010-2017 - Perry Nguyen, Lukas Schulze, Sami Vänttinen</p>
|
||||
</div>
|
||||
</div> <!-- /container -->
|
||||
</body>
|
||||
</html>
|
||||
314
chromeKeePassXC/options/options.js
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
if(cIPJQ) {
|
||||
var $ = cIPJQ.noConflict(true);
|
||||
}
|
||||
|
||||
$(function() {
|
||||
options.initMenu();
|
||||
options.initGeneralSettings();
|
||||
options.initConnectedDatabases();
|
||||
options.initSpecifiedCredentialFields();
|
||||
options.initAbout();
|
||||
});
|
||||
|
||||
var options = options || {};
|
||||
|
||||
options.settings = typeof(localStorage.settings)=='undefined' ? {} : JSON.parse(localStorage.settings);
|
||||
options.keyRing = typeof(localStorage.keyRing)=='undefined' ? {} : JSON.parse(localStorage.keyRing);
|
||||
|
||||
options.initMenu = function() {
|
||||
$(".navbar:first ul.nav:first li a").click(function(e) {
|
||||
e.preventDefault();
|
||||
$(".navbar:first ul.nav:first li").removeClass("active");
|
||||
$(this).parent("li").addClass("active");
|
||||
$("div.tab").hide();
|
||||
$("div.tab#tab-" + $(this).attr("href").substring(1)).fadeIn();
|
||||
});
|
||||
|
||||
$("div.tab:first").show();
|
||||
}
|
||||
|
||||
options.initGeneralSettings = function() {
|
||||
$("#tab-general-settings input[type=checkbox]").each(function() {
|
||||
$(this).attr("checked", options.settings[$(this).attr("name")]);
|
||||
});
|
||||
|
||||
$("#tab-general-settings input[type=checkbox]").change(function() {
|
||||
options.settings[$(this).attr("name")] = $(this).is(':checked');
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
});
|
||||
|
||||
$("#tab-general-settings input[type=radio]").each(function() {
|
||||
if($(this).val() == options.settings[$(this).attr("name")]) {
|
||||
$(this).attr("checked", options.settings[$(this).attr("name")]);
|
||||
}
|
||||
});
|
||||
|
||||
$("#tab-general-settings input[type=radio]").change(function() {
|
||||
options.settings[$(this).attr("name")] = $(this).val();
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
});
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: "get_keepassxc_versions"
|
||||
}, options.showKeePassXCVersions);
|
||||
|
||||
$("#tab-general-settings button.checkUpdateKeePassXC:first").click(function(e) {
|
||||
e.preventDefault();
|
||||
$(this).attr("disabled", true);
|
||||
chrome.extension.sendMessage({
|
||||
action: "check_update_keepassxc"
|
||||
}, options.showKeePassXCVersions);
|
||||
});
|
||||
|
||||
$("#showDangerousSettings").click(function() {
|
||||
$('#dangerousSettings').is(":visible") ? $(this).text("Show these settings anyway") : $(this).text("Hide");
|
||||
$("#dangerousSettings").toggle();
|
||||
});
|
||||
|
||||
$("#hostname").val(options.settings["hostname"]);
|
||||
$("#port").val(options.settings["port"]);
|
||||
$("#blinkTimeout").val(options.settings["blinkTimeout"]);
|
||||
$("#blinkMinTimeout").val(options.settings["blinkMinTimeout"]);
|
||||
$("#allowedRedirect").val(options.settings["allowedRedirect"]);
|
||||
|
||||
$("#portButton").click(function() {
|
||||
var port = $.trim($("#port").val());
|
||||
var portNumber = parseInt(port);
|
||||
if(isNaN(port) || portNumber < 1025 || portNumber > 99999) {
|
||||
$("#port").closest(".control-group").addClass("error");
|
||||
alert("The port number has to be in range 1025 - 99999.\nNothing saved!");
|
||||
return;
|
||||
}
|
||||
|
||||
options.settings["port"] = portNumber.toString();
|
||||
$("#port").closest(".control-group").removeClass("error").addClass("success");
|
||||
setTimeout(function() {$("#port").closest(".control-group").removeClass("success")}, 2500);
|
||||
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
});
|
||||
|
||||
$("#hostnameButton").click(function() {
|
||||
var hostname = $("#hostname").val();
|
||||
if($.trim(hostname) == "") {
|
||||
$("#hostname").closest(".control-group").addClass("error");
|
||||
alert("Hostname cannot be empty.\nNothing saved!");
|
||||
return;
|
||||
}
|
||||
|
||||
options.settings["hostname"] = hostname;
|
||||
$("#hostname").closest(".control-group").removeClass("error").addClass("success");
|
||||
setTimeout(function() {$("#hostname").closest(".control-group").removeClass("success")}, 2500);
|
||||
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
});
|
||||
|
||||
$("#blinkTimeoutButton").click(function(){
|
||||
var blinkTimeout = $.trim($("#blinkTimeout").val());
|
||||
var blinkTimeoutval = parseInt(blinkTimeout);
|
||||
|
||||
options.settings["blinkTimeout"] = blinkTimeoutval.toString();
|
||||
$("#blinkTimeout").closest(".control-group").removeClass("error").addClass("success");
|
||||
setTimeout(function() {$("#blinkTimeout").closest(".control-group").removeClass("success")}, 2500);
|
||||
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
});
|
||||
|
||||
$("#blinkMinTimeoutButton").click(function(){
|
||||
var blinkMinTimeout = $.trim($("#blinkMinTimeout").val());
|
||||
var blinkMinTimeoutval = parseInt(blinkMinTimeout);
|
||||
|
||||
options.settings["blinkMinTimeout"] = blinkMinTimeoutval.toString();
|
||||
$("#blinkMinTimeout").closest(".control-group").removeClass("error").addClass("success");
|
||||
setTimeout(function() {$("#blinkMinTimeout").closest(".control-group").removeClass("success")}, 2500);
|
||||
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
});
|
||||
|
||||
$("#allowedRedirectButton").click(function(){
|
||||
var allowedRedirect = $.trim($("#allowedRedirect").val());
|
||||
var allowedRedirectval = parseInt(allowedRedirect);
|
||||
|
||||
options.settings["allowedRedirect"] = allowedRedirectval.toString();
|
||||
$("#allowedRedirect").closest(".control-group").removeClass("error").addClass("success");
|
||||
setTimeout(function() {$("#allowedRedirect").closest(".control-group").removeClass("success")}, 2500);
|
||||
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
options.showKeePassXCVersions = function(response) {
|
||||
if(response.current <= 0) {
|
||||
response.current = "unknown";
|
||||
}
|
||||
if(response.latest <= 0) {
|
||||
response.latest = "unknown";
|
||||
}
|
||||
$("#tab-general-settings .kphVersion:first em.yourVersion:first").text(response.current);
|
||||
$("#tab-general-settings .kphVersion:first em.latestVersion:first").text(response.latest);
|
||||
|
||||
$("#tab-about em.versionKPH").text(response.current);
|
||||
|
||||
$("#tab-general-settings button.checkUpdateKeePassXC:first").attr("disabled", false);
|
||||
}
|
||||
|
||||
options.initConnectedDatabases = function() {
|
||||
$("#dialogDeleteConnectedDatabase").modal({keyboard: true, show: false, backdrop: true});
|
||||
$("#tab-connected-databases tr.clone:first button.delete:first").click(function(e) {
|
||||
e.preventDefault();
|
||||
$("#dialogDeleteConnectedDatabase").data("hash", $(this).closest("tr").data("hash"));
|
||||
$("#dialogDeleteConnectedDatabase .modal-body:first span:first").text($(this).closest("tr").children("td:first").text());
|
||||
$("#dialogDeleteConnectedDatabase").modal("show");
|
||||
});
|
||||
|
||||
$("#dialogDeleteConnectedDatabase .modal-footer:first button.yes:first").click(function(e) {
|
||||
$("#dialogDeleteConnectedDatabase").modal("hide");
|
||||
|
||||
var $hash = $("#dialogDeleteConnectedDatabase").data("hash");
|
||||
$("#tab-connected-databases #tr-cd-" + $hash).remove();
|
||||
|
||||
delete options.keyRing[$hash];
|
||||
localStorage.keyRing = JSON.stringify(options.keyRing);
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'load_keyring'
|
||||
});
|
||||
|
||||
if($("#tab-connected-databases table tbody:first tr").length > 2) {
|
||||
$("#tab-connected-databases table tbody:first tr.empty:first").hide();
|
||||
}
|
||||
else {
|
||||
$("#tab-connected-databases table tbody:first tr.empty:first").show();
|
||||
}
|
||||
});
|
||||
|
||||
$("#tab-connected-databases tr.clone:first .dropdown-menu:first").width("230px");
|
||||
|
||||
$("#tab-connected-databases tr.clone:first .color.dropdown .dropdown-menu a").click(function(e) {
|
||||
e.preventDefault();
|
||||
var $icon = $(this).attr("href").substring(1);
|
||||
var $hash = $(this).closest("tr").data("hash");
|
||||
|
||||
$(this).parent().parent().find("a.dropdown-toggle:first").find("img:first").attr("src", "/icons/19x19/icon_normal_" + $icon + "_19x19.png");
|
||||
|
||||
options.keyRing[$hash].icon = $icon;
|
||||
localStorage.keyRing = JSON.stringify(options.keyRing);
|
||||
chrome.extension.sendMessage({
|
||||
action: 'load_keyring'
|
||||
});
|
||||
});
|
||||
|
||||
var $trClone = $("#tab-connected-databases table tr.clone:first").clone(true);
|
||||
$trClone.removeClass("clone");
|
||||
for(var hash in options.keyRing) {
|
||||
var $tr = $trClone.clone(true);
|
||||
$tr.data("hash", hash);
|
||||
$tr.attr("id", "tr-cd-" + hash);
|
||||
|
||||
var $icon = options.keyRing[hash].icon || "blue";
|
||||
$("a.dropdown-toggle:first img:first", $tr).attr("src", "/icons/19x19/icon_normal_" + $icon + "_19x19.png");
|
||||
|
||||
$tr.children("td:first").text(options.keyRing[hash].id);
|
||||
var lastUsed = (options.keyRing[hash].lastUsed) ? new Date(options.keyRing[hash].lastUsed).toLocaleString() : "unknown";
|
||||
$tr.children("td:eq(2)").text(lastUsed);
|
||||
var date = (options.keyRing[hash].created) ? new Date(options.keyRing[hash].created).toLocaleDateString() : "unknown";
|
||||
$tr.children("td:eq(3)").text(date);
|
||||
$("#tab-connected-databases table tbody:first").append($tr);
|
||||
}
|
||||
|
||||
if($("#tab-connected-databases table tbody:first tr").length > 2) {
|
||||
$("#tab-connected-databases table tbody:first tr.empty:first").hide();
|
||||
}
|
||||
else {
|
||||
$("#tab-connected-databases table tbody:first tr.empty:first").show();
|
||||
}
|
||||
$("#connect-button").click(function() {
|
||||
chrome.extension.sendMessage({
|
||||
action: "associate"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
options.initSpecifiedCredentialFields = function() {
|
||||
$("#dialogDeleteSpecifiedCredentialFields").modal({keyboard: true, show: false, backdrop: true});
|
||||
$("#tab-specified-fields tr.clone:first button.delete:first").click(function(e) {
|
||||
e.preventDefault();
|
||||
$("#dialogDeleteSpecifiedCredentialFields").data("url", $(this).closest("tr").data("url"));
|
||||
$("#dialogDeleteSpecifiedCredentialFields").data("tr-id", $(this).closest("tr").attr("id"));
|
||||
$("#dialogDeleteSpecifiedCredentialFields .modal-body:first strong:first").text($(this).closest("tr").children("td:first").text());
|
||||
$("#dialogDeleteSpecifiedCredentialFields").modal("show");
|
||||
});
|
||||
|
||||
$("#dialogDeleteSpecifiedCredentialFields .modal-footer:first button.yes:first").click(function(e) {
|
||||
$("#dialogDeleteSpecifiedCredentialFields").modal("hide");
|
||||
|
||||
var $url = $("#dialogDeleteSpecifiedCredentialFields").data("url");
|
||||
var $trId = $("#dialogDeleteSpecifiedCredentialFields").data("tr-id");
|
||||
$("#tab-specified-fields #" + $trId).remove();
|
||||
|
||||
delete options.settings["defined-credential-fields"][$url];
|
||||
localStorage.settings = JSON.stringify(options.settings);
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
|
||||
if($("#tab-specified-fields table tbody:first tr").length > 2) {
|
||||
$("#tab-specified-fields table tbody:first tr.empty:first").hide();
|
||||
}
|
||||
else {
|
||||
$("#tab-specified-fields table tbody:first tr.empty:first").show();
|
||||
}
|
||||
});
|
||||
|
||||
var $trClone = $("#tab-specified-fields table tr.clone:first").clone(true);
|
||||
$trClone.removeClass("clone");
|
||||
var counter = 1;
|
||||
for(var url in options.settings["defined-credential-fields"]) {
|
||||
var $tr = $trClone.clone(true);
|
||||
$tr.data("url", url);
|
||||
$tr.attr("id", "tr-scf" + counter);
|
||||
counter += 1;
|
||||
|
||||
$tr.children("td:first").text(url);
|
||||
$("#tab-specified-fields table tbody:first").append($tr);
|
||||
}
|
||||
|
||||
if($("#tab-specified-fields table tbody:first tr").length > 2) {
|
||||
$("#tab-specified-fields table tbody:first tr.empty:first").hide();
|
||||
}
|
||||
else {
|
||||
$("#tab-specified-fields table tbody:first tr.empty:first").show();
|
||||
}
|
||||
}
|
||||
|
||||
options.initAbout = function() {
|
||||
$("#tab-about em.versionCIP").text(chrome.app.getDetails().version);
|
||||
}
|
||||
74
chromeKeePassXC/popups/popup.css
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
body {
|
||||
font-family: sans-serif;
|
||||
min-width:357px;
|
||||
overflow-x:hidden;
|
||||
background: #eee;
|
||||
font-size: 15px;
|
||||
}
|
||||
.credentials ul {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
list-style-position: inside;
|
||||
}
|
||||
.credentials li {
|
||||
list-style: none;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
padding-left: 10px;
|
||||
padding-right: 5px;
|
||||
margin-left: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.credentials a {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
color: #336;
|
||||
}
|
||||
.credentials li:hover {
|
||||
cursor: pointer;
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
.settings {
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-bottom: 1px solid #333;
|
||||
font-size: 90%;
|
||||
}
|
||||
.settings label {
|
||||
display: block;
|
||||
}
|
||||
.settings label input {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.settings .description {
|
||||
margin-top: 3px;
|
||||
font-size: 80%;
|
||||
color: #787878;
|
||||
}
|
||||
.small {
|
||||
margin-top: 3px;
|
||||
margin-left: 12px;
|
||||
font-size: 80%;
|
||||
color: #787878;
|
||||
}
|
||||
#update-available {
|
||||
display: none;
|
||||
font-size: 90%;
|
||||
color: #cc0000;
|
||||
font-weight: bold;
|
||||
border-top: 1px solid #333;
|
||||
padding-top: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
#update-available a:link,
|
||||
#update-available a:visited {
|
||||
text-decoration: underline;
|
||||
color: #cc0000;
|
||||
}
|
||||
#update-available a:hover,
|
||||
#update-available a:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
81
chromeKeePassXC/popups/popup.html
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>KeePassXC - Popup</title>
|
||||
<link rel="stylesheet" href="popup.css" />
|
||||
<link rel="stylesheet" href="../bootstrap-btn.css" />
|
||||
<script type="text/javascript" src="../jquery-1.11.1.min.js"></script>
|
||||
<!--<script type="text/javascript" src="../jquery-3.2.0.min.js">-->
|
||||
<script type="text/javascript" src="popup_functions.js"></script>
|
||||
<script type="text/javascript" src="popup.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="settings" class="settings">
|
||||
<button id="btn-options" class="b2c-btn b2c-btn-small b2c-btn-warning">Settings</button>
|
||||
<button id="btn-choose-credential-fields" class="b2c-btn b2c-btn-small">Choose own credential fields for this page</button>
|
||||
|
||||
<div id="update-available">
|
||||
You use an old version of KeePassXC.
|
||||
<br />
|
||||
<a target="_blank" href="https://keepassxc.org/download">Please download the latest version from keepassxc.org</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="initial-state">
|
||||
<p><img style="margin-right: 1em" src="throbber.gif"/> Checking status...</p>
|
||||
</div>
|
||||
|
||||
<div id="not-configured" style="display: none">
|
||||
<p>
|
||||
chromeKeePassXC has not been configured.
|
||||
Press the connect button to register and pair with KeePassXC.
|
||||
</p>
|
||||
<div style="text-align: right">
|
||||
<button id="connect-button" class="b2c-btn b2c-btn-primary">Connect</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="need-reconfigure" style="display: none">
|
||||
<p>
|
||||
chromeKeePassXC has been disconnected from KeePassXC.
|
||||
</p>
|
||||
<code id="need-reconfigure-message"></code>
|
||||
<p>
|
||||
Press the reconnect button to establish a new connection.
|
||||
</p>
|
||||
<div style="text-align: right">
|
||||
<button id="reconnect-button" class="b2c-btn b2c-btn-primary">Reconnect</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="configured-not-associated" style="display: none">
|
||||
<p>
|
||||
chromeKeePassXC has been configured using the identifier
|
||||
<em id="unassociated-identifier"></em> and has not yet
|
||||
connected to KeePassXC.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="configured-and-associated" style="display: none">
|
||||
<p>
|
||||
chromeKeePassXC has been configured using the identifier
|
||||
"<em id="associated-identifier"></em>" and is successfully
|
||||
connected to KeePassXC.
|
||||
</p>
|
||||
<div style="text-align: right">
|
||||
<button id="redetect-fields-button" class="b2c-btn">Redetect credential fields</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="error-encountered" style="display: none">
|
||||
<p>
|
||||
chromeKeePassXC has encountered an error:
|
||||
</p>
|
||||
<p style="margin-left: 1em">
|
||||
<code id="error-message"></code>
|
||||
</p>
|
||||
<div style="text-align: right">
|
||||
<button id="reload-status-button" class="b2c-btn">Reload</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
73
chromeKeePassXC/popups/popup.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
function status_response(r) {
|
||||
$('#initial-state').hide();
|
||||
$('#error-encountered').hide();
|
||||
$('#need-reconfigure').hide();
|
||||
$('#not-configured').hide();
|
||||
$('#configured-and-associated').hide();
|
||||
$('#configured-not-associated').hide();
|
||||
|
||||
|
||||
if(!r.keePassXCAvailable || r.databaseClosed) {
|
||||
$('#error-message').html(r.error);
|
||||
$('#error-encountered').show();
|
||||
}
|
||||
else if(!r.configured) {
|
||||
$('#not-configured').show();
|
||||
}
|
||||
else if(r.encryptionKeyUnrecognized) {
|
||||
$('#need-reconfigure').show();
|
||||
$('#need-reconfigure-message').html(r.error);
|
||||
}
|
||||
else if(!r.associated) {
|
||||
//$('#configured-not-associated').show();
|
||||
//$('#unassociated-identifier').html(r.identifier);
|
||||
$('#need-reconfigure').show();
|
||||
$('#need-reconfigure-message').html(r.error);
|
||||
}
|
||||
else if(typeof(r.error) != "undefined") {
|
||||
$('#error-encountered').show();
|
||||
$('#error-message').html(r.error);
|
||||
}
|
||||
else {
|
||||
$('#configured-and-associated').show();
|
||||
$('#associated-identifier').html(r.identifier);
|
||||
}
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$("#connect-button").click(function() {
|
||||
chrome.extension.sendMessage({
|
||||
action: "associate"
|
||||
});
|
||||
close();
|
||||
});
|
||||
|
||||
$("#reconnect-button").click(function() {
|
||||
chrome.extension.sendMessage({
|
||||
action: "associate"
|
||||
});
|
||||
close();
|
||||
});
|
||||
|
||||
$("#reload-status-button").click(function() {
|
||||
chrome.extension.sendMessage({
|
||||
action: "get_status"
|
||||
}, status_response);
|
||||
});
|
||||
|
||||
$("#redetect-fields-button").click(function() {
|
||||
chrome.tabs.query({"active": true, "windowId": chrome.windows.WINDOW_ID_CURRENT}, function(tabs) {
|
||||
if (tabs.length === 0)
|
||||
return; // For example: only the background devtools or a popup are opened
|
||||
var tab = tabs[0];
|
||||
|
||||
chrome.tabs.sendMessage(tab.id, {
|
||||
action: "redetect_fields"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: "get_status"
|
||||
}, status_response);
|
||||
});
|
||||
38
chromeKeePassXC/popups/popup_functions.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
var $ = cIPJQ.noConflict(true);
|
||||
var _settings = typeof(localStorage.settings)=='undefined' ? {} : JSON.parse(localStorage.settings);
|
||||
//var global = chrome.extension.getBackgroundPage();
|
||||
|
||||
function updateAvailableResponse(available) {
|
||||
if(available) {
|
||||
$("#update-available").show();
|
||||
}
|
||||
else {
|
||||
$("#update-available").hide();
|
||||
}
|
||||
}
|
||||
|
||||
function initSettings() {
|
||||
$("#settings #btn-options").click(function() {
|
||||
close();
|
||||
chrome.tabs.create({
|
||||
url: "../options/options.html"
|
||||
})
|
||||
});
|
||||
|
||||
$("#settings #btn-choose-credential-fields").click(function() {
|
||||
var global = chrome.extension.getBackgroundPage();
|
||||
chrome.tabs.sendMessage(global.page.currentTabId, {
|
||||
action: "choose_credential_fields"
|
||||
});
|
||||
close();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$(function() {
|
||||
initSettings();
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: "update_available_keepassxc"
|
||||
}, updateAvailableResponse);
|
||||
});
|
||||
29
chromeKeePassXC/popups/popup_httpauth.html
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>KeePassXC - Popup</title>
|
||||
<link rel="stylesheet" href="popup.css" />
|
||||
<link rel="stylesheet" href="../bootstrap-btn.css" />
|
||||
<script type="text/javascript" src="../jquery-1.11.1.min.js"></script>
|
||||
<script type="text/javascript" src="popup_functions.js"></script>
|
||||
<script type="text/javascript" src="popup_httpauth.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="settings" class="settings">
|
||||
<button id="btn-options" class="b2c-btn b2c-btn-small b2c-btn-warning">Settings</button>
|
||||
<button id="btn-choose-credential-fields" class="b2c-btn b2c-btn-small">Choose own credential fields for this page</button>
|
||||
|
||||
<div id="update-available">
|
||||
You use an old version of KeePassXC.
|
||||
<br />
|
||||
<a target="_blank" href="https://keepassxc.org/download">Please download the latest version from keepassxc.org</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="credentials">
|
||||
<p>
|
||||
Select the login information you would like to get logged in with:
|
||||
</p>
|
||||
<ul id="login-list"></ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
21
chromeKeePassXC/popups/popup_httpauth.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
$(function() {
|
||||
var global = chrome.extension.getBackgroundPage();
|
||||
|
||||
chrome.tabs.getSelected(null, function(tab) {
|
||||
//var data = global.tab_httpauth_list["tab" + tab.id];
|
||||
var data = global.page.tabs[tab.id].loginList;
|
||||
var ul = document.getElementById("login-list");
|
||||
for (var i = 0; i < data.logins.length; i++) {
|
||||
var li = document.createElement("li");
|
||||
var a = document.createElement("a");
|
||||
a.textContent = data.logins[i].Login + " (" + data.logins[i].Name + ")";
|
||||
li.appendChild(a);
|
||||
$(a).data("url", data.url.replace(/:\/\//g, "://" + data.logins[i].Login + ":" + data.logins[i].Password + "@"));
|
||||
$(a).click(function() {
|
||||
chrome.tabs.update(tab.id, {"url": $(this).data("url")});
|
||||
close();
|
||||
});
|
||||
ul.appendChild(li);
|
||||
}
|
||||
});
|
||||
});
|
||||
29
chromeKeePassXC/popups/popup_login.html
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>KeePassXC - Popup</title>
|
||||
<link rel="stylesheet" href="popup.css" />
|
||||
<link rel="stylesheet" href="../bootstrap-btn.css" />
|
||||
<script type="text/javascript" src="../jquery-1.11.1.min.js"></script>
|
||||
<script type="text/javascript" src="popup_functions.js"></script>
|
||||
<script type="text/javascript" src="popup_login.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="settings" class="settings">
|
||||
<button id="btn-options" class="b2c-btn b2c-btn-small b2c-btn-warning">Settings</button>
|
||||
<button id="btn-choose-credential-fields" class="b2c-btn b2c-btn-small">Choose own credential fields for this page</button>
|
||||
|
||||
<div id="update-available">
|
||||
You use an old version of KeePassXC.
|
||||
<br />
|
||||
<a target="_blank" href="https://keepassxc.org/download">Please download the latest version from keepassxc.org</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="credentials">
|
||||
<p>
|
||||
Select the login information you would like to get entered into the page:
|
||||
</p>
|
||||
<ul id="login-list"></ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
28
chromeKeePassXC/popups/popup_login.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
$(function() {
|
||||
var global = chrome.extension.getBackgroundPage();
|
||||
|
||||
chrome.tabs.query({"active": true, "windowId": chrome.windows.WINDOW_ID_CURRENT}, function(tabs) {
|
||||
if (tabs.length === 0)
|
||||
return; // For example: only the background devtools or a popup are opened
|
||||
var tab = tabs[0];
|
||||
|
||||
var logins = global.page.tabs[tab.id].loginList;
|
||||
var ul = document.getElementById("login-list");
|
||||
for (var i = 0; i < logins.length; i++) {
|
||||
var li = document.createElement("li");
|
||||
var a = document.createElement("a");
|
||||
a.textContent = logins[i];
|
||||
li.appendChild(a);
|
||||
a.setAttribute("id", "" + i);
|
||||
a.addEventListener('click', function(e) {
|
||||
var id = e.target.id;
|
||||
chrome.tabs.sendMessage(tab.id, {
|
||||
action: 'fill_user_pass_with_specific_login',
|
||||
id: id
|
||||
});
|
||||
close();
|
||||
});
|
||||
ul.appendChild(li);
|
||||
}
|
||||
});
|
||||
});
|
||||
29
chromeKeePassXC/popups/popup_multiple-fields.html
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>KeePassXC - Popup</title>
|
||||
<link rel="stylesheet" href="popup.css" />
|
||||
<link rel="stylesheet" href="../bootstrap-btn.css" />
|
||||
<script type="text/javascript" src="../jquery-1.11.1.min.js"></script>
|
||||
<script type="text/javascript" src="popup_functions.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="settings" class="settings">
|
||||
<button id="btn-options" class="b2c-btn b2c-btn-small b2c-btn-warning">Settings</button>
|
||||
<button id="btn-choose-credential-fields" class="b2c-btn b2c-btn-small">Choose own credential fields for this page</button>
|
||||
|
||||
<div id="update-available">
|
||||
You use an old version of KeePassXC.
|
||||
<br />
|
||||
<a target="_blank" href="https://keepassxc.org/download">Please download the latest version from keepassxc.org</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p>
|
||||
chromeKeePassXC found more than one password field on this page. To enter your
|
||||
logins, right-click on one of the password fields, and choose either the
|
||||
"<code>Fill User + Pass</code>" or "<code>Fill Pass Only</code>" command.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
47
chromeKeePassXC/popups/popup_remember.html
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>KeePassXC - Popup</title>
|
||||
<link rel="stylesheet" href="popup.css" />
|
||||
<link rel="stylesheet" href="../bootstrap-btn.css" />
|
||||
<script type="text/javascript" src="../jquery-1.11.1.min.js"></script>
|
||||
<script type="text/javascript" src="popup_functions.js"></script>
|
||||
<script type="text/javascript" src="popup_remember.js"></script>
|
||||
<style type="text/css">
|
||||
.credentials {display: none; border-top: 1px solid #333;}
|
||||
.connected-database {display: none; font-size: 85%; color: #787878;}
|
||||
.credentials .username-new {display: none;}
|
||||
.credentials .username-exists {display: none;}
|
||||
.small { font-weight: bold; }
|
||||
.small .normal { font-weight: normal; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="buttons">
|
||||
<p>
|
||||
Username or password changed! Save it?
|
||||
<br />
|
||||
<span class="small information-url">Url: <span class="normal"></span></span>
|
||||
<br />
|
||||
<span class="small information-username">Username: <span class="normal"></span></span>
|
||||
</p>
|
||||
<p>
|
||||
<button id="btn-new" class="b2c-btn b2c-btn-success">New</button>
|
||||
<button id="btn-update" class="b2c-btn b2c-btn-warning">Update</button>
|
||||
<button id="btn-dismiss" class="b2c-btn b2c-btn-danger">Dismiss</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="connected-database">
|
||||
<p>Credentials will be saved in connected database with identifier <em></em>.</p>
|
||||
</div>
|
||||
|
||||
<div class="credentials">
|
||||
<p class="username-new">The used username <strong></strong> is currently not saved!</p>
|
||||
<p class="username-exists">The credentials with the used username <strong></strong> are marked bold.</p>
|
||||
<p>
|
||||
Please choose the credentials you want to update:
|
||||
</p>
|
||||
<ul id="list"></ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
124
chromeKeePassXC/popups/popup_remember.js
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
var _tab;
|
||||
|
||||
function _initialize(tab) {
|
||||
_tab = tab;
|
||||
|
||||
// no credentials set or credentials already cleared
|
||||
if(!_tab.credentials.username) {
|
||||
_close();
|
||||
return;
|
||||
}
|
||||
|
||||
// no existing credentials to update --> disable update-button
|
||||
if(_tab.credentials.list.length == 0) {
|
||||
$("#btn-update").attr("disabled", true).removeClass("b2c-btn-warning");
|
||||
}
|
||||
|
||||
var url = _tab.credentials.url;
|
||||
url = (url.length > 50) ? url.substring(0, 50) + "..." : url;
|
||||
$(".information-url:first span:first").text(url);
|
||||
$(".information-username:first span:first").text(_tab.credentials.username);
|
||||
|
||||
$("#btn-new").click(function(e) {
|
||||
chrome.extension.sendMessage({
|
||||
action: 'add_credentials',
|
||||
args: [_tab.credentials.username, _tab.credentials.password, _tab.credentials.url]
|
||||
}, _verifyResult);
|
||||
});
|
||||
|
||||
$("#btn-update").click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// only one entry which could be updated
|
||||
if(_tab.credentials.list.length == 1) {
|
||||
chrome.extension.sendMessage({
|
||||
action: 'update_credentials',
|
||||
args: [_tab.credentials.list[0].Uuid, _tab.credentials.username, _tab.credentials.password, _tab.credentials.url]
|
||||
}, _verifyResult);
|
||||
}
|
||||
else {
|
||||
$(".credentials:first .username-new:first strong:first").text(_tab.credentials.username);
|
||||
$(".credentials:first .username-exists:first strong:first").text(_tab.credentials.username);
|
||||
|
||||
if(_tab.credentials.usernameExists) {
|
||||
$(".credentials:first .username-new:first").hide();
|
||||
$(".credentials:first .username-exists:first").show();
|
||||
}
|
||||
else {
|
||||
$(".credentials:first .username-new:first").show();
|
||||
$(".credentials:first .username-exists:first").hide();
|
||||
}
|
||||
|
||||
for(var i = 0; i < _tab.credentials.list.length; i++) {
|
||||
var $a = $("<a>")
|
||||
.attr("href", "#")
|
||||
.text(_tab.credentials.list[i].Login + " (" + _tab.credentials.list[i].Name + ")")
|
||||
.data("entryId", i)
|
||||
.click(function(e) {
|
||||
e.preventDefault();
|
||||
chrome.extension.sendMessage({
|
||||
action: 'update_credentials',
|
||||
args: [_tab.credentials.list[$(this).data("entryId")].Uuid, _tab.credentials.username, _tab.credentials.password, _tab.credentials.url]
|
||||
}, _verifyResult);
|
||||
});
|
||||
|
||||
if(_tab.credentials.usernameExists && _tab.credentials.username == _tab.credentials.list[i].Login) {
|
||||
$a.css("font-weight", "bold");
|
||||
}
|
||||
|
||||
var $li = $("<li>").append($a);
|
||||
$("ul#list").append($li);
|
||||
}
|
||||
|
||||
$(".credentials").show();
|
||||
}
|
||||
});
|
||||
|
||||
$("#btn-dismiss").click(function(e) {
|
||||
e.preventDefault();
|
||||
_close();
|
||||
});
|
||||
}
|
||||
|
||||
function _connected_database(db) {
|
||||
if(db.count > 1 && db.identifier) {
|
||||
$(".connected-database:first em:first").text(db.identifier);
|
||||
$(".connected-database:first").show();
|
||||
}
|
||||
else {
|
||||
$(".connected-database:first").hide();
|
||||
}
|
||||
}
|
||||
|
||||
function _verifyResult(code) {
|
||||
if(code == "success") {
|
||||
_close();
|
||||
}
|
||||
}
|
||||
|
||||
function _close() {
|
||||
chrome.extension.sendMessage({
|
||||
action: 'remove_credentials_from_tab_information'
|
||||
});
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'pop_stack'
|
||||
});
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
$(function() {
|
||||
chrome.extension.sendMessage({
|
||||
action: 'stack_add',
|
||||
args: ["icon_remember_red_background_19x19.png", "popup_remember.html", 10, true, 0]
|
||||
});
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'get_tab_information'
|
||||
}, _initialize);
|
||||
|
||||
chrome.extension.sendMessage({
|
||||
action: 'get_connected_database'
|
||||
}, _connected_database);
|
||||
});
|
||||
BIN
chromeKeePassXC/popups/throbber.gif
Normal file
|
After Width: | Height: | Size: 673 B |
9
com.varjolintu.chromekeepassxc.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "com.varjolintu.chromekeepassxc",
|
||||
"description": "KeepassXC integration with Chrome with Native Messaging support",
|
||||
"path": "<KeePassXC path here>",
|
||||
"type": "stdio",
|
||||
"allowed_origins": [
|
||||
"chrome-extension://ffojhfbafadajlgddbgadkbbchliloel/"
|
||||
]
|
||||
}
|
||||