Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
344771dbdf | ||
|
|
d38dba7272 | ||
|
|
409f005eec | ||
|
|
df7903e146 | ||
|
|
49edaef79d | ||
|
|
fcbed9ef01 | ||
|
|
3edb414d23 | ||
|
|
d779c21cc1 | ||
|
|
8d32bc56ae | ||
|
|
9d03ed06c3 | ||
|
|
ee290e5c14 | ||
|
|
789761b177 | ||
|
|
cd0876d58a | ||
|
|
bfae4da56c | ||
|
|
f342ed5940 | ||
|
|
c7373fee28 | ||
|
|
44b2955652 | ||
|
|
8a4af69008 | ||
|
|
6650382e19 | ||
|
|
a1f5e0ba1c | ||
|
|
035bb6b285 | ||
|
|
c0107fb90e | ||
|
|
138be9d14c | ||
|
|
61f474217b | ||
|
|
d31c5eed0a | ||
|
|
5060de689b | ||
|
|
b95424ddf3 | ||
|
|
e40a442a30 | ||
|
|
b5134a9faf | ||
|
|
a791d449ce | ||
|
|
43e1a9d539 | ||
|
|
e91f80d10e | ||
|
|
9db855c7fb | ||
|
|
2dc3636b26 | ||
|
|
4d9df012f6 | ||
|
|
ff9d0d75ef | ||
|
|
4e160b3b33 | ||
|
|
5048acc9f9 | ||
|
|
1841541bc4 | ||
|
|
11d9af3844 | ||
|
|
e30b618241 | ||
|
|
966327571d | ||
|
|
303d50c197 | ||
|
|
bcdfdec211 | ||
|
|
fb769d2ac5 | ||
|
|
f8043ae16d | ||
|
|
7150f2f5c5 | ||
|
|
81bd2e3065 | ||
|
|
78c9618807 | ||
|
|
bed8939b8a | ||
|
|
9443d93500 | ||
|
|
877eba66be | ||
|
|
3af8aba40c | ||
|
|
7ece02c73d | ||
|
|
ebbd2b3ac4 | ||
|
|
a85eff4277 | ||
|
|
98f1c776be | ||
|
|
6b554c67ed | ||
|
|
f2ae35080d | ||
|
|
0ff6c93a95 | ||
|
|
9147600b97 | ||
|
|
fafe56166e | ||
|
|
0a024b2594 | ||
|
|
b4c2a393f1 | ||
|
|
39dcef46d2 | ||
|
|
d6a88583f5 | ||
|
|
1c17b84dcf | ||
|
|
cecaf1b5cc | ||
|
|
888338e107 | ||
|
|
32055abf29 | ||
|
|
0f72dffaf1 | ||
|
|
5d1be43b65 | ||
|
|
dc7089c38c | ||
|
|
34540f0844 | ||
|
|
e818713484 | ||
|
|
6e2289994c | ||
|
|
05a9ba46d0 | ||
|
|
70bb30ba0c | ||
|
|
444d7e9b35 | ||
|
|
47164c7a92 | ||
|
|
ad00ceb4ce | ||
|
|
473e3ca11f | ||
|
|
35c0431cec | ||
|
|
70c784db83 | ||
|
|
d448099a2d | ||
|
|
e3a7ea57e0 | ||
|
|
fa6133200e | ||
|
|
dfa67bdca9 | ||
|
|
8c9c4ef7b2 | ||
|
|
1adb18a7e7 | ||
|
|
f50fdb7777 | ||
|
|
33bf2c93d0 | ||
|
|
f2abcc9e43 | ||
|
|
5ef69aa045 | ||
|
|
1c0f274868 | ||
|
|
1f592f50a9 | ||
|
|
30fdb54e94 | ||
|
|
4f552be5a9 | ||
|
|
1439df9f9a | ||
|
|
e676a0e258 |
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -25,3 +25,9 @@
|
|||||||
[submodule "platform-darwin/External/libjson-c"]
|
[submodule "platform-darwin/External/libjson-c"]
|
||||||
path = platform-darwin/External/libjson-c
|
path = platform-darwin/External/libjson-c
|
||||||
url = https://github.com/lhunath/json-c.git
|
url = https://github.com/lhunath/json-c.git
|
||||||
|
[submodule "public/site"]
|
||||||
|
path = public/site
|
||||||
|
url = https://github.com/Lyndir/MasterPassword.git
|
||||||
|
branch = gh-pages
|
||||||
|
shallow = true
|
||||||
|
update = none
|
||||||
|
|||||||
12
.travis.yml
12
.travis.yml
@@ -1,10 +1,20 @@
|
|||||||
language: objective-c
|
language: objective-c
|
||||||
osx_image: xcode8.3
|
os: osx
|
||||||
|
osx_image: xcode9.2
|
||||||
env: TERM=dumb SHLVL=0
|
env: TERM=dumb SHLVL=0
|
||||||
git:
|
git:
|
||||||
submodules: true
|
submodules: true
|
||||||
script:
|
script:
|
||||||
- "( brew install libsodium json-c )"
|
- "( brew install libsodium json-c )"
|
||||||
- "( cd ./platform-independent/cli-c && ./clean && targets='mpw mpw-bench mpw-tests' ./build && ./mpw-tests && ./mpw-cli-tests )"
|
- "( cd ./platform-independent/cli-c && ./clean && targets='mpw mpw-bench mpw-tests' ./build && ./mpw-tests && ./mpw-cli-tests )"
|
||||||
|
- "( cd ./gradle && ./gradlew --info clean test )"
|
||||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword iOS' -sdk iphonesimulator )"
|
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword iOS' -sdk iphonesimulator )"
|
||||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword macOS' )"
|
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword macOS' )"
|
||||||
|
notifications:
|
||||||
|
webhooks:
|
||||||
|
urls:
|
||||||
|
- "https://scalar.vector.im/api/neb/services/hooks/dHJhdmlzLWNpLyU0MGxodW5hdGglM0FseW5kaXIuY29tLyUyMWR2S1JpaW1uc0Z3dWdseEpHSyUzQWx5bmRpci5jb20"
|
||||||
|
on_success: change # always|never|change
|
||||||
|
on_failure: always
|
||||||
|
on_start: never
|
||||||
|
|
||||||
|
|||||||
606
core/c/aes.c
Normal file
606
core/c/aes.c
Normal file
@@ -0,0 +1,606 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Source: https://github.com/kokke/tiny-AES-c
|
||||||
|
|
||||||
|
This is an implementation of the AES algorithm, specifically ECB and CBC mode.
|
||||||
|
Block size can be chosen in aes.h - available choices are AES128, AES192, AES256.
|
||||||
|
|
||||||
|
The implementation is verified against the test vectors in:
|
||||||
|
National Institute of Standards and Technology Special Publication 800-38A 2001 ED
|
||||||
|
|
||||||
|
ECB-AES128
|
||||||
|
----------
|
||||||
|
|
||||||
|
plain-text:
|
||||||
|
6bc1bee22e409f96e93d7e117393172a
|
||||||
|
ae2d8a571e03ac9c9eb76fac45af8e51
|
||||||
|
30c81c46a35ce411e5fbc1191a0a52ef
|
||||||
|
f69f2445df4f9b17ad2b417be66c3710
|
||||||
|
|
||||||
|
key:
|
||||||
|
2b7e151628aed2a6abf7158809cf4f3c
|
||||||
|
|
||||||
|
resulting cipher
|
||||||
|
3ad77bb40d7a3660a89ecaf32466ef97
|
||||||
|
f5d3d58503b9699de785895a96fdbaaf
|
||||||
|
43b1cd7f598ece23881b00e3ed030688
|
||||||
|
7b0c785e27e8ad3f8223207104725dd4
|
||||||
|
|
||||||
|
|
||||||
|
NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
|
||||||
|
You should pad the end of the string with zeros if this is not the case.
|
||||||
|
For AES192/256 the block size is proportionally larger.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Includes: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include "aes.h"
|
||||||
|
#include "mpw-util.h"
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Defines: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
// The number of columns comprising a state in AES. This is a constant in AES. Value=4
|
||||||
|
#define Nb 4
|
||||||
|
|
||||||
|
#if defined(AES_256) && (AES_256 == 1)
|
||||||
|
#define Nk 8
|
||||||
|
#define KEYLEN 32
|
||||||
|
#define Nr 14
|
||||||
|
#define keyExpSize 240
|
||||||
|
#elif defined(AES_192) && (AES_192 == 1)
|
||||||
|
#define Nk 6
|
||||||
|
#define KEYLEN 24
|
||||||
|
#define Nr 12
|
||||||
|
#define keyExpSize 208
|
||||||
|
#elif defined(AES_128) && (AES_128 == 1)
|
||||||
|
#define Nk 4 // The number of 32 bit words in a key.
|
||||||
|
#define KEYLEN 16 // Key length in bytes
|
||||||
|
#define Nr 10 // The number of rounds in AES Cipher.
|
||||||
|
#define keyExpSize 176
|
||||||
|
#else
|
||||||
|
#error Must define either AES_128, AES_192 or AES_256.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// jcallan@github points out that declaring Multiply as a function
|
||||||
|
// reduces code size considerably with the Keil ARM compiler.
|
||||||
|
// See this link for more information: https://github.com/kokke/tiny-AES128-C/pull/3
|
||||||
|
#ifndef MULTIPLY_AS_A_FUNCTION
|
||||||
|
#define MULTIPLY_AS_A_FUNCTION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Private variables: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
// state - array holding the intermediate results during decryption.
|
||||||
|
typedef uint8_t state_t[4][4];
|
||||||
|
static state_t* state;
|
||||||
|
|
||||||
|
// The array that stores the round keys.
|
||||||
|
static uint8_t RoundKey[keyExpSize];
|
||||||
|
|
||||||
|
// The Key input to the AES Program
|
||||||
|
static const uint8_t* Key;
|
||||||
|
|
||||||
|
#if defined(AES_CBC) && AES_CBC
|
||||||
|
// Initial Vector used only for CBC mode
|
||||||
|
static uint8_t* Iv;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
|
||||||
|
// The numbers below can be computed dynamically trading ROM for RAM -
|
||||||
|
// This can be useful in (embedded) bootloader applications, where ROM is often limited.
|
||||||
|
static const uint8_t sbox[256] = {
|
||||||
|
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
|
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 };
|
||||||
|
|
||||||
|
static const uint8_t rsbox[256] = {
|
||||||
|
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 };
|
||||||
|
|
||||||
|
// The round constant word array, Rcon[i], contains the values given by
|
||||||
|
// x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
|
||||||
|
static const uint8_t Rcon[11] = {
|
||||||
|
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES128-C/pull/12),
|
||||||
|
* that you can remove most of the elements in the Rcon array, because they are unused.
|
||||||
|
*
|
||||||
|
* From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon
|
||||||
|
*
|
||||||
|
* "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed),
|
||||||
|
* up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
|
||||||
|
*
|
||||||
|
* ... which is why the full array below has been 'disabled' below.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
static const uint8_t Rcon[256] = {
|
||||||
|
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, 0x8d };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Private functions: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
static uint8_t getSBoxValue(uint8_t num)
|
||||||
|
{
|
||||||
|
return sbox[num];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t getSBoxInvert(uint8_t num)
|
||||||
|
{
|
||||||
|
return rsbox[num];
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
|
||||||
|
static void KeyExpansion(void)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint8_t k, tempa[4]; // Used for the column/row operations
|
||||||
|
|
||||||
|
// The first round key is the key itself.
|
||||||
|
for (i = 0; i < Nk; ++i)
|
||||||
|
{
|
||||||
|
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
|
||||||
|
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
|
||||||
|
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
|
||||||
|
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other round keys are found from the previous round keys.
|
||||||
|
//i == Nk
|
||||||
|
for (; i < Nb * (Nr + 1); ++i)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tempa[0]=RoundKey[(i-1) * 4 + 0];
|
||||||
|
tempa[1]=RoundKey[(i-1) * 4 + 1];
|
||||||
|
tempa[2]=RoundKey[(i-1) * 4 + 2];
|
||||||
|
tempa[3]=RoundKey[(i-1) * 4 + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i % Nk == 0)
|
||||||
|
{
|
||||||
|
// This function shifts the 4 bytes in a word to the left once.
|
||||||
|
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
|
||||||
|
|
||||||
|
// Function RotWord()
|
||||||
|
{
|
||||||
|
k = tempa[0];
|
||||||
|
tempa[0] = tempa[1];
|
||||||
|
tempa[1] = tempa[2];
|
||||||
|
tempa[2] = tempa[3];
|
||||||
|
tempa[3] = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubWord() is a function that takes a four-byte input word and
|
||||||
|
// applies the S-box to each of the four bytes to produce an output word.
|
||||||
|
|
||||||
|
// Function Subword()
|
||||||
|
{
|
||||||
|
tempa[0] = getSBoxValue(tempa[0]);
|
||||||
|
tempa[1] = getSBoxValue(tempa[1]);
|
||||||
|
tempa[2] = getSBoxValue(tempa[2]);
|
||||||
|
tempa[3] = getSBoxValue(tempa[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempa[0] = tempa[0] ^ Rcon[i/Nk];
|
||||||
|
}
|
||||||
|
#if defined(AES256) && (AES256 == 1)
|
||||||
|
if (i % Nk == 4)
|
||||||
|
{
|
||||||
|
// Function Subword()
|
||||||
|
{
|
||||||
|
tempa[0] = getSBoxValue(tempa[0]);
|
||||||
|
tempa[1] = getSBoxValue(tempa[1]);
|
||||||
|
tempa[2] = getSBoxValue(tempa[2]);
|
||||||
|
tempa[3] = getSBoxValue(tempa[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
RoundKey[i * 4 + 0] = RoundKey[(i - Nk) * 4 + 0] ^ tempa[0];
|
||||||
|
RoundKey[i * 4 + 1] = RoundKey[(i - Nk) * 4 + 1] ^ tempa[1];
|
||||||
|
RoundKey[i * 4 + 2] = RoundKey[(i - Nk) * 4 + 2] ^ tempa[2];
|
||||||
|
RoundKey[i * 4 + 3] = RoundKey[(i - Nk) * 4 + 3] ^ tempa[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function adds the round key to state.
|
||||||
|
// The round key is added to the state by an XOR function.
|
||||||
|
static void AddRoundKey(uint8_t round)
|
||||||
|
{
|
||||||
|
uint8_t i,j;
|
||||||
|
for (i=0;i<4;++i)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 4; ++j)
|
||||||
|
{
|
||||||
|
(*state)[i][j] ^= RoundKey[round * Nb * 4 + i * Nb + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The SubBytes Function Substitutes the values in the
|
||||||
|
// state matrix with values in an S-box.
|
||||||
|
static void SubBytes(void)
|
||||||
|
{
|
||||||
|
uint8_t i, j;
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 4; ++j)
|
||||||
|
{
|
||||||
|
(*state)[j][i] = getSBoxValue((*state)[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ShiftRows() function shifts the rows in the state to the left.
|
||||||
|
// Each row is shifted with different offset.
|
||||||
|
// Offset = Row number. So the first row is not shifted.
|
||||||
|
static void ShiftRows(void)
|
||||||
|
{
|
||||||
|
uint8_t temp;
|
||||||
|
|
||||||
|
// Rotate first row 1 columns to left
|
||||||
|
temp = (*state)[0][1];
|
||||||
|
(*state)[0][1] = (*state)[1][1];
|
||||||
|
(*state)[1][1] = (*state)[2][1];
|
||||||
|
(*state)[2][1] = (*state)[3][1];
|
||||||
|
(*state)[3][1] = temp;
|
||||||
|
|
||||||
|
// Rotate second row 2 columns to left
|
||||||
|
temp = (*state)[0][2];
|
||||||
|
(*state)[0][2] = (*state)[2][2];
|
||||||
|
(*state)[2][2] = temp;
|
||||||
|
|
||||||
|
temp = (*state)[1][2];
|
||||||
|
(*state)[1][2] = (*state)[3][2];
|
||||||
|
(*state)[3][2] = temp;
|
||||||
|
|
||||||
|
// Rotate third row 3 columns to left
|
||||||
|
temp = (*state)[0][3];
|
||||||
|
(*state)[0][3] = (*state)[3][3];
|
||||||
|
(*state)[3][3] = (*state)[2][3];
|
||||||
|
(*state)[2][3] = (*state)[1][3];
|
||||||
|
(*state)[1][3] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t xtime(uint8_t x)
|
||||||
|
{
|
||||||
|
return (uint8_t)((x << 1) ^ (((x >> 7) & 1) * 0x1b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// MixColumns function mixes the columns of the state matrix
|
||||||
|
static void MixColumns(void)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t Tmp,Tm,t;
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
t = (*state)[i][0];
|
||||||
|
Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;
|
||||||
|
Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ;
|
||||||
|
Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ;
|
||||||
|
Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ;
|
||||||
|
Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply is used to multiply numbers in the field GF(2^8)
|
||||||
|
#if MULTIPLY_AS_A_FUNCTION
|
||||||
|
static uint8_t Multiply(uint8_t x, uint8_t y)
|
||||||
|
{
|
||||||
|
return (((y & 1) * x) ^
|
||||||
|
((y>>1 & 1) * xtime(x)) ^
|
||||||
|
((y>>2 & 1) * xtime(xtime(x))) ^
|
||||||
|
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^
|
||||||
|
((y>>4 & 1) * xtime(xtime(xtime(xtime(x))))));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define Multiply(x, y) (uint8_t) \
|
||||||
|
( ((y & 1) * x) ^ \
|
||||||
|
((y>>1 & 1) * xtime(x)) ^ \
|
||||||
|
((y>>2 & 1) * xtime(xtime(x))) ^ \
|
||||||
|
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \
|
||||||
|
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// MixColumns function mixes the columns of the state matrix.
|
||||||
|
// The method used to multiply may be difficult to understand for the inexperienced.
|
||||||
|
// Please use the references to gain more information.
|
||||||
|
static void InvMixColumns(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t a, b, c, d;
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
a = (*state)[i][0];
|
||||||
|
b = (*state)[i][1];
|
||||||
|
c = (*state)[i][2];
|
||||||
|
d = (*state)[i][3];
|
||||||
|
|
||||||
|
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
|
||||||
|
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
|
||||||
|
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
|
||||||
|
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The SubBytes Function Substitutes the values in the
|
||||||
|
// state matrix with values in an S-box.
|
||||||
|
static void InvSubBytes(void)
|
||||||
|
{
|
||||||
|
uint8_t i,j;
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 4; ++j)
|
||||||
|
{
|
||||||
|
(*state)[j][i] = getSBoxInvert((*state)[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InvShiftRows(void)
|
||||||
|
{
|
||||||
|
uint8_t temp;
|
||||||
|
|
||||||
|
// Rotate first row 1 columns to right
|
||||||
|
temp = (*state)[3][1];
|
||||||
|
(*state)[3][1] = (*state)[2][1];
|
||||||
|
(*state)[2][1] = (*state)[1][1];
|
||||||
|
(*state)[1][1] = (*state)[0][1];
|
||||||
|
(*state)[0][1] = temp;
|
||||||
|
|
||||||
|
// Rotate second row 2 columns to right
|
||||||
|
temp = (*state)[0][2];
|
||||||
|
(*state)[0][2] = (*state)[2][2];
|
||||||
|
(*state)[2][2] = temp;
|
||||||
|
|
||||||
|
temp = (*state)[1][2];
|
||||||
|
(*state)[1][2] = (*state)[3][2];
|
||||||
|
(*state)[3][2] = temp;
|
||||||
|
|
||||||
|
// Rotate third row 3 columns to right
|
||||||
|
temp = (*state)[0][3];
|
||||||
|
(*state)[0][3] = (*state)[1][3];
|
||||||
|
(*state)[1][3] = (*state)[2][3];
|
||||||
|
(*state)[2][3] = (*state)[3][3];
|
||||||
|
(*state)[3][3] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Cipher is the main function that encrypts the PlainText.
|
||||||
|
static void Cipher(void)
|
||||||
|
{
|
||||||
|
uint8_t round = 0;
|
||||||
|
|
||||||
|
// Add the First round key to the state before starting the rounds.
|
||||||
|
AddRoundKey(0);
|
||||||
|
|
||||||
|
// There will be Nr rounds.
|
||||||
|
// The first Nr-1 rounds are identical.
|
||||||
|
// These Nr-1 rounds are executed in the loop below.
|
||||||
|
for (round = 1; round < Nr; ++round)
|
||||||
|
{
|
||||||
|
SubBytes();
|
||||||
|
ShiftRows();
|
||||||
|
MixColumns();
|
||||||
|
AddRoundKey(round);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last round is given below.
|
||||||
|
// The MixColumns function is not here in the last round.
|
||||||
|
SubBytes();
|
||||||
|
ShiftRows();
|
||||||
|
AddRoundKey(Nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InvCipher(void)
|
||||||
|
{
|
||||||
|
uint8_t round=0;
|
||||||
|
|
||||||
|
// Add the First round key to the state before starting the rounds.
|
||||||
|
AddRoundKey(Nr);
|
||||||
|
|
||||||
|
// There will be Nr rounds.
|
||||||
|
// The first Nr-1 rounds are identical.
|
||||||
|
// These Nr-1 rounds are executed in the loop below.
|
||||||
|
for (round = (Nr - 1); round > 0; --round)
|
||||||
|
{
|
||||||
|
InvShiftRows();
|
||||||
|
InvSubBytes();
|
||||||
|
AddRoundKey(round);
|
||||||
|
InvMixColumns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last round is given below.
|
||||||
|
// The MixColumns function is not here in the last round.
|
||||||
|
InvShiftRows();
|
||||||
|
InvSubBytes();
|
||||||
|
AddRoundKey(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Public functions: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
#if defined(AES_ECB) && (AES_ECB == 1)
|
||||||
|
|
||||||
|
|
||||||
|
void AES_ECB_encrypt(uint8_t *output, const uint8_t *input, const uint32_t length, const uint8_t *key)
|
||||||
|
{
|
||||||
|
// Copy input to output, and work in-memory on output
|
||||||
|
memcpy(output, input, length);
|
||||||
|
state = (state_t*)output;
|
||||||
|
|
||||||
|
Key = key;
|
||||||
|
KeyExpansion();
|
||||||
|
|
||||||
|
// The next function call encrypts the PlainText with the Key using AES algorithm.
|
||||||
|
Cipher();
|
||||||
|
|
||||||
|
mpw_zero( RoundKey, keyExpSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_ECB_decrypt(uint8_t *output, const uint8_t *input, const uint32_t length, const uint8_t *key)
|
||||||
|
{
|
||||||
|
// Copy input to output, and work in-memory on output
|
||||||
|
memcpy(output, input, length);
|
||||||
|
state = (state_t*)output;
|
||||||
|
|
||||||
|
// The KeyExpansion routine must be called before encryption.
|
||||||
|
Key = key;
|
||||||
|
KeyExpansion();
|
||||||
|
|
||||||
|
InvCipher();
|
||||||
|
|
||||||
|
mpw_zero( RoundKey, keyExpSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #if defined(AES_ECB) && (AES_ECB == 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(AES_CBC) && (AES_CBC == 1)
|
||||||
|
|
||||||
|
|
||||||
|
static void XorWithIv(uint8_t* buf)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < AES_BLOCKLEN; ++i) //WAS for(i = 0; i < KEYLEN; ++i) but the block in AES is always 128bit so 16 bytes!
|
||||||
|
{
|
||||||
|
buf[i] ^= Iv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
|
||||||
|
{
|
||||||
|
uintptr_t i;
|
||||||
|
uint8_t extra = (uint8_t)(length % AES_BLOCKLEN); /* Remaining bytes in the last non-full block */
|
||||||
|
|
||||||
|
// Skip the key expansion if key is passed as 0
|
||||||
|
if (0 != key)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
KeyExpansion();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iv != 0)
|
||||||
|
{
|
||||||
|
Iv = (uint8_t*)iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < length; i += AES_BLOCKLEN)
|
||||||
|
{
|
||||||
|
XorWithIv(input);
|
||||||
|
memcpy(output, input, AES_BLOCKLEN);
|
||||||
|
state = (state_t*)output;
|
||||||
|
Cipher();
|
||||||
|
Iv = output;
|
||||||
|
input += AES_BLOCKLEN;
|
||||||
|
output += AES_BLOCKLEN;
|
||||||
|
//printf("Step %d - %d", i/16, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extra)
|
||||||
|
{
|
||||||
|
memcpy(output, input, extra);
|
||||||
|
state = (state_t*)output;
|
||||||
|
Cipher();
|
||||||
|
}
|
||||||
|
|
||||||
|
mpw_zero( RoundKey, keyExpSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
|
||||||
|
{
|
||||||
|
uintptr_t i;
|
||||||
|
uint8_t extra = (uint8_t)(length % AES_BLOCKLEN); /* Remaining bytes in the last non-full block */
|
||||||
|
|
||||||
|
// Skip the key expansion if key is passed as 0
|
||||||
|
if (0 != key)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
KeyExpansion();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If iv is passed as 0, we continue to encrypt without re-setting the Iv
|
||||||
|
if (iv != 0)
|
||||||
|
{
|
||||||
|
Iv = (uint8_t*)iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < length; i += AES_BLOCKLEN)
|
||||||
|
{
|
||||||
|
memcpy(output, input, AES_BLOCKLEN);
|
||||||
|
state = (state_t*)output;
|
||||||
|
InvCipher();
|
||||||
|
XorWithIv(output);
|
||||||
|
Iv = input;
|
||||||
|
input += AES_BLOCKLEN;
|
||||||
|
output += AES_BLOCKLEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extra)
|
||||||
|
{
|
||||||
|
memcpy(output, input, extra);
|
||||||
|
state = (state_t*)output;
|
||||||
|
InvCipher();
|
||||||
|
}
|
||||||
|
|
||||||
|
mpw_zero( RoundKey, keyExpSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #if defined(AES_CBC) && (AES_CBC == 1)
|
||||||
50
core/c/aes.h
Normal file
50
core/c/aes.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Source: https://github.com/kokke/tiny-AES-c
|
||||||
|
|
||||||
|
This is an implementation of the AES algorithm, specifically ECB and CBC mode.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AES_H_
|
||||||
|
#define _AES_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
// #define the macros below to 1/0 to enable/disable the mode of operation.
|
||||||
|
//
|
||||||
|
// AES_CBC enables AES encryption in CBC-mode of operation.
|
||||||
|
// AES_ECB enables the basic ECB 16-byte block algorithm. Both can be enabled simultaneously.
|
||||||
|
|
||||||
|
// The #ifndef-guard allows it to be configured before #include'ing or at compile time.
|
||||||
|
#ifndef AES_CBC
|
||||||
|
#define AES_CBC 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef AES_ECB
|
||||||
|
#define AES_ECB 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define AES_128 1
|
||||||
|
//#define AES_192 1
|
||||||
|
//#define AES_256 1
|
||||||
|
#define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only
|
||||||
|
|
||||||
|
#if defined(AES_ECB) && (AES_ECB == 1)
|
||||||
|
|
||||||
|
void AES_ECB_encrypt(uint8_t *output, const uint8_t *input, const uint32_t length, const uint8_t *key);
|
||||||
|
void AES_ECB_decrypt(uint8_t *output, const uint8_t *input, const uint32_t length, const uint8_t *key);
|
||||||
|
|
||||||
|
#endif // #if defined(AES_ECB) && (AES_ECB == !)
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(AES_CBC) && (AES_CBC == 1)
|
||||||
|
|
||||||
|
void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, const uint32_t length, const uint8_t* key, const uint8_t* iv);
|
||||||
|
void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, const uint32_t length, const uint8_t* key, const uint8_t* iv);
|
||||||
|
|
||||||
|
#endif // #if defined(AES_CBC) && (AES_CBC == 1)
|
||||||
|
|
||||||
|
|
||||||
|
#endif //_AES_H_
|
||||||
@@ -29,9 +29,9 @@ MPMasterKey mpw_masterKey(const char *fullName, const char *masterPassword, cons
|
|||||||
if (masterPassword && !strlen( masterPassword ))
|
if (masterPassword && !strlen( masterPassword ))
|
||||||
masterPassword = NULL;
|
masterPassword = NULL;
|
||||||
|
|
||||||
trc( "-- mpw_masterKey (algorithm: %u)\n", algorithmVersion );
|
trc( "-- mpw_masterKey (algorithm: %u)", algorithmVersion );
|
||||||
trc( "fullName: %s\n", fullName );
|
trc( "fullName: %s", fullName );
|
||||||
trc( "masterPassword.id: %s\n", masterPassword? mpw_id_buf( masterPassword, strlen( masterPassword ) ): NULL );
|
trc( "masterPassword.id: %s", masterPassword? mpw_id_buf( masterPassword, strlen( masterPassword ) ): NULL );
|
||||||
if (!fullName || !masterPassword)
|
if (!fullName || !masterPassword)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ MPMasterKey mpw_masterKey(const char *fullName, const char *masterPassword, cons
|
|||||||
case MPAlgorithmVersion3:
|
case MPAlgorithmVersion3:
|
||||||
return mpw_masterKey_v3( fullName, masterPassword );
|
return mpw_masterKey_v3( fullName, masterPassword );
|
||||||
default:
|
default:
|
||||||
err( "Unsupported version: %d\n", algorithmVersion );
|
err( "Unsupported version: %d", algorithmVersion );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,16 +54,14 @@ MPSiteKey mpw_siteKey(
|
|||||||
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
|
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
|
||||||
const MPKeyPurpose keyPurpose, const char *keyContext, const MPAlgorithmVersion algorithmVersion) {
|
const MPKeyPurpose keyPurpose, const char *keyContext, const MPAlgorithmVersion algorithmVersion) {
|
||||||
|
|
||||||
if (siteName && !strlen( siteName ))
|
|
||||||
siteName = NULL;
|
|
||||||
if (keyContext && !strlen( keyContext ))
|
if (keyContext && !strlen( keyContext ))
|
||||||
keyContext = NULL;
|
keyContext = NULL;
|
||||||
|
|
||||||
trc( "-- mpw_siteKey (algorithm: %u)\n", algorithmVersion );
|
trc( "-- mpw_siteKey (algorithm: %u)", algorithmVersion );
|
||||||
trc( "siteName: %s\n", siteName );
|
trc( "siteName: %s", siteName );
|
||||||
trc( "siteCounter: %d\n", siteCounter );
|
trc( "siteCounter: %d", siteCounter );
|
||||||
trc( "keyPurpose: %d (%s)\n", keyPurpose, mpw_nameForPurpose( keyPurpose ) );
|
trc( "keyPurpose: %d (%s)", keyPurpose, mpw_nameForPurpose( keyPurpose ) );
|
||||||
trc( "keyContext: %s\n", keyContext );
|
trc( "keyContext: %s", keyContext );
|
||||||
if (!masterKey || !siteName)
|
if (!masterKey || !siteName)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -77,7 +75,7 @@ MPSiteKey mpw_siteKey(
|
|||||||
case MPAlgorithmVersion3:
|
case MPAlgorithmVersion3:
|
||||||
return mpw_siteKey_v3( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
return mpw_siteKey_v3( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
||||||
default:
|
default:
|
||||||
err( "Unsupported version: %d\n", algorithmVersion );
|
err( "Unsupported version: %d", algorithmVersion );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,8 +86,6 @@ const char *mpw_siteResult(
|
|||||||
const MPResultType resultType, const char *resultParam,
|
const MPResultType resultType, const char *resultParam,
|
||||||
const MPAlgorithmVersion algorithmVersion) {
|
const MPAlgorithmVersion algorithmVersion) {
|
||||||
|
|
||||||
if (siteName && !strlen( siteName ))
|
|
||||||
siteName = NULL;
|
|
||||||
if (keyContext && !strlen( keyContext ))
|
if (keyContext && !strlen( keyContext ))
|
||||||
keyContext = NULL;
|
keyContext = NULL;
|
||||||
if (resultParam && !strlen( resultParam ))
|
if (resultParam && !strlen( resultParam ))
|
||||||
@@ -99,9 +95,9 @@ const char *mpw_siteResult(
|
|||||||
if (!siteKey)
|
if (!siteKey)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
trc( "-- mpw_siteResult (algorithm: %u)\n", algorithmVersion );
|
trc( "-- mpw_siteResult (algorithm: %u)", algorithmVersion );
|
||||||
trc( "resultType: %d (%s)\n", resultType, mpw_nameForType( resultType ) );
|
trc( "resultType: %d (%s)", resultType, mpw_nameForType( resultType ) );
|
||||||
trc( "resultParam: %s\n", resultParam );
|
trc( "resultParam: %s", resultParam );
|
||||||
|
|
||||||
char *sitePassword = NULL;
|
char *sitePassword = NULL;
|
||||||
if (resultType & MPResultTypeClassTemplate) {
|
if (resultType & MPResultTypeClassTemplate) {
|
||||||
@@ -115,7 +111,7 @@ const char *mpw_siteResult(
|
|||||||
case MPAlgorithmVersion3:
|
case MPAlgorithmVersion3:
|
||||||
return mpw_sitePasswordFromTemplate_v3( masterKey, siteKey, resultType, resultParam );
|
return mpw_sitePasswordFromTemplate_v3( masterKey, siteKey, resultType, resultParam );
|
||||||
default:
|
default:
|
||||||
err( "Unsupported version: %d\n", algorithmVersion );
|
err( "Unsupported version: %d", algorithmVersion );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,7 +126,7 @@ const char *mpw_siteResult(
|
|||||||
case MPAlgorithmVersion3:
|
case MPAlgorithmVersion3:
|
||||||
return mpw_sitePasswordFromCrypt_v3( masterKey, siteKey, resultType, resultParam );
|
return mpw_sitePasswordFromCrypt_v3( masterKey, siteKey, resultType, resultParam );
|
||||||
default:
|
default:
|
||||||
err( "Unsupported version: %d\n", algorithmVersion );
|
err( "Unsupported version: %d", algorithmVersion );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,12 +141,12 @@ const char *mpw_siteResult(
|
|||||||
case MPAlgorithmVersion3:
|
case MPAlgorithmVersion3:
|
||||||
return mpw_sitePasswordFromDerive_v3( masterKey, siteKey, resultType, resultParam );
|
return mpw_sitePasswordFromDerive_v3( masterKey, siteKey, resultType, resultParam );
|
||||||
default:
|
default:
|
||||||
err( "Unsupported version: %d\n", algorithmVersion );
|
err( "Unsupported version: %d", algorithmVersion );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
err( "Unsupported password type: %d\n", resultType );
|
err( "Unsupported password type: %d", resultType );
|
||||||
}
|
}
|
||||||
|
|
||||||
return sitePassword;
|
return sitePassword;
|
||||||
@@ -162,20 +158,18 @@ const char *mpw_siteState(
|
|||||||
const MPResultType resultType, const char *resultParam,
|
const MPResultType resultType, const char *resultParam,
|
||||||
const MPAlgorithmVersion algorithmVersion) {
|
const MPAlgorithmVersion algorithmVersion) {
|
||||||
|
|
||||||
if (siteName && !strlen( siteName ))
|
|
||||||
siteName = NULL;
|
|
||||||
if (keyContext && !strlen( keyContext ))
|
if (keyContext && !strlen( keyContext ))
|
||||||
keyContext = NULL;
|
keyContext = NULL;
|
||||||
if (resultParam && !strlen( resultParam ))
|
if (resultParam && !strlen( resultParam ))
|
||||||
resultParam = NULL;
|
resultParam = NULL;
|
||||||
|
|
||||||
MPSiteKey siteKey = mpw_siteKey_v0( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
MPSiteKey siteKey = mpw_siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
|
||||||
if (!siteKey)
|
if (!siteKey)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
trc( "-- mpw_siteState (algorithm: %u)\n", algorithmVersion );
|
trc( "-- mpw_siteState (algorithm: %u)", algorithmVersion );
|
||||||
trc( "resultType: %d (%s)\n", resultType, mpw_nameForType( resultType ) );
|
trc( "resultType: %d (%s)", resultType, mpw_nameForType( resultType ) );
|
||||||
trc( "resultParam: %s\n", resultParam );
|
trc( "resultParam: %zu bytes = %s", sizeof( resultParam ), resultParam );
|
||||||
if (!masterKey || !resultParam)
|
if (!masterKey || !resultParam)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -189,7 +183,44 @@ const char *mpw_siteState(
|
|||||||
case MPAlgorithmVersion3:
|
case MPAlgorithmVersion3:
|
||||||
return mpw_siteState_v3( masterKey, siteKey, resultType, resultParam );
|
return mpw_siteState_v3( masterKey, siteKey, resultType, resultParam );
|
||||||
default:
|
default:
|
||||||
err( "Unsupported version: %d\n", algorithmVersion );
|
err( "Unsupported version: %d", algorithmVersion );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MPIdenticon mpw_identicon(const char *fullName, const char *masterPassword) {
|
||||||
|
|
||||||
|
const char *leftArm[] = { "╔", "╚", "╰", "═" };
|
||||||
|
const char *rightArm[] = { "╗", "╝", "╯", "═" };
|
||||||
|
const char *body[] = { "█", "░", "▒", "▓", "☺", "☻" };
|
||||||
|
const char *accessory[] = {
|
||||||
|
"◈", "◎", "◐", "◑", "◒", "◓", "☀", "☁", "☂", "☃", "", "★", "☆", "☎", "☏", "⎈", "⌂", "☘", "☢", "☣",
|
||||||
|
"☕", "⌚", "⌛", "⏰", "⚡", "⛄", "⛅", "☔", "♔", "♕", "♖", "♗", "♘", "♙", "♚", "♛", "♜", "♝", "♞", "♟",
|
||||||
|
"♨", "♩", "♪", "♫", "⚐", "⚑", "⚔", "⚖", "⚙", "⚠", "⌘", "⏎", "✄", "✆", "✈", "✉", "✌"
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t *identiconSeed = NULL;
|
||||||
|
if (fullName && strlen( fullName ) && masterPassword && strlen( masterPassword ))
|
||||||
|
identiconSeed = mpw_hash_hmac_sha256(
|
||||||
|
(const uint8_t *)masterPassword, strlen( masterPassword ),
|
||||||
|
(const uint8_t *)fullName, strlen( fullName ) );
|
||||||
|
if (!identiconSeed)
|
||||||
|
return (MPIdenticon){
|
||||||
|
.leftArm = "",
|
||||||
|
.body = "",
|
||||||
|
.rightArm = "",
|
||||||
|
.accessory = "",
|
||||||
|
.color=0,
|
||||||
|
};
|
||||||
|
|
||||||
|
MPIdenticon identicon = {
|
||||||
|
.leftArm = leftArm[identiconSeed[0] % (sizeof( leftArm ) / sizeof( leftArm[0] ))],
|
||||||
|
.body = body[identiconSeed[1] % (sizeof( body ) / sizeof( body[0] ))],
|
||||||
|
.rightArm = rightArm[identiconSeed[2] % (sizeof( rightArm ) / sizeof( rightArm[0] ))],
|
||||||
|
.accessory = accessory[identiconSeed[3] % (sizeof( accessory ) / sizeof( accessory[0] ))],
|
||||||
|
.color = (uint8_t)(identiconSeed[4] % (MPIdenticonColorLast - MPIdenticonColorFirst + 1) + MPIdenticonColorFirst),
|
||||||
|
};
|
||||||
|
mpw_free( &identiconSeed, 32 );
|
||||||
|
|
||||||
|
return identicon;
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,4 +66,7 @@ const char *mpw_siteState(
|
|||||||
const MPResultType resultType, const char *resultParam,
|
const MPResultType resultType, const char *resultParam,
|
||||||
const MPAlgorithmVersion algorithmVersion);
|
const MPAlgorithmVersion algorithmVersion);
|
||||||
|
|
||||||
|
/** @return A fingerprint for a user. */
|
||||||
|
MPIdenticon mpw_identicon(const char *fullName, const char *masterPassword);
|
||||||
|
|
||||||
#endif // _MPW_ALGORITHM_H
|
#endif // _MPW_ALGORITHM_H
|
||||||
|
|||||||
@@ -52,10 +52,10 @@ static MPMasterKey mpw_masterKey_v0(
|
|||||||
const char *fullName, const char *masterPassword) {
|
const char *fullName, const char *masterPassword) {
|
||||||
|
|
||||||
const char *keyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
|
const char *keyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
|
||||||
trc( "keyScope: %s\n", keyScope );
|
trc( "keyScope: %s", keyScope );
|
||||||
|
|
||||||
// Calculate the master key salt.
|
// Calculate the master key salt.
|
||||||
trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s\n",
|
trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
||||||
keyScope, mpw_hex_l( (uint32_t)mpw_utf8_strlen( fullName ) ), fullName );
|
keyScope, mpw_hex_l( (uint32_t)mpw_utf8_strlen( fullName ) ), fullName );
|
||||||
size_t masterKeySaltSize = 0;
|
size_t masterKeySaltSize = 0;
|
||||||
uint8_t *masterKeySalt = NULL;
|
uint8_t *masterKeySalt = NULL;
|
||||||
@@ -63,20 +63,20 @@ static MPMasterKey mpw_masterKey_v0(
|
|||||||
mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)mpw_utf8_strlen( fullName ) );
|
mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)mpw_utf8_strlen( fullName ) );
|
||||||
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
|
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
|
||||||
if (!masterKeySalt) {
|
if (!masterKeySalt) {
|
||||||
err( "Could not allocate master key salt: %s\n", strerror( errno ) );
|
err( "Could not allocate master key salt: %s", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( " => masterKeySalt.id: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
|
trc( " => masterKeySalt.id: %s", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
|
||||||
|
|
||||||
// Calculate the master key.
|
// Calculate the master key.
|
||||||
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p );
|
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )", MP_N, MP_r, MP_p );
|
||||||
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
|
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
|
||||||
mpw_free( &masterKeySalt, masterKeySaltSize );
|
mpw_free( &masterKeySalt, masterKeySaltSize );
|
||||||
if (!masterKey) {
|
if (!masterKey) {
|
||||||
err( "Could not derive master key: %s\n", strerror( errno ) );
|
err( "Could not derive master key: %s", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( " => masterKey.id: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
|
trc( " => masterKey.id: %s", mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||||
|
|
||||||
return masterKey;
|
return masterKey;
|
||||||
}
|
}
|
||||||
@@ -86,14 +86,14 @@ static MPSiteKey mpw_siteKey_v0(
|
|||||||
MPKeyPurpose keyPurpose, const char *keyContext) {
|
MPKeyPurpose keyPurpose, const char *keyContext) {
|
||||||
|
|
||||||
const char *keyScope = mpw_scopeForPurpose( keyPurpose );
|
const char *keyScope = mpw_scopeForPurpose( keyPurpose );
|
||||||
trc( "keyScope: %s\n", keyScope );
|
trc( "keyScope: %s", keyScope );
|
||||||
|
|
||||||
// OTP counter value.
|
// OTP counter value.
|
||||||
if (siteCounter == MPCounterValueTOTP)
|
if (siteCounter == MPCounterValueTOTP)
|
||||||
siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window;
|
siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window;
|
||||||
|
|
||||||
// Calculate the site seed.
|
// Calculate the site seed.
|
||||||
trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s\n",
|
trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
|
||||||
keyScope, mpw_hex_l( (uint32_t)mpw_utf8_strlen( siteName ) ), siteName, mpw_hex_l( siteCounter ),
|
keyScope, mpw_hex_l( (uint32_t)mpw_utf8_strlen( siteName ) ), siteName, mpw_hex_l( siteCounter ),
|
||||||
keyContext? mpw_hex_l( (uint32_t)mpw_utf8_strlen( keyContext ) ): NULL, keyContext );
|
keyContext? mpw_hex_l( (uint32_t)mpw_utf8_strlen( keyContext ) ): NULL, keyContext );
|
||||||
size_t siteSaltSize = 0;
|
size_t siteSaltSize = 0;
|
||||||
@@ -107,20 +107,20 @@ static MPSiteKey mpw_siteKey_v0(
|
|||||||
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
|
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
|
||||||
}
|
}
|
||||||
if (!siteSalt) {
|
if (!siteSalt) {
|
||||||
err( "Could not allocate site salt: %s\n", strerror( errno ) );
|
err( "Could not allocate site salt: %s", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
|
trc( " => siteSalt.id: %s", mpw_id_buf( siteSalt, siteSaltSize ) );
|
||||||
|
|
||||||
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n",
|
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )",
|
||||||
mpw_id_buf( masterKey, MPMasterKeySize ) );
|
mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||||
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
|
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
|
||||||
mpw_free( &siteSalt, siteSaltSize );
|
mpw_free( &siteSalt, siteSaltSize );
|
||||||
if (!siteKey) {
|
if (!siteKey) {
|
||||||
err( "Could not derive site key: %s\n", strerror( errno ) );
|
err( "Could not derive site key: %s", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( " => siteKey.id: %s\n", mpw_id_buf( siteKey, MPSiteKeySize ) );
|
trc( " => siteKey.id: %s", mpw_id_buf( siteKey, MPSiteKeySize ) );
|
||||||
|
|
||||||
return siteKey;
|
return siteKey;
|
||||||
}
|
}
|
||||||
@@ -134,11 +134,11 @@ static const char *mpw_sitePasswordFromTemplate_v0(
|
|||||||
uint16_t seedByte;
|
uint16_t seedByte;
|
||||||
mpw_uint16( (uint16_t)_siteKey[0], (uint8_t *)&seedByte );
|
mpw_uint16( (uint16_t)_siteKey[0], (uint8_t *)&seedByte );
|
||||||
const char *template = mpw_templateForType_v0( resultType, seedByte );
|
const char *template = mpw_templateForType_v0( resultType, seedByte );
|
||||||
trc( "template: %u => %s\n", seedByte, template );
|
trc( "template: %u => %s", seedByte, template );
|
||||||
if (!template)
|
if (!template)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (strlen( template ) > MPSiteKeySize) {
|
if (strlen( template ) > MPSiteKeySize) {
|
||||||
err( "Template too long for password seed: %zu\n", strlen( template ) );
|
err( "Template too long for password seed: %zu", strlen( template ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,10 +147,10 @@ static const char *mpw_sitePasswordFromTemplate_v0(
|
|||||||
for (size_t c = 0; c < strlen( template ); ++c) {
|
for (size_t c = 0; c < strlen( template ); ++c) {
|
||||||
mpw_uint16( (uint16_t)_siteKey[c + 1], (uint8_t *)&seedByte );
|
mpw_uint16( (uint16_t)_siteKey[c + 1], (uint8_t *)&seedByte );
|
||||||
sitePassword[c] = mpw_characterFromClass_v0( template[c], seedByte );
|
sitePassword[c] = mpw_characterFromClass_v0( template[c], seedByte );
|
||||||
trc( " - class: %c, index: %5u (0x%02hX) => character: %c\n",
|
trc( " - class: %c, index: %5u (0x%02hX) => character: %c",
|
||||||
template[c], seedByte, seedByte, sitePassword[c] );
|
template[c], seedByte, seedByte, sitePassword[c] );
|
||||||
}
|
}
|
||||||
trc( " => password: %s\n", sitePassword );
|
trc( " => password: %s", sitePassword );
|
||||||
|
|
||||||
return sitePassword;
|
return sitePassword;
|
||||||
}
|
}
|
||||||
@@ -159,28 +159,28 @@ static const char *mpw_sitePasswordFromCrypt_v0(
|
|||||||
MPMasterKey masterKey, MPSiteKey __unused siteKey, MPResultType __unused resultType, const char *cipherText) {
|
MPMasterKey masterKey, MPSiteKey __unused siteKey, MPResultType __unused resultType, const char *cipherText) {
|
||||||
|
|
||||||
if (!cipherText) {
|
if (!cipherText) {
|
||||||
err( "Missing encrypted state.\n" );
|
err( "Missing encrypted state." );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Base64-decode
|
// Base64-decode
|
||||||
uint8_t *cipherBuf = calloc( 1, mpw_base64_decode_max( cipherText ) );
|
uint8_t *cipherBuf = calloc( 1, mpw_base64_decode_max( cipherText ) );
|
||||||
size_t bufSize = (size_t)mpw_base64_decode( cipherBuf, cipherText );
|
size_t bufSize = (size_t)mpw_base64_decode( cipherBuf, cipherText ), cipherBufSize = bufSize;
|
||||||
if ((int)bufSize < 0) {
|
if ((int)bufSize < 0) {
|
||||||
err( "Base64 decoding error." );
|
err( "Base64 decoding error." );
|
||||||
mpw_free( &cipherBuf, mpw_base64_decode_max( cipherText ) );
|
mpw_free( &cipherBuf, mpw_base64_decode_max( cipherText ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( "b64 decoded: %zu bytes = %s\n", bufSize, mpw_hex( cipherBuf, bufSize ) );
|
trc( "b64 decoded: %zu bytes = %s", bufSize, mpw_hex( cipherBuf, bufSize ) );
|
||||||
|
|
||||||
// Decrypt
|
// Decrypt
|
||||||
const uint8_t *plainBytes = mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, bufSize );
|
const uint8_t *plainBytes = mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, &bufSize );
|
||||||
mpw_free( &cipherBuf, bufSize );
|
mpw_free( &cipherBuf, cipherBufSize );
|
||||||
const char *plainText = strndup( (char *)plainBytes, bufSize );
|
const char *plainText = mpw_strndup( (char *)plainBytes, bufSize );
|
||||||
mpw_free( &plainBytes, bufSize );
|
mpw_free( &plainBytes, bufSize );
|
||||||
if (!plainText)
|
if (!plainText)
|
||||||
err( "AES decryption error: %s\n", strerror( errno ) );
|
err( "AES decryption error: %s", strerror( errno ) );
|
||||||
trc( "decrypted -> plainText: %s = %s\n", plainText, mpw_hex( plainText, sizeof( plainText ) ) );
|
trc( "decrypted -> plainText: %zu bytes = %s = %s", strlen( plainText ), plainText, mpw_hex( plainText, strlen( plainText ) ) );
|
||||||
|
|
||||||
return plainText;
|
return plainText;
|
||||||
}
|
}
|
||||||
@@ -191,21 +191,23 @@ static const char *mpw_sitePasswordFromDerive_v0(
|
|||||||
switch (resultType) {
|
switch (resultType) {
|
||||||
case MPResultTypeDeriveKey: {
|
case MPResultTypeDeriveKey: {
|
||||||
if (!resultParam) {
|
if (!resultParam) {
|
||||||
err( "Missing key size parameter.\n" );
|
err( "Missing key size parameter." );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
int resultParamInt = atoi( resultParam );
|
int resultParamInt = atoi( resultParam );
|
||||||
|
if (!resultParamInt)
|
||||||
|
resultParamInt = 512;
|
||||||
if (resultParamInt < 128 || resultParamInt > 512 || resultParamInt % 8 != 0) {
|
if (resultParamInt < 128 || resultParamInt > 512 || resultParamInt % 8 != 0) {
|
||||||
err( "Parameter is not a valid key size (should be 128 - 512): %s\n", resultParam );
|
err( "Parameter is not a valid key size (should be 128 - 512): %s", resultParam );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
uint16_t keySize = (uint16_t)(resultParamInt / 8);
|
uint16_t keySize = (uint16_t)(resultParamInt / 8);
|
||||||
trc( "keySize: %u\n", keySize );
|
trc( "keySize: %u", keySize );
|
||||||
|
|
||||||
// Derive key
|
// Derive key
|
||||||
const uint8_t *resultKey = mpw_kdf_blake2b( keySize, siteKey, MPSiteKeySize, NULL, 0, 0, NULL );
|
const uint8_t *resultKey = mpw_kdf_blake2b( keySize, siteKey, MPSiteKeySize, NULL, 0, 0, NULL );
|
||||||
if (!resultKey) {
|
if (!resultKey) {
|
||||||
err( "Could not derive result key: %s\n", strerror( errno ) );
|
err( "Could not derive result key: %s", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,13 +219,13 @@ static const char *mpw_sitePasswordFromDerive_v0(
|
|||||||
mpw_free_string( &b64Key );
|
mpw_free_string( &b64Key );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
trc( "b64 encoded -> key.id: %s\n", mpw_id_buf( b64Key, strlen( b64Key ) ) );
|
trc( "b64 encoded -> key: %s", b64Key );
|
||||||
mpw_free( &resultKey, keySize );
|
mpw_free( &resultKey, keySize );
|
||||||
|
|
||||||
return b64Key;
|
return b64Key;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err( "Unsupported derived password type: %d\n", resultType );
|
err( "Unsupported derived password type: %d", resultType );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,12 +235,12 @@ static const char *mpw_siteState_v0(
|
|||||||
|
|
||||||
// Encrypt
|
// Encrypt
|
||||||
size_t bufSize = strlen( plainText );
|
size_t bufSize = strlen( plainText );
|
||||||
const uint8_t *cipherBuf = mpw_aes_encrypt( masterKey, MPMasterKeySize, (const uint8_t *)plainText, bufSize );
|
const uint8_t *cipherBuf = mpw_aes_encrypt( masterKey, MPMasterKeySize, (const uint8_t *)plainText, &bufSize );
|
||||||
if (!cipherBuf) {
|
if (!cipherBuf) {
|
||||||
err( "AES encryption error: %s\n", strerror( errno ) );
|
err( "AES encryption error: %s", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( "cipherBuf: %zu bytes = %s\n", bufSize, mpw_hex( cipherBuf, bufSize ) );
|
trc( "cipherBuf: %zu bytes = %s", bufSize, mpw_hex( cipherBuf, bufSize ) );
|
||||||
|
|
||||||
// Base64-encode
|
// Base64-encode
|
||||||
size_t b64Max = mpw_base64_encode_max( bufSize );
|
size_t b64Max = mpw_base64_encode_max( bufSize );
|
||||||
@@ -248,7 +250,7 @@ static const char *mpw_siteState_v0(
|
|||||||
mpw_free_string( &cipherText );
|
mpw_free_string( &cipherText );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
trc( "b64 encoded -> cipherText: %s = %s\n", cipherText, mpw_hex( cipherText, sizeof( cipherText ) ) );
|
trc( "b64 encoded -> cipherText: %s", cipherText );
|
||||||
mpw_free( &cipherBuf, bufSize );
|
mpw_free( &cipherBuf, bufSize );
|
||||||
|
|
||||||
return cipherText;
|
return cipherText;
|
||||||
|
|||||||
@@ -58,11 +58,11 @@ static const char *mpw_sitePasswordFromTemplate_v1(
|
|||||||
// Determine the template.
|
// Determine the template.
|
||||||
uint8_t seedByte = siteKey[0];
|
uint8_t seedByte = siteKey[0];
|
||||||
const char *template = mpw_templateForType( resultType, seedByte );
|
const char *template = mpw_templateForType( resultType, seedByte );
|
||||||
trc( "template: %u => %s\n", seedByte, template );
|
trc( "template: %u => %s", seedByte, template );
|
||||||
if (!template)
|
if (!template)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (strlen( template ) > MPSiteKeySize) {
|
if (strlen( template ) > MPSiteKeySize) {
|
||||||
err( "Template too long for password seed: %zu\n", strlen( template ) );
|
err( "Template too long for password seed: %zu", strlen( template ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,10 +71,10 @@ static const char *mpw_sitePasswordFromTemplate_v1(
|
|||||||
for (size_t c = 0; c < strlen( template ); ++c) {
|
for (size_t c = 0; c < strlen( template ); ++c) {
|
||||||
seedByte = siteKey[c + 1];
|
seedByte = siteKey[c + 1];
|
||||||
sitePassword[c] = mpw_characterFromClass( template[c], seedByte );
|
sitePassword[c] = mpw_characterFromClass( template[c], seedByte );
|
||||||
trc( " - class: %c, index: %3u (0x%02hhX) => character: %c\n",
|
trc( " - class: %c, index: %3u (0x%02hhX) => character: %c",
|
||||||
template[c], seedByte, seedByte, sitePassword[c] );
|
template[c], seedByte, seedByte, sitePassword[c] );
|
||||||
}
|
}
|
||||||
trc( " => password: %s\n", sitePassword );
|
trc( " => password: %s", sitePassword );
|
||||||
|
|
||||||
return sitePassword;
|
return sitePassword;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,14 +51,14 @@ static MPSiteKey mpw_siteKey_v2(
|
|||||||
MPKeyPurpose keyPurpose, const char *keyContext) {
|
MPKeyPurpose keyPurpose, const char *keyContext) {
|
||||||
|
|
||||||
const char *keyScope = mpw_scopeForPurpose( keyPurpose );
|
const char *keyScope = mpw_scopeForPurpose( keyPurpose );
|
||||||
trc( "keyScope: %s\n", keyScope );
|
trc( "keyScope: %s", keyScope );
|
||||||
|
|
||||||
// OTP counter value.
|
// OTP counter value.
|
||||||
if (siteCounter == MPCounterValueTOTP)
|
if (siteCounter == MPCounterValueTOTP)
|
||||||
siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window;
|
siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window;
|
||||||
|
|
||||||
// Calculate the site seed.
|
// Calculate the site seed.
|
||||||
trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s\n",
|
trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
|
||||||
keyScope, mpw_hex_l( (uint32_t)strlen( siteName ) ), siteName, mpw_hex_l( siteCounter ),
|
keyScope, mpw_hex_l( (uint32_t)strlen( siteName ) ), siteName, mpw_hex_l( siteCounter ),
|
||||||
keyContext? mpw_hex_l( (uint32_t)strlen( keyContext ) ): NULL, keyContext );
|
keyContext? mpw_hex_l( (uint32_t)strlen( keyContext ) ): NULL, keyContext );
|
||||||
size_t siteSaltSize = 0;
|
size_t siteSaltSize = 0;
|
||||||
@@ -72,20 +72,20 @@ static MPSiteKey mpw_siteKey_v2(
|
|||||||
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
|
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
|
||||||
}
|
}
|
||||||
if (!siteSalt) {
|
if (!siteSalt) {
|
||||||
err( "Could not allocate site salt: %s\n", strerror( errno ) );
|
err( "Could not allocate site salt: %s", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
|
trc( " => siteSalt.id: %s", mpw_id_buf( siteSalt, siteSaltSize ) );
|
||||||
|
|
||||||
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n",
|
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )",
|
||||||
mpw_id_buf( masterKey, MPMasterKeySize ) );
|
mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||||
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
|
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
|
||||||
mpw_free( &siteSalt, siteSaltSize );
|
mpw_free( &siteSalt, siteSaltSize );
|
||||||
if (!siteKey) {
|
if (!siteKey) {
|
||||||
err( "Could not derive site key: %s\n", strerror( errno ) );
|
err( "Could not derive site key: %s", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( " => siteKey.id: %s\n", mpw_id_buf( siteKey, MPSiteKeySize ) );
|
trc( " => siteKey.id: %s", mpw_id_buf( siteKey, MPSiteKeySize ) );
|
||||||
|
|
||||||
return siteKey;
|
return siteKey;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ static MPMasterKey mpw_masterKey_v3(
|
|||||||
const char *fullName, const char *masterPassword) {
|
const char *fullName, const char *masterPassword) {
|
||||||
|
|
||||||
const char *keyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
|
const char *keyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
|
||||||
trc( "keyScope: %s\n", keyScope );
|
trc( "keyScope: %s", keyScope );
|
||||||
|
|
||||||
// Calculate the master key salt.
|
// Calculate the master key salt.
|
||||||
trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s\n",
|
trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
||||||
keyScope, mpw_hex_l( (uint32_t)strlen( fullName ) ), fullName );
|
keyScope, mpw_hex_l( (uint32_t)strlen( fullName ) ), fullName );
|
||||||
size_t masterKeySaltSize = 0;
|
size_t masterKeySaltSize = 0;
|
||||||
uint8_t *masterKeySalt = NULL;
|
uint8_t *masterKeySalt = NULL;
|
||||||
@@ -55,20 +55,20 @@ static MPMasterKey mpw_masterKey_v3(
|
|||||||
mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)strlen( fullName ) );
|
mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)strlen( fullName ) );
|
||||||
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
|
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
|
||||||
if (!masterKeySalt) {
|
if (!masterKeySalt) {
|
||||||
err( "Could not allocate master key salt: %s\n", strerror( errno ) );
|
err( "Could not allocate master key salt: %s", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( " => masterKeySalt.id: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
|
trc( " => masterKeySalt.id: %s", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
|
||||||
|
|
||||||
// Calculate the master key.
|
// Calculate the master key.
|
||||||
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p );
|
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )", MP_N, MP_r, MP_p );
|
||||||
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
|
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
|
||||||
mpw_free( &masterKeySalt, masterKeySaltSize );
|
mpw_free( &masterKeySalt, masterKeySaltSize );
|
||||||
if (!masterKey) {
|
if (!masterKey) {
|
||||||
err( "Could not derive master key: %s\n", strerror( errno ) );
|
err( "Could not derive master key: %s", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( " => masterKey.id: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
|
trc( " => masterKey.id: %s", mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||||
|
|
||||||
return masterKey;
|
return masterKey;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "mpw-marshall-util.h"
|
#include "mpw-marshal-util.h"
|
||||||
#include "mpw-util.h"
|
#include "mpw-util.h"
|
||||||
|
|
||||||
char *mpw_get_token(const char **in, const char *eol, char *delim) {
|
char *mpw_get_token(const char **in, const char *eol, char *delim) {
|
||||||
@@ -28,7 +28,7 @@ char *mpw_get_token(const char **in, const char *eol, char *delim) {
|
|||||||
|
|
||||||
// Find characters up to the first delim.
|
// Find characters up to the first delim.
|
||||||
size_t len = strcspn( *in, delim );
|
size_t len = strcspn( *in, delim );
|
||||||
char *token = len && len <= (size_t)(eol - *in)? strndup( *in, len ): NULL;
|
char *token = len && len <= (size_t)(eol - *in)? mpw_strndup( *in, len ): NULL;
|
||||||
|
|
||||||
// Advance past the delimitor.
|
// Advance past the delimitor.
|
||||||
*in = min( eol, *in + len + 1 );
|
*in = min( eol, *in + len + 1 );
|
||||||
@@ -38,7 +38,7 @@ char *mpw_get_token(const char **in, const char *eol, char *delim) {
|
|||||||
time_t mpw_mktime(
|
time_t mpw_mktime(
|
||||||
const char *time) {
|
const char *time) {
|
||||||
|
|
||||||
struct tm tm = { .tm_isdst = -1, .tm_gmtoff = 0 };
|
struct tm tm = { .tm_isdst = -1 };
|
||||||
if (time && sscanf( time, "%4d-%2d-%2dT%2d:%2d:%2dZ",
|
if (time && sscanf( time, "%4d-%2d-%2dT%2d:%2d:%2dZ",
|
||||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
||||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec ) == 6) {
|
&tm.tm_hour, &tm.tm_min, &tm.tm_sec ) == 6) {
|
||||||
@@ -55,10 +55,10 @@ json_object *mpw_get_json_section(
|
|||||||
json_object *obj, const char *section) {
|
json_object *obj, const char *section) {
|
||||||
|
|
||||||
json_object *json_value = obj;
|
json_object *json_value = obj;
|
||||||
char *sectionTokenizer = strdup( section ), *sectionToken = sectionTokenizer;
|
char *sectionTokenizer = mpw_strdup( section ), *sectionToken = sectionTokenizer;
|
||||||
for (sectionToken = strtok( sectionToken, "." ); sectionToken; sectionToken = strtok( NULL, "." ))
|
for (sectionToken = strtok( sectionToken, "." ); sectionToken; sectionToken = strtok( NULL, "." ))
|
||||||
if (!json_object_object_get_ex( json_value, sectionToken, &json_value ) || !json_value) {
|
if (!json_object_object_get_ex( json_value, sectionToken, &json_value ) || !json_value) {
|
||||||
trc( "While resolving: %s: Missing value for: %s\n", section, sectionToken );
|
trc( "While resolving: %s: Missing value for: %s", section, sectionToken );
|
||||||
json_value = NULL;
|
json_value = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ bool mpw_update_masterKey(MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyA
|
|||||||
*masterKeyAlgorithm = targetKeyAlgorithm;
|
*masterKeyAlgorithm = targetKeyAlgorithm;
|
||||||
*masterKey = mpw_masterKey( fullName, masterPassword, *masterKeyAlgorithm );
|
*masterKey = mpw_masterKey( fullName, masterPassword, *masterKeyAlgorithm );
|
||||||
if (!*masterKey) {
|
if (!*masterKey) {
|
||||||
err( "Couldn't derive master key for user %s, algorithm %d.\n", fullName, *masterKeyAlgorithm );
|
err( "Couldn't derive master key for user %s, algorithm %d.", fullName, *masterKeyAlgorithm );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,11 +16,13 @@
|
|||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef _MPW_MARSHALL_UTIL_H
|
#ifndef _MPW_MARSHAL_UTIL_H
|
||||||
#define _MPW_MARSHALL_UTIL_H
|
#define _MPW_MARSHAL_UTIL_H
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#if MPW_JSON
|
||||||
#include "json-c/json.h"
|
#include "json-c/json.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "mpw-algorithm.h"
|
#include "mpw-algorithm.h"
|
||||||
|
|
||||||
@@ -37,6 +39,7 @@ time_t mpw_mktime(
|
|||||||
|
|
||||||
/// JSON parsing.
|
/// JSON parsing.
|
||||||
|
|
||||||
|
#if MPW_JSON
|
||||||
/** Search for a JSON child object in a JSON object tree.
|
/** Search for a JSON child object in a JSON object tree.
|
||||||
* @param section A dot-delimited list of JSON object keys to walk toward the child object.
|
* @param section A dot-delimited list of JSON object keys to walk toward the child object.
|
||||||
* @return A new JSON object or NULL if one of the section's object keys was not found in the source object's tree. */
|
* @return A new JSON object or NULL if one of the section's object keys was not found in the source object's tree. */
|
||||||
@@ -57,6 +60,7 @@ int64_t mpw_get_json_int(
|
|||||||
* @return The boolean value or defaultValue if one of the section's object keys was not found in the source object's tree. */
|
* @return The boolean value or defaultValue if one of the section's object keys was not found in the source object's tree. */
|
||||||
bool mpw_get_json_boolean(
|
bool mpw_get_json_boolean(
|
||||||
json_object *obj, const char *section, bool defaultValue);
|
json_object *obj, const char *section, bool defaultValue);
|
||||||
|
#endif
|
||||||
|
|
||||||
/// mpw.
|
/// mpw.
|
||||||
|
|
||||||
@@ -66,4 +70,4 @@ bool mpw_update_masterKey(
|
|||||||
MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, MPAlgorithmVersion targetKeyAlgorithm,
|
MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, MPAlgorithmVersion targetKeyAlgorithm,
|
||||||
const char *fullName, const char *masterPassword);
|
const char *fullName, const char *masterPassword);
|
||||||
|
|
||||||
#endif // _MPW_MARSHALL_UTIL_H
|
#endif // _MPW_MARSHAL_UTIL_H
|
||||||
@@ -21,11 +21,11 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "mpw-marshall.h"
|
#include "mpw-marshal.h"
|
||||||
#include "mpw-util.h"
|
#include "mpw-util.h"
|
||||||
#include "mpw-marshall-util.h"
|
#include "mpw-marshal-util.h"
|
||||||
|
|
||||||
MPMarshalledUser *mpw_marshall_user(
|
MPMarshalledUser *mpw_marshal_user(
|
||||||
const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) {
|
const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) {
|
||||||
|
|
||||||
MPMarshalledUser *user;
|
MPMarshalledUser *user;
|
||||||
@@ -33,8 +33,8 @@ MPMarshalledUser *mpw_marshall_user(
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
*user = (MPMarshalledUser){
|
*user = (MPMarshalledUser){
|
||||||
.fullName = strdup( fullName ),
|
.fullName = mpw_strdup( fullName ),
|
||||||
.masterPassword = strdup( masterPassword ),
|
.masterPassword = mpw_strdup( masterPassword ),
|
||||||
.algorithm = algorithmVersion,
|
.algorithm = algorithmVersion,
|
||||||
.redacted = true,
|
.redacted = true,
|
||||||
|
|
||||||
@@ -46,9 +46,9 @@ MPMarshalledUser *mpw_marshall_user(
|
|||||||
.sites = NULL,
|
.sites = NULL,
|
||||||
};
|
};
|
||||||
return user;
|
return user;
|
||||||
};
|
}
|
||||||
|
|
||||||
MPMarshalledSite *mpw_marshall_site(
|
MPMarshalledSite *mpw_marshal_site(
|
||||||
MPMarshalledUser *user, const char *siteName, const MPResultType resultType,
|
MPMarshalledUser *user, const char *siteName, const MPResultType resultType,
|
||||||
const MPCounterValue siteCounter, const MPAlgorithmVersion algorithmVersion) {
|
const MPCounterValue siteCounter, const MPAlgorithmVersion algorithmVersion) {
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ MPMarshalledSite *mpw_marshall_site(
|
|||||||
|
|
||||||
MPMarshalledSite *site = &user->sites[user->sites_count - 1];
|
MPMarshalledSite *site = &user->sites[user->sites_count - 1];
|
||||||
*site = (MPMarshalledSite){
|
*site = (MPMarshalledSite){
|
||||||
.name = strdup( siteName ),
|
.name = mpw_strdup( siteName ),
|
||||||
.content = NULL,
|
.content = NULL,
|
||||||
.type = resultType,
|
.type = resultType,
|
||||||
.counter = siteCounter,
|
.counter = siteCounter,
|
||||||
@@ -74,7 +74,7 @@ MPMarshalledSite *mpw_marshall_site(
|
|||||||
.questions = NULL,
|
.questions = NULL,
|
||||||
};
|
};
|
||||||
return site;
|
return site;
|
||||||
};
|
}
|
||||||
|
|
||||||
MPMarshalledQuestion *mpw_marshal_question(
|
MPMarshalledQuestion *mpw_marshal_question(
|
||||||
MPMarshalledSite *site, const char *keyword) {
|
MPMarshalledSite *site, const char *keyword) {
|
||||||
@@ -86,7 +86,7 @@ MPMarshalledQuestion *mpw_marshal_question(
|
|||||||
|
|
||||||
MPMarshalledQuestion *question = &site->questions[site->questions_count - 1];
|
MPMarshalledQuestion *question = &site->questions[site->questions_count - 1];
|
||||||
*question = (MPMarshalledQuestion){
|
*question = (MPMarshalledQuestion){
|
||||||
.keyword = strdup( keyword ),
|
.keyword = mpw_strdup( keyword ),
|
||||||
.content = NULL,
|
.content = NULL,
|
||||||
.type = MPResultTypeTemplatePhrase,
|
.type = MPResultTypeTemplatePhrase,
|
||||||
};
|
};
|
||||||
@@ -94,14 +94,14 @@ MPMarshalledQuestion *mpw_marshal_question(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool mpw_marshal_info_free(
|
bool mpw_marshal_info_free(
|
||||||
MPMarshallInfo **info) {
|
MPMarshalInfo **info) {
|
||||||
|
|
||||||
if (!info || !*info)
|
if (!info || !*info)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
success &= mpw_free_strings( &(*info)->fullName, &(*info)->keyID, NULL );
|
success &= mpw_free_strings( &(*info)->fullName, &(*info)->keyID, NULL );
|
||||||
success &= mpw_free( info, sizeof( MPMarshallInfo ) );
|
success &= mpw_free( info, sizeof( MPMarshalInfo ) );
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@@ -132,22 +132,22 @@ bool mpw_marshal_free(
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mpw_marshall_write_flat(
|
static bool mpw_marshal_write_flat(
|
||||||
char **out, const MPMarshalledUser *user, MPMarshallError *error) {
|
char **out, const MPMarshalledUser *user, MPMarshalError *error) {
|
||||||
|
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
||||||
if (!user->fullName || !strlen( user->fullName )) {
|
if (!user->fullName || !strlen( user->fullName )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." };
|
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!user->masterPassword || !strlen( user->masterPassword )) {
|
if (!user->masterPassword || !strlen( user->masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Missing master password." };
|
*error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Missing master password." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MPMasterKey masterKey = NULL;
|
MPMasterKey masterKey = NULL;
|
||||||
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
|
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ static bool mpw_marshall_write_flat(
|
|||||||
if (!user->redacted) {
|
if (!user->redacted) {
|
||||||
// Clear Text
|
// Clear Text
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,9 +198,9 @@ static bool mpw_marshall_write_flat(
|
|||||||
else {
|
else {
|
||||||
// Redacted
|
// Redacted
|
||||||
if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
|
if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
|
||||||
content = strdup( site->content );
|
content = mpw_strdup( site->content );
|
||||||
if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent ))
|
if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent ))
|
||||||
loginContent = strdup( site->loginContent );
|
loginContent = mpw_strdup( site->loginContent );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
|
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
|
||||||
@@ -211,27 +211,27 @@ static bool mpw_marshall_write_flat(
|
|||||||
}
|
}
|
||||||
mpw_free( &masterKey, MPMasterKeySize );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
|
|
||||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MPW_JSON
|
#if MPW_JSON
|
||||||
static bool mpw_marshall_write_json(
|
static bool mpw_marshal_write_json(
|
||||||
char **out, const MPMarshalledUser *user, MPMarshallError *error) {
|
char **out, const MPMarshalledUser *user, MPMarshalError *error) {
|
||||||
|
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
||||||
if (!user->fullName || !strlen( user->fullName )) {
|
if (!user->fullName || !strlen( user->fullName )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." };
|
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!user->masterPassword || !strlen( user->masterPassword )) {
|
if (!user->masterPassword || !strlen( user->masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Missing master password." };
|
*error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Missing master password." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MPMasterKey masterKey = NULL;
|
MPMasterKey masterKey = NULL;
|
||||||
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
|
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +272,7 @@ static bool mpw_marshall_write_json(
|
|||||||
if (!user->redacted) {
|
if (!user->redacted) {
|
||||||
// Clear Text
|
// Clear Text
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,9 +284,9 @@ static bool mpw_marshall_write_json(
|
|||||||
else {
|
else {
|
||||||
// Redacted
|
// Redacted
|
||||||
if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
|
if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
|
||||||
content = strdup( site->content );
|
content = mpw_strdup( site->content );
|
||||||
if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent ))
|
if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent ))
|
||||||
loginContent = strdup( site->loginContent );
|
loginContent = mpw_strdup( site->loginContent );
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object *json_site = json_object_new_object();
|
json_object *json_site = json_object_new_object();
|
||||||
@@ -340,32 +340,32 @@ static bool mpw_marshall_write_json(
|
|||||||
mpw_free( &masterKey, MPMasterKeySize );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
json_object_put( json_file );
|
json_object_put( json_file );
|
||||||
|
|
||||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool mpw_marshall_write(
|
bool mpw_marshal_write(
|
||||||
char **out, const MPMarshallFormat outFormat, const MPMarshalledUser *user, MPMarshallError *error) {
|
char **out, const MPMarshalFormat outFormat, const MPMarshalledUser *user, MPMarshalError *error) {
|
||||||
|
|
||||||
switch (outFormat) {
|
switch (outFormat) {
|
||||||
case MPMarshallFormatNone:
|
case MPMarshalFormatNone:
|
||||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||||
return false;
|
return false;
|
||||||
case MPMarshallFormatFlat:
|
case MPMarshalFormatFlat:
|
||||||
return mpw_marshall_write_flat( out, user, error );
|
return mpw_marshal_write_flat( out, user, error );
|
||||||
#if MPW_JSON
|
#if MPW_JSON
|
||||||
case MPMarshallFormatJSON:
|
case MPMarshalFormatJSON:
|
||||||
return mpw_marshall_write_json( out, user, error );
|
return mpw_marshal_write_json( out, user, error );
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) };
|
*error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mpw_marshall_read_flat_info(
|
static void mpw_marshal_read_flat_info(
|
||||||
const char *in, MPMarshallInfo *info) {
|
const char *in, MPMarshalInfo *info) {
|
||||||
|
|
||||||
info->algorithm = MPAlgorithmVersionCurrent;
|
info->algorithm = MPAlgorithmVersionCurrent;
|
||||||
|
|
||||||
@@ -397,9 +397,9 @@ static void mpw_marshall_read_flat_info(
|
|||||||
if (strcmp( headerName, "Algorithm" ) == 0)
|
if (strcmp( headerName, "Algorithm" ) == 0)
|
||||||
info->algorithm = (MPAlgorithmVersion)atoi( headerValue );
|
info->algorithm = (MPAlgorithmVersion)atoi( headerValue );
|
||||||
if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0)
|
if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0)
|
||||||
info->fullName = strdup( headerValue );
|
info->fullName = mpw_strdup( headerValue );
|
||||||
if (strcmp( headerName, "Key ID" ) == 0)
|
if (strcmp( headerName, "Key ID" ) == 0)
|
||||||
info->keyID = strdup( headerValue );
|
info->keyID = mpw_strdup( headerValue );
|
||||||
if (strcmp( headerName, "Passwords" ) == 0)
|
if (strcmp( headerName, "Passwords" ) == 0)
|
||||||
info->redacted = strcmp( headerValue, "VISIBLE" ) != 0;
|
info->redacted = strcmp( headerValue, "VISIBLE" ) != 0;
|
||||||
if (strcmp( headerName, "Date" ) == 0)
|
if (strcmp( headerName, "Date" ) == 0)
|
||||||
@@ -411,12 +411,12 @@ static void mpw_marshall_read_flat_info(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static MPMarshalledUser *mpw_marshall_read_flat(
|
static MPMarshalledUser *mpw_marshal_read_flat(
|
||||||
const char *in, const char *masterPassword, MPMarshallError *error) {
|
const char *in, const char *masterPassword, MPMarshalError *error) {
|
||||||
|
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
||||||
if (!in || !strlen( in )) {
|
if (!in || !strlen( in )) {
|
||||||
error->type = MPMarshallErrorStructure;
|
error->type = MPMarshalErrorStructure;
|
||||||
error->description = mpw_str( "No input data." );
|
error->description = mpw_str( "No input data." );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -455,23 +455,23 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" );
|
char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" );
|
||||||
char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
||||||
if (!headerName || !headerValue) {
|
if (!headerName || !headerValue) {
|
||||||
error->type = MPMarshallErrorStructure;
|
error->type = MPMarshalErrorStructure;
|
||||||
error->description = mpw_str( "Invalid header: %s", strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) );
|
error->description = mpw_str( "Invalid header: %s", mpw_strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp( headerName, "Format" ) == 0)
|
if (strcmp( headerName, "Format" ) == 0)
|
||||||
format = (unsigned int)atoi( headerValue );
|
format = (unsigned int)atoi( headerValue );
|
||||||
if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0)
|
if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0)
|
||||||
fullName = strdup( headerValue );
|
fullName = mpw_strdup( headerValue );
|
||||||
if (strcmp( headerName, "Avatar" ) == 0)
|
if (strcmp( headerName, "Avatar" ) == 0)
|
||||||
avatar = (unsigned int)atoi( headerValue );
|
avatar = (unsigned int)atoi( headerValue );
|
||||||
if (strcmp( headerName, "Key ID" ) == 0)
|
if (strcmp( headerName, "Key ID" ) == 0)
|
||||||
keyID = strdup( headerValue );
|
keyID = mpw_strdup( headerValue );
|
||||||
if (strcmp( headerName, "Algorithm" ) == 0) {
|
if (strcmp( headerName, "Algorithm" ) == 0) {
|
||||||
int value = atoi( headerValue );
|
int value = atoi( headerValue );
|
||||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user algorithm version: %s", headerValue ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user algorithm version: %s", headerValue ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
algorithm = (MPAlgorithmVersion)value;
|
algorithm = (MPAlgorithmVersion)value;
|
||||||
@@ -479,7 +479,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
if (strcmp( headerName, "Default Type" ) == 0) {
|
if (strcmp( headerName, "Default Type" ) == 0) {
|
||||||
int value = atoi( headerValue );
|
int value = atoi( headerValue );
|
||||||
if (!mpw_nameForType( (MPResultType)value )) {
|
if (!mpw_nameForType( (MPResultType)value )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user default type: %s", headerValue ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user default type: %s", headerValue ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
defaultType = (MPResultType)value;
|
defaultType = (MPResultType)value;
|
||||||
@@ -493,7 +493,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
if (!headerEnded)
|
if (!headerEnded)
|
||||||
continue;
|
continue;
|
||||||
if (!fullName) {
|
if (!fullName) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing header: Full Name" };
|
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing header: Full Name" };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (positionInLine >= endOfLine)
|
if (positionInLine >= endOfLine)
|
||||||
@@ -501,15 +501,15 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
|
if (keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Master password doesn't match key ID." };
|
*error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Master password doesn't match key ID." };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!(user = mpw_marshall_user( fullName, masterPassword, algorithm ))) {
|
if (!(user = mpw_marshal_user( fullName, masterPassword, algorithm ))) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new user." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new user." };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,11 +527,11 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
str_uses = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
str_uses = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
||||||
char *typeAndVersion = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
char *typeAndVersion = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
||||||
if (typeAndVersion) {
|
if (typeAndVersion) {
|
||||||
str_type = strdup( strtok( typeAndVersion, ":" ) );
|
str_type = mpw_strdup( strtok( typeAndVersion, ":" ) );
|
||||||
str_algorithm = strdup( strtok( NULL, "" ) );
|
str_algorithm = mpw_strdup( strtok( NULL, "" ) );
|
||||||
mpw_free_string( &typeAndVersion );
|
mpw_free_string( &typeAndVersion );
|
||||||
}
|
}
|
||||||
str_counter = strdup( "1" );
|
str_counter = mpw_strdup( "1" );
|
||||||
siteLoginName = NULL;
|
siteLoginName = NULL;
|
||||||
siteName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
siteName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
||||||
siteContent = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
siteContent = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
||||||
@@ -542,9 +542,9 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
str_uses = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
str_uses = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
||||||
char *typeAndVersionAndCounter = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
char *typeAndVersionAndCounter = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
||||||
if (typeAndVersionAndCounter) {
|
if (typeAndVersionAndCounter) {
|
||||||
str_type = strdup( strtok( typeAndVersionAndCounter, ":" ) );
|
str_type = mpw_strdup( strtok( typeAndVersionAndCounter, ":" ) );
|
||||||
str_algorithm = strdup( strtok( NULL, ":" ) );
|
str_algorithm = mpw_strdup( strtok( NULL, ":" ) );
|
||||||
str_counter = strdup( strtok( NULL, "" ) );
|
str_counter = mpw_strdup( strtok( NULL, "" ) );
|
||||||
mpw_free_string( &typeAndVersionAndCounter );
|
mpw_free_string( &typeAndVersionAndCounter );
|
||||||
}
|
}
|
||||||
siteLoginName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
siteLoginName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
||||||
@@ -553,7 +553,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unexpected import format: %u", format ) };
|
*error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unexpected import format: %u", format ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -561,31 +561,31 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
if (siteName && str_type && str_counter && str_algorithm && str_uses && str_lastUsed) {
|
if (siteName && str_type && str_counter && str_algorithm && str_uses && str_lastUsed) {
|
||||||
MPResultType siteType = (MPResultType)atoi( str_type );
|
MPResultType siteType = (MPResultType)atoi( str_type );
|
||||||
if (!mpw_nameForType( siteType )) {
|
if (!mpw_nameForType( siteType )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site type: %s: %s", siteName, str_type ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site type: %s: %s", siteName, str_type ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
long long int value = atoll( str_counter );
|
long long int value = atoll( str_counter );
|
||||||
if (value < MPCounterValueFirst || value > MPCounterValueLast) {
|
if (value < MPCounterValueFirst || value > MPCounterValueLast) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site counter: %s: %s", siteName, str_counter ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site counter: %s: %s", siteName, str_counter ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
MPCounterValue siteCounter = (MPCounterValue)value;
|
MPCounterValue siteCounter = (MPCounterValue)value;
|
||||||
value = atoll( str_algorithm );
|
value = atoll( str_algorithm );
|
||||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site algorithm: %s: %s", siteName, str_algorithm ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site algorithm: %s: %s", siteName, str_algorithm ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
|
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
|
||||||
time_t siteLastUsed = mpw_mktime( str_lastUsed );
|
time_t siteLastUsed = mpw_mktime( str_lastUsed );
|
||||||
if (!siteLastUsed) {
|
if (!siteLastUsed) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MPMarshalledSite *site = mpw_marshall_site(
|
MPMarshalledSite *site = mpw_marshal_site(
|
||||||
user, siteName, siteType, siteCounter, siteAlgorithm );
|
user, siteName, siteType, siteCounter, siteAlgorithm );
|
||||||
if (!site) {
|
if (!site) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new site." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new site." };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,7 +594,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
if (!user->redacted) {
|
if (!user->redacted) {
|
||||||
// Clear Text
|
// Clear Text
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,13 +608,13 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
else {
|
else {
|
||||||
// Redacted
|
// Redacted
|
||||||
if (siteContent && strlen( siteContent ))
|
if (siteContent && strlen( siteContent ))
|
||||||
site->content = strdup( siteContent );
|
site->content = mpw_strdup( siteContent );
|
||||||
if (siteLoginName && strlen( siteLoginName ))
|
if (siteLoginName && strlen( siteLoginName ))
|
||||||
site->loginContent = strdup( siteLoginName );
|
site->loginContent = mpw_strdup( siteLoginName );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
error->type = MPMarshallErrorMissing;
|
error->type = MPMarshalErrorMissing;
|
||||||
error->description = mpw_str(
|
error->description = mpw_str(
|
||||||
"Missing one of: lastUsed=%s, uses=%s, type=%s, version=%s, counter=%s, loginName=%s, siteName=%s",
|
"Missing one of: lastUsed=%s, uses=%s, type=%s, version=%s, counter=%s, loginName=%s, siteName=%s",
|
||||||
str_lastUsed, str_uses, str_type, str_algorithm, str_counter, siteLoginName, siteName );
|
str_lastUsed, str_uses, str_type, str_algorithm, str_counter, siteLoginName, siteName );
|
||||||
@@ -627,13 +627,13 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
mpw_free_strings( &fullName, &keyID, NULL );
|
mpw_free_strings( &fullName, &keyID, NULL );
|
||||||
mpw_free( &masterKey, MPMasterKeySize );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
|
|
||||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MPW_JSON
|
#if MPW_JSON
|
||||||
static void mpw_marshall_read_json_info(
|
static void mpw_marshal_read_json_info(
|
||||||
const char *in, MPMarshallInfo *info) {
|
const char *in, MPMarshalInfo *info) {
|
||||||
|
|
||||||
// Parse JSON.
|
// Parse JSON.
|
||||||
enum json_tokener_error json_error = json_tokener_success;
|
enum json_tokener_error json_error = json_tokener_success;
|
||||||
@@ -650,18 +650,18 @@ static void mpw_marshall_read_json_info(
|
|||||||
|
|
||||||
// Section: "user"
|
// Section: "user"
|
||||||
info->algorithm = (MPAlgorithmVersion)mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent );
|
info->algorithm = (MPAlgorithmVersion)mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent );
|
||||||
info->fullName = strdup( mpw_get_json_string( json_file, "user.full_name", NULL ) );
|
info->fullName = mpw_strdup( mpw_get_json_string( json_file, "user.full_name", NULL ) );
|
||||||
info->keyID = strdup( mpw_get_json_string( json_file, "user.key_id", NULL ) );
|
info->keyID = mpw_strdup( mpw_get_json_string( json_file, "user.key_id", NULL ) );
|
||||||
|
|
||||||
json_object_put( json_file );
|
json_object_put( json_file );
|
||||||
}
|
}
|
||||||
|
|
||||||
static MPMarshalledUser *mpw_marshall_read_json(
|
static MPMarshalledUser *mpw_marshal_read_json(
|
||||||
const char *in, const char *masterPassword, MPMarshallError *error) {
|
const char *in, const char *masterPassword, MPMarshalError *error) {
|
||||||
|
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
||||||
if (!in || !strlen( in )) {
|
if (!in || !strlen( in )) {
|
||||||
error->type = MPMarshallErrorStructure;
|
error->type = MPMarshalErrorStructure;
|
||||||
error->description = mpw_str( "No input data." );
|
error->description = mpw_str( "No input data." );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -670,7 +670,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
|||||||
enum json_tokener_error json_error = json_tokener_success;
|
enum json_tokener_error json_error = json_tokener_success;
|
||||||
json_object *json_file = json_tokener_parse_verbose( in, &json_error );
|
json_object *json_file = json_tokener_parse_verbose( in, &json_error );
|
||||||
if (!json_file || json_error != json_tokener_success) {
|
if (!json_file || json_error != json_tokener_success) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorStructure, mpw_str( "JSON error: %s", json_tokener_error_desc( json_error ) ) };
|
*error = (MPMarshalError){ MPMarshalErrorStructure, mpw_str( "JSON error: %s", json_tokener_error_desc( json_error ) ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,7 +682,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
|||||||
// Section: "export"
|
// Section: "export"
|
||||||
int64_t fileFormat = mpw_get_json_int( json_file, "export.format", 0 );
|
int64_t fileFormat = mpw_get_json_int( json_file, "export.format", 0 );
|
||||||
if (fileFormat < 1) {
|
if (fileFormat < 1) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported format: %u", fileFormat ) };
|
*error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported format: %u", fileFormat ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
bool fileRedacted = mpw_get_json_boolean( json_file, "export.redacted", true );
|
bool fileRedacted = mpw_get_json_boolean( json_file, "export.redacted", true );
|
||||||
@@ -694,34 +694,34 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
|||||||
const char *keyID = mpw_get_json_string( json_file, "user.key_id", NULL );
|
const char *keyID = mpw_get_json_string( json_file, "user.key_id", NULL );
|
||||||
int64_t value = mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent );
|
int64_t value = mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent );
|
||||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user algorithm version: %u", value ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user algorithm version: %u", value ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
MPAlgorithmVersion algorithm = (MPAlgorithmVersion)value;
|
MPAlgorithmVersion algorithm = (MPAlgorithmVersion)value;
|
||||||
MPResultType defaultType = (MPResultType)mpw_get_json_int( json_file, "user.default_type", MPResultTypeDefault );
|
MPResultType defaultType = (MPResultType)mpw_get_json_int( json_file, "user.default_type", MPResultTypeDefault );
|
||||||
if (!mpw_nameForType( defaultType )) {
|
if (!mpw_nameForType( defaultType )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user default type: %u", defaultType ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user default type: %u", defaultType ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
time_t lastUsed = mpw_mktime( str_lastUsed );
|
time_t lastUsed = mpw_mktime( str_lastUsed );
|
||||||
if (!lastUsed) {
|
if (!lastUsed) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user last used: %s", str_lastUsed ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user last used: %s", str_lastUsed ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!fullName || !strlen( fullName )) {
|
if (!fullName || !strlen( fullName )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing value for full name." };
|
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing value for full name." };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
|
if (keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Master password doesn't match key ID." };
|
*error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Master password doesn't match key ID." };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!(user = mpw_marshall_user( fullName, masterPassword, algorithm ))) {
|
if (!(user = mpw_marshal_user( fullName, masterPassword, algorithm ))) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new user." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new user." };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
user->redacted = fileRedacted;
|
user->redacted = fileRedacted;
|
||||||
@@ -736,18 +736,18 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
|||||||
const char *siteName = json_site.key;
|
const char *siteName = json_site.key;
|
||||||
value = mpw_get_json_int( json_site.val, "algorithm", (int32_t)user->algorithm );
|
value = mpw_get_json_int( json_site.val, "algorithm", (int32_t)user->algorithm );
|
||||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site algorithm version: %s: %d", siteName, value ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site algorithm version: %s: %d", siteName, value ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
|
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
|
||||||
MPResultType siteType = (MPResultType)mpw_get_json_int( json_site.val, "type", (int32_t)user->defaultType );
|
MPResultType siteType = (MPResultType)mpw_get_json_int( json_site.val, "type", (int32_t)user->defaultType );
|
||||||
if (!mpw_nameForType( siteType )) {
|
if (!mpw_nameForType( siteType )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site type: %s: %u", siteName, siteType ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site type: %s: %u", siteName, siteType ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
value = mpw_get_json_int( json_site.val, "counter", 1 );
|
value = mpw_get_json_int( json_site.val, "counter", 1 );
|
||||||
if (value < MPCounterValueFirst || value > MPCounterValueLast) {
|
if (value < MPCounterValueFirst || value > MPCounterValueLast) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site counter: %s: %d", siteName, value ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site counter: %s: %d", siteName, value ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
MPCounterValue siteCounter = (MPCounterValue)value;
|
MPCounterValue siteCounter = (MPCounterValue)value;
|
||||||
@@ -758,27 +758,27 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
|||||||
str_lastUsed = mpw_get_json_string( json_site.val, "last_used", NULL );
|
str_lastUsed = mpw_get_json_string( json_site.val, "last_used", NULL );
|
||||||
time_t siteLastUsed = mpw_mktime( str_lastUsed );
|
time_t siteLastUsed = mpw_mktime( str_lastUsed );
|
||||||
if (!siteLastUsed) {
|
if (!siteLastUsed) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed ) };
|
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object *json_site_mpw = mpw_get_json_section( json_site.val, "_ext_mpw" );
|
json_object *json_site_mpw = mpw_get_json_section( json_site.val, "_ext_mpw" );
|
||||||
const char *siteURL = mpw_get_json_string( json_site_mpw, "url", NULL );
|
const char *siteURL = mpw_get_json_string( json_site_mpw, "url", NULL );
|
||||||
|
|
||||||
MPMarshalledSite *site = mpw_marshall_site( user, siteName, siteType, siteCounter, siteAlgorithm );
|
MPMarshalledSite *site = mpw_marshal_site( user, siteName, siteType, siteCounter, siteAlgorithm );
|
||||||
if (!site) {
|
if (!site) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new site." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new site." };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
site->loginType = siteLoginType;
|
site->loginType = siteLoginType;
|
||||||
site->url = siteURL? strdup( siteURL ): NULL;
|
site->url = siteURL? mpw_strdup( siteURL ): NULL;
|
||||||
site->uses = siteUses;
|
site->uses = siteUses;
|
||||||
site->lastUsed = siteLastUsed;
|
site->lastUsed = siteLastUsed;
|
||||||
if (!user->redacted) {
|
if (!user->redacted) {
|
||||||
// Clear Text
|
// Clear Text
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -792,9 +792,9 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
|||||||
else {
|
else {
|
||||||
// Redacted
|
// Redacted
|
||||||
if (siteContent && strlen( siteContent ))
|
if (siteContent && strlen( siteContent ))
|
||||||
site->content = strdup( siteContent );
|
site->content = mpw_strdup( siteContent );
|
||||||
if (siteLoginName && strlen( siteLoginName ))
|
if (siteLoginName && strlen( siteLoginName ))
|
||||||
site->loginContent = strdup( siteLoginName );
|
site->loginContent = mpw_strdup( siteLoginName );
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object_iter json_site_question;
|
json_object_iter json_site_question;
|
||||||
@@ -813,32 +813,32 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
|||||||
else {
|
else {
|
||||||
// Redacted
|
// Redacted
|
||||||
if (answerContent && strlen( answerContent ))
|
if (answerContent && strlen( answerContent ))
|
||||||
question->content = strdup( answerContent );
|
question->content = mpw_strdup( answerContent );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
json_object_put( json_file );
|
json_object_put( json_file );
|
||||||
|
|
||||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MPMarshallInfo *mpw_marshall_read_info(
|
MPMarshalInfo *mpw_marshal_read_info(
|
||||||
const char *in) {
|
const char *in) {
|
||||||
|
|
||||||
MPMarshallInfo *info = malloc( sizeof( MPMarshallInfo ) );
|
MPMarshalInfo *info = malloc( sizeof( MPMarshalInfo ) );
|
||||||
*info = (MPMarshallInfo){ .format = MPMarshallFormatNone };
|
*info = (MPMarshalInfo){ .format = MPMarshalFormatNone };
|
||||||
|
|
||||||
if (in && strlen( in )) {
|
if (in && strlen( in )) {
|
||||||
if (in[0] == '#') {
|
if (in[0] == '#') {
|
||||||
*info = (MPMarshallInfo){ .format = MPMarshallFormatFlat };
|
*info = (MPMarshalInfo){ .format = MPMarshalFormatFlat };
|
||||||
mpw_marshall_read_flat_info( in, info );
|
mpw_marshal_read_flat_info( in, info );
|
||||||
}
|
}
|
||||||
else if (in[0] == '{') {
|
else if (in[0] == '{') {
|
||||||
*info = (MPMarshallInfo){ .format = MPMarshallFormatJSON };
|
*info = (MPMarshalInfo){ .format = MPMarshalFormatJSON };
|
||||||
#if MPW_JSON
|
#if MPW_JSON
|
||||||
mpw_marshall_read_json_info( in, info );
|
mpw_marshal_read_json_info( in, info );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -846,30 +846,30 @@ MPMarshallInfo *mpw_marshall_read_info(
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
MPMarshalledUser *mpw_marshall_read(
|
MPMarshalledUser *mpw_marshal_read(
|
||||||
const char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error) {
|
const char *in, const MPMarshalFormat inFormat, const char *masterPassword, MPMarshalError *error) {
|
||||||
|
|
||||||
switch (inFormat) {
|
switch (inFormat) {
|
||||||
case MPMarshallFormatNone:
|
case MPMarshalFormatNone:
|
||||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||||
return false;
|
return false;
|
||||||
case MPMarshallFormatFlat:
|
case MPMarshalFormatFlat:
|
||||||
return mpw_marshall_read_flat( in, masterPassword, error );
|
return mpw_marshal_read_flat( in, masterPassword, error );
|
||||||
#if MPW_JSON
|
#if MPW_JSON
|
||||||
case MPMarshallFormatJSON:
|
case MPMarshalFormatJSON:
|
||||||
return mpw_marshall_read_json( in, masterPassword, error );
|
return mpw_marshal_read_json( in, masterPassword, error );
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported input format: %u", inFormat ) };
|
*error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported input format: %u", inFormat ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MPMarshallFormat mpw_formatWithName(
|
const MPMarshalFormat mpw_formatWithName(
|
||||||
const char *formatName) {
|
const char *formatName) {
|
||||||
|
|
||||||
if (!formatName || !strlen( formatName ))
|
if (!formatName || !strlen( formatName ))
|
||||||
return MPMarshallFormatNone;
|
return MPMarshalFormatNone;
|
||||||
|
|
||||||
// Lower-case to standardize it.
|
// Lower-case to standardize it.
|
||||||
size_t stdFormatNameSize = strlen( formatName );
|
size_t stdFormatNameSize = strlen( formatName );
|
||||||
@@ -878,46 +878,46 @@ const MPMarshallFormat mpw_formatWithName(
|
|||||||
stdFormatName[c] = (char)tolower( formatName[c] );
|
stdFormatName[c] = (char)tolower( formatName[c] );
|
||||||
stdFormatName[stdFormatNameSize] = '\0';
|
stdFormatName[stdFormatNameSize] = '\0';
|
||||||
|
|
||||||
if (strncmp( mpw_nameForFormat( MPMarshallFormatNone ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
if (strncmp( mpw_nameForFormat( MPMarshalFormatNone ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
||||||
return MPMarshallFormatNone;
|
return MPMarshalFormatNone;
|
||||||
if (strncmp( mpw_nameForFormat( MPMarshallFormatFlat ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
if (strncmp( mpw_nameForFormat( MPMarshalFormatFlat ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
||||||
return MPMarshallFormatFlat;
|
return MPMarshalFormatFlat;
|
||||||
if (strncmp( mpw_nameForFormat( MPMarshallFormatJSON ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
if (strncmp( mpw_nameForFormat( MPMarshalFormatJSON ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
||||||
return MPMarshallFormatJSON;
|
return MPMarshalFormatJSON;
|
||||||
|
|
||||||
dbg( "Not a format name: %s\n", stdFormatName );
|
dbg( "Not a format name: %s", stdFormatName );
|
||||||
return (MPMarshallFormat)ERR;
|
return (MPMarshalFormat)ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *mpw_nameForFormat(
|
const char *mpw_nameForFormat(
|
||||||
const MPMarshallFormat format) {
|
const MPMarshalFormat format) {
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case MPMarshallFormatNone:
|
case MPMarshalFormatNone:
|
||||||
return "none";
|
return "none";
|
||||||
case MPMarshallFormatFlat:
|
case MPMarshalFormatFlat:
|
||||||
return "flat";
|
return "flat";
|
||||||
case MPMarshallFormatJSON:
|
case MPMarshalFormatJSON:
|
||||||
return "json";
|
return "json";
|
||||||
default: {
|
default: {
|
||||||
dbg( "Unknown format: %d\n", format );
|
dbg( "Unknown format: %d", format );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *mpw_marshall_format_extension(
|
const char *mpw_marshal_format_extension(
|
||||||
const MPMarshallFormat format) {
|
const MPMarshalFormat format) {
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case MPMarshallFormatNone:
|
case MPMarshalFormatNone:
|
||||||
return NULL;
|
return NULL;
|
||||||
case MPMarshallFormatFlat:
|
case MPMarshalFormatFlat:
|
||||||
return "mpsites";
|
return "mpsites";
|
||||||
case MPMarshallFormatJSON:
|
case MPMarshalFormatJSON:
|
||||||
return "mpsites.json";
|
return "mpsites.json";
|
||||||
default: {
|
default: {
|
||||||
dbg( "Unknown format: %d\n", format );
|
dbg( "Unknown format: %d", format );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef _MPW_MARSHALL_H
|
#ifndef _MPW_MARSHAL_H
|
||||||
#define _MPW_MARSHALL_H
|
#define _MPW_MARSHAL_H
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@@ -25,37 +25,41 @@
|
|||||||
|
|
||||||
//// Types.
|
//// Types.
|
||||||
|
|
||||||
typedef mpw_enum( unsigned int, MPMarshallFormat ) {
|
typedef mpw_enum( unsigned int, MPMarshalFormat ) {
|
||||||
/** Generate a key for authentication. */
|
/** Do not marshal. */
|
||||||
MPMarshallFormatNone,
|
MPMarshalFormatNone,
|
||||||
/** Generate a key for authentication. */
|
/** Marshal using the line-based plain-text format. */
|
||||||
MPMarshallFormatFlat,
|
MPMarshalFormatFlat,
|
||||||
/** Generate a name for identification. */
|
/** Marshal using the JSON structured format. */
|
||||||
MPMarshallFormatJSON,
|
MPMarshalFormatJSON,
|
||||||
|
|
||||||
MPMarshallFormatDefault = MPMarshallFormatJSON,
|
#if MPW_JSON
|
||||||
|
MPMarshalFormatDefault = MPMarshalFormatJSON,
|
||||||
|
#else
|
||||||
|
MPMarshalFormatDefault = MPMarshalFormatFlat,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef mpw_enum( unsigned int, MPMarshallErrorType ) {
|
typedef mpw_enum( unsigned int, MPMarshalErrorType ) {
|
||||||
/** The marshalling operation completed successfully. */
|
/** The marshalling operation completed successfully. */
|
||||||
MPMarshallSuccess,
|
MPMarshalSuccess,
|
||||||
/** An error in the structure of the marshall file interrupted marshalling. */
|
/** An error in the structure of the marshall file interrupted marshalling. */
|
||||||
MPMarshallErrorStructure,
|
MPMarshalErrorStructure,
|
||||||
/** The marshall file uses an unsupported format version. */
|
/** The marshall file uses an unsupported format version. */
|
||||||
MPMarshallErrorFormat,
|
MPMarshalErrorFormat,
|
||||||
/** A required value is missing or not specified. */
|
/** A required value is missing or not specified. */
|
||||||
MPMarshallErrorMissing,
|
MPMarshalErrorMissing,
|
||||||
/** The given master password is not valid. */
|
/** The given master password is not valid. */
|
||||||
MPMarshallErrorMasterPassword,
|
MPMarshalErrorMasterPassword,
|
||||||
/** An illegal value was specified. */
|
/** An illegal value was specified. */
|
||||||
MPMarshallErrorIllegal,
|
MPMarshalErrorIllegal,
|
||||||
/** An internal system error interrupted marshalling. */
|
/** An internal system error interrupted marshalling. */
|
||||||
MPMarshallErrorInternal,
|
MPMarshalErrorInternal,
|
||||||
};
|
};
|
||||||
typedef struct MPMarshallError {
|
typedef struct MPMarshalError {
|
||||||
MPMarshallErrorType type;
|
MPMarshalErrorType type;
|
||||||
const char *description;
|
const char *description;
|
||||||
} MPMarshallError;
|
} MPMarshalError;
|
||||||
|
|
||||||
typedef struct MPMarshalledQuestion {
|
typedef struct MPMarshalledQuestion {
|
||||||
const char *keyword;
|
const char *keyword;
|
||||||
@@ -95,34 +99,34 @@ typedef struct MPMarshalledUser {
|
|||||||
MPMarshalledSite *sites;
|
MPMarshalledSite *sites;
|
||||||
} MPMarshalledUser;
|
} MPMarshalledUser;
|
||||||
|
|
||||||
typedef struct MPMarshallInfo {
|
typedef struct MPMarshalInfo {
|
||||||
MPMarshallFormat format;
|
MPMarshalFormat format;
|
||||||
MPAlgorithmVersion algorithm;
|
MPAlgorithmVersion algorithm;
|
||||||
const char *fullName;
|
const char *fullName;
|
||||||
const char *keyID;
|
const char *keyID;
|
||||||
bool redacted;
|
bool redacted;
|
||||||
time_t date;
|
time_t date;
|
||||||
} MPMarshallInfo;
|
} MPMarshalInfo;
|
||||||
|
|
||||||
//// Marshalling.
|
//// Marshalling.
|
||||||
|
|
||||||
/** Write the user and all associated data out to the given output buffer using the given marshalling format. */
|
/** Write the user and all associated data out to the given output buffer using the given marshalling format. */
|
||||||
bool mpw_marshall_write(
|
bool mpw_marshal_write(
|
||||||
char **out, const MPMarshallFormat outFormat, const MPMarshalledUser *user, MPMarshallError *error);
|
char **out, const MPMarshalFormat outFormat, const MPMarshalledUser *user, MPMarshalError *error);
|
||||||
/** Try to read metadata on the sites in the input buffer. */
|
/** Try to read metadata on the sites in the input buffer. */
|
||||||
MPMarshallInfo *mpw_marshall_read_info(
|
MPMarshalInfo *mpw_marshal_read_info(
|
||||||
const char *in);
|
const char *in);
|
||||||
/** Unmarshall sites in the given input buffer by parsing it using the given marshalling format. */
|
/** Unmarshall sites in the given input buffer by parsing it using the given marshalling format. */
|
||||||
MPMarshalledUser *mpw_marshall_read(
|
MPMarshalledUser *mpw_marshal_read(
|
||||||
const char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error);
|
const char *in, const MPMarshalFormat inFormat, const char *masterPassword, MPMarshalError *error);
|
||||||
|
|
||||||
//// Utilities.
|
//// Utilities.
|
||||||
|
|
||||||
/** Create a new user object ready for marshalling. */
|
/** Create a new user object ready for marshalling. */
|
||||||
MPMarshalledUser *mpw_marshall_user(
|
MPMarshalledUser *mpw_marshal_user(
|
||||||
const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion);
|
const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion);
|
||||||
/** Create a new site attached to the given user object, ready for marshalling. */
|
/** Create a new site attached to the given user object, ready for marshalling. */
|
||||||
MPMarshalledSite *mpw_marshall_site(
|
MPMarshalledSite *mpw_marshal_site(
|
||||||
MPMarshalledUser *user,
|
MPMarshalledUser *user,
|
||||||
const char *siteName, const MPResultType resultType, const MPCounterValue siteCounter, const MPAlgorithmVersion algorithmVersion);
|
const char *siteName, const MPResultType resultType, const MPCounterValue siteCounter, const MPAlgorithmVersion algorithmVersion);
|
||||||
/** Create a new question attached to the given site object, ready for marshalling. */
|
/** Create a new question attached to the given site object, ready for marshalling. */
|
||||||
@@ -130,7 +134,7 @@ MPMarshalledQuestion *mpw_marshal_question(
|
|||||||
MPMarshalledSite *site, const char *keyword);
|
MPMarshalledSite *site, const char *keyword);
|
||||||
/** Free the given user object and all associated data. */
|
/** Free the given user object and all associated data. */
|
||||||
bool mpw_marshal_info_free(
|
bool mpw_marshal_info_free(
|
||||||
MPMarshallInfo **info);
|
MPMarshalInfo **info);
|
||||||
bool mpw_marshal_free(
|
bool mpw_marshal_free(
|
||||||
MPMarshalledUser **user);
|
MPMarshalledUser **user);
|
||||||
|
|
||||||
@@ -139,17 +143,17 @@ bool mpw_marshal_free(
|
|||||||
/**
|
/**
|
||||||
* @return The purpose represented by the given name.
|
* @return The purpose represented by the given name.
|
||||||
*/
|
*/
|
||||||
const MPMarshallFormat mpw_formatWithName(
|
const MPMarshalFormat mpw_formatWithName(
|
||||||
const char *formatName);
|
const char *formatName);
|
||||||
/**
|
/**
|
||||||
* @return The standard name for the given purpose.
|
* @return The standard name for the given purpose.
|
||||||
*/
|
*/
|
||||||
const char *mpw_nameForFormat(
|
const char *mpw_nameForFormat(
|
||||||
const MPMarshallFormat format);
|
const MPMarshalFormat format);
|
||||||
/**
|
/**
|
||||||
* @return The file extension that's recommended for files that use the given marshalling format.
|
* @return The file extension that's recommended for files that use the given marshalling format.
|
||||||
*/
|
*/
|
||||||
const char *mpw_marshall_format_extension(
|
const char *mpw_marshal_format_extension(
|
||||||
const MPMarshallFormat format);
|
const MPMarshalFormat format);
|
||||||
|
|
||||||
#endif // _MPW_MARSHALL_H
|
#endif // _MPW_MARSHAL_H
|
||||||
@@ -22,6 +22,9 @@
|
|||||||
#include "mpw-types.h"
|
#include "mpw-types.h"
|
||||||
#include "mpw-util.h"
|
#include "mpw-util.h"
|
||||||
|
|
||||||
|
const size_t MPMasterKeySize = 64;
|
||||||
|
const size_t MPSiteKeySize = 256 / 8; // Size of HMAC-SHA-256
|
||||||
|
|
||||||
const MPResultType mpw_typeWithName(const char *typeName) {
|
const MPResultType mpw_typeWithName(const char *typeName) {
|
||||||
|
|
||||||
// Find what password type is represented by the type letter.
|
// Find what password type is represented by the type letter.
|
||||||
@@ -40,22 +43,21 @@ const MPResultType mpw_typeWithName(const char *typeName) {
|
|||||||
return MPResultTypeTemplatePIN;
|
return MPResultTypeTemplatePIN;
|
||||||
if ('n' == typeName[0])
|
if ('n' == typeName[0])
|
||||||
return MPResultTypeTemplateName;
|
return MPResultTypeTemplateName;
|
||||||
|
if ('p' == typeName[0])
|
||||||
|
return MPResultTypeTemplatePhrase;
|
||||||
if ('P' == typeName[0])
|
if ('P' == typeName[0])
|
||||||
return MPResultTypeStatefulPersonal;
|
return MPResultTypeStatefulPersonal;
|
||||||
if ('D' == typeName[0])
|
if ('D' == typeName[0])
|
||||||
return MPResultTypeStatefulDevice;
|
return MPResultTypeStatefulDevice;
|
||||||
if ('k' == typeName[0])
|
if ('K' == typeName[0])
|
||||||
return MPResultTypeDeriveKey;
|
return MPResultTypeDeriveKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lower-case and trim optionally leading "Generated" string from typeName to standardize it.
|
// Lower-case typeName to standardize it.
|
||||||
size_t stdTypeNameOffset = 0;
|
|
||||||
size_t stdTypeNameSize = strlen( typeName );
|
size_t stdTypeNameSize = strlen( typeName );
|
||||||
if (strstr( typeName, "Generated" ) == typeName)
|
|
||||||
stdTypeNameSize -= (stdTypeNameOffset = strlen( "Generated" ));
|
|
||||||
char stdTypeName[stdTypeNameSize + 1];
|
char stdTypeName[stdTypeNameSize + 1];
|
||||||
for (size_t c = 0; c < stdTypeNameSize; ++c)
|
for (size_t c = 0; c < stdTypeNameSize; ++c)
|
||||||
stdTypeName[c] = (char)tolower( typeName[c + stdTypeNameOffset] );
|
stdTypeName[c] = (char)tolower( typeName[c] );
|
||||||
stdTypeName[stdTypeNameSize] = '\0';
|
stdTypeName[stdTypeNameSize] = '\0';
|
||||||
|
|
||||||
// Find what password type is represented by the type name.
|
// Find what password type is represented by the type name.
|
||||||
@@ -82,7 +84,7 @@ const MPResultType mpw_typeWithName(const char *typeName) {
|
|||||||
if (strncmp( mpw_nameForType( MPResultTypeDeriveKey ), stdTypeName, strlen( stdTypeName ) ) == 0)
|
if (strncmp( mpw_nameForType( MPResultTypeDeriveKey ), stdTypeName, strlen( stdTypeName ) ) == 0)
|
||||||
return MPResultTypeDeriveKey;
|
return MPResultTypeDeriveKey;
|
||||||
|
|
||||||
dbg( "Not a generated type name: %s\n", stdTypeName );
|
dbg( "Not a generated type name: %s", stdTypeName );
|
||||||
return (MPResultType)ERR;
|
return (MPResultType)ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +114,7 @@ const char *mpw_nameForType(MPResultType resultType) {
|
|||||||
case MPResultTypeDeriveKey:
|
case MPResultTypeDeriveKey:
|
||||||
return "key";
|
return "key";
|
||||||
default: {
|
default: {
|
||||||
dbg( "Unknown password type: %d\n", resultType );
|
dbg( "Unknown password type: %d", resultType );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,7 +123,7 @@ const char *mpw_nameForType(MPResultType resultType) {
|
|||||||
const char **mpw_templatesForType(MPResultType type, size_t *count) {
|
const char **mpw_templatesForType(MPResultType type, size_t *count) {
|
||||||
|
|
||||||
if (!(type & MPResultTypeClassTemplate)) {
|
if (!(type & MPResultTypeClassTemplate)) {
|
||||||
dbg( "Not a generated type: %d\n", type );
|
dbg( "Not a generated type: %d", type );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +159,7 @@ const char **mpw_templatesForType(MPResultType type, size_t *count) {
|
|||||||
return mpw_alloc_array( count, const char *,
|
return mpw_alloc_array( count, const char *,
|
||||||
"cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" );
|
"cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" );
|
||||||
default: {
|
default: {
|
||||||
dbg( "Unknown generated type: %d\n", type );
|
dbg( "Unknown generated type: %d", type );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,7 +191,7 @@ const MPKeyPurpose mpw_purposeWithName(const char *purposeName) {
|
|||||||
if (strncmp( mpw_nameForPurpose( MPKeyPurposeRecovery ), stdPurposeName, strlen( stdPurposeName ) ) == 0)
|
if (strncmp( mpw_nameForPurpose( MPKeyPurposeRecovery ), stdPurposeName, strlen( stdPurposeName ) ) == 0)
|
||||||
return MPKeyPurposeRecovery;
|
return MPKeyPurposeRecovery;
|
||||||
|
|
||||||
dbg( "Not a purpose name: %s\n", stdPurposeName );
|
dbg( "Not a purpose name: %s", stdPurposeName );
|
||||||
return (MPKeyPurpose)ERR;
|
return (MPKeyPurpose)ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +205,7 @@ const char *mpw_nameForPurpose(MPKeyPurpose purpose) {
|
|||||||
case MPKeyPurposeRecovery:
|
case MPKeyPurposeRecovery:
|
||||||
return "recovery";
|
return "recovery";
|
||||||
default: {
|
default: {
|
||||||
dbg( "Unknown purpose: %d\n", purpose );
|
dbg( "Unknown purpose: %d", purpose );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,7 +221,7 @@ const char *mpw_scopeForPurpose(MPKeyPurpose purpose) {
|
|||||||
case MPKeyPurposeRecovery:
|
case MPKeyPurposeRecovery:
|
||||||
return "com.lyndir.masterpassword.answer";
|
return "com.lyndir.masterpassword.answer";
|
||||||
default: {
|
default: {
|
||||||
dbg( "Unknown purpose: %d\n", purpose );
|
dbg( "Unknown purpose: %d", purpose );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,7 +251,7 @@ const char *mpw_charactersInClass(char characterClass) {
|
|||||||
case ' ':
|
case ' ':
|
||||||
return " ";
|
return " ";
|
||||||
default: {
|
default: {
|
||||||
dbg( "Unknown character class: %c\n", characterClass );
|
dbg( "Unknown character class: %c", characterClass );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,8 @@
|
|||||||
|
|
||||||
//// Types.
|
//// Types.
|
||||||
|
|
||||||
#define MPMasterKeySize 64 /* bytes */
|
extern const size_t MPMasterKeySize, MPSiteKeySize; /* bytes */
|
||||||
typedef const uint8_t *MPMasterKey;
|
typedef const uint8_t *MPMasterKey, *MPSiteKey;
|
||||||
#define MPSiteKeySize (256 / 8) /* bytes */ // Size of HMAC-SHA-256
|
|
||||||
typedef const uint8_t *MPSiteKey;
|
|
||||||
typedef const char *MPKeyID;
|
typedef const char *MPKeyID;
|
||||||
|
|
||||||
typedef mpw_enum( uint8_t, MPKeyPurpose ) {
|
typedef mpw_enum( uint8_t, MPKeyPurpose ) {
|
||||||
@@ -72,30 +70,30 @@ typedef mpw_enum( uint16_t, MPSiteFeature ) {
|
|||||||
|
|
||||||
// bit 0-3 | MPResultTypeClass | MPSiteFeature
|
// bit 0-3 | MPResultTypeClass | MPSiteFeature
|
||||||
typedef mpw_enum( uint32_t, MPResultType ) {
|
typedef mpw_enum( uint32_t, MPResultType ) {
|
||||||
/** pg^VMAUBk5x3p%HP%i4= */
|
/** 16: pg^VMAUBk5x3p%HP%i4= */
|
||||||
MPResultTypeTemplateMaximum = 0x0 | MPResultTypeClassTemplate | 0x0,
|
MPResultTypeTemplateMaximum = 0x0 | MPResultTypeClassTemplate | 0x0,
|
||||||
/** BiroYena8:Kixa */
|
/** 17: BiroYena8:Kixa */
|
||||||
MPResultTypeTemplateLong = 0x1 | MPResultTypeClassTemplate | 0x0,
|
MPResultTypeTemplateLong = 0x1 | MPResultTypeClassTemplate | 0x0,
|
||||||
/** BirSuj0- */
|
/** 18: BirSuj0- */
|
||||||
MPResultTypeTemplateMedium = 0x2 | MPResultTypeClassTemplate | 0x0,
|
MPResultTypeTemplateMedium = 0x2 | MPResultTypeClassTemplate | 0x0,
|
||||||
/** pO98MoD0 */
|
/** 19: Bir8 */
|
||||||
MPResultTypeTemplateBasic = 0x4 | MPResultTypeClassTemplate | 0x0,
|
|
||||||
/** Bir8 */
|
|
||||||
MPResultTypeTemplateShort = 0x3 | MPResultTypeClassTemplate | 0x0,
|
MPResultTypeTemplateShort = 0x3 | MPResultTypeClassTemplate | 0x0,
|
||||||
/** 2798 */
|
/** 20: pO98MoD0 */
|
||||||
|
MPResultTypeTemplateBasic = 0x4 | MPResultTypeClassTemplate | 0x0,
|
||||||
|
/** 21: 2798 */
|
||||||
MPResultTypeTemplatePIN = 0x5 | MPResultTypeClassTemplate | 0x0,
|
MPResultTypeTemplatePIN = 0x5 | MPResultTypeClassTemplate | 0x0,
|
||||||
/** birsujano */
|
/** 30: birsujano */
|
||||||
MPResultTypeTemplateName = 0xE | MPResultTypeClassTemplate | 0x0,
|
MPResultTypeTemplateName = 0xE | MPResultTypeClassTemplate | 0x0,
|
||||||
/** bir yennoquce fefi */
|
/** 31: bir yennoquce fefi */
|
||||||
MPResultTypeTemplatePhrase = 0xF | MPResultTypeClassTemplate | 0x0,
|
MPResultTypeTemplatePhrase = 0xF | MPResultTypeClassTemplate | 0x0,
|
||||||
|
|
||||||
/** Custom saved password. */
|
/** 1056: Custom saved password. */
|
||||||
MPResultTypeStatefulPersonal = 0x0 | MPResultTypeClassStateful | MPSiteFeatureExportContent,
|
MPResultTypeStatefulPersonal = 0x0 | MPResultTypeClassStateful | MPSiteFeatureExportContent,
|
||||||
/** Custom saved password that should not be exported from the device. */
|
/** 2081: Custom saved password that should not be exported from the device. */
|
||||||
MPResultTypeStatefulDevice = 0x1 | MPResultTypeClassStateful | MPSiteFeatureDevicePrivate,
|
MPResultTypeStatefulDevice = 0x1 | MPResultTypeClassStateful | MPSiteFeatureDevicePrivate,
|
||||||
|
|
||||||
/** Derive a unique binary key. */
|
/** 4160: Derive a unique binary key. */
|
||||||
MPResultTypeDeriveKey = 0x0 | MPResultTypeClassDerive | MPSiteFeatureAlternative,
|
MPResultTypeDeriveKey = 0x0 | MPResultTypeClassDerive | MPSiteFeatureAlternative,
|
||||||
|
|
||||||
MPResultTypeDefault = MPResultTypeTemplateLong,
|
MPResultTypeDefault = MPResultTypeTemplateLong,
|
||||||
};
|
};
|
||||||
@@ -111,6 +109,28 @@ typedef mpw_enum ( uint32_t, MPCounterValue ) {
|
|||||||
MPCounterValueLast = UINT32_MAX,
|
MPCounterValueLast = UINT32_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** These colours are compatible with the original ANSI SGR. */
|
||||||
|
typedef mpw_enum( uint8_t, MPIdenticonColor ) {
|
||||||
|
MPIdenticonColorRed = 1,
|
||||||
|
MPIdenticonColorGreen,
|
||||||
|
MPIdenticonColorYellow,
|
||||||
|
MPIdenticonColorBlue,
|
||||||
|
MPIdenticonColorMagenta,
|
||||||
|
MPIdenticonColorCyan,
|
||||||
|
MPIdenticonColorWhite,
|
||||||
|
|
||||||
|
MPIdenticonColorFirst = MPIdenticonColorRed,
|
||||||
|
MPIdenticonColorLast = MPIdenticonColorWhite,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *leftArm;
|
||||||
|
const char *body;
|
||||||
|
const char *rightArm;
|
||||||
|
const char *accessory;
|
||||||
|
MPIdenticonColor color;
|
||||||
|
} MPIdenticon;
|
||||||
|
|
||||||
//// Type utilities.
|
//// Type utilities.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,18 +20,15 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#if MPW_COLOR
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <curses.h>
|
|
||||||
#include <term.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MPW_CPERCIVA
|
#if MPW_CPERCIVA
|
||||||
#include <scrypt/crypto_scrypt.h>
|
#include <scrypt/crypto_scrypt.h>
|
||||||
#include <scrypt/sha256.h>
|
#include <scrypt/sha256.h>
|
||||||
#elif MPW_SODIUM
|
#elif MPW_SODIUM
|
||||||
#include "sodium.h"
|
#include "sodium.h"
|
||||||
#endif
|
#endif
|
||||||
|
#define AES_ECB 0
|
||||||
|
#define AES_CBC 1
|
||||||
|
#include "aes.h"
|
||||||
|
|
||||||
#include "mpw-util.h"
|
#include "mpw-util.h"
|
||||||
|
|
||||||
@@ -134,31 +131,38 @@ bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __mpw_free(const void **buffer, const size_t bufferSize) {
|
void mpw_zero(void *buffer, size_t bufferSize) {
|
||||||
|
|
||||||
|
uint8_t *b = buffer;
|
||||||
|
for (; bufferSize > 0; --bufferSize)
|
||||||
|
*b++ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __mpw_free(void **buffer, const size_t bufferSize) {
|
||||||
|
|
||||||
if (!buffer || !*buffer)
|
if (!buffer || !*buffer)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
memset( (void *)*buffer, 0, bufferSize );
|
mpw_zero( *buffer, bufferSize );
|
||||||
free( (void *)*buffer );
|
free( *buffer );
|
||||||
*buffer = NULL;
|
*buffer = NULL;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __mpw_free_string(const char **string) {
|
bool __mpw_free_string(char **string) {
|
||||||
|
|
||||||
return *string && __mpw_free( (const void **)string, strlen( *string ) );
|
return *string && __mpw_free( (void **)string, strlen( *string ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __mpw_free_strings(const char **strings, ...) {
|
bool __mpw_free_strings(char **strings, ...) {
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start( args, strings );
|
va_start( args, strings );
|
||||||
success &= mpw_free_string( strings );
|
success &= mpw_free_string( strings );
|
||||||
for (const char **string; (string = va_arg( args, const char ** ));)
|
for (char **string; (string = va_arg( args, char ** ));)
|
||||||
success &= mpw_free_string( string );
|
success &= mpw_free_string( string );
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
@@ -207,7 +211,6 @@ uint8_t const *mpw_kdf_blake2b(const size_t subkeySize, const uint8_t *key, cons
|
|||||||
#if MPW_SODIUM
|
#if MPW_SODIUM
|
||||||
if (keySize < crypto_generichash_blake2b_KEYBYTES_MIN || keySize > crypto_generichash_blake2b_KEYBYTES_MAX ||
|
if (keySize < crypto_generichash_blake2b_KEYBYTES_MIN || keySize > crypto_generichash_blake2b_KEYBYTES_MAX ||
|
||||||
subkeySize < crypto_generichash_blake2b_KEYBYTES_MIN || subkeySize > crypto_generichash_blake2b_KEYBYTES_MAX ||
|
subkeySize < crypto_generichash_blake2b_KEYBYTES_MIN || subkeySize > crypto_generichash_blake2b_KEYBYTES_MAX ||
|
||||||
contextSize < crypto_generichash_blake2b_BYTES_MIN || contextSize > crypto_generichash_blake2b_BYTES_MAX ||
|
|
||||||
(personal && strlen( personal ) > crypto_generichash_blake2b_PERSONALBYTES)) {
|
(personal && strlen( personal ) > crypto_generichash_blake2b_PERSONALBYTES)) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
free( subkey );
|
free( subkey );
|
||||||
@@ -215,12 +218,12 @@ uint8_t const *mpw_kdf_blake2b(const size_t subkeySize, const uint8_t *key, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t saltBuf[crypto_generichash_blake2b_SALTBYTES];
|
uint8_t saltBuf[crypto_generichash_blake2b_SALTBYTES];
|
||||||
bzero( saltBuf, sizeof saltBuf );
|
mpw_zero( saltBuf, sizeof saltBuf );
|
||||||
if (id)
|
if (id)
|
||||||
mpw_uint64( id, saltBuf );
|
mpw_uint64( id, saltBuf );
|
||||||
|
|
||||||
uint8_t personalBuf[crypto_generichash_blake2b_PERSONALBYTES];
|
uint8_t personalBuf[crypto_generichash_blake2b_PERSONALBYTES];
|
||||||
bzero( personalBuf, sizeof saltBuf );
|
mpw_zero( personalBuf, sizeof personalBuf );
|
||||||
if (personal && strlen( personal ))
|
if (personal && strlen( personal ))
|
||||||
memcpy( personalBuf, personal, strlen( personal ) );
|
memcpy( personalBuf, personal, strlen( personal ) );
|
||||||
|
|
||||||
@@ -265,50 +268,47 @@ uint8_t const *mpw_hash_hmac_sha256(const uint8_t *key, const size_t keySize, co
|
|||||||
return mac;
|
return mac;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t keySize, const uint8_t *buf, const size_t bufSize) {
|
// We do our best to not fail on odd buf's, eg. non-padded cipher texts.
|
||||||
|
static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t keySize, const uint8_t *buf, size_t *bufSize) {
|
||||||
|
|
||||||
#if MPW_SODIUM
|
if (!key || keySize < 16 || !*bufSize)
|
||||||
if (!key || keySize < crypto_stream_KEYBYTES)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
uint8_t nonce[crypto_stream_NONCEBYTES];
|
// IV = zero
|
||||||
bzero( (void *)nonce, sizeof( nonce ) );
|
uint8_t iv[16];
|
||||||
|
mpw_zero( iv, sizeof iv );
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
// Add PKCS#7 padding
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
uint32_t aesSize = ((uint32_t)*bufSize + 15 / 16) * 16; // round up to block size.
|
||||||
#pragma clang diagnostic push
|
if (encrypt && !(*bufSize % 16)) // add pad block if plain text fits block size.
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
encrypt += 16;
|
||||||
if (encrypt) {
|
uint8_t aesBuf[aesSize];
|
||||||
uint8_t *const cipherBuf = malloc( bufSize );
|
memcpy( aesBuf, buf, *bufSize );
|
||||||
if (crypto_stream_aes128ctr_xor( cipherBuf, buf, bufSize, nonce, key ) != 0) {
|
memset( aesBuf + *bufSize, aesSize - *bufSize, aesSize - *bufSize );
|
||||||
mpw_free( &cipherBuf, bufSize );
|
uint8_t *resultBuf = malloc( aesSize );
|
||||||
return NULL;
|
|
||||||
}
|
if (encrypt)
|
||||||
return cipherBuf;
|
AES_CBC_encrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
|
||||||
}
|
else
|
||||||
else {
|
AES_CBC_decrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
|
||||||
uint8_t *const plainBuf = malloc( bufSize );
|
mpw_zero( aesBuf, aesSize );
|
||||||
if (crypto_stream_aes128ctr( plainBuf, bufSize, nonce, key ) != 0) {
|
mpw_zero( iv, 16 );
|
||||||
mpw_free( &plainBuf, bufSize );
|
|
||||||
return NULL;
|
// Truncate PKCS#7 padding
|
||||||
}
|
if (encrypt)
|
||||||
for (size_t c = 0; c < bufSize; ++c)
|
*bufSize = aesSize;
|
||||||
plainBuf[c] = buf[c] ^ plainBuf[c];
|
else if (*bufSize % 16 == 0 && resultBuf[aesSize - 1] < 16)
|
||||||
return plainBuf;
|
*bufSize -= resultBuf[aesSize - 1];
|
||||||
}
|
|
||||||
#pragma clang diagnostic pop
|
return resultBuf;
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#else
|
|
||||||
#error No crypto support for mpw_aes.
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t const *mpw_aes_encrypt(const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, const size_t bufSize) {
|
uint8_t const *mpw_aes_encrypt(const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, size_t *bufSize) {
|
||||||
|
|
||||||
return mpw_aes( true, key, keySize, plainBuf, bufSize );
|
return mpw_aes( true, key, keySize, plainBuf, bufSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t const *mpw_aes_decrypt(const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, const size_t bufSize) {
|
uint8_t const *mpw_aes_decrypt(const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, size_t *bufSize) {
|
||||||
|
|
||||||
return mpw_aes( false, key, keySize, cipherBuf, bufSize );
|
return mpw_aes( false, key, keySize, cipherBuf, bufSize );
|
||||||
}
|
}
|
||||||
@@ -338,7 +338,7 @@ const char *mpw_hotp(const uint8_t *key, size_t keySize, uint64_t movingFactor,
|
|||||||
|
|
||||||
// Render the OTP as `digits` decimal digits.
|
// Render the OTP as `digits` decimal digits.
|
||||||
otp %= (int)pow(10, digits);
|
otp %= (int)pow(10, digits);
|
||||||
return strdup( mpw_str( "%0*d", digits, otp ) );
|
return mpw_strdup( mpw_str( "%0*d", digits, otp ) );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -438,99 +438,6 @@ const char *mpw_hex_l(uint32_t number) {
|
|||||||
return mpw_hex( &buf, sizeof( buf ) );
|
return mpw_hex( &buf, sizeof( buf ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MPW_COLOR
|
|
||||||
static char *str_tputs;
|
|
||||||
static int str_tputs_cursor;
|
|
||||||
static const int str_tputs_max = 256;
|
|
||||||
|
|
||||||
static bool mpw_setupterm() {
|
|
||||||
|
|
||||||
if (!isatty( STDERR_FILENO ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
static bool termsetup;
|
|
||||||
if (!termsetup) {
|
|
||||||
int errret;
|
|
||||||
if (!(termsetup = (setupterm( NULL, STDERR_FILENO, &errret ) == OK))) {
|
|
||||||
wrn( "Terminal doesn't support color (setupterm errret %d).\n", errret );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mpw_tputc(int c) {
|
|
||||||
|
|
||||||
if (++str_tputs_cursor < str_tputs_max) {
|
|
||||||
str_tputs[str_tputs_cursor] = (char)c;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *mpw_tputs(const char *str, int affcnt) {
|
|
||||||
|
|
||||||
if (str_tputs)
|
|
||||||
mpw_free( &str_tputs, str_tputs_max );
|
|
||||||
str_tputs = calloc( str_tputs_max, sizeof( char ) );
|
|
||||||
str_tputs_cursor = -1;
|
|
||||||
|
|
||||||
char *result = tputs( str, affcnt, mpw_tputc ) == ERR? NULL: strndup( str_tputs, str_tputs_max );
|
|
||||||
if (str_tputs)
|
|
||||||
mpw_free( &str_tputs, str_tputs_max );
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char *mpw_identicon(const char *fullName, const char *masterPassword) {
|
|
||||||
|
|
||||||
const char *leftArm[] = { "╔", "╚", "╰", "═" };
|
|
||||||
const char *rightArm[] = { "╗", "╝", "╯", "═" };
|
|
||||||
const char *body[] = { "█", "░", "▒", "▓", "☺", "☻" };
|
|
||||||
const char *accessory[] = {
|
|
||||||
"◈", "◎", "◐", "◑", "◒", "◓", "☀", "☁", "☂", "☃", "☄", "★", "☆", "☎", "☏", "⎈", "⌂", "☘", "☢", "☣",
|
|
||||||
"☕", "⌚", "⌛", "⏰", "⚡", "⛄", "⛅", "☔", "♔", "♕", "♖", "♗", "♘", "♙", "♚", "♛", "♜", "♝", "♞", "♟",
|
|
||||||
"♨", "♩", "♪", "♫", "⚐", "⚑", "⚔", "⚖", "⚙", "⚠", "⌘", "⏎", "✄", "✆", "✈", "✉", "✌"
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t *identiconSeed = mpw_hash_hmac_sha256(
|
|
||||||
(const uint8_t *)masterPassword, strlen( masterPassword ),
|
|
||||||
(const uint8_t *)fullName, strlen( fullName ) );
|
|
||||||
if (!identiconSeed)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
char *colorString, *resetString;
|
|
||||||
#ifdef MPW_COLOR
|
|
||||||
if (mpw_setupterm()) {
|
|
||||||
uint8_t colorIdentifier = (uint8_t)(identiconSeed[4] % 7 + 1);
|
|
||||||
colorString = mpw_tputs( tparm( tgetstr( "AF", NULL ), colorIdentifier ), 1 );
|
|
||||||
resetString = mpw_tputs( tgetstr( "me", NULL ), 1 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
colorString = calloc( 1, sizeof( char ) );
|
|
||||||
resetString = calloc( 1, sizeof( char ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
char *identicon = (char *)calloc( 256, sizeof( char ) );
|
|
||||||
snprintf( identicon, 256, "%s%s%s%s%s%s",
|
|
||||||
colorString,
|
|
||||||
leftArm[identiconSeed[0] % (sizeof( leftArm ) / sizeof( leftArm[0] ))],
|
|
||||||
body[identiconSeed[1] % (sizeof( body ) / sizeof( body[0] ))],
|
|
||||||
rightArm[identiconSeed[2] % (sizeof( rightArm ) / sizeof( rightArm[0] ))],
|
|
||||||
accessory[identiconSeed[3] % (sizeof( accessory ) / sizeof( accessory[0] ))],
|
|
||||||
resetString );
|
|
||||||
|
|
||||||
mpw_free( &identiconSeed, 32 );
|
|
||||||
mpw_free_strings( &colorString, &resetString, NULL );
|
|
||||||
return identicon;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the amount of bytes used by UTF-8 to encode a single character that starts with the given byte.
|
* @return the amount of bytes used by UTF-8 to encode a single character that starts with the given byte.
|
||||||
*/
|
*/
|
||||||
@@ -561,3 +468,31 @@ const size_t mpw_utf8_strlen(const char *utf8String) {
|
|||||||
|
|
||||||
return charlen;
|
return charlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *mpw_strdup(const char *src) {
|
||||||
|
|
||||||
|
if (!src)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size_t len = strlen( src );
|
||||||
|
char *dst = malloc( len + 1 );
|
||||||
|
memcpy( dst, src, len );
|
||||||
|
dst[len] = '\0';
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *mpw_strndup(const char *src, size_t max) {
|
||||||
|
|
||||||
|
if (!src)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size_t len = 0;
|
||||||
|
for (; len < max && src[len] != '\0'; ++len);
|
||||||
|
|
||||||
|
char *dst = malloc( len + 1 );
|
||||||
|
memcpy( dst, src, len );
|
||||||
|
dst[len] = '\0';
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,49 +25,44 @@
|
|||||||
#include "mpw-types.h"
|
#include "mpw-types.h"
|
||||||
|
|
||||||
//// Logging.
|
//// Logging.
|
||||||
|
extern int mpw_verbosity;
|
||||||
|
|
||||||
|
#ifndef mpw_log_do
|
||||||
|
#define mpw_log_do(level, format, ...) \
|
||||||
|
fprintf( stderr, format "\n", ##__VA_ARGS__ )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef mpw_log
|
||||||
|
#define mpw_log(level, ...) ({ \
|
||||||
|
if (mpw_verbosity >= level) { \
|
||||||
|
mpw_log_do( level, ##__VA_ARGS__ ); \
|
||||||
|
}; })
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef trc
|
#ifndef trc
|
||||||
extern int mpw_verbosity;
|
|
||||||
#define trc_level 3
|
|
||||||
/** Logging internal state. */
|
/** Logging internal state. */
|
||||||
#define trc(...) ({ \
|
#define trc_level 3
|
||||||
if (mpw_verbosity >= trc_level) \
|
#define trc(...) mpw_log( trc_level, ##__VA_ARGS__ )
|
||||||
fprintf( stderr, __VA_ARGS__ ); })
|
|
||||||
#endif
|
|
||||||
#ifndef dbg
|
|
||||||
#define dbg_level 2
|
|
||||||
/** Logging state and events interesting when investigating issues. */
|
/** Logging state and events interesting when investigating issues. */
|
||||||
#define dbg(...) ({ \
|
#define dbg_level 2
|
||||||
if (mpw_verbosity >= dbg_level) \
|
#define dbg(...) mpw_log( dbg_level, ##__VA_ARGS__ )
|
||||||
fprintf( stderr, __VA_ARGS__ ); })
|
|
||||||
#endif
|
|
||||||
#ifndef inf
|
|
||||||
#define inf_level 1
|
|
||||||
/** User messages. */
|
/** User messages. */
|
||||||
#define inf(...) ({ \
|
#define inf_level 1
|
||||||
if (mpw_verbosity >= inf_level) \
|
#define inf(...) mpw_log( inf_level, ##__VA_ARGS__ )
|
||||||
fprintf( stderr, __VA_ARGS__ ); })
|
|
||||||
#endif
|
|
||||||
#ifndef wrn
|
|
||||||
#define wrn_level 0
|
|
||||||
/** Recoverable issues and user suggestions. */
|
/** Recoverable issues and user suggestions. */
|
||||||
#define wrn(...) ({ \
|
#define wrn_level 0
|
||||||
if (mpw_verbosity >= wrn_level) \
|
#define wrn(...) mpw_log( wrn_level, ##__VA_ARGS__ )
|
||||||
fprintf( stderr, __VA_ARGS__ ); })
|
|
||||||
#endif
|
|
||||||
#ifndef err
|
|
||||||
#define err_level -1
|
|
||||||
/** Unrecoverable issues. */
|
/** Unrecoverable issues. */
|
||||||
#define err(...) ({ \
|
#define err_level -1
|
||||||
if (mpw_verbosity >= err_level) \
|
#define err(...) mpw_log( err_level, ##__VA_ARGS__ )
|
||||||
fprintf( stderr, __VA_ARGS__ ); })
|
|
||||||
#endif
|
|
||||||
#ifndef ftl
|
|
||||||
#define ftl_level -2
|
|
||||||
/** Issues that lead to abortion. */
|
/** Issues that lead to abortion. */
|
||||||
#define ftl(...) ({ \
|
#define ftl_level -2
|
||||||
if (mpw_verbosity >= ftl_level) \
|
#define ftl(...) mpw_log( ftl_level, ##__VA_ARGS__ )
|
||||||
fprintf( stderr, __VA_ARGS__ ); })
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef min
|
#ifndef min
|
||||||
@@ -136,23 +131,25 @@ bool mpw_push_int(
|
|||||||
* @return true if successful, false if reallocation failed.
|
* @return true if successful, false if reallocation failed.
|
||||||
*/
|
*/
|
||||||
#define mpw_realloc(buffer, bufferSize, deltaSize) \
|
#define mpw_realloc(buffer, bufferSize, deltaSize) \
|
||||||
({ typeof(buffer) _b = buffer; const void *__b = *_b; (void)__b; __mpw_realloc( (const void **)_b, bufferSize, deltaSize ); })
|
({ __typeof__(buffer) _b = buffer; const void *__b = *_b; (void)__b; __mpw_realloc( (const void **)_b, bufferSize, deltaSize ); })
|
||||||
bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSize);
|
bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSize);
|
||||||
|
void mpw_zero(
|
||||||
|
void *buffer, size_t bufferSize);
|
||||||
/** Free a buffer after zero'ing its contents, then set the reference to NULL. */
|
/** Free a buffer after zero'ing its contents, then set the reference to NULL. */
|
||||||
#define mpw_free(buffer, bufferSize) \
|
#define mpw_free(buffer, bufferSize) \
|
||||||
({ typeof(buffer) _b = buffer; const void *__b = *_b; (void)__b; __mpw_free( (const void **)_b, bufferSize ); })
|
({ __typeof__(buffer) _b = buffer; const void *__b = *_b; (void)__b; __mpw_free( (void **)_b, bufferSize ); })
|
||||||
bool __mpw_free(
|
bool __mpw_free(
|
||||||
const void **buffer, const size_t bufferSize);
|
void **buffer, size_t bufferSize);
|
||||||
/** Free a string after zero'ing its contents, then set the reference to NULL. */
|
/** Free a string after zero'ing its contents, then set the reference to NULL. */
|
||||||
#define mpw_free_string(string) \
|
#define mpw_free_string(string) \
|
||||||
({ typeof(string) _s = string; const char *__s = *_s; (void)__s; __mpw_free_string( (const char **)_s ); })
|
({ __typeof__(string) _s = string; const char *__s = *_s; (void)__s; __mpw_free_string( (char **)_s ); })
|
||||||
bool __mpw_free_string(
|
bool __mpw_free_string(
|
||||||
const char **string);
|
char **string);
|
||||||
/** Free strings after zero'ing their contents, then set the references to NULL. Terminate the va_list with NULL. */
|
/** Free strings after zero'ing their contents, then set the references to NULL. Terminate the va_list with NULL. */
|
||||||
#define mpw_free_strings(strings, ...) \
|
#define mpw_free_strings(strings, ...) \
|
||||||
({ typeof(strings) _s = strings; const char *__s = *_s; (void)__s; __mpw_free_strings( (const char **)_s, __VA_ARGS__ ); })
|
({ __typeof__(strings) _s = strings; const char *__s = *_s; (void)__s; __mpw_free_strings( (char **)_s, __VA_ARGS__ ); })
|
||||||
bool __mpw_free_strings(
|
bool __mpw_free_strings(
|
||||||
const char **strings, ...);
|
char **strings, ...);
|
||||||
|
|
||||||
//// Cryptographic functions.
|
//// Cryptographic functions.
|
||||||
|
|
||||||
@@ -173,11 +170,11 @@ uint8_t const *mpw_hash_hmac_sha256(
|
|||||||
/** Encrypt a plainBuf with the given key using AES-128-CBC.
|
/** Encrypt a plainBuf with the given key using AES-128-CBC.
|
||||||
* @return A new bufSize allocated buffer containing the cipherBuf. */
|
* @return A new bufSize allocated buffer containing the cipherBuf. */
|
||||||
uint8_t const *mpw_aes_encrypt(
|
uint8_t const *mpw_aes_encrypt(
|
||||||
const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, const size_t bufSize);
|
const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, size_t *bufSize);
|
||||||
/** Decrypt a cipherBuf with the given key using AES-128-CBC.
|
/** Decrypt a cipherBuf with the given key using AES-128-CBC.
|
||||||
* @return A new bufSize allocated buffer containing the plainBuf. */
|
* @return A new bufSize allocated buffer containing the plainBuf. */
|
||||||
uint8_t const *mpw_aes_decrypt(
|
uint8_t const *mpw_aes_decrypt(
|
||||||
const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, const size_t bufSize);
|
const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, size_t *bufSize);
|
||||||
/** Calculate an OTP using RFC-4226.
|
/** Calculate an OTP using RFC-4226.
|
||||||
* @return A newly allocated string containing exactly `digits` decimal OTP digits. */
|
* @return A newly allocated string containing exactly `digits` decimal OTP digits. */
|
||||||
#if UNUSED
|
#if UNUSED
|
||||||
@@ -201,13 +198,14 @@ MPKeyID mpw_id_buf(const void *buf, size_t length);
|
|||||||
/** Compare two fingerprints for equality.
|
/** Compare two fingerprints for equality.
|
||||||
* @return true if the buffers represent identical fingerprints. */
|
* @return true if the buffers represent identical fingerprints. */
|
||||||
bool mpw_id_buf_equals(const char *id1, const char *id2);
|
bool mpw_id_buf_equals(const char *id1, const char *id2);
|
||||||
/** Encode a visual fingerprint for a user.
|
|
||||||
* @return A newly allocated string. */
|
|
||||||
const char *mpw_identicon(const char *fullName, const char *masterPassword);
|
|
||||||
|
|
||||||
//// String utilities.
|
//// String utilities.
|
||||||
|
|
||||||
/** @return The amount of display characters in the given UTF-8 string. */
|
/** @return The amount of display characters in the given UTF-8 string. */
|
||||||
const size_t mpw_utf8_strlen(const char *utf8String);
|
const size_t mpw_utf8_strlen(const char *utf8String);
|
||||||
|
/** Drop-in for POSIX strdup(3). */
|
||||||
|
char *mpw_strdup(const char *src);
|
||||||
|
/** Drop-in for POSIX strndup(3). */
|
||||||
|
char *mpw_strndup(const char *src, size_t max);
|
||||||
|
|
||||||
#endif // _MPW_UTIL_H
|
#endif // _MPW_UTIL_H
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ plugins {
|
|||||||
description = 'Master Password Algorithm Implementation'
|
description = 'Master Password Algorithm Implementation'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile (group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.6-p10') {
|
compile (group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.6-p11') {
|
||||||
exclude( module: 'joda-time' )
|
exclude( module: 'joda-time' )
|
||||||
}
|
}
|
||||||
|
compile group: 'com.lyndir.lhunath.opal', name: 'opal-crypto', version: '1.6-p11'
|
||||||
|
|
||||||
compile group: 'com.lambdaworks', name: 'scrypt', version: '1.4.0'
|
compile group: 'com.lambdaworks', name: 'scrypt', version: '1.4.0'
|
||||||
compile group: 'org.jetbrains', name: 'annotations', version: '13.0'
|
compile group: 'org.jetbrains', name: 'annotations', version: '13.0'
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.lyndir.lhunath.opal</groupId>
|
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||||
<artifactId>opal-system</artifactId>
|
<artifactId>opal-system</artifactId>
|
||||||
<version>1.6-p9</version>
|
<version>1.6-p11</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>joda-time</groupId>
|
<groupId>joda-time</groupId>
|
||||||
@@ -31,6 +31,11 @@
|
|||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||||
|
<artifactId>opal-crypto</artifactId>
|
||||||
|
<version>1.6-p11</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- EXTERNAL DEPENDENCIES -->
|
<!-- EXTERNAL DEPENDENCIES -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
|
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
|
||||||
|
import com.lyndir.lhunath.opal.system.MessageDigests;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see MPMasterKey.Version
|
||||||
|
*/
|
||||||
|
public interface MPAlgorithm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: validity for the time-based rolling counter.
|
||||||
|
*/
|
||||||
|
int mpw_otp_window = 5 * 60 /* s */;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Key ID hash.
|
||||||
|
*/
|
||||||
|
MessageDigests mpw_hash = MessageDigests.SHA256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Site digest.
|
||||||
|
*/
|
||||||
|
MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Platform-agnostic byte order.
|
||||||
|
*/
|
||||||
|
ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Input character encoding.
|
||||||
|
*/
|
||||||
|
Charset mpw_charset = Charsets.UTF_8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Master key size (byte).
|
||||||
|
*/
|
||||||
|
int mpw_dkLen = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scrypt: Parallelization parameter.
|
||||||
|
*/
|
||||||
|
int scrypt_p = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scrypt: Memory cost parameter.
|
||||||
|
*/
|
||||||
|
int scrypt_r = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scrypt: CPU cost parameter.
|
||||||
|
*/
|
||||||
|
int scrypt_N = 32768;
|
||||||
|
|
||||||
|
MPMasterKey.Version getAlgorithmVersion();
|
||||||
|
|
||||||
|
byte[] masterKey(String fullName, char[] masterPassword);
|
||||||
|
|
||||||
|
byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable String keyContext);
|
||||||
|
|
||||||
|
String siteResult(byte[] masterKey, final byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
|
||||||
|
|
||||||
|
String sitePasswordFromTemplate(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||||
|
|
||||||
|
String sitePasswordFromCrypt(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||||
|
|
||||||
|
String sitePasswordFromDerive(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||||
|
|
||||||
|
String siteState(byte[] masterKey, final byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable String keyContext, MPResultType resultType, String resultParam);
|
||||||
|
}
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
import static com.lyndir.masterpassword.MPUtils.*;
|
||||||
|
|
||||||
|
import com.google.common.base.*;
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
|
import com.lambdaworks.crypto.SCrypt;
|
||||||
|
import com.lyndir.lhunath.opal.crypto.CryptUtils;
|
||||||
|
import com.lyndir.lhunath.opal.system.*;
|
||||||
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
|
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
||||||
|
import java.nio.*;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.crypto.BadPaddingException;
|
||||||
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 2014-08-30
|
||||||
|
* @see MPMasterKey.Version#V0
|
||||||
|
*/
|
||||||
|
public class MPAlgorithmV0 implements MPAlgorithm {
|
||||||
|
|
||||||
|
protected final Logger logger = Logger.get( getClass() );
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPMasterKey.Version getAlgorithmVersion() {
|
||||||
|
|
||||||
|
return MPMasterKey.Version.V0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
||||||
|
|
||||||
|
byte[] fullNameBytes = fullName.getBytes( mpw_charset );
|
||||||
|
byte[] fullNameLengthBytes = bytesForInt( fullName.length() );
|
||||||
|
|
||||||
|
String keyScope = MPKeyPurpose.Authentication.getScope();
|
||||||
|
logger.trc( "keyScope: %s", keyScope );
|
||||||
|
|
||||||
|
// Calculate the master key salt.
|
||||||
|
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
||||||
|
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
||||||
|
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
||||||
|
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
||||||
|
|
||||||
|
// Calculate the master key.
|
||||||
|
logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
|
||||||
|
scrypt_N, scrypt_r, scrypt_p );
|
||||||
|
byte[] masterPasswordBytes = bytesForChars( masterPassword );
|
||||||
|
byte[] masterKey = scrypt( masterKeySalt, masterPasswordBytes );
|
||||||
|
Arrays.fill( masterKeySalt, (byte) 0 );
|
||||||
|
Arrays.fill( masterPasswordBytes, (byte) 0 );
|
||||||
|
logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
|
||||||
|
|
||||||
|
return masterKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
||||||
|
try {
|
||||||
|
//if (isAllowNative())
|
||||||
|
return SCrypt.scrypt( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
|
||||||
|
//else
|
||||||
|
// return SCrypt.scryptJ( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
|
||||||
|
}
|
||||||
|
catch (final GeneralSecurityException e) {
|
||||||
|
throw logger.bug( e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable final String keyContext) {
|
||||||
|
|
||||||
|
String keyScope = keyPurpose.getScope();
|
||||||
|
logger.trc( "keyScope: %s", keyScope );
|
||||||
|
|
||||||
|
// OTP counter value.
|
||||||
|
if (siteCounter.longValue() == 0)
|
||||||
|
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (mpw_otp_window * 1000)) * mpw_otp_window );
|
||||||
|
|
||||||
|
// Calculate the site seed.
|
||||||
|
byte[] siteNameBytes = siteName.getBytes( mpw_charset );
|
||||||
|
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
|
||||||
|
byte[] siteCounterBytes = bytesForInt( siteCounter );
|
||||||
|
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( mpw_charset );
|
||||||
|
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: bytesForInt( keyContextBytes.length );
|
||||||
|
logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
|
||||||
|
keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
|
||||||
|
(keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
|
||||||
|
|
||||||
|
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
||||||
|
if (keyContextBytes != null)
|
||||||
|
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
|
||||||
|
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
|
||||||
|
|
||||||
|
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
|
||||||
|
byte[] sitePasswordSeedBytes = mpw_digest.of( masterKey, sitePasswordInfo );
|
||||||
|
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
|
||||||
|
|
||||||
|
return sitePasswordSeedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
|
||||||
|
final MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
|
||||||
|
|
||||||
|
switch (resultType.getTypeClass()) {
|
||||||
|
case Template:
|
||||||
|
return sitePasswordFromTemplate( masterKey, siteKey, resultType, resultParam );
|
||||||
|
case Stateful:
|
||||||
|
return sitePasswordFromCrypt( masterKey, siteKey, resultType, resultParam );
|
||||||
|
case Derive:
|
||||||
|
return sitePasswordFromDerive( masterKey, siteKey, resultType, resultParam );
|
||||||
|
}
|
||||||
|
|
||||||
|
throw logger.bug( "Unsupported result type class: %s", resultType.getTypeClass() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
||||||
|
@Nullable final String resultParam) {
|
||||||
|
|
||||||
|
int[] _siteKey = new int[siteKey.length];
|
||||||
|
for (int i = 0; i < siteKey.length; ++i) {
|
||||||
|
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder );
|
||||||
|
Arrays.fill( buf.array(), (byte) ((siteKey[i] > 0)? 0x00: 0xFF) );
|
||||||
|
buf.position( 2 );
|
||||||
|
buf.put( siteKey[i] ).rewind();
|
||||||
|
_siteKey[i] = buf.getInt() & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the template.
|
||||||
|
Preconditions.checkState( _siteKey.length > 0 );
|
||||||
|
int templateIndex = _siteKey[0];
|
||||||
|
MPTemplate template = resultType.getTemplateAtRollingIndex( templateIndex );
|
||||||
|
logger.trc( "template: %d => %s", templateIndex, template.getTemplateString() );
|
||||||
|
|
||||||
|
// Encode the password from the seed using the template.
|
||||||
|
StringBuilder password = new StringBuilder( template.length() );
|
||||||
|
for (int i = 0; i < template.length(); ++i) {
|
||||||
|
int characterIndex = _siteKey[i + 1];
|
||||||
|
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
|
||||||
|
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
|
||||||
|
logger.trc( " - class: %c, index: %5d (0x%2H) => character: %c",
|
||||||
|
characterClass.getIdentifier(), characterIndex, _siteKey[i + 1], passwordCharacter );
|
||||||
|
|
||||||
|
password.append( passwordCharacter );
|
||||||
|
}
|
||||||
|
logger.trc( " => password: %s", password );
|
||||||
|
|
||||||
|
return password.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
||||||
|
@Nullable final String resultParam) {
|
||||||
|
|
||||||
|
Preconditions.checkNotNull( resultParam );
|
||||||
|
Preconditions.checkArgument( !resultParam.isEmpty() );
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Base64-decode
|
||||||
|
byte[] cipherBuf = CryptUtils.decodeBase64( resultParam );
|
||||||
|
logger.trc( "b64 decoded: %d bytes = %s", cipherBuf.length, CodeUtils.encodeHex( cipherBuf ) );
|
||||||
|
|
||||||
|
// Decrypt
|
||||||
|
byte[] plainBuf = CryptUtils.decrypt( cipherBuf, masterKey, true );
|
||||||
|
String plainText = mpw_charset.decode( ByteBuffer.wrap( plainBuf ) ).toString();
|
||||||
|
logger.trc( "decrypted -> plainText: %d bytes = %s = %s", plainBuf.length, plainText, CodeUtils.encodeHex( plainBuf ) );
|
||||||
|
|
||||||
|
return plainText;
|
||||||
|
}
|
||||||
|
catch (final BadPaddingException e) {
|
||||||
|
throw Throwables.propagate( e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
||||||
|
@Nullable final String resultParam) {
|
||||||
|
|
||||||
|
if (resultType == MPResultType.DeriveKey) {
|
||||||
|
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
|
||||||
|
if (resultParamInt == 0)
|
||||||
|
resultParamInt = 512;
|
||||||
|
if ((resultParamInt < 128) || (resultParamInt > 512) || ((resultParamInt % 8) != 0))
|
||||||
|
throw logger.bug( "Parameter is not a valid key size (should be 128 - 512): %s", resultParam );
|
||||||
|
int keySize = resultParamInt / 8;
|
||||||
|
logger.trc( "keySize: %d", keySize );
|
||||||
|
|
||||||
|
// Derive key
|
||||||
|
byte[] resultKey = null; // TODO: mpw_kdf_blake2b( keySize, siteKey, MPSiteKeySize, NULL, 0, 0, NULL );
|
||||||
|
if (resultKey == null)
|
||||||
|
throw logger.bug( "Could not derive result key." );
|
||||||
|
|
||||||
|
// Base64-encode
|
||||||
|
String b64Key = Verify.verifyNotNull( CryptUtils.encodeBase64( resultKey ) );
|
||||||
|
logger.trc( "b64 encoded -> key: %s", b64Key );
|
||||||
|
|
||||||
|
return b64Key;
|
||||||
|
} else
|
||||||
|
throw logger.bug( "Unsupported derived password type: %s", resultType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
|
||||||
|
final MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable final String keyContext, final MPResultType resultType, final String resultParam) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Encrypt
|
||||||
|
byte[] cipherBuf = CryptUtils.encrypt( resultParam.getBytes( mpw_charset ), masterKey, true );
|
||||||
|
logger.trc( "cipherBuf: %d bytes = %s", cipherBuf.length, CodeUtils.encodeHex( cipherBuf ) );
|
||||||
|
|
||||||
|
// Base64-encode
|
||||||
|
String cipherText = Verify.verifyNotNull( CryptUtils.encodeBase64( cipherBuf ) );
|
||||||
|
logger.trc( "b64 encoded -> cipherText: %s", cipherText );
|
||||||
|
|
||||||
|
return cipherText;
|
||||||
|
}
|
||||||
|
catch (final IllegalBlockSizeException e) {
|
||||||
|
throw logger.bug( e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see MPMasterKey.Version#V1
|
||||||
|
*
|
||||||
|
* @author lhunath, 2014-08-30
|
||||||
|
*/
|
||||||
|
public class MPAlgorithmV1 extends MPAlgorithmV0 {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPMasterKey.Version getAlgorithmVersion() {
|
||||||
|
|
||||||
|
return MPMasterKey.Version.V1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
||||||
|
|
||||||
|
// Determine the template.
|
||||||
|
Preconditions.checkState( siteKey.length > 0 );
|
||||||
|
int templateIndex = siteKey[0] & 0xFF; // Convert to unsigned int.
|
||||||
|
MPTemplate template = resultType.getTemplateAtRollingIndex( templateIndex );
|
||||||
|
logger.trc( "template: %d => %s", templateIndex, template.getTemplateString() );
|
||||||
|
|
||||||
|
// Encode the password from the seed using the template.
|
||||||
|
StringBuilder password = new StringBuilder( template.length() );
|
||||||
|
for (int i = 0; i < template.length(); ++i) {
|
||||||
|
int characterIndex = siteKey[i + 1] & 0xFF; // Convert to unsigned int.
|
||||||
|
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
|
||||||
|
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
|
||||||
|
logger.trc( " - class: %c, index: %3d (0x%2H) => character: %c",
|
||||||
|
characterClass.getIdentifier(), characterIndex, siteKey[i + 1], passwordCharacter );
|
||||||
|
|
||||||
|
password.append( passwordCharacter );
|
||||||
|
}
|
||||||
|
logger.trc( " => password: %s", password );
|
||||||
|
|
||||||
|
return password.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
import static com.lyndir.masterpassword.MPUtils.*;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see MPMasterKey.Version#V2
|
||||||
|
*
|
||||||
|
* @author lhunath, 2014-08-30
|
||||||
|
*/
|
||||||
|
public class MPAlgorithmV2 extends MPAlgorithmV1 {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPMasterKey.Version getAlgorithmVersion() {
|
||||||
|
|
||||||
|
return MPMasterKey.Version.V2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable final String keyContext) {
|
||||||
|
|
||||||
|
String keyScope = keyPurpose.getScope();
|
||||||
|
logger.trc( "keyScope: %s", keyScope );
|
||||||
|
|
||||||
|
// OTP counter value.
|
||||||
|
if (siteCounter.longValue() == 0)
|
||||||
|
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPAlgorithm.mpw_otp_window * 1000)) * MPAlgorithm.mpw_otp_window );
|
||||||
|
|
||||||
|
// Calculate the site seed.
|
||||||
|
byte[] siteNameBytes = siteName.getBytes( MPAlgorithm.mpw_charset );
|
||||||
|
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
|
||||||
|
byte[] siteCounterBytes = bytesForInt( siteCounter );
|
||||||
|
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( MPAlgorithm.mpw_charset );
|
||||||
|
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: bytesForInt( keyContextBytes.length );
|
||||||
|
logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
|
||||||
|
keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
|
||||||
|
(keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
|
||||||
|
|
||||||
|
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( MPAlgorithm.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
||||||
|
if (keyContextBytes != null)
|
||||||
|
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
|
||||||
|
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
|
||||||
|
|
||||||
|
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
|
||||||
|
byte[] sitePasswordSeedBytes = MPAlgorithm.mpw_digest.of( masterKey, sitePasswordInfo );
|
||||||
|
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
|
||||||
|
|
||||||
|
return sitePasswordSeedBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
import static com.lyndir.masterpassword.MPUtils.*;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see MPMasterKey.Version#V3
|
||||||
|
*
|
||||||
|
* @author lhunath, 2014-08-30
|
||||||
|
*/
|
||||||
|
public class MPAlgorithmV3 extends MPAlgorithmV2 {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPMasterKey.Version getAlgorithmVersion() {
|
||||||
|
|
||||||
|
return MPMasterKey.Version.V3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
||||||
|
|
||||||
|
byte[] fullNameBytes = fullName.getBytes( MPAlgorithm.mpw_charset );
|
||||||
|
byte[] fullNameLengthBytes = MPUtils.bytesForInt( fullNameBytes.length );
|
||||||
|
|
||||||
|
String keyScope = MPKeyPurpose.Authentication.getScope();
|
||||||
|
logger.trc( "keyScope: %s", keyScope );
|
||||||
|
|
||||||
|
// Calculate the master key salt.
|
||||||
|
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
||||||
|
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
||||||
|
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( MPAlgorithm.mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
||||||
|
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
||||||
|
|
||||||
|
// Calculate the master key.
|
||||||
|
logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
|
||||||
|
MPAlgorithm.scrypt_N, MPAlgorithm.scrypt_r, MPAlgorithm.scrypt_p );
|
||||||
|
byte[] mpBytes = bytesForChars( masterPassword );
|
||||||
|
byte[] masterKey = scrypt( masterKeySalt, mpBytes );
|
||||||
|
Arrays.fill( masterKeySalt, (byte) 0 );
|
||||||
|
Arrays.fill( mpBytes, (byte) 0 );
|
||||||
|
logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
|
||||||
|
|
||||||
|
return masterKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,11 +18,8 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword;
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
|
import org.joda.time.format.ISODateTimeFormat;
|
||||||
import com.lyndir.lhunath.opal.system.MessageDigests;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,68 +29,18 @@ public final class MPConstant {
|
|||||||
|
|
||||||
/* Environment */
|
/* Environment */
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: default user name if one is not provided.
|
|
||||||
*/
|
|
||||||
public static final String env_userName = "MP_USERNAME";
|
|
||||||
/**
|
|
||||||
* mpw: default site type if one is not provided.
|
|
||||||
*
|
|
||||||
* @see MPSiteType#forOption(String)
|
|
||||||
*/
|
|
||||||
public static final String env_siteType = "MP_SITETYPE";
|
|
||||||
/**
|
|
||||||
* mpw: default site counter value if one is not provided.
|
|
||||||
*/
|
|
||||||
public static final String env_siteCounter = "MP_SITECOUNTER";
|
|
||||||
/**
|
/**
|
||||||
* mpw: default path to look for run configuration files if the platform default is not desired.
|
* mpw: default path to look for run configuration files if the platform default is not desired.
|
||||||
*/
|
*/
|
||||||
public static final String env_rcDir = "MP_RCDIR";
|
public static final String env_rcDir = "MPW_RCDIR";
|
||||||
/**
|
/**
|
||||||
* mpw: permit automatic update checks.
|
* mpw: permit automatic update checks.
|
||||||
*/
|
*/
|
||||||
public static final String env_checkUpdates = "MP_CHECKUPDATES";
|
public static final String env_checkUpdates = "MPW_CHECKUPDATES";
|
||||||
|
|
||||||
/* Algorithm */
|
/* Algorithm */
|
||||||
|
|
||||||
/**
|
|
||||||
* scrypt: CPU cost parameter.
|
|
||||||
*/
|
|
||||||
public static final int scrypt_N = 32768;
|
|
||||||
/**
|
|
||||||
* scrypt: Memory cost parameter.
|
|
||||||
*/
|
|
||||||
public static final int scrypt_r = 8;
|
|
||||||
/**
|
|
||||||
* scrypt: Parallelization parameter.
|
|
||||||
*/
|
|
||||||
public static final int scrypt_p = 2;
|
|
||||||
/**
|
|
||||||
* mpw: Master key size (byte).
|
|
||||||
*/
|
|
||||||
public static final int mpw_dkLen = 64;
|
|
||||||
/**
|
|
||||||
* mpw: Input character encoding.
|
|
||||||
*/
|
|
||||||
public static final Charset mpw_charset = Charsets.UTF_8;
|
|
||||||
/**
|
|
||||||
* mpw: Platform-agnostic byte order.
|
|
||||||
*/
|
|
||||||
public static final ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN;
|
|
||||||
/**
|
|
||||||
* mpw: Site digest.
|
|
||||||
*/
|
|
||||||
public static final MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256;
|
|
||||||
/**
|
|
||||||
* mpw: Key ID hash.
|
|
||||||
*/
|
|
||||||
public static final MessageDigests mpw_hash = MessageDigests.SHA256;
|
|
||||||
/**
|
|
||||||
* mpw: validity for the time-based rolling counter.
|
|
||||||
*/
|
|
||||||
public static final int mpw_counter_timeout = 5 * 60 /* s */;
|
|
||||||
|
|
||||||
|
|
||||||
public static final int MS_PER_S = 1000;
|
public static final int MS_PER_S = 1000;
|
||||||
|
|
||||||
|
public static final DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,10 @@
|
|||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author lhunath, 15-02-04
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
@ParametersAreNonnullByDefault
|
|
||||||
package com.lyndir.masterpassword;
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
/**
|
||||||
|
* @author lhunath, 2017-09-21
|
||||||
|
*/
|
||||||
|
public class MPInvalidatedException extends Exception {
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
|
import java.util.Locale;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.NonNls;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 14-12-02
|
||||||
|
*/
|
||||||
|
public enum MPKeyPurpose {
|
||||||
|
/**
|
||||||
|
* Generate a key for authentication.
|
||||||
|
*/
|
||||||
|
Authentication( "authentication", "Generate a key for authentication.", "com.lyndir.masterpassword" ),
|
||||||
|
/**
|
||||||
|
* Generate a name for identification.
|
||||||
|
*/
|
||||||
|
Identification( "identification", "Generate a name for identification.", "com.lyndir.masterpassword.login" ),
|
||||||
|
/**
|
||||||
|
* Generate a recovery token.
|
||||||
|
*/
|
||||||
|
Recovery( "recovery", "Generate a recovery token.", "com.lyndir.masterpassword.answer" );
|
||||||
|
|
||||||
|
static final Logger logger = Logger.get( MPResultType.class );
|
||||||
|
|
||||||
|
private final String shortName;
|
||||||
|
private final String description;
|
||||||
|
private final String scope;
|
||||||
|
|
||||||
|
MPKeyPurpose(final String shortName, final String description, @NonNls final String scope) {
|
||||||
|
this.shortName = shortName;
|
||||||
|
this.description = description;
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getShortName() {
|
||||||
|
return shortName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getScope() {
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param shortNamePrefix The name for the purpose to look up. It is a case insensitive prefix of the purpose's short name.
|
||||||
|
*
|
||||||
|
* @return The purpose registered with the given name.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
@Contract("!null -> !null")
|
||||||
|
public static MPKeyPurpose forName(@Nullable final String shortNamePrefix) {
|
||||||
|
|
||||||
|
if (shortNamePrefix == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
for (final MPKeyPurpose type : values())
|
||||||
|
if (type.getShortName().toLowerCase( Locale.ROOT ).startsWith( shortNamePrefix.toLowerCase( Locale.ROOT ) ))
|
||||||
|
return type;
|
||||||
|
|
||||||
|
throw logger.bug( "No purpose for name: %s", shortNamePrefix );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MPKeyPurpose forInt(final int keyPurpose) {
|
||||||
|
|
||||||
|
return values()[keyPurpose];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int toInt() {
|
||||||
|
|
||||||
|
return ordinal();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
import static com.lyndir.masterpassword.MPUtils.*;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 2014-08-30
|
||||||
|
*/
|
||||||
|
public class MPMasterKey {
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
private static final Logger logger = Logger.get( MPMasterKey.class );
|
||||||
|
|
||||||
|
private final EnumMap<Version, byte[]> keyByVersion = new EnumMap<>( Version.class );
|
||||||
|
private final String fullName;
|
||||||
|
private final char[] masterPassword;
|
||||||
|
|
||||||
|
private boolean invalidated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param masterPassword The characters of the user's master password. Note: this array is held by reference and its contents
|
||||||
|
* invalidated on {@link #invalidate()}.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
|
||||||
|
public MPMasterKey(final String fullName, final char[] masterPassword) {
|
||||||
|
|
||||||
|
this.fullName = fullName;
|
||||||
|
this.masterPassword = masterPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive the master key for a user based on their name and master password.
|
||||||
|
*
|
||||||
|
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||||
|
*/
|
||||||
|
private byte[] masterKey(final Version algorithmVersion)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
Preconditions.checkArgument( masterPassword.length > 0 );
|
||||||
|
|
||||||
|
if (invalidated)
|
||||||
|
throw new MPInvalidatedException();
|
||||||
|
|
||||||
|
byte[] key = keyByVersion.get( algorithmVersion );
|
||||||
|
if (key == null) {
|
||||||
|
logger.trc( "-- mpw_masterKey (algorithm: %d)", algorithmVersion.toInt() );
|
||||||
|
logger.trc( "fullName: %s", fullName );
|
||||||
|
logger.trc( "masterPassword.id: %s", CodeUtils.encodeHex( idForBytes( bytesForChars( masterPassword ) ) ) );
|
||||||
|
|
||||||
|
keyByVersion.put( algorithmVersion, key = algorithmVersion.getAlgorithm().masterKey( fullName, masterPassword ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive the master key for a user based on their name and master password.
|
||||||
|
*
|
||||||
|
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||||
|
*/
|
||||||
|
private byte[] siteKey(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable final String keyContext, final Version algorithmVersion)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
Preconditions.checkArgument( !siteName.isEmpty() );
|
||||||
|
|
||||||
|
byte[] masterKey = masterKey( algorithmVersion );
|
||||||
|
|
||||||
|
logger.trc( "-- mpw_siteKey (algorithm: %d)", algorithmVersion.toInt() );
|
||||||
|
logger.trc( "siteName: %s", siteName );
|
||||||
|
logger.trc( "siteCounter: %s", siteCounter );
|
||||||
|
logger.trc( "keyPurpose: %d (%s)", keyPurpose.toInt(), keyPurpose.getShortName() );
|
||||||
|
logger.trc( "keyContext: %s", keyContext );
|
||||||
|
|
||||||
|
return algorithmVersion.getAlgorithm().siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a site result token.
|
||||||
|
*
|
||||||
|
* @param siteName A site identifier.
|
||||||
|
* @param siteCounter The result identifier.
|
||||||
|
* @param keyPurpose The intended purpose for this site result.
|
||||||
|
* @param keyContext A site-scoped result modifier.
|
||||||
|
* @param resultType The type of result to generate.
|
||||||
|
* @param resultParam A parameter for the resultType. For stateful result types, the output of
|
||||||
|
* {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}.
|
||||||
|
*
|
||||||
|
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||||
|
*/
|
||||||
|
public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
||||||
|
final Version algorithmVersion)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
|
byte[] masterKey = masterKey( algorithmVersion );
|
||||||
|
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
|
||||||
|
|
||||||
|
logger.trc( "-- mpw_siteResult (algorithm: %d)", algorithmVersion.toInt() );
|
||||||
|
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
||||||
|
logger.trc( "resultParam: %s", resultParam );
|
||||||
|
|
||||||
|
return algorithmVersion.getAlgorithm().siteResult(
|
||||||
|
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt a stateful site token for persistence.
|
||||||
|
*
|
||||||
|
* @param siteName A site identifier.
|
||||||
|
* @param siteCounter The result identifier.
|
||||||
|
* @param keyPurpose The intended purpose for the site token.
|
||||||
|
* @param keyContext A site-scoped key modifier.
|
||||||
|
* @param resultType The type of result token to encrypt.
|
||||||
|
* @param resultParam The result token desired from
|
||||||
|
* {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}.
|
||||||
|
*
|
||||||
|
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||||
|
*/
|
||||||
|
public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
||||||
|
final Version algorithmVersion)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
|
Preconditions.checkNotNull( resultParam );
|
||||||
|
Preconditions.checkArgument( !resultParam.isEmpty() );
|
||||||
|
|
||||||
|
byte[] masterKey = masterKey( algorithmVersion );
|
||||||
|
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
|
||||||
|
|
||||||
|
logger.trc( "-- mpw_siteState (algorithm: %d)", algorithmVersion.toInt() );
|
||||||
|
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
||||||
|
logger.trc( "resultParam: %d bytes = %s", resultParam.getBytes( MPAlgorithm.mpw_charset ).length, resultParam );
|
||||||
|
|
||||||
|
return algorithmVersion.getAlgorithm().siteState(
|
||||||
|
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public String getFullName() {
|
||||||
|
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate an identifier for the master key.
|
||||||
|
*
|
||||||
|
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||||
|
*/
|
||||||
|
public byte[] getKeyID(final Version algorithmVersion)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
|
return idForBytes( masterKey( algorithmVersion ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wipe this key's secrets from memory, making the object permanently unusable.
|
||||||
|
*/
|
||||||
|
public void invalidate() {
|
||||||
|
|
||||||
|
invalidated = true;
|
||||||
|
for (final byte[] key : keyByVersion.values())
|
||||||
|
Arrays.fill( key, (byte) 0 );
|
||||||
|
Arrays.fill( masterPassword, (char) 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The algorithm iterations.
|
||||||
|
*/
|
||||||
|
public enum Version {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bugs:
|
||||||
|
* - does math with chars whose signedness was platform-dependent.
|
||||||
|
* - miscounted the byte-length for multi-byte site names.
|
||||||
|
* - miscounted the byte-length for multi-byte user names.
|
||||||
|
*/
|
||||||
|
V0( new MPAlgorithmV0() ),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bugs:
|
||||||
|
* - miscounted the byte-length for multi-byte site names.
|
||||||
|
* - miscounted the byte-length for multi-byte user names.
|
||||||
|
*/
|
||||||
|
V1( new MPAlgorithmV1() ),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bugs:
|
||||||
|
* - miscounted the byte-length for multi-byte user names.
|
||||||
|
*/
|
||||||
|
V2( new MPAlgorithmV2() ),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bugs:
|
||||||
|
* - no known issues.
|
||||||
|
*/
|
||||||
|
V3( new MPAlgorithmV3() );
|
||||||
|
|
||||||
|
public static final Version CURRENT = V3;
|
||||||
|
|
||||||
|
private final MPAlgorithm algorithm;
|
||||||
|
|
||||||
|
Version(final MPAlgorithm algorithm) {
|
||||||
|
this.algorithm = algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MPAlgorithm getAlgorithm() {
|
||||||
|
return algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Version fromInt(final int algorithmVersion) {
|
||||||
|
|
||||||
|
return values()[algorithmVersion];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int toInt() {
|
||||||
|
|
||||||
|
return ordinal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,6 @@ import com.lyndir.lhunath.opal.system.logging.Logger;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NonNls;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,15 +31,21 @@ import org.jetbrains.annotations.NonNls;
|
|||||||
*
|
*
|
||||||
* @author lhunath
|
* @author lhunath
|
||||||
*/
|
*/
|
||||||
public enum MPSiteType {
|
public enum MPResultType {
|
||||||
|
// bit 0-3 | MPResultTypeClass | MPSiteFeature
|
||||||
|
|
||||||
GeneratedMaximum( "Max", "20 characters, contains symbols.", //
|
/**
|
||||||
ImmutableList.of( "x", "max", "maximum" ), // NON-NLS
|
* pg^VMAUBk5x3p%HP%i4=
|
||||||
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ), new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
|
*/
|
||||||
MPSiteTypeClass.Generated, 0x0 ),
|
GeneratedMaximum( "maximum", "20 characters, contains symbols.", //
|
||||||
|
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ),
|
||||||
|
new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
|
||||||
|
MPResultTypeClass.Template, 0x0 ),
|
||||||
|
|
||||||
GeneratedLong( "Long", "Copy-friendly, 14 characters, contains symbols.", //
|
/**
|
||||||
ImmutableList.of( "l", "long" ), // NON-NLS
|
* BiroYena8:Kixa
|
||||||
|
*/
|
||||||
|
GeneratedLong( "long", "Copy-friendly, 14 characters, contains symbols.", //
|
||||||
ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ),
|
ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ),
|
||||||
new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
|
new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
|
||||||
new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ),
|
new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ),
|
||||||
@@ -52,65 +57,92 @@ public enum MPSiteType {
|
|||||||
new MPTemplate( "CvcvCvccnoCvcc" ), new MPTemplate( "CvcvCvccCvccno" ),
|
new MPTemplate( "CvcvCvccnoCvcc" ), new MPTemplate( "CvcvCvccCvccno" ),
|
||||||
new MPTemplate( "CvccnoCvcvCvcc" ), new MPTemplate( "CvccCvcvnoCvcc" ),
|
new MPTemplate( "CvccnoCvcvCvcc" ), new MPTemplate( "CvccCvcvnoCvcc" ),
|
||||||
new MPTemplate( "CvccCvcvCvccno" ) ), //
|
new MPTemplate( "CvccCvcvCvccno" ) ), //
|
||||||
MPSiteTypeClass.Generated, 0x1 ),
|
MPResultTypeClass.Template, 0x1 ),
|
||||||
|
|
||||||
GeneratedMedium( "Medium", "Copy-friendly, 8 characters, contains symbols.", //
|
/**
|
||||||
ImmutableList.of( "m", "med", "medium" ), // NON-NLS
|
* BirSuj0-
|
||||||
ImmutableList.of( new MPTemplate( "CvcnoCvc" ), new MPTemplate( "CvcCvcno" ) ), //
|
*/
|
||||||
MPSiteTypeClass.Generated, 0x2 ),
|
GeneratedMedium( "medium", "Copy-friendly, 8 characters, contains symbols.", //
|
||||||
|
ImmutableList.of( new MPTemplate( "CvcnoCvc" ),
|
||||||
|
new MPTemplate( "CvcCvcno" ) ), //
|
||||||
|
MPResultTypeClass.Template, 0x2 ),
|
||||||
|
|
||||||
GeneratedBasic( "Basic", "8 characters, no symbols.", //
|
/**
|
||||||
ImmutableList.of( "b", "basic" ), // NON-NLS
|
* pO98MoD0
|
||||||
ImmutableList.of( new MPTemplate( "aaanaaan" ), new MPTemplate( "aannaaan" ), new MPTemplate( "aaannaaa" ) ), //
|
*/
|
||||||
MPSiteTypeClass.Generated, 0x3 ),
|
GeneratedBasic( "basic", "8 characters, no symbols.", //
|
||||||
|
ImmutableList.of( new MPTemplate( "aaanaaan" ),
|
||||||
|
new MPTemplate( "aannaaan" ),
|
||||||
|
new MPTemplate( "aaannaaa" ) ), //
|
||||||
|
MPResultTypeClass.Template, 0x3 ),
|
||||||
|
|
||||||
GeneratedShort( "Short", "Copy-friendly, 4 characters, no symbols.", //
|
/**
|
||||||
ImmutableList.of( "s", "short" ), // NON-NLS
|
* Bir8
|
||||||
|
*/
|
||||||
|
GeneratedShort( "short", "Copy-friendly, 4 characters, no symbols.", //
|
||||||
ImmutableList.of( new MPTemplate( "Cvcn" ) ), //
|
ImmutableList.of( new MPTemplate( "Cvcn" ) ), //
|
||||||
MPSiteTypeClass.Generated, 0x4 ),
|
MPResultTypeClass.Template, 0x4 ),
|
||||||
|
|
||||||
GeneratedPIN( "PIN", "4 numbers.", //
|
/**
|
||||||
ImmutableList.of( "i", "pin" ), // NON-NLS
|
* 2798
|
||||||
|
*/
|
||||||
|
GeneratedPIN( "pin", "4 numbers.", //
|
||||||
ImmutableList.of( new MPTemplate( "nnnn" ) ), //
|
ImmutableList.of( new MPTemplate( "nnnn" ) ), //
|
||||||
MPSiteTypeClass.Generated, 0x5 ),
|
MPResultTypeClass.Template, 0x5 ),
|
||||||
|
|
||||||
GeneratedName( "Name", "9 letter name.", //
|
/**
|
||||||
ImmutableList.of( "n", "name" ), // NON-NLS
|
* birsujano
|
||||||
|
*/
|
||||||
|
GeneratedName( "name", "9 letter name.", //
|
||||||
ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), //
|
ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), //
|
||||||
MPSiteTypeClass.Generated, 0xE ),
|
MPResultTypeClass.Template, 0xE ),
|
||||||
|
|
||||||
GeneratedPhrase( "Phrase", "20 character sentence.", //
|
/**
|
||||||
ImmutableList.of( "p", "phrase" ), // NON-NLS
|
* bir yennoquce fefi
|
||||||
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ), new MPTemplate( "cvc cvccvcvcv cvcv" ),
|
*/
|
||||||
|
GeneratedPhrase( "phrase", "20 character sentence.", //
|
||||||
|
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ),
|
||||||
|
new MPTemplate( "cvc cvccvcvcv cvcv" ),
|
||||||
new MPTemplate( "cv cvccv cvc cvcvccv" ) ), //
|
new MPTemplate( "cv cvccv cvc cvcvccv" ) ), //
|
||||||
MPSiteTypeClass.Generated, 0xF ),
|
MPResultTypeClass.Template, 0xF ),
|
||||||
|
|
||||||
StoredPersonal( "Personal", "AES-encrypted, exportable.", //
|
/**
|
||||||
ImmutableList.of( "personal" ), // NON-NLS
|
* Custom saved password.
|
||||||
|
*/
|
||||||
|
StoredPersonal( "personal", "AES-encrypted, exportable.", //
|
||||||
ImmutableList.<MPTemplate>of(), //
|
ImmutableList.<MPTemplate>of(), //
|
||||||
MPSiteTypeClass.Stored, 0x0, MPSiteFeature.ExportContent ),
|
MPResultTypeClass.Stateful, 0x0, MPSiteFeature.ExportContent ),
|
||||||
|
|
||||||
StoredDevicePrivate( "Device", "AES-encrypted, not exported.", //
|
/**
|
||||||
ImmutableList.of( "device" ), // NON-NLS
|
* Custom saved password that should not be exported from the device.
|
||||||
|
*/
|
||||||
|
StoredDevicePrivate( "device", "AES-encrypted, not exported.", //
|
||||||
ImmutableList.<MPTemplate>of(), //
|
ImmutableList.<MPTemplate>of(), //
|
||||||
MPSiteTypeClass.Stored, 0x1, MPSiteFeature.DevicePrivate );
|
MPResultTypeClass.Stateful, 0x1, MPSiteFeature.DevicePrivate ),
|
||||||
|
|
||||||
static final Logger logger = Logger.get( MPSiteType.class );
|
/**
|
||||||
|
* Derive a unique binary key.
|
||||||
|
*/
|
||||||
|
DeriveKey( "key", "Encryption key.", //
|
||||||
|
ImmutableList.<MPTemplate>of(), //
|
||||||
|
MPResultTypeClass.Derive, 0x0, MPSiteFeature.Alternative );
|
||||||
|
|
||||||
|
public static final MPResultType DEFAULT = GeneratedLong;
|
||||||
|
|
||||||
|
static final Logger logger = Logger.get( MPResultType.class );
|
||||||
|
|
||||||
private final String shortName;
|
private final String shortName;
|
||||||
private final String description;
|
private final String description;
|
||||||
private final List<String> options;
|
|
||||||
private final List<MPTemplate> templates;
|
private final List<MPTemplate> templates;
|
||||||
private final MPSiteTypeClass typeClass;
|
private final MPResultTypeClass typeClass;
|
||||||
private final int typeIndex;
|
private final int typeIndex;
|
||||||
private final Set<MPSiteFeature> typeFeatures;
|
private final Set<MPSiteFeature> typeFeatures;
|
||||||
|
|
||||||
MPSiteType(final String shortName, final String description, final List<String> options, final List<MPTemplate> templates,
|
MPResultType(final String shortName, final String description, final List<MPTemplate> templates,
|
||||||
final MPSiteTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
|
final MPResultTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
|
||||||
|
|
||||||
this.shortName = shortName;
|
this.shortName = shortName;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.options = options;
|
|
||||||
this.templates = templates;
|
this.templates = templates;
|
||||||
this.typeClass = typeClass;
|
this.typeClass = typeClass;
|
||||||
this.typeIndex = typeIndex;
|
this.typeIndex = typeIndex;
|
||||||
@@ -131,11 +163,7 @@ public enum MPSiteType {
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getOptions() {
|
public MPResultTypeClass getTypeClass() {
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MPSiteTypeClass getTypeClass() {
|
|
||||||
|
|
||||||
return typeClass;
|
return typeClass;
|
||||||
}
|
}
|
||||||
@@ -154,35 +182,22 @@ public enum MPSiteType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param option The option to select a type with. It is matched case insensitively.
|
* @param shortNamePrefix The name for the type to look up. It is a case insensitive prefix of the type's short name.
|
||||||
*
|
|
||||||
* @return The type registered for the given option.
|
|
||||||
*/
|
|
||||||
public static MPSiteType forOption(final String option) {
|
|
||||||
|
|
||||||
for (final MPSiteType type : values())
|
|
||||||
if (type.getOptions().contains( option.toLowerCase( Locale.ROOT ) ))
|
|
||||||
return type;
|
|
||||||
|
|
||||||
throw logger.bug( "No type for option: %s", option );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param name The name fromInt the type to look up. It is matched case insensitively.
|
|
||||||
*
|
*
|
||||||
* @return The type registered with the given name.
|
* @return The type registered with the given name.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
@Contract("!null -> !null")
|
@Contract("!null -> !null")
|
||||||
public static MPSiteType forName(@Nullable final String name) {
|
public static MPResultType forName(@Nullable final String shortNamePrefix) {
|
||||||
|
|
||||||
if (name == null)
|
if (shortNamePrefix == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
for (final MPSiteType type : values())
|
for (final MPResultType type : values())
|
||||||
if (type.name().equalsIgnoreCase( name ))
|
if (type.getShortName().toLowerCase( Locale.ROOT ).startsWith( shortNamePrefix.toLowerCase( Locale.ROOT ) ))
|
||||||
return type;
|
return type;
|
||||||
|
|
||||||
throw logger.bug( "No type for name: %s", name );
|
throw logger.bug( "No type for name: %s", shortNamePrefix );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -190,10 +205,10 @@ public enum MPSiteType {
|
|||||||
*
|
*
|
||||||
* @return All types that support the given class.
|
* @return All types that support the given class.
|
||||||
*/
|
*/
|
||||||
public static ImmutableList<MPSiteType> forClass(final MPSiteTypeClass typeClass) {
|
public static ImmutableList<MPResultType> forClass(final MPResultTypeClass typeClass) {
|
||||||
|
|
||||||
ImmutableList.Builder<MPSiteType> types = ImmutableList.builder();
|
ImmutableList.Builder<MPResultType> types = ImmutableList.builder();
|
||||||
for (final MPSiteType type : values())
|
for (final MPResultType type : values())
|
||||||
if (type.getTypeClass() == typeClass)
|
if (type.getTypeClass() == typeClass)
|
||||||
types.add( type );
|
types.add( type );
|
||||||
|
|
||||||
@@ -205,27 +220,28 @@ public enum MPSiteType {
|
|||||||
*
|
*
|
||||||
* @return The type registered with the given type.
|
* @return The type registered with the given type.
|
||||||
*/
|
*/
|
||||||
public static MPSiteType forType(final int type) {
|
public static MPResultType forType(final int type) {
|
||||||
|
|
||||||
for (final MPSiteType siteType : values())
|
for (final MPResultType resultType : values())
|
||||||
if (siteType.getType() == type)
|
if (resultType.getType() == type)
|
||||||
return siteType;
|
return resultType;
|
||||||
|
|
||||||
throw logger.bug( "No type: %s", type );
|
throw logger.bug( "No type: %s", type );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mask The mask for which we look up types.
|
* @param mask The type mask for which we look up types.
|
||||||
*
|
*
|
||||||
* @return All types that support the given mask.
|
* @return All types that support the given mask's class & features.
|
||||||
*/
|
*/
|
||||||
public static ImmutableList<MPSiteType> forMask(final int mask) {
|
public static ImmutableList<MPResultType> forMask(final int mask) {
|
||||||
|
|
||||||
int typeMask = mask & ~0xF;
|
int typeMask = mask & ~0xF; // Ignore resultType bit 0-3
|
||||||
ImmutableList.Builder<MPSiteType> types = ImmutableList.builder();
|
|
||||||
for (final MPSiteType siteType : values())
|
ImmutableList.Builder<MPResultType> types = ImmutableList.builder();
|
||||||
if (((siteType.getType() & ~0xF) & typeMask) != 0)
|
for (final MPResultType resultType : values())
|
||||||
types.add( siteType );
|
if (((resultType.getType() & ~0xF) & typeMask) != 0)
|
||||||
|
types.add( resultType );
|
||||||
|
|
||||||
return types.build();
|
return types.build();
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <i>07 04, 2012</i>
|
||||||
|
*
|
||||||
|
* @author lhunath
|
||||||
|
*/
|
||||||
|
public enum MPResultTypeClass {
|
||||||
|
// bit 4 - 9
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the site key to generate a password from a template.
|
||||||
|
*/
|
||||||
|
Template( 1 << 4 ),
|
||||||
|
/**
|
||||||
|
* Use the site key to encrypt and decrypt a stateful entity.
|
||||||
|
*/
|
||||||
|
Stateful( 1 << 5 ),
|
||||||
|
/**
|
||||||
|
* Use the site key to derive a site-specific object.
|
||||||
|
*/
|
||||||
|
Derive( 1 << 6 );
|
||||||
|
|
||||||
|
private final int mask;
|
||||||
|
|
||||||
|
MPResultTypeClass(final int mask) {
|
||||||
|
this.mask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMask() {
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ package com.lyndir.masterpassword;
|
|||||||
* @author lhunath
|
* @author lhunath
|
||||||
*/
|
*/
|
||||||
public enum MPSiteFeature {
|
public enum MPSiteFeature {
|
||||||
|
// bit 10 - 15
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export the key-protected content data.
|
* Export the key-protected content data.
|
||||||
@@ -33,7 +34,12 @@ public enum MPSiteFeature {
|
|||||||
/**
|
/**
|
||||||
* Never export content.
|
* Never export content.
|
||||||
*/
|
*/
|
||||||
DevicePrivate( 1 << 11 );
|
DevicePrivate( 1 << 11 ),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't use this as the primary authentication result type.
|
||||||
|
*/
|
||||||
|
Alternative( 1 << 12 );
|
||||||
|
|
||||||
MPSiteFeature(final int mask) {
|
MPSiteFeature(final int mask) {
|
||||||
this.mask = mask;
|
this.mask = mask;
|
||||||
|
|||||||
@@ -1,103 +0,0 @@
|
|||||||
//==============================================================================
|
|
||||||
// This file is part of Master Password.
|
|
||||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
|
||||||
//
|
|
||||||
// Master Password is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Master Password is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You can find a copy of the GNU General Public License in the
|
|
||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
package com.lyndir.masterpassword;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import org.jetbrains.annotations.Contract;
|
|
||||||
import org.jetbrains.annotations.NonNls;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author lhunath, 14-12-02
|
|
||||||
*/
|
|
||||||
public enum MPSiteVariant {
|
|
||||||
Password( "Generate a key for authentication.", "Doesn't currently use a context.", //
|
|
||||||
ImmutableList.of( "p", "password" ), "com.lyndir.masterpassword" ), // NON-NLS
|
|
||||||
Login( "Generate a name for identification.", "Doesn't currently use a context.", //
|
|
||||||
ImmutableList.of( "l", "login" ), "com.lyndir.masterpassword.login" ), // NON-NLS
|
|
||||||
Answer( "Generate an answer to a security question.", "Empty for a universal site answer or\nthe most significant word(s) of the question.", //
|
|
||||||
ImmutableList.of( "a", "answer" ), "com.lyndir.masterpassword.answer" ); // NON-NLS
|
|
||||||
|
|
||||||
static final Logger logger = Logger.get( MPSiteType.class );
|
|
||||||
|
|
||||||
private final String description;
|
|
||||||
private final String contextDescription;
|
|
||||||
private final List<String> options;
|
|
||||||
private final String scope;
|
|
||||||
|
|
||||||
MPSiteVariant(final String description, final String contextDescription, final List<String> options, @NonNls final String scope) {
|
|
||||||
this.contextDescription = contextDescription;
|
|
||||||
|
|
||||||
this.options = options;
|
|
||||||
this.description = description;
|
|
||||||
this.scope = scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getContextDescription() {
|
|
||||||
return contextDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getOptions() {
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getScope() {
|
|
||||||
return scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param option The option to select a variant with. It is matched case insensitively.
|
|
||||||
*
|
|
||||||
* @return The variant registered for the given option.
|
|
||||||
*/
|
|
||||||
public static MPSiteVariant forOption(final String option) {
|
|
||||||
|
|
||||||
for (final MPSiteVariant variant : values())
|
|
||||||
if (variant.getOptions().contains( option.toLowerCase( Locale.ROOT ) ))
|
|
||||||
return variant;
|
|
||||||
|
|
||||||
throw logger.bug( "No variant for option: %s", option );
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @param name The name fromInt the variant to look up. It is matched case insensitively.
|
|
||||||
*
|
|
||||||
* @return The variant registered with the given name.
|
|
||||||
*/
|
|
||||||
@Contract("!null -> !null")
|
|
||||||
public static MPSiteVariant forName(@Nullable final String name) {
|
|
||||||
|
|
||||||
if (name == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
for (final MPSiteVariant type : values())
|
|
||||||
if (type.name().equalsIgnoreCase( name ))
|
|
||||||
return type;
|
|
||||||
|
|
||||||
throw logger.bug( "No variant for name: %s", name );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.CharBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 2017-09-20
|
||||||
|
*/
|
||||||
|
public final class MPUtils {
|
||||||
|
|
||||||
|
public static byte[] bytesForInt(final int number) {
|
||||||
|
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithm.mpw_byteOrder ).putInt( number ).array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] bytesForInt(final UnsignedInteger number) {
|
||||||
|
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithm.mpw_byteOrder ).putInt( number.intValue() ).array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] bytesForChars(final char[] characters) {
|
||||||
|
ByteBuffer byteBuffer = MPAlgorithm.mpw_charset.encode( CharBuffer.wrap( characters ) );
|
||||||
|
|
||||||
|
byte[] bytes = new byte[byteBuffer.remaining()];
|
||||||
|
byteBuffer.get( bytes );
|
||||||
|
|
||||||
|
Arrays.fill( byteBuffer.array(), (byte) 0 );
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] idForBytes(final byte[] bytes) {
|
||||||
|
return MPAlgorithm.mpw_hash.of( bytes );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,219 +0,0 @@
|
|||||||
//==============================================================================
|
|
||||||
// This file is part of Master Password.
|
|
||||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
|
||||||
//
|
|
||||||
// Master Password is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Master Password is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You can find a copy of the GNU General Public License in the
|
|
||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
package com.lyndir.masterpassword;
|
|
||||||
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
|
||||||
import com.lyndir.lhunath.opal.system.*;
|
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author lhunath, 2014-08-30
|
|
||||||
*/
|
|
||||||
public abstract class MasterKey {
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
|
||||||
private static final Logger logger = Logger.get( MasterKey.class );
|
|
||||||
private static boolean allowNativeByDefault = true;
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
private final String fullName;
|
|
||||||
private boolean allowNative = allowNativeByDefault;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private byte[] masterKey;
|
|
||||||
|
|
||||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
|
||||||
public static MasterKey create(final String fullName, final char[] masterPassword) {
|
|
||||||
|
|
||||||
return create( Version.CURRENT, fullName, masterPassword );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
|
||||||
public static MasterKey create(final Version version, final String fullName, final char[] masterPassword) {
|
|
||||||
|
|
||||||
switch (version) {
|
|
||||||
case V0:
|
|
||||||
return new MasterKeyV0( fullName ).revalidate( masterPassword );
|
|
||||||
case V1:
|
|
||||||
return new MasterKeyV1( fullName ).revalidate( masterPassword );
|
|
||||||
case V2:
|
|
||||||
return new MasterKeyV2( fullName ).revalidate( masterPassword );
|
|
||||||
case V3:
|
|
||||||
return new MasterKeyV3( fullName ).revalidate( masterPassword );
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new UnsupportedOperationException( strf( "Unsupported version: %s", version ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isAllowNativeByDefault() {
|
|
||||||
return allowNativeByDefault;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Native libraries are useful for speeding up the performance of cryptographical functions.
|
|
||||||
* Sometimes, however, we may prefer to use Java-only code.
|
|
||||||
* For instance, for auditability / trust or because the native code doesn't work on our CPU/platform.
|
|
||||||
* <p/>
|
|
||||||
* This setter affects the default setting for any newly created {@link MasterKey}s.
|
|
||||||
*
|
|
||||||
* @param allowNative false to disallow the use of native libraries.
|
|
||||||
*/
|
|
||||||
public static void setAllowNativeByDefault(final boolean allowNative) {
|
|
||||||
allowNativeByDefault = allowNative;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected MasterKey(@Nonnull final String fullName) {
|
|
||||||
|
|
||||||
this.fullName = fullName;
|
|
||||||
logger.trc( "fullName: %s", fullName );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
|
||||||
protected abstract byte[] deriveKey(char[] masterPassword);
|
|
||||||
|
|
||||||
public abstract Version getAlgorithmVersion();
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
public String getFullName() {
|
|
||||||
|
|
||||||
return fullName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAllowNative() {
|
|
||||||
return allowNative;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MasterKey setAllowNative(final boolean allowNative) {
|
|
||||||
this.allowNative = allowNative;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
protected byte[] getKey() {
|
|
||||||
|
|
||||||
Preconditions.checkState( isValid() );
|
|
||||||
return Preconditions.checkNotNull( masterKey );
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getKeyID() {
|
|
||||||
|
|
||||||
return idForBytes( getKey() );
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract String encode(@Nonnull String siteName, MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
|
|
||||||
MPSiteVariant siteVariant, @Nullable String siteContext);
|
|
||||||
|
|
||||||
public boolean isValid() {
|
|
||||||
return masterKey != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void invalidate() {
|
|
||||||
|
|
||||||
if (masterKey != null) {
|
|
||||||
Arrays.fill( masterKey, (byte) 0 );
|
|
||||||
masterKey = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
|
||||||
public MasterKey revalidate(final char[] masterPassword) {
|
|
||||||
invalidate();
|
|
||||||
|
|
||||||
logger.trc( "masterPassword: %s", new String( masterPassword ) );
|
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
masterKey = deriveKey( masterPassword );
|
|
||||||
|
|
||||||
if (masterKey == null)
|
|
||||||
logger.dbg( "masterKey calculation failed after %.2fs.", (double)(System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
|
|
||||||
else
|
|
||||||
logger.trc( "masterKey ID: %s (derived in %.2fs)", CodeUtils.encodeHex( idForBytes( masterKey ) ),
|
|
||||||
(double)(System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract byte[] bytesForInt(int number);
|
|
||||||
|
|
||||||
protected abstract byte[] bytesForInt(@Nonnull UnsignedInteger number);
|
|
||||||
|
|
||||||
protected abstract byte[] idForBytes(byte[] bytes);
|
|
||||||
|
|
||||||
public enum Version {
|
|
||||||
/**
|
|
||||||
* bugs:
|
|
||||||
* - does math with chars whose signedness was platform-dependent.
|
|
||||||
* - miscounted the byte-length fromInt multi-byte site names.
|
|
||||||
* - miscounted the byte-length fromInt multi-byte full names.
|
|
||||||
*/
|
|
||||||
V0,
|
|
||||||
/**
|
|
||||||
* bugs:
|
|
||||||
* - miscounted the byte-length fromInt multi-byte site names.
|
|
||||||
* - miscounted the byte-length fromInt multi-byte full names.
|
|
||||||
*/
|
|
||||||
V1,
|
|
||||||
/**
|
|
||||||
* bugs:
|
|
||||||
* - miscounted the byte-length fromInt multi-byte full names.
|
|
||||||
*/
|
|
||||||
V2,
|
|
||||||
/**
|
|
||||||
* bugs:
|
|
||||||
* - no known issues.
|
|
||||||
*/
|
|
||||||
V3;
|
|
||||||
|
|
||||||
public static final Version CURRENT = V3;
|
|
||||||
|
|
||||||
public static Version fromInt(final int algorithmVersion) {
|
|
||||||
|
|
||||||
return values()[algorithmVersion];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int toInt() {
|
|
||||||
|
|
||||||
return ordinal();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toBundleVersion() {
|
|
||||||
switch (this) {
|
|
||||||
case V0:
|
|
||||||
return "1.0";
|
|
||||||
case V1:
|
|
||||||
return "2.0";
|
|
||||||
case V2:
|
|
||||||
return "2.1";
|
|
||||||
case V3:
|
|
||||||
return "2.2";
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new UnsupportedOperationException( strf( "Unsupported version: %s", this ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
//==============================================================================
|
|
||||||
// This file is part of Master Password.
|
|
||||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
|
||||||
//
|
|
||||||
// Master Password is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Master Password is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You can find a copy of the GNU General Public License in the
|
|
||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
package com.lyndir.masterpassword;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.google.common.primitives.Bytes;
|
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
|
||||||
import com.lambdaworks.crypto.SCrypt;
|
|
||||||
import com.lyndir.lhunath.opal.system.*;
|
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
|
||||||
import java.nio.*;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bugs:
|
|
||||||
* - V2: miscounted the byte-length fromInt multi-byte full names.
|
|
||||||
* - V1: miscounted the byte-length fromInt multi-byte site names.
|
|
||||||
* - V0: does math with chars whose signedness was platform-dependent.
|
|
||||||
*
|
|
||||||
* @author lhunath, 2014-08-30
|
|
||||||
*/
|
|
||||||
public class MasterKeyV0 extends MasterKey {
|
|
||||||
|
|
||||||
private static final int MP_intLen = 32;
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
|
||||||
private static final Logger logger = Logger.get( MasterKeyV0.class );
|
|
||||||
|
|
||||||
public MasterKeyV0(final String fullName) {
|
|
||||||
super( fullName );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Version getAlgorithmVersion() {
|
|
||||||
|
|
||||||
return Version.V0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
protected byte[] deriveKey(final char[] masterPassword) {
|
|
||||||
String fullName = getFullName();
|
|
||||||
byte[] fullNameBytes = fullName.getBytes( MPConstant.mpw_charset );
|
|
||||||
byte[] fullNameLengthBytes = bytesForInt( fullName.length() );
|
|
||||||
|
|
||||||
String mpKeyScope = MPSiteVariant.Password.getScope();
|
|
||||||
byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MPConstant.mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
|
||||||
logger.trc( "key scope: %s", mpKeyScope );
|
|
||||||
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
|
||||||
|
|
||||||
ByteBuffer mpBytesBuf = MPConstant.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
|
|
||||||
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
|
|
||||||
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
|
|
||||||
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
|
|
||||||
|
|
||||||
return scrypt( masterKeySalt, mpBytes );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
|
||||||
try {
|
|
||||||
if (isAllowNative())
|
|
||||||
return SCrypt.scrypt( mpBytes, masterKeySalt, MPConstant.scrypt_N, MPConstant.scrypt_r, MPConstant.scrypt_p, MPConstant.mpw_dkLen );
|
|
||||||
else
|
|
||||||
return SCrypt.scryptJ( mpBytes, masterKeySalt, MPConstant.scrypt_N, MPConstant.scrypt_r, MPConstant.scrypt_p, MPConstant.mpw_dkLen );
|
|
||||||
}
|
|
||||||
catch (final GeneralSecurityException e) {
|
|
||||||
logger.bug( e );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Arrays.fill( mpBytes, (byte) 0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
|
|
||||||
final MPSiteVariant siteVariant, @Nullable final String siteContext) {
|
|
||||||
Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
|
|
||||||
Preconditions.checkArgument( !siteName.isEmpty() );
|
|
||||||
|
|
||||||
logger.trc( "siteName: %s", siteName );
|
|
||||||
logger.trc( "siteCounter: %d", siteCounter.longValue() );
|
|
||||||
logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
|
|
||||||
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
|
|
||||||
|
|
||||||
if (siteCounter.longValue() == 0)
|
|
||||||
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
|
|
||||||
|
|
||||||
String siteScope = siteVariant.getScope();
|
|
||||||
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
|
|
||||||
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
|
|
||||||
byte[] siteCounterBytes = bytesForInt( siteCounter );
|
|
||||||
byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
|
|
||||||
byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
|
|
||||||
logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
|
|
||||||
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
|
|
||||||
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
|
|
||||||
(siteContextBytes == null)? "(null)": siteContext );
|
|
||||||
|
|
||||||
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
|
||||||
if (siteContextBytes != null)
|
|
||||||
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
|
|
||||||
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
|
|
||||||
|
|
||||||
byte[] sitePasswordSeedBytes = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
|
|
||||||
int[] sitePasswordSeed = new int[sitePasswordSeedBytes.length];
|
|
||||||
for (int i = 0; i < sitePasswordSeedBytes.length; ++i) {
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( ByteOrder.BIG_ENDIAN );
|
|
||||||
Arrays.fill( buf.array(), (byte) ((sitePasswordSeedBytes[i] > 0)? 0x00: 0xFF) );
|
|
||||||
buf.position( 2 );
|
|
||||||
buf.put( sitePasswordSeedBytes[i] ).rewind();
|
|
||||||
sitePasswordSeed[i] = buf.getInt() & 0xFFFF;
|
|
||||||
}
|
|
||||||
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
|
|
||||||
|
|
||||||
Preconditions.checkState( sitePasswordSeed.length > 0 );
|
|
||||||
int templateIndex = sitePasswordSeed[0];
|
|
||||||
MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
|
|
||||||
logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
|
|
||||||
|
|
||||||
StringBuilder password = new StringBuilder( template.length() );
|
|
||||||
for (int i = 0; i < template.length(); ++i) {
|
|
||||||
int characterIndex = sitePasswordSeed[i + 1];
|
|
||||||
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
|
|
||||||
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
|
|
||||||
logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
|
|
||||||
sitePasswordSeed[i + 1], passwordCharacter );
|
|
||||||
|
|
||||||
password.append( passwordCharacter );
|
|
||||||
}
|
|
||||||
|
|
||||||
return password.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected byte[] bytesForInt(final int number) {
|
|
||||||
return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MPConstant.mpw_byteOrder ).putInt( number ).array();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected byte[] bytesForInt(@Nonnull final UnsignedInteger number) {
|
|
||||||
return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MPConstant.mpw_byteOrder ).putInt( number.intValue() ).array();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected byte[] idForBytes(final byte[] bytes) {
|
|
||||||
return MPConstant.mpw_hash.of( bytes );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
//==============================================================================
|
|
||||||
// This file is part of Master Password.
|
|
||||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
|
||||||
//
|
|
||||||
// Master Password is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Master Password is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You can find a copy of the GNU General Public License in the
|
|
||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
package com.lyndir.masterpassword;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.google.common.primitives.Bytes;
|
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
|
||||||
import com.lyndir.lhunath.opal.system.*;
|
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bugs:
|
|
||||||
* - V2: miscounted the byte-length fromInt multi-byte full names.
|
|
||||||
* - V1: miscounted the byte-length fromInt multi-byte site names.
|
|
||||||
*
|
|
||||||
* @author lhunath, 2014-08-30
|
|
||||||
*/
|
|
||||||
public class MasterKeyV1 extends MasterKeyV0 {
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
|
||||||
private static final Logger logger = Logger.get( MasterKeyV1.class );
|
|
||||||
|
|
||||||
public MasterKeyV1(final String fullName) {
|
|
||||||
super( fullName );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Version getAlgorithmVersion() {
|
|
||||||
|
|
||||||
return Version.V1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
|
|
||||||
final MPSiteVariant siteVariant, @Nullable final String siteContext) {
|
|
||||||
Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
|
|
||||||
Preconditions.checkArgument( !siteName.isEmpty() );
|
|
||||||
|
|
||||||
logger.trc( "siteName: %s", siteName );
|
|
||||||
logger.trc( "siteCounter: %d", siteCounter.longValue() );
|
|
||||||
logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
|
|
||||||
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
|
|
||||||
|
|
||||||
if (siteCounter.longValue() == 0)
|
|
||||||
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
|
|
||||||
|
|
||||||
String siteScope = siteVariant.getScope();
|
|
||||||
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
|
|
||||||
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
|
|
||||||
byte[] siteCounterBytes = bytesForInt( siteCounter );
|
|
||||||
byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
|
|
||||||
byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
|
|
||||||
logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
|
|
||||||
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
|
|
||||||
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
|
|
||||||
(siteContextBytes == null)? "(null)": siteContext );
|
|
||||||
|
|
||||||
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
|
||||||
if (siteContextBytes != null)
|
|
||||||
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
|
|
||||||
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
|
|
||||||
|
|
||||||
byte[] sitePasswordSeed = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
|
|
||||||
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) );
|
|
||||||
|
|
||||||
Preconditions.checkState( sitePasswordSeed.length > 0 );
|
|
||||||
int templateIndex = sitePasswordSeed[0] & 0xFF; // Mask the integer's sign.
|
|
||||||
MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
|
|
||||||
logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
|
|
||||||
|
|
||||||
StringBuilder password = new StringBuilder( template.length() );
|
|
||||||
for (int i = 0; i < template.length(); ++i) {
|
|
||||||
int characterIndex = sitePasswordSeed[i + 1] & 0xFF; // Mask the integer's sign.
|
|
||||||
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
|
|
||||||
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
|
|
||||||
logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
|
|
||||||
sitePasswordSeed[i + 1], passwordCharacter );
|
|
||||||
|
|
||||||
password.append( passwordCharacter );
|
|
||||||
}
|
|
||||||
|
|
||||||
return password.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
//==============================================================================
|
|
||||||
// This file is part of Master Password.
|
|
||||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
|
||||||
//
|
|
||||||
// Master Password is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Master Password is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You can find a copy of the GNU General Public License in the
|
|
||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
package com.lyndir.masterpassword;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.google.common.primitives.Bytes;
|
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
|
||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bugs:
|
|
||||||
* - V2: miscounted the byte-length fromInt multi-byte full names.
|
|
||||||
*
|
|
||||||
* @author lhunath, 2014-08-30
|
|
||||||
*/
|
|
||||||
public class MasterKeyV2 extends MasterKeyV1 {
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
|
||||||
private static final Logger logger = Logger.get( MasterKeyV2.class );
|
|
||||||
|
|
||||||
public MasterKeyV2(final String fullName) {
|
|
||||||
super( fullName );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Version getAlgorithmVersion() {
|
|
||||||
|
|
||||||
return Version.V2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
|
|
||||||
final MPSiteVariant siteVariant, @Nullable final String siteContext) {
|
|
||||||
Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
|
|
||||||
Preconditions.checkArgument( !siteName.isEmpty() );
|
|
||||||
|
|
||||||
logger.trc( "siteName: %s", siteName );
|
|
||||||
logger.trc( "siteCounter: %d", siteCounter.longValue() );
|
|
||||||
logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
|
|
||||||
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
|
|
||||||
|
|
||||||
if (siteCounter.longValue() == 0)
|
|
||||||
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
|
|
||||||
|
|
||||||
String siteScope = siteVariant.getScope();
|
|
||||||
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
|
|
||||||
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
|
|
||||||
byte[] siteCounterBytes = bytesForInt( siteCounter );
|
|
||||||
byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
|
|
||||||
byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
|
|
||||||
logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
|
|
||||||
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
|
|
||||||
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
|
|
||||||
(siteContextBytes == null)? "(null)": siteContext );
|
|
||||||
|
|
||||||
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
|
||||||
if (siteContextBytes != null)
|
|
||||||
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
|
|
||||||
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
|
|
||||||
|
|
||||||
byte[] sitePasswordSeed = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
|
|
||||||
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) );
|
|
||||||
|
|
||||||
Preconditions.checkState( sitePasswordSeed.length > 0 );
|
|
||||||
int templateIndex = sitePasswordSeed[0] & 0xFF; // Mask the integer's sign.
|
|
||||||
MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
|
|
||||||
logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
|
|
||||||
|
|
||||||
StringBuilder password = new StringBuilder( template.length() );
|
|
||||||
for (int i = 0; i < template.length(); ++i) {
|
|
||||||
int characterIndex = sitePasswordSeed[i + 1] & 0xFF; // Mask the integer's sign.
|
|
||||||
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
|
|
||||||
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
|
|
||||||
logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
|
|
||||||
sitePasswordSeed[i + 1], passwordCharacter );
|
|
||||||
|
|
||||||
password.append( passwordCharacter );
|
|
||||||
}
|
|
||||||
|
|
||||||
return password.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
//==============================================================================
|
|
||||||
// This file is part of Master Password.
|
|
||||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
|
||||||
//
|
|
||||||
// Master Password is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Master Password is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You can find a copy of the GNU General Public License in the
|
|
||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
package com.lyndir.masterpassword;
|
|
||||||
|
|
||||||
import com.google.common.primitives.Bytes;
|
|
||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.CharBuffer;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bugs:
|
|
||||||
* - no known issues.
|
|
||||||
*
|
|
||||||
* @author lhunath, 2014-08-30
|
|
||||||
*/
|
|
||||||
public class MasterKeyV3 extends MasterKeyV2 {
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
|
||||||
private static final Logger logger = Logger.get( MasterKeyV3.class );
|
|
||||||
|
|
||||||
public MasterKeyV3(final String fullName) {
|
|
||||||
super( fullName );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Version getAlgorithmVersion() {
|
|
||||||
|
|
||||||
return Version.V3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
protected byte[] deriveKey(final char[] masterPassword) {
|
|
||||||
byte[] fullNameBytes = getFullName().getBytes( MPConstant.mpw_charset );
|
|
||||||
byte[] fullNameLengthBytes = bytesForInt( fullNameBytes.length );
|
|
||||||
|
|
||||||
String mpKeyScope = MPSiteVariant.Password.getScope();
|
|
||||||
byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MPConstant.mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
|
||||||
logger.trc( "key scope: %s", mpKeyScope );
|
|
||||||
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
|
||||||
|
|
||||||
ByteBuffer mpBytesBuf = MPConstant.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
|
|
||||||
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
|
|
||||||
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
|
|
||||||
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
|
|
||||||
|
|
||||||
return scrypt( masterKeySalt, mpBytes );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.lyndir.masterpassword.model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author lhunath, 14-12-17
|
|
||||||
*/
|
|
||||||
public class IncorrectMasterPasswordException extends Exception {
|
|
||||||
|
|
||||||
private final MPUser user;
|
|
||||||
|
|
||||||
public IncorrectMasterPasswordException(final MPUser user) {
|
|
||||||
super( "Incorrect master password for user: " + user.getFullName() );
|
|
||||||
|
|
||||||
this.user = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MPUser getUser() {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
|
import com.lyndir.masterpassword.*;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.joda.time.Instant;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 14-12-05
|
||||||
|
*/
|
||||||
|
public class MPFileSite extends MPSite {
|
||||||
|
|
||||||
|
private final MPFileUser user;
|
||||||
|
private String siteName;
|
||||||
|
@Nullable
|
||||||
|
private String siteContent;
|
||||||
|
private UnsignedInteger siteCounter;
|
||||||
|
private MPResultType resultType;
|
||||||
|
private MPMasterKey.Version algorithmVersion;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String loginContent;
|
||||||
|
@Nullable
|
||||||
|
private MPResultType loginType;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String url;
|
||||||
|
private int uses;
|
||||||
|
private Instant lastUsed;
|
||||||
|
|
||||||
|
public MPFileSite(final MPFileUser user, final String siteName) {
|
||||||
|
this( user, siteName, DEFAULT_COUNTER, MPResultType.DEFAULT, MPMasterKey.Version.CURRENT );
|
||||||
|
}
|
||||||
|
|
||||||
|
public MPFileSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
|
||||||
|
final MPMasterKey.Version algorithmVersion) {
|
||||||
|
this.user = user;
|
||||||
|
this.siteName = siteName;
|
||||||
|
this.siteCounter = siteCounter;
|
||||||
|
this.resultType = resultType;
|
||||||
|
this.algorithmVersion = algorithmVersion;
|
||||||
|
this.lastUsed = new Instant();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteContent,
|
||||||
|
final UnsignedInteger siteCounter,
|
||||||
|
final MPResultType resultType, final MPMasterKey.Version algorithmVersion,
|
||||||
|
@Nullable final String loginContent, @Nullable final MPResultType loginType,
|
||||||
|
@Nullable final String url, final int uses, final Instant lastUsed) {
|
||||||
|
this.user = user;
|
||||||
|
this.siteName = siteName;
|
||||||
|
this.siteContent = siteContent;
|
||||||
|
this.siteCounter = siteCounter;
|
||||||
|
this.resultType = resultType;
|
||||||
|
this.algorithmVersion = algorithmVersion;
|
||||||
|
this.loginContent = loginContent;
|
||||||
|
this.loginType = loginType;
|
||||||
|
this.url = url;
|
||||||
|
this.uses = uses;
|
||||||
|
this.lastUsed = lastUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String resultFor(final MPMasterKey masterKey)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
|
return resultFor( masterKey, MPKeyPurpose.Authentication, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
|
return resultFor( masterKey, keyPurpose, keyContext, getSiteContent() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String loginFor(final MPMasterKey masterKey)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
|
if (loginType == null)
|
||||||
|
loginType = MPResultType.GeneratedName;
|
||||||
|
|
||||||
|
return loginFor( masterKey, loginType, loginContent );
|
||||||
|
}
|
||||||
|
|
||||||
|
public MPFileUser getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSiteName() {
|
||||||
|
return siteName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSiteName(final String siteName) {
|
||||||
|
this.siteName = siteName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getSiteContent() {
|
||||||
|
return siteContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSitePassword(final MPMasterKey masterKey, @Nullable final MPResultType resultType, @Nullable final String result)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
this.resultType = resultType;
|
||||||
|
if (result == null)
|
||||||
|
this.siteContent = null;
|
||||||
|
else
|
||||||
|
this.siteContent = masterKey.siteState(
|
||||||
|
getSiteName(), getSiteCounter(), MPKeyPurpose.Authentication, null, getResultType(), result, getAlgorithmVersion() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnsignedInteger getSiteCounter() {
|
||||||
|
return siteCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSiteCounter(final UnsignedInteger siteCounter) {
|
||||||
|
this.siteCounter = siteCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPResultType getResultType() {
|
||||||
|
return resultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setResultType(final MPResultType resultType) {
|
||||||
|
this.resultType = resultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPMasterKey.Version getAlgorithmVersion() {
|
||||||
|
return algorithmVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAlgorithmVersion(final MPMasterKey.Version algorithmVersion) {
|
||||||
|
this.algorithmVersion = algorithmVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public MPResultType getLoginType() {
|
||||||
|
return loginType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getLoginContent() {
|
||||||
|
return loginContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoginName(final MPMasterKey masterKey, @Nullable final MPResultType loginType, @Nullable final String result)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
this.loginType = loginType;
|
||||||
|
if (this.loginType != null)
|
||||||
|
if (result == null)
|
||||||
|
this.loginContent = null;
|
||||||
|
else
|
||||||
|
this.loginContent = masterKey.siteState(
|
||||||
|
siteName, DEFAULT_COUNTER, MPKeyPurpose.Identification, null, this.loginType, result, algorithmVersion );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(@Nullable final String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUses() {
|
||||||
|
return uses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getLastUsed() {
|
||||||
|
return lastUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void use() {
|
||||||
|
uses++;
|
||||||
|
lastUsed = new Instant();
|
||||||
|
user.use();
|
||||||
|
}
|
||||||
|
}
|
||||||
172
core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java
Executable file
172
core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java
Executable file
@@ -0,0 +1,172 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import com.google.common.collect.*;
|
||||||
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
|
import com.lyndir.masterpassword.*;
|
||||||
|
import java.util.*;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.joda.time.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 14-12-07
|
||||||
|
*/
|
||||||
|
public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileUser> {
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
private static final Logger logger = Logger.get( MPFileUser.class );
|
||||||
|
|
||||||
|
private final String fullName;
|
||||||
|
private final Collection<MPFileSite> sites = Sets.newHashSet();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private byte[] keyID;
|
||||||
|
private MPMasterKey.Version algorithmVersion;
|
||||||
|
|
||||||
|
private int avatar;
|
||||||
|
private MPResultType defaultType;
|
||||||
|
private ReadableInstant lastUsed;
|
||||||
|
|
||||||
|
public MPFileUser(final String fullName) {
|
||||||
|
this( fullName, null, MPMasterKey.Version.CURRENT );
|
||||||
|
}
|
||||||
|
|
||||||
|
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPMasterKey.Version algorithmVersion) {
|
||||||
|
this( fullName, keyID, algorithmVersion, 0, MPResultType.DEFAULT, new Instant() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPMasterKey.Version algorithmVersion, final int avatar,
|
||||||
|
final MPResultType defaultType, final ReadableInstant lastUsed) {
|
||||||
|
this.fullName = fullName;
|
||||||
|
this.keyID = (keyID == null)? null: keyID.clone();
|
||||||
|
this.algorithmVersion = algorithmVersion;
|
||||||
|
this.avatar = avatar;
|
||||||
|
this.defaultType = defaultType;
|
||||||
|
this.lastUsed = lastUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFullName() {
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPMasterKey.Version getAlgorithmVersion() {
|
||||||
|
return algorithmVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlgorithmVersion(final MPMasterKey.Version algorithmVersion) {
|
||||||
|
this.algorithmVersion = algorithmVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAvatar() {
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvatar(final int avatar) {
|
||||||
|
this.avatar = avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MPResultType getDefaultType() {
|
||||||
|
return defaultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultType(final MPResultType defaultType) {
|
||||||
|
this.defaultType = defaultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadableInstant getLastUsed() {
|
||||||
|
return lastUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void use() {
|
||||||
|
lastUsed = new Instant();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterable<MPFileSite> getSites() {
|
||||||
|
return sites;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSite(final MPFileSite site) {
|
||||||
|
sites.add( site );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteSite(final MPFileSite site) {
|
||||||
|
sites.remove( site );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<MPFileSite> findSites(final String query) {
|
||||||
|
ImmutableList.Builder<MPFileSite> results = ImmutableList.builder();
|
||||||
|
for (final MPFileSite site : getSites())
|
||||||
|
if (site.getSiteName().startsWith( query ))
|
||||||
|
results.add( site );
|
||||||
|
|
||||||
|
return results.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs an authentication attempt against the keyID for this user.
|
||||||
|
*
|
||||||
|
* Note: If this user doesn't have a keyID set yet, authentication will always succeed and the key ID will be set as a result.
|
||||||
|
*
|
||||||
|
* @param masterPassword The password to authenticate with.
|
||||||
|
*
|
||||||
|
* @return The master key for the user if authentication was successful.
|
||||||
|
*
|
||||||
|
* @throws MPIncorrectMasterPasswordException If authentication fails due to the given master password not matching the user's keyID.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public MPMasterKey authenticate(final char[] masterPassword)
|
||||||
|
throws MPIncorrectMasterPasswordException {
|
||||||
|
try {
|
||||||
|
key = new MPMasterKey( getFullName(), masterPassword );
|
||||||
|
if ((keyID == null) || (keyID.length == 0))
|
||||||
|
keyID = key.getKeyID( algorithmVersion );
|
||||||
|
else if (!Arrays.equals( key.getKeyID( algorithmVersion ), keyID ))
|
||||||
|
throw new MPIncorrectMasterPasswordException( this );
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
catch (final MPInvalidatedException e) {
|
||||||
|
throw logger.bug( e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void save()
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
MPFileUserManager.get().save( this, getMasterKey() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(final MPFileUser o) {
|
||||||
|
int comparison = getLastUsed().compareTo( o.getLastUsed() );
|
||||||
|
if (comparison == 0)
|
||||||
|
comparison = getFullName().compareTo( o.getFullName() );
|
||||||
|
|
||||||
|
return comparison;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
|
||||||
|
|
||||||
|
import com.google.common.base.*;
|
||||||
|
import com.google.common.collect.*;
|
||||||
|
import com.google.common.io.CharSink;
|
||||||
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
|
import com.lyndir.masterpassword.*;
|
||||||
|
import java.io.*;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages user data stored in user-specific {@code .mpsites} files under {@code .mpw.d}.
|
||||||
|
*
|
||||||
|
* @author lhunath, 14-12-07
|
||||||
|
*/
|
||||||
|
public class MPFileUserManager extends MPUserManager {
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
private static final Logger logger = Logger.get( MPFileUserManager.class );
|
||||||
|
private static final MPFileUserManager instance;
|
||||||
|
|
||||||
|
static {
|
||||||
|
String rcDir = System.getenv( MPConstant.env_rcDir );
|
||||||
|
if (rcDir != null)
|
||||||
|
instance = create( new File( rcDir ) );
|
||||||
|
else
|
||||||
|
instance = create( new File( ifNotNullElseNullable( System.getProperty( "user.home" ), System.getenv( "HOME" ) ), ".mpw.d" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private final File userFilesDirectory;
|
||||||
|
|
||||||
|
public static MPFileUserManager get() {
|
||||||
|
MPUserManager.instance = instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MPFileUserManager create(final File userFilesDirectory) {
|
||||||
|
return new MPFileUserManager( userFilesDirectory );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MPFileUserManager(final File userFilesDirectory) {
|
||||||
|
|
||||||
|
super( unmarshallUsers( userFilesDirectory ) );
|
||||||
|
this.userFilesDirectory = userFilesDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Iterable<MPFileUser> unmarshallUsers(final File userFilesDirectory) {
|
||||||
|
if (!userFilesDirectory.mkdirs() && !userFilesDirectory.isDirectory()) {
|
||||||
|
logger.err( "Couldn't create directory for user files: %s", userFilesDirectory );
|
||||||
|
return ImmutableList.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
return FluentIterable.from( listUserFiles( userFilesDirectory ) ).transform( new Function<File, MPFileUser>() {
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public MPFileUser apply(@Nullable final File file) {
|
||||||
|
try {
|
||||||
|
return new MPFlatUnmarshaller().unmarshall( Preconditions.checkNotNull( file ) );
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
logger.err( e, "Couldn't read user from: %s", file );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ).filter( Predicates.notNull() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ImmutableList<File> listUserFiles(final File userFilesDirectory) {
|
||||||
|
return ImmutableList.copyOf( ifNotNullElse( userFilesDirectory.listFiles( new FilenameFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(final File dir, final String name) {
|
||||||
|
return name.endsWith( ".mpsites" );
|
||||||
|
}
|
||||||
|
} ), new File[0] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteUser(final MPFileUser user) {
|
||||||
|
super.deleteUser( user );
|
||||||
|
|
||||||
|
// Remove deleted users.
|
||||||
|
File userFile = getUserFile( user );
|
||||||
|
if (userFile.exists() && !userFile.delete())
|
||||||
|
logger.err( "Couldn't delete file: %s", userFile );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the current user state to disk.
|
||||||
|
*/
|
||||||
|
public void save(final MPFileUser user, final MPMasterKey masterKey)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
try {
|
||||||
|
new CharSink() {
|
||||||
|
@Override
|
||||||
|
public Writer openStream()
|
||||||
|
throws IOException {
|
||||||
|
return new OutputStreamWriter( new FileOutputStream( getUserFile( user ) ), Charsets.UTF_8 );
|
||||||
|
}
|
||||||
|
}.write( new MPFlatMarshaller().marshall( user, masterKey, MPMarshaller.ContentMode.PROTECTED ) );
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
logger.err( e, "Unable to save sites for user: %s", user );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private File getUserFile(final MPFileUser user) {
|
||||||
|
return new File( userFilesDirectory, user.getFullName() + ".mpsites" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The location on the file system where the user models are stored.
|
||||||
|
*/
|
||||||
|
public File getPath() {
|
||||||
|
return userFilesDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
|
||||||
|
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||||
|
|
||||||
|
import com.lyndir.masterpassword.*;
|
||||||
|
import org.joda.time.Instant;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 2017-09-20
|
||||||
|
*/
|
||||||
|
public class MPFlatMarshaller implements MPMarshaller {
|
||||||
|
|
||||||
|
private static final int FORMAT = 1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
StringBuilder content = new StringBuilder();
|
||||||
|
content.append( "# Master Password site export\n" );
|
||||||
|
content.append( "# " ).append( contentMode.description() ).append( '\n' );
|
||||||
|
content.append( "# \n" );
|
||||||
|
content.append( "##\n" );
|
||||||
|
content.append( "# Format: " ).append( FORMAT ).append( '\n' );
|
||||||
|
content.append( "# Date: " ).append( MPConstant.dateTimeFormatter.print( new Instant() ) ).append( '\n' );
|
||||||
|
content.append( "# User Name: " ).append( user.getFullName() ).append( '\n' );
|
||||||
|
content.append( "# Full Name: " ).append( user.getFullName() ).append( '\n' );
|
||||||
|
content.append( "# Avatar: " ).append( user.getAvatar() ).append( '\n' );
|
||||||
|
content.append( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' );
|
||||||
|
content.append( "# Algorithm: " ).append( MPMasterKey.Version.CURRENT.toInt() ).append( '\n' );
|
||||||
|
content.append( "# Default Type: " ).append( user.getDefaultType().getType() ).append( '\n' );
|
||||||
|
content.append( "# Passwords: " ).append( contentMode.name() ).append( '\n' );
|
||||||
|
content.append( "##\n" );
|
||||||
|
content.append( "#\n" );
|
||||||
|
content.append( "# Last Times Password Login\t Site\tSite\n" );
|
||||||
|
content.append( "# used used type name\t name\tpassword\n" );
|
||||||
|
|
||||||
|
for (final MPFileSite site : user.getSites()) {
|
||||||
|
String loginName = site.getLoginContent();
|
||||||
|
String password = site.getSiteContent();
|
||||||
|
if (!contentMode.isRedacted()) {
|
||||||
|
loginName = site.loginFor( masterKey );
|
||||||
|
password = site.resultFor( masterKey );
|
||||||
|
}
|
||||||
|
|
||||||
|
content.append( strf( "%s %8d %8s %25s\t%25s\t%s\n", //
|
||||||
|
MPConstant.dateTimeFormatter.print( site.getLastUsed() ), // lastUsed
|
||||||
|
site.getUses(), // uses
|
||||||
|
strf( "%d:%d:%d", //
|
||||||
|
site.getResultType().getType(), // type
|
||||||
|
site.getAlgorithmVersion().toInt(), // algorithm
|
||||||
|
site.getSiteCounter().intValue() ), // counter
|
||||||
|
ifNotNullElse( loginName, "" ), // loginName
|
||||||
|
site.getSiteName(), // siteName
|
||||||
|
ifNotNullElse( password, "" ) // password
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return content.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import com.google.common.base.*;
|
||||||
|
import com.google.common.io.CharStreams;
|
||||||
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
|
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
||||||
|
import com.lyndir.masterpassword.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 14-12-07
|
||||||
|
*/
|
||||||
|
public class MPFlatUnmarshaller implements MPUnmarshaller {
|
||||||
|
|
||||||
|
private static final Pattern[] unmarshallFormats = {
|
||||||
|
Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)? +([^\t]+)\t(.*)" ),
|
||||||
|
Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)?(:\\d+)? +([^\t]*)\t *([^\t]+)\t(.*)" ) };
|
||||||
|
private static final Pattern headerFormat = Pattern.compile( "^#\\s*([^:]+): (.*)" );
|
||||||
|
private static final Pattern colon = Pattern.compile( ":" );
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public MPFileUser unmarshall(@Nonnull final File file)
|
||||||
|
throws IOException {
|
||||||
|
try (Reader reader = new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 )) {
|
||||||
|
return unmarshall( CharStreams.toString( reader ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public MPFileUser unmarshall(@Nonnull final String content) {
|
||||||
|
MPFileUser user = null;
|
||||||
|
byte[] keyID = null;
|
||||||
|
String fullName = null;
|
||||||
|
int mpVersion = 0, importFormat = 0, avatar = 0;
|
||||||
|
boolean clearContent = false, headerStarted = false;
|
||||||
|
MPResultType defaultType = MPResultType.DEFAULT;
|
||||||
|
|
||||||
|
//noinspection HardcodedLineSeparator
|
||||||
|
for (final String line : Splitter.on( CharMatcher.anyOf( "\r\n" ) ).omitEmptyStrings().split( content ))
|
||||||
|
// Header delimitor.
|
||||||
|
if (line.startsWith( "##" ))
|
||||||
|
if (!headerStarted)
|
||||||
|
// Starts the header.
|
||||||
|
headerStarted = true;
|
||||||
|
else
|
||||||
|
// Ends the header.
|
||||||
|
user = new MPFileUser( fullName, keyID, MPMasterKey.Version.fromInt( mpVersion ), avatar, defaultType, new DateTime( 0 ) );
|
||||||
|
|
||||||
|
// Comment.
|
||||||
|
else if (line.startsWith( "#" )) {
|
||||||
|
if (headerStarted && (user == null)) {
|
||||||
|
// In header.
|
||||||
|
Matcher headerMatcher = headerFormat.matcher( line );
|
||||||
|
if (headerMatcher.matches()) {
|
||||||
|
String name = headerMatcher.group( 1 ), value = headerMatcher.group( 2 );
|
||||||
|
if ("Full Name".equalsIgnoreCase( name ) || "User Name".equalsIgnoreCase( name ))
|
||||||
|
fullName = value;
|
||||||
|
else if ("Key ID".equalsIgnoreCase( name ))
|
||||||
|
keyID = CodeUtils.decodeHex( value );
|
||||||
|
else if ("Algorithm".equalsIgnoreCase( name ))
|
||||||
|
mpVersion = ConversionUtils.toIntegerNN( value );
|
||||||
|
else if ("Format".equalsIgnoreCase( name ))
|
||||||
|
importFormat = ConversionUtils.toIntegerNN( value );
|
||||||
|
else if ("Avatar".equalsIgnoreCase( name ))
|
||||||
|
avatar = ConversionUtils.toIntegerNN( value );
|
||||||
|
else if ("Passwords".equalsIgnoreCase( name ))
|
||||||
|
clearContent = "visible".equalsIgnoreCase( value );
|
||||||
|
else if ("Default Type".equalsIgnoreCase( name ))
|
||||||
|
defaultType = MPResultType.forType( ConversionUtils.toIntegerNN( value ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No comment.
|
||||||
|
else if (user != null) {
|
||||||
|
Matcher siteMatcher = unmarshallFormats[importFormat].matcher( line );
|
||||||
|
if (!siteMatcher.matches())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
MPFileSite site;
|
||||||
|
switch (importFormat) {
|
||||||
|
case 0:
|
||||||
|
site = new MPFileSite( user, //
|
||||||
|
siteMatcher.group( 5 ), siteMatcher.group( 6 ), MPFileSite.DEFAULT_COUNTER,
|
||||||
|
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
|
||||||
|
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
|
||||||
|
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ),
|
||||||
|
null, null, null, ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
|
||||||
|
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
site = new MPFileSite( user, //
|
||||||
|
siteMatcher.group( 7 ), siteMatcher.group( 8 ),
|
||||||
|
UnsignedInteger.valueOf( colon.matcher( siteMatcher.group( 5 ) ).replaceAll( "" ) ),
|
||||||
|
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
|
||||||
|
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
|
||||||
|
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ),
|
||||||
|
siteMatcher.group( 6 ), MPResultType.GeneratedName, null,
|
||||||
|
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
|
||||||
|
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException( "Unexpected format: " + importFormat );
|
||||||
|
}
|
||||||
|
|
||||||
|
user.addSite( site );
|
||||||
|
}
|
||||||
|
|
||||||
|
return Preconditions.checkNotNull( user, "No full header found in import file." );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 14-12-17
|
||||||
|
*/
|
||||||
|
public class MPIncorrectMasterPasswordException extends Exception {
|
||||||
|
|
||||||
|
private final MPFileUser user;
|
||||||
|
|
||||||
|
public MPIncorrectMasterPasswordException(final MPFileUser user) {
|
||||||
|
super( "Incorrect master password for user: " + user.getFullName() );
|
||||||
|
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MPFileUser getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import com.lyndir.masterpassword.MPMasterKey;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 2017-09-20
|
||||||
|
*/
|
||||||
|
public class MPJSONMarshaller implements MPMarshaller {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode) {
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 2017-09-20
|
||||||
|
*/
|
||||||
|
public class MPJSONUnmarshaller implements MPUnmarshaller {
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public MPFileUser unmarshall(@Nonnull final File file)
|
||||||
|
throws IOException {
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public MPFileUser unmarshall(@Nonnull final String content) {
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 2017-09-20
|
||||||
|
*/
|
||||||
|
public enum MPMarshalFormat {
|
||||||
|
/**
|
||||||
|
* Marshal using the line-based plain-text format.
|
||||||
|
*/
|
||||||
|
Flat {
|
||||||
|
@Override
|
||||||
|
public MPMarshaller marshaller() {
|
||||||
|
return new MPFlatMarshaller();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPUnmarshaller unmarshaller() {
|
||||||
|
return new MPFlatUnmarshaller();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marshal using the JSON structured format.
|
||||||
|
*/
|
||||||
|
JSON {
|
||||||
|
@Override
|
||||||
|
public MPMarshaller marshaller() {
|
||||||
|
return new MPJSONMarshaller();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPUnmarshaller unmarshaller() {
|
||||||
|
return new MPJSONUnmarshaller();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final MPMarshalFormat DEFAULT = JSON;
|
||||||
|
|
||||||
|
public abstract MPMarshaller marshaller();
|
||||||
|
|
||||||
|
public abstract MPUnmarshaller unmarshaller();
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import com.lyndir.masterpassword.MPInvalidatedException;
|
||||||
|
import com.lyndir.masterpassword.MPMasterKey;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 14-12-07
|
||||||
|
*/
|
||||||
|
public interface MPMarshaller {
|
||||||
|
|
||||||
|
String marshall(MPFileUser user, MPMasterKey masterKey, ContentMode contentMode)
|
||||||
|
throws MPInvalidatedException;
|
||||||
|
|
||||||
|
enum ContentMode {
|
||||||
|
PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key." ),
|
||||||
|
VISIBLE( "Export of site names and passwords in clear-text." );
|
||||||
|
|
||||||
|
private final String description;
|
||||||
|
private boolean redacted;
|
||||||
|
|
||||||
|
ContentMode(final String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String description() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRedacted() {
|
||||||
|
return redacted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,21 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
package com.lyndir.masterpassword.model;
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||||
@@ -6,138 +24,58 @@ import com.google.common.primitives.UnsignedInteger;
|
|||||||
import com.lyndir.masterpassword.*;
|
import com.lyndir.masterpassword.*;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import org.joda.time.Instant;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author lhunath, 14-12-05
|
* @author lhunath, 14-12-16
|
||||||
*/
|
*/
|
||||||
public class MPSite {
|
public abstract class MPSite {
|
||||||
|
|
||||||
public static final MPSiteType DEFAULT_TYPE = MPSiteType.GeneratedLong;
|
public static final UnsignedInteger DEFAULT_COUNTER = UnsignedInteger.ONE;
|
||||||
public static final UnsignedInteger DEFAULT_COUNTER = UnsignedInteger.valueOf( 1 );
|
|
||||||
|
|
||||||
private final MPUser user;
|
public abstract String getSiteName();
|
||||||
private MasterKey.Version algorithmVersion;
|
|
||||||
private Instant lastUsed;
|
|
||||||
private String siteName;
|
|
||||||
private MPSiteType siteType;
|
|
||||||
private UnsignedInteger siteCounter;
|
|
||||||
private int uses;
|
|
||||||
private String loginName;
|
|
||||||
|
|
||||||
public MPSite(final MPUser user, final String siteName) {
|
public abstract void setSiteName(String siteName);
|
||||||
this( user, siteName, DEFAULT_TYPE, DEFAULT_COUNTER );
|
|
||||||
|
public abstract UnsignedInteger getSiteCounter();
|
||||||
|
|
||||||
|
public abstract void setSiteCounter(UnsignedInteger siteCounter);
|
||||||
|
|
||||||
|
public abstract MPResultType getResultType();
|
||||||
|
|
||||||
|
public abstract void setResultType(MPResultType resultType);
|
||||||
|
|
||||||
|
public abstract MPMasterKey.Version getAlgorithmVersion();
|
||||||
|
|
||||||
|
public abstract void setAlgorithmVersion(MPMasterKey.Version algorithmVersion);
|
||||||
|
|
||||||
|
public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
|
||||||
|
@Nullable final String siteContent)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
|
return masterKey.siteResult(
|
||||||
|
getSiteName(), getSiteCounter(), keyPurpose, keyContext, getResultType(), siteContent, getAlgorithmVersion() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPSite(final MPUser user, final String siteName, final MPSiteType siteType, final UnsignedInteger siteCounter) {
|
public String loginFor(final MPMasterKey masterKey, final MPResultType loginType, @Nullable final String loginContent)
|
||||||
this.user = user;
|
throws MPInvalidatedException {
|
||||||
this.algorithmVersion = MasterKey.Version.CURRENT;
|
|
||||||
this.lastUsed = new Instant();
|
|
||||||
this.siteName = siteName;
|
|
||||||
this.siteType = siteType;
|
|
||||||
this.siteCounter = siteCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected MPSite(final MPUser user, final MasterKey.Version algorithmVersion, final Instant lastUsed, final String siteName,
|
return masterKey.siteResult(
|
||||||
final MPSiteType siteType, final UnsignedInteger siteCounter, final int uses, @Nullable final String loginName,
|
getSiteName(), DEFAULT_COUNTER, MPKeyPurpose.Identification, null, loginType, loginContent, getAlgorithmVersion() );
|
||||||
@Nullable final String importContent) {
|
|
||||||
this.user = user;
|
|
||||||
this.algorithmVersion = algorithmVersion;
|
|
||||||
this.lastUsed = lastUsed;
|
|
||||||
this.siteName = siteName;
|
|
||||||
this.siteType = siteType;
|
|
||||||
this.siteCounter = siteCounter;
|
|
||||||
this.uses = uses;
|
|
||||||
this.loginName = loginName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String resultFor(final MasterKey masterKey) {
|
|
||||||
return resultFor( masterKey, MPSiteVariant.Password, null );
|
|
||||||
}
|
|
||||||
|
|
||||||
public String resultFor(final MasterKey masterKey, final MPSiteVariant variant, @Nullable final String context) {
|
|
||||||
return masterKey.encode( siteName, siteType, siteCounter, variant, context );
|
|
||||||
}
|
|
||||||
|
|
||||||
public MPUser getUser() {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
protected String exportContent() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MasterKey.Version getAlgorithmVersion() {
|
|
||||||
return algorithmVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAlgorithmVersion(final MasterKey.Version mpVersion) {
|
|
||||||
this.algorithmVersion = mpVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getLastUsed() {
|
|
||||||
return lastUsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateLastUsed() {
|
|
||||||
lastUsed = new Instant();
|
|
||||||
user.updateLastUsed();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSiteName() {
|
|
||||||
return siteName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSiteName(final String siteName) {
|
|
||||||
this.siteName = siteName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MPSiteType getSiteType() {
|
|
||||||
return siteType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSiteType(final MPSiteType siteType) {
|
|
||||||
this.siteType = siteType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnsignedInteger getSiteCounter() {
|
|
||||||
return siteCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSiteCounter(final UnsignedInteger siteCounter) {
|
|
||||||
this.siteCounter = siteCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getUses() {
|
|
||||||
return uses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUses(final int uses) {
|
|
||||||
this.uses = uses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLoginName() {
|
|
||||||
return loginName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLoginName(final String loginName) {
|
|
||||||
this.loginName = loginName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object obj) {
|
public boolean equals(final Object obj) {
|
||||||
return (this == obj) || ((obj instanceof MPSite) && Objects.equals( siteName, ((MPSite) obj).siteName ));
|
return (this == obj) || ((obj instanceof MPSite) && Objects.equals( getSiteName(), ((MPSite) obj).getSiteName() ));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hashCode( siteName );
|
return Objects.hashCode( getSiteName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return strf( "{MPSite: %s}", siteName );
|
return strf( "{%s: %s}", getClass().getSimpleName(), getSiteName() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
package com.lyndir.masterpassword.model;
|
|
||||||
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.lyndir.masterpassword.MasterKey;
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import org.joda.time.Instant;
|
|
||||||
import org.joda.time.format.DateTimeFormatter;
|
|
||||||
import org.joda.time.format.ISODateTimeFormat;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author lhunath, 14-12-07
|
|
||||||
*/
|
|
||||||
public class MPSiteMarshaller {
|
|
||||||
|
|
||||||
private static final DateTimeFormatter rfc3339 = ISODateTimeFormat.dateTimeNoMillis();
|
|
||||||
|
|
||||||
private final StringBuilder export = new StringBuilder();
|
|
||||||
private ContentMode contentMode = ContentMode.PROTECTED;
|
|
||||||
private MasterKey masterKey;
|
|
||||||
|
|
||||||
public static MPSiteMarshaller marshallSafe(final MPUser user) {
|
|
||||||
MPSiteMarshaller marshaller = new MPSiteMarshaller();
|
|
||||||
marshaller.marshallHeaderForSafeContent( user );
|
|
||||||
for (final MPSite site : user.getSites())
|
|
||||||
marshaller.marshallSite( site );
|
|
||||||
|
|
||||||
return marshaller;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MPSiteMarshaller marshallVisible(final MPUser user, final MasterKey masterKey) {
|
|
||||||
MPSiteMarshaller marshaller = new MPSiteMarshaller();
|
|
||||||
marshaller.marshallHeaderForVisibleContentWithKey( user, masterKey );
|
|
||||||
for (final MPSite site : user.getSites())
|
|
||||||
marshaller.marshallSite( site );
|
|
||||||
|
|
||||||
return marshaller;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String marshallHeaderForSafeContent(final MPUser user) {
|
|
||||||
return marshallHeader( ContentMode.PROTECTED, user, null );
|
|
||||||
}
|
|
||||||
|
|
||||||
private String marshallHeaderForVisibleContentWithKey(final MPUser user, final MasterKey masterKey) {
|
|
||||||
return marshallHeader( ContentMode.VISIBLE, user, masterKey );
|
|
||||||
}
|
|
||||||
|
|
||||||
private String marshallHeader(final ContentMode contentMode, final MPUser user, @Nullable final MasterKey masterKey) {
|
|
||||||
this.contentMode = contentMode;
|
|
||||||
this.masterKey = masterKey;
|
|
||||||
|
|
||||||
StringBuilder header = new StringBuilder();
|
|
||||||
header.append( "# Master Password site export\n" );
|
|
||||||
header.append( "# " ).append( this.contentMode.description() ).append( '\n' );
|
|
||||||
header.append( "# \n" );
|
|
||||||
header.append( "##\n" );
|
|
||||||
header.append( "# Format: 1\n" );
|
|
||||||
header.append( "# Date: " ).append( rfc3339.print( new Instant() ) ).append( '\n' );
|
|
||||||
header.append( "# User Name: " ).append( user.getFullName() ).append( '\n' );
|
|
||||||
header.append( "# Full Name: " ).append( user.getFullName() ).append( '\n' );
|
|
||||||
header.append( "# Avatar: " ).append( user.getAvatar() ).append( '\n' );
|
|
||||||
header.append( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' );
|
|
||||||
header.append( "# Version: " ).append( MasterKey.Version.CURRENT.toBundleVersion() ).append( '\n' );
|
|
||||||
header.append( "# Algorithm: " ).append( MasterKey.Version.CURRENT.toInt() ).append( '\n' );
|
|
||||||
header.append( "# Default Type: " ).append( user.getDefaultType().getType() ).append( '\n' );
|
|
||||||
header.append( "# Passwords: " ).append( this.contentMode.name() ).append( '\n' );
|
|
||||||
header.append( "##\n" );
|
|
||||||
header.append( "#\n" );
|
|
||||||
header.append( "# Last Times Password Login\t Site\tSite\n" );
|
|
||||||
header.append( "# used used type name\t name\tpassword\n" );
|
|
||||||
|
|
||||||
export.append( header );
|
|
||||||
return header.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String marshallSite(final MPSite site) {
|
|
||||||
String exportLine = strf( "%s %8d %8s %25s\t%25s\t%s", //
|
|
||||||
rfc3339.print( site.getLastUsed() ), // lastUsed
|
|
||||||
site.getUses(), // uses
|
|
||||||
strf( "%d:%d:%d", //
|
|
||||||
site.getSiteType().getType(), // type
|
|
||||||
site.getAlgorithmVersion().toInt(), // algorithm
|
|
||||||
site.getSiteCounter().intValue() ), // counter
|
|
||||||
ifNotNullElse( site.getLoginName(), "" ), // loginName
|
|
||||||
site.getSiteName(), // siteName
|
|
||||||
ifNotNullElse( contentMode.contentForSite( site, masterKey ), "" ) // password
|
|
||||||
);
|
|
||||||
export.append( exportLine ).append( '\n' );
|
|
||||||
|
|
||||||
return exportLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExport() {
|
|
||||||
return export.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContentMode getContentMode() {
|
|
||||||
return contentMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ContentMode {
|
|
||||||
PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key." ) {
|
|
||||||
@Override
|
|
||||||
public String contentForSite(final MPSite site, @Nullable final MasterKey masterKey) {
|
|
||||||
return site.exportContent();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
VISIBLE( "Export of site names and passwords in clear-text." ) {
|
|
||||||
@Override
|
|
||||||
public String contentForSite(final MPSite site, @Nonnull final MasterKey masterKey) {
|
|
||||||
return site.resultFor( Preconditions.checkNotNull( masterKey, "Master key is required when content mode is VISIBLE." ) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final String description;
|
|
||||||
|
|
||||||
ContentMode(final String description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String description() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract String contentForSite(MPSite site, MasterKey masterKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,21 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
package com.lyndir.masterpassword.model;
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||||
@@ -10,13 +28,13 @@ import java.util.Objects;
|
|||||||
*/
|
*/
|
||||||
public class MPSiteResult {
|
public class MPSiteResult {
|
||||||
|
|
||||||
private final MPSite site;
|
private final MPFileSite site;
|
||||||
|
|
||||||
public MPSiteResult(final MPSite site) {
|
public MPSiteResult(final MPFileSite site) {
|
||||||
this.site = site;
|
this.site = site;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPSite getSite() {
|
public MPFileSite getSite() {
|
||||||
return site;
|
return site;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,163 +0,0 @@
|
|||||||
package com.lyndir.masterpassword.model;
|
|
||||||
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
|
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.io.CharStreams;
|
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
|
||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
|
||||||
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
|
||||||
import com.lyndir.lhunath.opal.system.util.NNOperation;
|
|
||||||
import com.lyndir.masterpassword.MPSiteType;
|
|
||||||
import com.lyndir.masterpassword.MasterKey;
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import org.joda.time.DateTime;
|
|
||||||
import org.joda.time.format.DateTimeFormatter;
|
|
||||||
import org.joda.time.format.ISODateTimeFormat;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author lhunath, 14-12-07
|
|
||||||
*/
|
|
||||||
public class MPSiteUnmarshaller {
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
|
||||||
private static final Logger logger = Logger.get( MPSite.class );
|
|
||||||
private static final DateTimeFormatter rfc3339 = ISODateTimeFormat.dateTimeNoMillis();
|
|
||||||
private static final Pattern[] unmarshallFormats = {
|
|
||||||
Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)? +([^\t]+)\t(.*)" ),
|
|
||||||
Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)?(:\\d+)? +([^\t]*)\t *([^\t]+)\t(.*)" ) };
|
|
||||||
private static final Pattern headerFormat = Pattern.compile( "^#\\s*([^:]+): (.*)" );
|
|
||||||
|
|
||||||
private final int importFormat;
|
|
||||||
@SuppressWarnings({ "FieldCanBeLocal", "unused" })
|
|
||||||
private final int mpVersion;
|
|
||||||
@SuppressWarnings({ "FieldCanBeLocal", "unused" })
|
|
||||||
private final boolean clearContent;
|
|
||||||
private final MPUser user;
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
public static MPSiteUnmarshaller unmarshall(@Nonnull final File file)
|
|
||||||
throws IOException {
|
|
||||||
try (Reader reader = new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 )) {
|
|
||||||
return unmarshall( CharStreams.readLines( reader ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
public static MPSiteUnmarshaller unmarshall(@Nonnull final List<String> lines) {
|
|
||||||
byte[] keyID = null;
|
|
||||||
String fullName = null;
|
|
||||||
int mpVersion = 0, importFormat = 0, avatar = 0;
|
|
||||||
boolean clearContent = false, headerStarted = false;
|
|
||||||
MPSiteType defaultType = MPSiteType.GeneratedLong;
|
|
||||||
MPSiteUnmarshaller marshaller = null;
|
|
||||||
final ImmutableList.Builder<MPSite> sites = ImmutableList.builder();
|
|
||||||
|
|
||||||
for (final String line : lines)
|
|
||||||
// Header delimitor.
|
|
||||||
if (line.startsWith( "##" ))
|
|
||||||
if (!headerStarted)
|
|
||||||
// Starts the header.
|
|
||||||
headerStarted = true;
|
|
||||||
else
|
|
||||||
// Ends the header.
|
|
||||||
marshaller = new MPSiteUnmarshaller( importFormat, mpVersion, fullName, keyID, avatar, defaultType, clearContent );
|
|
||||||
|
|
||||||
// Comment.
|
|
||||||
else if (line.startsWith( "#" )) {
|
|
||||||
if (headerStarted && (marshaller == null)) {
|
|
||||||
// In header.
|
|
||||||
Matcher headerMatcher = headerFormat.matcher( line );
|
|
||||||
if (headerMatcher.matches()) {
|
|
||||||
String name = headerMatcher.group( 1 ), value = headerMatcher.group( 2 );
|
|
||||||
if ("Full Name".equalsIgnoreCase( name ) || "User Name".equalsIgnoreCase( name ))
|
|
||||||
fullName = value;
|
|
||||||
else if ("Key ID".equalsIgnoreCase( name ))
|
|
||||||
keyID = CodeUtils.decodeHex( value );
|
|
||||||
else if ("Algorithm".equalsIgnoreCase( name ))
|
|
||||||
mpVersion = ConversionUtils.toIntegerNN( value );
|
|
||||||
else if ("Format".equalsIgnoreCase( name ))
|
|
||||||
importFormat = ConversionUtils.toIntegerNN( value );
|
|
||||||
else if ("Avatar".equalsIgnoreCase( name ))
|
|
||||||
avatar = ConversionUtils.toIntegerNN( value );
|
|
||||||
else if ("Passwords".equalsIgnoreCase( name ))
|
|
||||||
clearContent = "visible".equalsIgnoreCase( value );
|
|
||||||
else if ("Default Type".equalsIgnoreCase( name ))
|
|
||||||
defaultType = MPSiteType.forType( ConversionUtils.toIntegerNN( value ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No comment.
|
|
||||||
else if (marshaller != null)
|
|
||||||
ifNotNull( marshaller.unmarshallSite( line ), new NNOperation<MPSite>() {
|
|
||||||
@Override
|
|
||||||
public void apply(@Nonnull final MPSite site) {
|
|
||||||
sites.add( site );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
return Preconditions.checkNotNull( marshaller, "No full header found in import file." );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected MPSiteUnmarshaller(final int importFormat, final int mpVersion, final String fullName, final byte[] keyID, final int avatar,
|
|
||||||
final MPSiteType defaultType, final boolean clearContent) {
|
|
||||||
this.importFormat = importFormat;
|
|
||||||
this.mpVersion = mpVersion;
|
|
||||||
this.clearContent = clearContent;
|
|
||||||
|
|
||||||
user = new MPUser( fullName, keyID, MasterKey.Version.fromInt( mpVersion ), avatar, defaultType, new DateTime( 0 ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public MPSite unmarshallSite(@Nonnull final String siteLine) {
|
|
||||||
Matcher siteMatcher = unmarshallFormats[importFormat].matcher( siteLine );
|
|
||||||
if (!siteMatcher.matches())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
MPSite site;
|
|
||||||
switch (importFormat) {
|
|
||||||
case 0:
|
|
||||||
site = new MPSite( user, //
|
|
||||||
MasterKey.Version.fromInt( ConversionUtils.toIntegerNN( siteMatcher.group( 4 ).replace( ":", "" ) ) ), //
|
|
||||||
rfc3339.parseDateTime( siteMatcher.group( 1 ) ).toInstant(), //
|
|
||||||
siteMatcher.group( 5 ), //
|
|
||||||
MPSiteType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ), MPSite.DEFAULT_COUNTER, //
|
|
||||||
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ), //
|
|
||||||
null, //
|
|
||||||
siteMatcher.group( 6 ) );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
site = new MPSite( user, //
|
|
||||||
MasterKey.Version.fromInt( ConversionUtils.toIntegerNN( siteMatcher.group( 4 ).replace( ":", "" ) ) ), //
|
|
||||||
rfc3339.parseDateTime( siteMatcher.group( 1 ) ).toInstant(), //
|
|
||||||
siteMatcher.group( 7 ), //
|
|
||||||
MPSiteType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
|
|
||||||
UnsignedInteger.valueOf( siteMatcher.group( 5 ).replace( ":", "" ) ), //
|
|
||||||
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ), //
|
|
||||||
siteMatcher.group( 6 ), //
|
|
||||||
siteMatcher.group( 8 ) );
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw logger.bug( "Unexpected format: %d", importFormat );
|
|
||||||
}
|
|
||||||
|
|
||||||
user.addSite( site );
|
|
||||||
return site;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MPUser getUser() {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,24 +16,21 @@
|
|||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
package com.lyndir.masterpassword;
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <i>07 04, 2012</i>
|
* @author lhunath, 14-12-07
|
||||||
*
|
|
||||||
* @author lhunath
|
|
||||||
*/
|
*/
|
||||||
public enum MPSiteTypeClass {
|
public interface MPUnmarshaller {
|
||||||
Generated( 1 << 4 ),
|
|
||||||
Stored( 1 << 5 );
|
|
||||||
|
|
||||||
private final int mask;
|
@Nonnull
|
||||||
|
MPFileUser unmarshall(@Nonnull File file)
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
MPSiteTypeClass(final int mask) {
|
@Nonnull
|
||||||
this.mask = mask;
|
MPFileUser unmarshall(@Nonnull String content);
|
||||||
}
|
|
||||||
|
|
||||||
public int getMask() {
|
|
||||||
return mask;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,153 +1,86 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
package com.lyndir.masterpassword.model;
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
import com.lyndir.masterpassword.MPSiteType;
|
import com.lyndir.masterpassword.MPInvalidatedException;
|
||||||
import com.lyndir.masterpassword.MasterKey;
|
import com.lyndir.masterpassword.MPMasterKey;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import org.joda.time.*;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author lhunath, 14-12-07
|
* @author lhunath, 2014-06-08
|
||||||
*/
|
*/
|
||||||
public class MPUser implements Comparable<MPUser> {
|
public abstract class MPUser<S extends MPSite> {
|
||||||
|
|
||||||
private final String fullName;
|
|
||||||
private final Collection<MPSite> sites = Sets.newHashSet();
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private byte[] keyID;
|
protected MPMasterKey key;
|
||||||
private final MasterKey.Version algorithmVersion;
|
|
||||||
private int avatar;
|
|
||||||
private MPSiteType defaultType;
|
|
||||||
private ReadableInstant lastUsed;
|
|
||||||
|
|
||||||
public MPUser(final String fullName) {
|
public abstract String getFullName();
|
||||||
this( fullName, null );
|
|
||||||
|
public boolean isMasterKeyAvailable() {
|
||||||
|
return key != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPUser(final String fullName, @Nullable final byte[] keyID) {
|
|
||||||
this( fullName, keyID, MasterKey.Version.CURRENT, 0, MPSiteType.GeneratedLong, new DateTime() );
|
|
||||||
}
|
|
||||||
|
|
||||||
public MPUser(final String fullName, @Nullable final byte[] keyID, final MasterKey.Version algorithmVersion, final int avatar,
|
|
||||||
final MPSiteType defaultType, final ReadableInstant lastUsed) {
|
|
||||||
this.fullName = fullName;
|
|
||||||
this.keyID = (keyID == null)? null: keyID.clone();
|
|
||||||
this.algorithmVersion = algorithmVersion;
|
|
||||||
this.avatar = avatar;
|
|
||||||
this.defaultType = defaultType;
|
|
||||||
this.lastUsed = lastUsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<MPSiteResult> findSitesByName(final String query) {
|
|
||||||
ImmutableList.Builder<MPSiteResult> results = ImmutableList.builder();
|
|
||||||
for (final MPSite site : getSites())
|
|
||||||
if (site.getSiteName().startsWith( query ))
|
|
||||||
results.add( new MPSiteResult( site ) );
|
|
||||||
|
|
||||||
return results.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSite(final MPSite site) {
|
|
||||||
sites.add( site );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteSite(final MPSite site) {
|
|
||||||
sites.remove( site );
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFullName() {
|
|
||||||
return fullName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasKeyID() {
|
|
||||||
return keyID != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String exportKeyID() {
|
|
||||||
return CodeUtils.encodeHex( keyID );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs an authentication attempt against the keyID for this user.
|
|
||||||
*
|
|
||||||
* Note: If this user doesn't have a keyID set yet, authentication will always succeed and the key ID will be set as a result.
|
|
||||||
*
|
|
||||||
* @param masterPassword The password to authenticate with.
|
|
||||||
*
|
|
||||||
* @return The master key for the user if authentication was successful.
|
|
||||||
*
|
|
||||||
* @throws IncorrectMasterPasswordException If authentication fails due to the given master password not matching the user's keyID.
|
|
||||||
*/
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
public MPMasterKey getMasterKey() {
|
||||||
public MasterKey authenticate(final char[] masterPassword)
|
return Preconditions.checkNotNull( key, "User is not authenticated: " + getFullName() );
|
||||||
throws IncorrectMasterPasswordException {
|
|
||||||
MasterKey masterKey = MasterKey.create( algorithmVersion, getFullName(), masterPassword );
|
|
||||||
if ((keyID == null) || (keyID.length == 0))
|
|
||||||
keyID = masterKey.getKeyID();
|
|
||||||
else if (!Arrays.equals( masterKey.getKeyID(), keyID ))
|
|
||||||
throw new IncorrectMasterPasswordException( this );
|
|
||||||
|
|
||||||
return masterKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String exportKeyID()
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithmVersion() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract MPMasterKey.Version getAlgorithmVersion();
|
||||||
|
|
||||||
public int getAvatar() {
|
public int getAvatar() {
|
||||||
return avatar;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAvatar(final int avatar) {
|
public abstract void addSite(S site);
|
||||||
this.avatar = avatar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MPSiteType getDefaultType() {
|
public abstract void deleteSite(S site);
|
||||||
return defaultType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultType(final MPSiteType defaultType) {
|
public abstract Collection<S> findSites(String query);
|
||||||
this.defaultType = defaultType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadableInstant getLastUsed() {
|
@Nonnull
|
||||||
return lastUsed;
|
public abstract MPMasterKey authenticate(char[] masterPassword)
|
||||||
}
|
throws MPIncorrectMasterPasswordException;
|
||||||
|
|
||||||
public void updateLastUsed() {
|
@Override
|
||||||
lastUsed = new Instant();
|
public int hashCode() {
|
||||||
}
|
return Objects.hashCode( getFullName() );
|
||||||
|
|
||||||
public Iterable<MPSite> getSites() {
|
|
||||||
return sites;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object obj) {
|
public boolean equals(final Object obj) {
|
||||||
return (this == obj) || ((obj instanceof MPUser) && Objects.equals( fullName, ((MPUser) obj).fullName ));
|
return (this == obj) || ((obj instanceof MPUser) && Objects.equals( getFullName(), ((MPUser<?>) obj).getFullName() ));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hashCode( fullName );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return strf( "{MPUser: %s}", fullName );
|
return strf( "{%s: %s}", getClass().getSimpleName(), getFullName() );
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(final MPUser o) {
|
|
||||||
int comparison = lastUsed.compareTo( o.lastUsed );
|
|
||||||
if (comparison == 0)
|
|
||||||
comparison = fullName.compareTo( o.fullName );
|
|
||||||
|
|
||||||
return comparison;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,124 +0,0 @@
|
|||||||
package com.lyndir.masterpassword.model;
|
|
||||||
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
|
|
||||||
|
|
||||||
import com.google.common.base.*;
|
|
||||||
import com.google.common.collect.*;
|
|
||||||
import com.google.common.io.CharSink;
|
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
|
||||||
import com.lyndir.masterpassword.MPConstant;
|
|
||||||
import java.io.*;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages user data stored in user-specific {@code .mpsites} files under {@code .mpw.d}.
|
|
||||||
* @author lhunath, 14-12-07
|
|
||||||
*/
|
|
||||||
public class MPUserFileManager extends MPUserManager {
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
|
||||||
private static final Logger logger = Logger.get( MPUserFileManager.class );
|
|
||||||
private static final MPUserFileManager instance;
|
|
||||||
|
|
||||||
static {
|
|
||||||
String rcDir = System.getenv( MPConstant.env_rcDir );
|
|
||||||
if (rcDir != null)
|
|
||||||
instance = create( new File( rcDir ) );
|
|
||||||
else
|
|
||||||
instance = create( new File( ifNotNullElseNullable( System.getProperty( "user.home" ), System.getenv( "HOME" ) ), ".mpw.d" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private final File userFilesDirectory;
|
|
||||||
|
|
||||||
public static MPUserFileManager get() {
|
|
||||||
MPUserManager.instance = instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MPUserFileManager create(final File userFilesDirectory) {
|
|
||||||
return new MPUserFileManager( userFilesDirectory );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected MPUserFileManager(final File userFilesDirectory) {
|
|
||||||
|
|
||||||
super( unmarshallUsers( userFilesDirectory ) );
|
|
||||||
this.userFilesDirectory = userFilesDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Iterable<MPUser> unmarshallUsers(final File userFilesDirectory) {
|
|
||||||
if (!userFilesDirectory.mkdirs() && !userFilesDirectory.isDirectory()) {
|
|
||||||
logger.err( "Couldn't create directory for user files: %s", userFilesDirectory );
|
|
||||||
return ImmutableList.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
return FluentIterable.from( listUserFiles( userFilesDirectory ) ).transform( new Function<File, MPUser>() {
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public MPUser apply(@Nullable final File file) {
|
|
||||||
try {
|
|
||||||
return MPSiteUnmarshaller.unmarshall( Preconditions.checkNotNull( file ) ).getUser();
|
|
||||||
}
|
|
||||||
catch (final IOException e) {
|
|
||||||
logger.err( e, "Couldn't read user from: %s", file );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ).filter( Predicates.notNull() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ImmutableList<File> listUserFiles(final File userFilesDirectory) {
|
|
||||||
return ImmutableList.copyOf( ifNotNullElse( userFilesDirectory.listFiles( new FilenameFilter() {
|
|
||||||
@Override
|
|
||||||
public boolean accept(final File dir, final String name) {
|
|
||||||
return name.endsWith( ".mpsites" );
|
|
||||||
}
|
|
||||||
} ), new File[0] ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addUser(final MPUser user) {
|
|
||||||
super.addUser( user );
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteUser(final MPUser user) {
|
|
||||||
super.deleteUser( user );
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write the current user state to disk.
|
|
||||||
*/
|
|
||||||
public void save() {
|
|
||||||
// Save existing users.
|
|
||||||
for (final MPUser user : getUsers())
|
|
||||||
try {
|
|
||||||
new CharSink() {
|
|
||||||
@Override
|
|
||||||
public Writer openStream()
|
|
||||||
throws IOException {
|
|
||||||
File mpsitesFile = new File( userFilesDirectory, user.getFullName() + ".mpsites" );
|
|
||||||
return new OutputStreamWriter( new FileOutputStream( mpsitesFile ), Charsets.UTF_8 );
|
|
||||||
}
|
|
||||||
}.write( MPSiteMarshaller.marshallSafe( user ).getExport() );
|
|
||||||
}
|
|
||||||
catch (final IOException e) {
|
|
||||||
logger.err( e, "Unable to save sites for user: %s", user );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove deleted users.
|
|
||||||
for (final File userFile : listUserFiles( userFilesDirectory ))
|
|
||||||
if (getUserNamed( userFile.getName().replaceFirst( "\\.mpsites$", "" ) ) == null)
|
|
||||||
if (!userFile.delete())
|
|
||||||
logger.err( "Couldn't delete file: %s", userFile );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The location on the file system where the user models are stored.
|
|
||||||
*/
|
|
||||||
public File getPath() {
|
|
||||||
return userFilesDirectory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,25 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
package com.lyndir.masterpassword.model;
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
|
import com.lyndir.masterpassword.MPInvalidatedException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
@@ -9,31 +28,31 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public abstract class MPUserManager {
|
public abstract class MPUserManager {
|
||||||
|
|
||||||
private final Map<String, MPUser> usersByName = Maps.newHashMap();
|
private final Map<String, MPFileUser> usersByName = Maps.newHashMap();
|
||||||
static MPUserManager instance;
|
static MPUserManager instance;
|
||||||
|
|
||||||
public static MPUserManager get() {
|
public static MPUserManager get() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MPUserManager(final Iterable<MPUser> users) {
|
protected MPUserManager(final Iterable<MPFileUser> users) {
|
||||||
for (final MPUser user : users)
|
for (final MPFileUser user : users)
|
||||||
usersByName.put( user.getFullName(), user );
|
usersByName.put( user.getFullName(), user );
|
||||||
}
|
}
|
||||||
|
|
||||||
public SortedSet<MPUser> getUsers() {
|
public SortedSet<MPFileUser> getUsers() {
|
||||||
return FluentIterable.from( usersByName.values() ).toSortedSet( Ordering.natural() );
|
return FluentIterable.from( usersByName.values() ).toSortedSet( Ordering.natural() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPUser getUserNamed(final String fullName) {
|
public MPFileUser getUserNamed(final String fullName) {
|
||||||
return usersByName.get( fullName );
|
return usersByName.get( fullName );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addUser(final MPUser user) {
|
public void addUser(final MPFileUser user) {
|
||||||
usersByName.put( user.getFullName(), user );
|
usersByName.put( user.getFullName(), user );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteUser(final MPUser user) {
|
public void deleteUser(final MPFileUser user) {
|
||||||
usersByName.remove( user.getFullName() );
|
usersByName.remove( user.getFullName() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author lhunath, 15-02-04
|
* @author lhunath, 15-02-04
|
||||||
|
|||||||
@@ -23,12 +23,10 @@ import com.google.common.collect.Lists;
|
|||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
||||||
import com.lyndir.lhunath.opal.system.util.NNFunctionNN;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.xml.parsers.*;
|
import javax.xml.parsers.*;
|
||||||
import org.xml.sax.Attributes;
|
import org.xml.sax.Attributes;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
@@ -38,7 +36,7 @@ import org.xml.sax.ext.DefaultHandler2;
|
|||||||
/**
|
/**
|
||||||
* @author lhunath, 2015-12-22
|
* @author lhunath, 2015-12-22
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("HardCodedStringLiteral")
|
@SuppressWarnings({ "HardCodedStringLiteral", "ProhibitedExceptionDeclared" })
|
||||||
public class MPTestSuite implements Callable<Boolean> {
|
public class MPTestSuite implements Callable<Boolean> {
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
@@ -99,12 +97,12 @@ public class MPTestSuite implements Callable<Boolean> {
|
|||||||
currentCase.siteName = text;
|
currentCase.siteName = text;
|
||||||
if ("siteCounter".equals( qName ))
|
if ("siteCounter".equals( qName ))
|
||||||
currentCase.siteCounter = text.isEmpty()? null: UnsignedInteger.valueOf( text );
|
currentCase.siteCounter = text.isEmpty()? null: UnsignedInteger.valueOf( text );
|
||||||
if ("siteType".equals( qName ))
|
if ("resultType".equals( qName ))
|
||||||
currentCase.siteType = text;
|
currentCase.resultType = text;
|
||||||
if ("siteVariant".equals( qName ))
|
if ("keyPurpose".equals( qName ))
|
||||||
currentCase.siteVariant = text;
|
currentCase.keyPurpose = text;
|
||||||
if ("siteContext".equals( qName ))
|
if ("keyContext".equals( qName ))
|
||||||
currentCase.siteContext = text;
|
currentCase.keyContext = text;
|
||||||
if ("result".equals( qName ))
|
if ("result".equals( qName ))
|
||||||
currentCase.result = text;
|
currentCase.result = text;
|
||||||
}
|
}
|
||||||
@@ -134,7 +132,8 @@ public class MPTestSuite implements Callable<Boolean> {
|
|||||||
return tests;
|
return tests;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean forEach(final String testName, final NNFunctionNN<MPTests.Case, Boolean> testFunction) {
|
public boolean forEach(final String testName, final TestCase testFunction)
|
||||||
|
throws Exception {
|
||||||
List<MPTests.Case> cases = tests.getCases();
|
List<MPTests.Case> cases = tests.getCases();
|
||||||
for (int c = 0; c < cases.size(); c++) {
|
for (int c = 0; c < cases.size(); c++) {
|
||||||
MPTests.Case testCase = cases.get( c );
|
MPTests.Case testCase = cases.get( c );
|
||||||
@@ -144,7 +143,7 @@ public class MPTestSuite implements Callable<Boolean> {
|
|||||||
progress( Logger.Target.INFO, c, cases.size(), //
|
progress( Logger.Target.INFO, c, cases.size(), //
|
||||||
"[%s] on %s...", testName, testCase.getIdentifier() );
|
"[%s] on %s...", testName, testCase.getIdentifier() );
|
||||||
|
|
||||||
if (!testFunction.apply( testCase )) {
|
if (!testFunction.run( testCase )) {
|
||||||
progress( Logger.Target.ERROR, cases.size(), cases.size(), //
|
progress( Logger.Target.ERROR, cases.size(), cases.size(), //
|
||||||
"[%s] on %s: FAILED!", testName, testCase.getIdentifier() );
|
"[%s] on %s: FAILED!", testName, testCase.getIdentifier() );
|
||||||
|
|
||||||
@@ -168,13 +167,14 @@ public class MPTestSuite implements Callable<Boolean> {
|
|||||||
@Override
|
@Override
|
||||||
public Boolean call()
|
public Boolean call()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
return forEach( "mpw", new NNFunctionNN<MPTests.Case, Boolean>() {
|
return forEach( "mpw", new TestCase() {
|
||||||
@Nonnull
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean apply(@Nonnull final MPTests.Case testCase) {
|
public boolean run(final MPTests.Case testCase)
|
||||||
MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() );
|
throws Exception {
|
||||||
String sitePassword = masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(),
|
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), testCase.getMasterPassword().toCharArray() );
|
||||||
testCase.getSiteVariant(), testCase.getSiteContext() );
|
String sitePassword = masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||||
|
testCase.getKeyContext(), testCase.getResultType(),
|
||||||
|
null, testCase.getAlgorithm() );
|
||||||
|
|
||||||
return testCase.getResult().equals( sitePassword );
|
return testCase.getResult().equals( sitePassword );
|
||||||
}
|
}
|
||||||
@@ -195,4 +195,11 @@ public class MPTestSuite implements Callable<Boolean> {
|
|||||||
|
|
||||||
void progress(int current, int max, String messageFormat, Object... args);
|
void progress(int current, int max, String messageFormat, Object... args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface TestCase {
|
||||||
|
|
||||||
|
boolean run(MPTests.Case testCase)
|
||||||
|
throws Exception;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,18 +66,18 @@ public class MPTests {
|
|||||||
|
|
||||||
public static class Case {
|
public static class Case {
|
||||||
|
|
||||||
String identifier;
|
String identifier;
|
||||||
String parent;
|
String parent;
|
||||||
Integer algorithm;
|
Integer algorithm;
|
||||||
String fullName;
|
String fullName;
|
||||||
String masterPassword;
|
String masterPassword;
|
||||||
String keyID;
|
String keyID;
|
||||||
String siteName;
|
String siteName;
|
||||||
UnsignedInteger siteCounter;
|
UnsignedInteger siteCounter;
|
||||||
String siteType;
|
String resultType;
|
||||||
String siteVariant;
|
String keyPurpose;
|
||||||
String siteContext;
|
String keyContext;
|
||||||
String result;
|
String result;
|
||||||
|
|
||||||
private transient Case parentCase;
|
private transient Case parentCase;
|
||||||
|
|
||||||
@@ -130,25 +130,25 @@ public class MPTests {
|
|||||||
return checkNotNull( parentCase.siteCounter );
|
return checkNotNull( parentCase.siteCounter );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
siteType = ifNotNullElse( siteType, new NNSupplier<String>() {
|
resultType = ifNotNullElse( resultType, new NNSupplier<String>() {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String get() {
|
public String get() {
|
||||||
return checkNotNull( parentCase.siteType );
|
return checkNotNull( parentCase.resultType );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
siteVariant = ifNotNullElse( siteVariant, new NNSupplier<String>() {
|
keyPurpose = ifNotNullElse( keyPurpose, new NNSupplier<String>() {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String get() {
|
public String get() {
|
||||||
return checkNotNull( parentCase.siteVariant );
|
return checkNotNull( parentCase.keyPurpose );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
siteContext = ifNotNullElse( siteContext, new NNSupplier<String>() {
|
keyContext = ifNotNullElse( keyContext, new NNSupplier<String>() {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String get() {
|
public String get() {
|
||||||
return (parentCase == null)? "": checkNotNull( parentCase.siteContext );
|
return (parentCase == null)? "": checkNotNull( parentCase.keyContext );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
result = ifNotNullElse( result, new NNSupplier<String>() {
|
result = ifNotNullElse( result, new NNSupplier<String>() {
|
||||||
@@ -171,8 +171,8 @@ public class MPTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public MasterKey.Version getAlgorithm() {
|
public MPMasterKey.Version getAlgorithm() {
|
||||||
return MasterKey.Version.fromInt( checkNotNull( algorithm ) );
|
return MPMasterKey.Version.fromInt( checkNotNull( algorithm ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@@ -181,8 +181,8 @@ public class MPTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public char[] getMasterPassword() {
|
public String getMasterPassword() {
|
||||||
return checkNotNull( masterPassword ).toCharArray();
|
return checkNotNull( masterPassword );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@@ -200,18 +200,18 @@ public class MPTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public MPSiteType getSiteType() {
|
public MPResultType getResultType() {
|
||||||
return MPSiteType.forName( checkNotNull( siteType ) );
|
return MPResultType.forName( checkNotNull( resultType ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public MPSiteVariant getSiteVariant() {
|
public MPKeyPurpose getKeyPurpose() {
|
||||||
return MPSiteVariant.forName( checkNotNull( siteVariant ) );
|
return MPKeyPurpose.forName( checkNotNull( keyPurpose ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public String getSiteContext() {
|
public String getKeyContext() {
|
||||||
return checkNotNull( siteContext );
|
return checkNotNull( keyContext );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
|||||||
@@ -1,279 +0,0 @@
|
|||||||
<tests>
|
|
||||||
<!-- Default values for all parameters. -->
|
|
||||||
<case id="default">
|
|
||||||
<algorithm>-1</algorithm>
|
|
||||||
<fullName>Robert Lee Mitchell</fullName>
|
|
||||||
<masterPassword>banana colored duckling</masterPassword>
|
|
||||||
<keyID>98EEF4D1DF46D849574A82A03C3177056B15DFFCA29BB3899DE4628453675302</keyID>
|
|
||||||
<siteName>masterpasswordapp.com</siteName>
|
|
||||||
<siteCounter>1</siteCounter>
|
|
||||||
<resultType>GeneratedLong</resultType>
|
|
||||||
<keyPurpose>Authentication</keyPurpose>
|
|
||||||
<result><!-- abstract --></result>
|
|
||||||
</case>
|
|
||||||
|
|
||||||
<!-- Algorithm 3 -->
|
|
||||||
<case id="v3" parent="default">
|
|
||||||
<algorithm>3</algorithm>
|
|
||||||
<result>Jejr5[RepuSosp</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_mb_fullName" parent="v3">
|
|
||||||
<fullName>⛄</fullName>
|
|
||||||
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
|
|
||||||
<result>NopaDajh8=Fene</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_mb_masterPassword" parent="v3">
|
|
||||||
<masterPassword>⛄</masterPassword>
|
|
||||||
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
|
|
||||||
<result>QesuHirv5-Xepl</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_mb_siteName" parent="v3">
|
|
||||||
<siteName>⛄</siteName>
|
|
||||||
<result>LiheCuwhSerz6)</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_loginName" parent="v3">
|
|
||||||
<keyPurpose>Identification</keyPurpose>
|
|
||||||
<resultType>GeneratedName</resultType>
|
|
||||||
<result>wohzaqage</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_securityAnswer" parent="v3">
|
|
||||||
<keyPurpose>Recovery</keyPurpose>
|
|
||||||
<resultType>GeneratedPhrase</resultType>
|
|
||||||
<result>xin diyjiqoja hubu</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_securityAnswer_context" parent="v3_securityAnswer">
|
|
||||||
<keyContext>question</keyContext>
|
|
||||||
<result>xogx tem cegyiva jab</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_type_maximum" parent="v3">
|
|
||||||
<resultType>GeneratedMaximum</resultType>
|
|
||||||
<result>W6@692^B1#&@gVdSdLZ@</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_type_medium" parent="v3">
|
|
||||||
<resultType>GeneratedMedium</resultType>
|
|
||||||
<result>Jej2$Quv</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_type_basic" parent="v3">
|
|
||||||
<resultType>GeneratedBasic</resultType>
|
|
||||||
<result>WAo2xIg6</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_type_short" parent="v3">
|
|
||||||
<resultType>GeneratedShort</resultType>
|
|
||||||
<result>Jej2</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_type_pin" parent="v3">
|
|
||||||
<resultType>GeneratedPIN</resultType>
|
|
||||||
<result>7662</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_type_name" parent="v3">
|
|
||||||
<resultType>GeneratedName</resultType>
|
|
||||||
<result>jejraquvo</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_type_phrase" parent="v3">
|
|
||||||
<resultType>GeneratedPhrase</resultType>
|
|
||||||
<result>jejr quv cabsibu tam</result>
|
|
||||||
</case>
|
|
||||||
<case id="v3_counter_ceiling" parent="v3">
|
|
||||||
<siteCounter>4294967295</siteCounter>
|
|
||||||
<result>XambHoqo6[Peni</result>
|
|
||||||
</case>
|
|
||||||
|
|
||||||
<!-- Algorithm 2 -->
|
|
||||||
<case id="v2" parent="default">
|
|
||||||
<algorithm>2</algorithm>
|
|
||||||
<result>Jejr5[RepuSosp</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_mb_fullName" parent="v2">
|
|
||||||
<fullName>⛄</fullName>
|
|
||||||
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
|
|
||||||
<result>WaqoGuho2[Xaxw</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_mb_masterPassword" parent="v2">
|
|
||||||
<masterPassword>⛄</masterPassword>
|
|
||||||
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
|
|
||||||
<result>QesuHirv5-Xepl</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_mb_siteName" parent="v2">
|
|
||||||
<siteName>⛄</siteName>
|
|
||||||
<result>LiheCuwhSerz6)</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_loginName" parent="v2">
|
|
||||||
<keyPurpose>Identification</keyPurpose>
|
|
||||||
<resultType>GeneratedName</resultType>
|
|
||||||
<result>wohzaqage</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_securityAnswer" parent="v2">
|
|
||||||
<keyPurpose>Recovery</keyPurpose>
|
|
||||||
<resultType>GeneratedPhrase</resultType>
|
|
||||||
<result>xin diyjiqoja hubu</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_securityAnswer_context" parent="v2_securityAnswer">
|
|
||||||
<keyContext>question</keyContext>
|
|
||||||
<result>xogx tem cegyiva jab</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_type_maximum" parent="v2">
|
|
||||||
<resultType>GeneratedMaximum</resultType>
|
|
||||||
<result>W6@692^B1#&@gVdSdLZ@</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_type_medium" parent="v2">
|
|
||||||
<resultType>GeneratedMedium</resultType>
|
|
||||||
<result>Jej2$Quv</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_type_basic" parent="v2">
|
|
||||||
<resultType>GeneratedBasic</resultType>
|
|
||||||
<result>WAo2xIg6</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_type_short" parent="v2">
|
|
||||||
<resultType>GeneratedShort</resultType>
|
|
||||||
<result>Jej2</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_type_pin" parent="v2">
|
|
||||||
<resultType>GeneratedPIN</resultType>
|
|
||||||
<result>7662</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_type_name" parent="v2">
|
|
||||||
<resultType>GeneratedName</resultType>
|
|
||||||
<result>jejraquvo</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_type_phrase" parent="v2">
|
|
||||||
<resultType>GeneratedPhrase</resultType>
|
|
||||||
<result>jejr quv cabsibu tam</result>
|
|
||||||
</case>
|
|
||||||
<case id="v2_counter_ceiling" parent="v2">
|
|
||||||
<siteCounter>4294967295</siteCounter>
|
|
||||||
<result>XambHoqo6[Peni</result>
|
|
||||||
</case>
|
|
||||||
|
|
||||||
<!-- Algorithm 1 -->
|
|
||||||
<case id="v1" parent="default">
|
|
||||||
<algorithm>1</algorithm>
|
|
||||||
<result>Jejr5[RepuSosp</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_mb_fullName" parent="v1">
|
|
||||||
<fullName>⛄</fullName>
|
|
||||||
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
|
|
||||||
<result>WaqoGuho2[Xaxw</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_mb_masterPassword" parent="v1">
|
|
||||||
<masterPassword>⛄</masterPassword>
|
|
||||||
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
|
|
||||||
<result>QesuHirv5-Xepl</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_mb_siteName" parent="v1">
|
|
||||||
<siteName>⛄</siteName>
|
|
||||||
<result>WawiYarp2@Kodh</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_loginName" parent="v1">
|
|
||||||
<keyPurpose>Identification</keyPurpose>
|
|
||||||
<resultType>GeneratedName</resultType>
|
|
||||||
<result>wohzaqage</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_securityAnswer" parent="v1">
|
|
||||||
<keyPurpose>Recovery</keyPurpose>
|
|
||||||
<resultType>GeneratedPhrase</resultType>
|
|
||||||
<result>xin diyjiqoja hubu</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_securityAnswer_context" parent="v1_securityAnswer">
|
|
||||||
<keyContext>question</keyContext>
|
|
||||||
<result>xogx tem cegyiva jab</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_type_maximum" parent="v1">
|
|
||||||
<resultType>GeneratedMaximum</resultType>
|
|
||||||
<result>W6@692^B1#&@gVdSdLZ@</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_type_medium" parent="v1">
|
|
||||||
<resultType>GeneratedMedium</resultType>
|
|
||||||
<result>Jej2$Quv</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_type_basic" parent="v1">
|
|
||||||
<resultType>GeneratedBasic</resultType>
|
|
||||||
<result>WAo2xIg6</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_type_short" parent="v1">
|
|
||||||
<resultType>GeneratedShort</resultType>
|
|
||||||
<result>Jej2</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_type_pin" parent="v1">
|
|
||||||
<resultType>GeneratedPIN</resultType>
|
|
||||||
<result>7662</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_type_name" parent="v1">
|
|
||||||
<resultType>GeneratedName</resultType>
|
|
||||||
<result>jejraquvo</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_type_phrase" parent="v1">
|
|
||||||
<resultType>GeneratedPhrase</resultType>
|
|
||||||
<result>jejr quv cabsibu tam</result>
|
|
||||||
</case>
|
|
||||||
<case id="v1_counter_ceiling" parent="v1">
|
|
||||||
<siteCounter>4294967295</siteCounter>
|
|
||||||
<result>XambHoqo6[Peni</result>
|
|
||||||
</case>
|
|
||||||
|
|
||||||
<!-- Algorithm 0 -->
|
|
||||||
<case id="v0" parent="default">
|
|
||||||
<algorithm>0</algorithm>
|
|
||||||
<result>Feji5@ReduWosh</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_mb_fullName" parent="v0">
|
|
||||||
<fullName>⛄</fullName>
|
|
||||||
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
|
|
||||||
<result>HajrYudo7@Mamh</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_mb_masterPassword" parent="v0">
|
|
||||||
<masterPassword>⛄</masterPassword>
|
|
||||||
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
|
|
||||||
<result>MewmDini0]Meho</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_mb_siteName" parent="v0">
|
|
||||||
<siteName>⛄</siteName>
|
|
||||||
<result>HahiVana2@Nole</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_loginName" parent="v0">
|
|
||||||
<keyPurpose>Identification</keyPurpose>
|
|
||||||
<resultType>GeneratedName</resultType>
|
|
||||||
<result>lozwajave</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_securityAnswer" parent="v0">
|
|
||||||
<keyPurpose>Recovery</keyPurpose>
|
|
||||||
<resultType>GeneratedPhrase</resultType>
|
|
||||||
<result>miy lirfijoja dubu</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_securityAnswer_context" parent="v0_securityAnswer">
|
|
||||||
<keyContext>question</keyContext>
|
|
||||||
<result>movm bex gevrica jaf</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_type_maximum" parent="v0">
|
|
||||||
<resultType>GeneratedMaximum</resultType>
|
|
||||||
<result>w1!3bA3icmRAc)SS@lwl</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_type_medium" parent="v0">
|
|
||||||
<resultType>GeneratedMedium</resultType>
|
|
||||||
<result>Fej7]Jug</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_type_basic" parent="v0">
|
|
||||||
<resultType>GeneratedBasic</resultType>
|
|
||||||
<result>wvH7irC1</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_type_short" parent="v0">
|
|
||||||
<resultType>GeneratedShort</resultType>
|
|
||||||
<result>Fej7</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_type_pin" parent="v0">
|
|
||||||
<resultType>GeneratedPIN</resultType>
|
|
||||||
<result>2117</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_type_name" parent="v0">
|
|
||||||
<resultType>GeneratedName</resultType>
|
|
||||||
<result>fejrajugo</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_type_phrase" parent="v0">
|
|
||||||
<resultType>GeneratedPhrase</resultType>
|
|
||||||
<result>fejr jug gabsibu bax</result>
|
|
||||||
</case>
|
|
||||||
<case id="v0_counter_ceiling" parent="v0">
|
|
||||||
<siteCounter>4294967295</siteCounter>
|
|
||||||
<result>QateDojh1@Hecn</result>
|
|
||||||
</case>
|
|
||||||
</tests>
|
|
||||||
|
|
||||||
1
core/java/tests/src/main/resources/mpw_tests.xml
Symbolic link
1
core/java/tests/src/main/resources/mpw_tests.xml
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../../../../mpw_tests.xml
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
|
import java.util.Random;
|
||||||
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
|
||||||
|
public class MPMasterKeyTest {
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
private static final Logger logger = Logger.get( MPMasterKeyTest.class );
|
||||||
|
|
||||||
|
private MPTestSuite testSuite;
|
||||||
|
|
||||||
|
@BeforeMethod
|
||||||
|
public void setUp()
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
testSuite = new MPTestSuite();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMasterKey()
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
testSuite.forEach( "testMasterKey", new MPTestSuite.TestCase() {
|
||||||
|
@Override
|
||||||
|
public boolean run(final MPTests.Case testCase)
|
||||||
|
throws Exception {
|
||||||
|
char[] masterPassword = testCase.getMasterPassword().toCharArray();
|
||||||
|
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
|
||||||
|
|
||||||
|
// Test key
|
||||||
|
assertEquals(
|
||||||
|
CodeUtils.encodeHex( masterKey.getKeyID( testCase.getAlgorithm() ) ),
|
||||||
|
testCase.getKeyID(),
|
||||||
|
"[testMasterKey] keyID mismatch: " + testCase );
|
||||||
|
|
||||||
|
// Test invalidation
|
||||||
|
masterKey.invalidate();
|
||||||
|
try {
|
||||||
|
masterKey.getKeyID( testCase.getAlgorithm() );
|
||||||
|
fail( "[testMasterKey] invalidate ineffective: " + testCase );
|
||||||
|
}
|
||||||
|
catch (final MPInvalidatedException ignored) {
|
||||||
|
}
|
||||||
|
assertNotEquals(
|
||||||
|
masterPassword,
|
||||||
|
testCase.getMasterPassword().toCharArray(),
|
||||||
|
"[testMasterKey] masterPassword not wiped: " + testCase );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSiteResult()
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
testSuite.forEach( "testSiteResult", new MPTestSuite.TestCase() {
|
||||||
|
@Override
|
||||||
|
public boolean run(final MPTests.Case testCase)
|
||||||
|
throws Exception {
|
||||||
|
char[] masterPassword = testCase.getMasterPassword().toCharArray();
|
||||||
|
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
|
||||||
|
|
||||||
|
// Test site result
|
||||||
|
assertEquals(
|
||||||
|
masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||||
|
testCase.getKeyContext(), testCase.getResultType(),
|
||||||
|
null, testCase.getAlgorithm() ),
|
||||||
|
testCase.getResult(),
|
||||||
|
"[testSiteResult] result mismatch: " + testCase );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSiteState()
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
MPTests.Case testCase = testSuite.getTests().getDefaultCase();
|
||||||
|
char[] masterPassword = testCase.getMasterPassword().toCharArray();
|
||||||
|
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
|
||||||
|
|
||||||
|
String password = randomString( 8 );
|
||||||
|
for (final MPMasterKey.Version version : MPMasterKey.Version.values()) {
|
||||||
|
MPResultType resultType = MPResultType.StoredPersonal;
|
||||||
|
|
||||||
|
// Test site state
|
||||||
|
String state = masterKey.siteState( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||||
|
testCase.getKeyContext(), resultType, password, version );
|
||||||
|
String result = masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||||
|
testCase.getKeyContext(), resultType, state, version );
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
result,
|
||||||
|
password,
|
||||||
|
"[testSiteState] state mismatch: " + testCase );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String randomString(int length) {
|
||||||
|
Random random = new Random();
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
while (length > 0) {
|
||||||
|
int codePoint = random.nextInt( Character.MAX_CODE_POINT - Character.MIN_CODE_POINT ) + Character.MIN_CODE_POINT;
|
||||||
|
if (!Character.isDefined( codePoint ) || (Character.getType( codePoint ) == Character.PRIVATE_USE) || Character.isSurrogate(
|
||||||
|
(char) codePoint ))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
builder.appendCodePoint( codePoint );
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
//==============================================================================
|
|
||||||
// This file is part of Master Password.
|
|
||||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
|
||||||
//
|
|
||||||
// Master Password is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Master Password is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You can find a copy of the GNU General Public License in the
|
|
||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
package com.lyndir.masterpassword;
|
|
||||||
|
|
||||||
import static org.testng.Assert.*;
|
|
||||||
|
|
||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
|
||||||
import com.lyndir.lhunath.opal.system.util.NNFunctionNN;
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import org.jetbrains.annotations.NonNls;
|
|
||||||
import org.testng.annotations.BeforeMethod;
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
|
|
||||||
public class MasterKeyTest {
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
|
||||||
private static final Logger logger = Logger.get( MasterKeyTest.class );
|
|
||||||
|
|
||||||
@NonNls
|
|
||||||
private MPTestSuite testSuite;
|
|
||||||
|
|
||||||
@BeforeMethod
|
|
||||||
public void setUp()
|
|
||||||
throws Exception {
|
|
||||||
|
|
||||||
testSuite = new MPTestSuite();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEncode()
|
|
||||||
throws Exception {
|
|
||||||
|
|
||||||
testSuite.forEach( "testEncode", new NNFunctionNN<MPTests.Case, Boolean>() {
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public Boolean apply(@Nonnull final MPTests.Case testCase) {
|
|
||||||
MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() );
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(),
|
|
||||||
testCase.getSiteVariant(), testCase.getSiteContext() ),
|
|
||||||
testCase.getResult(), "[testEncode] Failed test case: " + testCase );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetUserName()
|
|
||||||
throws Exception {
|
|
||||||
|
|
||||||
MPTests.Case defaultCase = testSuite.getTests().getDefaultCase();
|
|
||||||
|
|
||||||
assertEquals( MasterKey.create( defaultCase.getFullName(), defaultCase.getMasterPassword() ).getFullName(),
|
|
||||||
defaultCase.getFullName(), "[testGetUserName] Failed test case: " + defaultCase );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetKeyID()
|
|
||||||
throws Exception {
|
|
||||||
|
|
||||||
testSuite.forEach( "testGetKeyID", new NNFunctionNN<MPTests.Case, Boolean>() {
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public Boolean apply(@Nonnull final MPTests.Case testCase) {
|
|
||||||
MasterKey masterKey = MasterKey.create( testCase.getFullName(), testCase.getMasterPassword() );
|
|
||||||
|
|
||||||
assertEquals( CodeUtils.encodeHex( masterKey.getKeyID() ),
|
|
||||||
testCase.getKeyID(), "[testGetKeyID] Failed test case: " + testCase );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInvalidate()
|
|
||||||
throws Exception {
|
|
||||||
|
|
||||||
try {
|
|
||||||
MPTests.Case defaultCase = testSuite.getTests().getDefaultCase();
|
|
||||||
|
|
||||||
MasterKey masterKey = MasterKey.create( defaultCase.getFullName(), defaultCase.getMasterPassword() );
|
|
||||||
masterKey.invalidate();
|
|
||||||
masterKey.encode( defaultCase.getSiteName(), defaultCase.getSiteType(), defaultCase.getSiteCounter(),
|
|
||||||
defaultCase.getSiteVariant(), defaultCase.getSiteContext() );
|
|
||||||
|
|
||||||
fail( "[testInvalidate] Master key should have been invalidated, but was still usable." );
|
|
||||||
}
|
|
||||||
catch (final IllegalStateException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<logger name="com.lyndir" level="${mp.log.level:-INFO}" />
|
<logger name="com.lyndir" level="${mp.log.level:-TRACE}" />
|
||||||
|
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="stdout" />
|
<appender-ref ref="stdout" />
|
||||||
|
|||||||
279
core/mpw_tests.xml
Normal file
279
core/mpw_tests.xml
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
<tests>
|
||||||
|
<!-- Default values for all parameters. -->
|
||||||
|
<case id="default">
|
||||||
|
<algorithm>-1</algorithm>
|
||||||
|
<fullName>Robert Lee Mitchell</fullName>
|
||||||
|
<masterPassword>banana colored duckling</masterPassword>
|
||||||
|
<keyID>98EEF4D1DF46D849574A82A03C3177056B15DFFCA29BB3899DE4628453675302</keyID>
|
||||||
|
<siteName>masterpasswordapp.com</siteName>
|
||||||
|
<siteCounter>1</siteCounter>
|
||||||
|
<resultType>Long</resultType>
|
||||||
|
<keyPurpose>Authentication</keyPurpose>
|
||||||
|
<result><!-- abstract --></result>
|
||||||
|
</case>
|
||||||
|
|
||||||
|
<!-- Algorithm 3 -->
|
||||||
|
<case id="v3" parent="default">
|
||||||
|
<algorithm>3</algorithm>
|
||||||
|
<result>Jejr5[RepuSosp</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_mb_fullName" parent="v3">
|
||||||
|
<fullName>⛄</fullName>
|
||||||
|
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
|
||||||
|
<result>NopaDajh8=Fene</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_mb_masterPassword" parent="v3">
|
||||||
|
<masterPassword>⛄</masterPassword>
|
||||||
|
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
|
||||||
|
<result>QesuHirv5-Xepl</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_mb_siteName" parent="v3">
|
||||||
|
<siteName>⛄</siteName>
|
||||||
|
<result>LiheCuwhSerz6)</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_loginName" parent="v3">
|
||||||
|
<keyPurpose>Identification</keyPurpose>
|
||||||
|
<resultType>Name</resultType>
|
||||||
|
<result>wohzaqage</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_securityAnswer" parent="v3">
|
||||||
|
<keyPurpose>Recovery</keyPurpose>
|
||||||
|
<resultType>Phrase</resultType>
|
||||||
|
<result>xin diyjiqoja hubu</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_securityAnswer_context" parent="v3_securityAnswer">
|
||||||
|
<keyContext>question</keyContext>
|
||||||
|
<result>xogx tem cegyiva jab</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_type_maximum" parent="v3">
|
||||||
|
<resultType>Maximum</resultType>
|
||||||
|
<result>W6@692^B1#&@gVdSdLZ@</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_type_medium" parent="v3">
|
||||||
|
<resultType>Medium</resultType>
|
||||||
|
<result>Jej2$Quv</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_type_basic" parent="v3">
|
||||||
|
<resultType>Basic</resultType>
|
||||||
|
<result>WAo2xIg6</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_type_short" parent="v3">
|
||||||
|
<resultType>Short</resultType>
|
||||||
|
<result>Jej2</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_type_pin" parent="v3">
|
||||||
|
<resultType>PIN</resultType>
|
||||||
|
<result>7662</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_type_name" parent="v3">
|
||||||
|
<resultType>Name</resultType>
|
||||||
|
<result>jejraquvo</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_type_phrase" parent="v3">
|
||||||
|
<resultType>Phrase</resultType>
|
||||||
|
<result>jejr quv cabsibu tam</result>
|
||||||
|
</case>
|
||||||
|
<case id="v3_counter_ceiling" parent="v3">
|
||||||
|
<siteCounter>4294967295</siteCounter>
|
||||||
|
<result>XambHoqo6[Peni</result>
|
||||||
|
</case>
|
||||||
|
|
||||||
|
<!-- Algorithm 2 -->
|
||||||
|
<case id="v2" parent="default">
|
||||||
|
<algorithm>2</algorithm>
|
||||||
|
<result>Jejr5[RepuSosp</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_mb_fullName" parent="v2">
|
||||||
|
<fullName>⛄</fullName>
|
||||||
|
<keyID>4D5851D0B093D65DE0CF13D94877270468C0B65A6E42CA50D393AC9B99C457B5</keyID>
|
||||||
|
<result>WaqoGuho2[Xaxw</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_mb_masterPassword" parent="v2">
|
||||||
|
<masterPassword>⛄</masterPassword>
|
||||||
|
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
|
||||||
|
<result>QesuHirv5-Xepl</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_mb_siteName" parent="v2">
|
||||||
|
<siteName>⛄</siteName>
|
||||||
|
<result>LiheCuwhSerz6)</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_loginName" parent="v2">
|
||||||
|
<keyPurpose>Identification</keyPurpose>
|
||||||
|
<resultType>Name</resultType>
|
||||||
|
<result>wohzaqage</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_securityAnswer" parent="v2">
|
||||||
|
<keyPurpose>Recovery</keyPurpose>
|
||||||
|
<resultType>Phrase</resultType>
|
||||||
|
<result>xin diyjiqoja hubu</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_securityAnswer_context" parent="v2_securityAnswer">
|
||||||
|
<keyContext>question</keyContext>
|
||||||
|
<result>xogx tem cegyiva jab</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_type_maximum" parent="v2">
|
||||||
|
<resultType>Maximum</resultType>
|
||||||
|
<result>W6@692^B1#&@gVdSdLZ@</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_type_medium" parent="v2">
|
||||||
|
<resultType>Medium</resultType>
|
||||||
|
<result>Jej2$Quv</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_type_basic" parent="v2">
|
||||||
|
<resultType>Basic</resultType>
|
||||||
|
<result>WAo2xIg6</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_type_short" parent="v2">
|
||||||
|
<resultType>Short</resultType>
|
||||||
|
<result>Jej2</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_type_pin" parent="v2">
|
||||||
|
<resultType>PIN</resultType>
|
||||||
|
<result>7662</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_type_name" parent="v2">
|
||||||
|
<resultType>Name</resultType>
|
||||||
|
<result>jejraquvo</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_type_phrase" parent="v2">
|
||||||
|
<resultType>Phrase</resultType>
|
||||||
|
<result>jejr quv cabsibu tam</result>
|
||||||
|
</case>
|
||||||
|
<case id="v2_counter_ceiling" parent="v2">
|
||||||
|
<siteCounter>4294967295</siteCounter>
|
||||||
|
<result>XambHoqo6[Peni</result>
|
||||||
|
</case>
|
||||||
|
|
||||||
|
<!-- Algorithm 1 -->
|
||||||
|
<case id="v1" parent="default">
|
||||||
|
<algorithm>1</algorithm>
|
||||||
|
<result>Jejr5[RepuSosp</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_mb_fullName" parent="v1">
|
||||||
|
<fullName>⛄</fullName>
|
||||||
|
<keyID>4D5851D0B093D65DE0CF13D94877270468C0B65A6E42CA50D393AC9B99C457B5</keyID>
|
||||||
|
<result>WaqoGuho2[Xaxw</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_mb_masterPassword" parent="v1">
|
||||||
|
<masterPassword>⛄</masterPassword>
|
||||||
|
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
|
||||||
|
<result>QesuHirv5-Xepl</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_mb_siteName" parent="v1">
|
||||||
|
<siteName>⛄</siteName>
|
||||||
|
<result>WawiYarp2@Kodh</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_loginName" parent="v1">
|
||||||
|
<keyPurpose>Identification</keyPurpose>
|
||||||
|
<resultType>Name</resultType>
|
||||||
|
<result>wohzaqage</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_securityAnswer" parent="v1">
|
||||||
|
<keyPurpose>Recovery</keyPurpose>
|
||||||
|
<resultType>Phrase</resultType>
|
||||||
|
<result>xin diyjiqoja hubu</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_securityAnswer_context" parent="v1_securityAnswer">
|
||||||
|
<keyContext>question</keyContext>
|
||||||
|
<result>xogx tem cegyiva jab</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_type_maximum" parent="v1">
|
||||||
|
<resultType>Maximum</resultType>
|
||||||
|
<result>W6@692^B1#&@gVdSdLZ@</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_type_medium" parent="v1">
|
||||||
|
<resultType>Medium</resultType>
|
||||||
|
<result>Jej2$Quv</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_type_basic" parent="v1">
|
||||||
|
<resultType>Basic</resultType>
|
||||||
|
<result>WAo2xIg6</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_type_short" parent="v1">
|
||||||
|
<resultType>Short</resultType>
|
||||||
|
<result>Jej2</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_type_pin" parent="v1">
|
||||||
|
<resultType>PIN</resultType>
|
||||||
|
<result>7662</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_type_name" parent="v1">
|
||||||
|
<resultType>Name</resultType>
|
||||||
|
<result>jejraquvo</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_type_phrase" parent="v1">
|
||||||
|
<resultType>Phrase</resultType>
|
||||||
|
<result>jejr quv cabsibu tam</result>
|
||||||
|
</case>
|
||||||
|
<case id="v1_counter_ceiling" parent="v1">
|
||||||
|
<siteCounter>4294967295</siteCounter>
|
||||||
|
<result>XambHoqo6[Peni</result>
|
||||||
|
</case>
|
||||||
|
|
||||||
|
<!-- Algorithm 0 -->
|
||||||
|
<case id="v0" parent="default">
|
||||||
|
<algorithm>0</algorithm>
|
||||||
|
<result>Feji5@ReduWosh</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_mb_fullName" parent="v0">
|
||||||
|
<fullName>⛄</fullName>
|
||||||
|
<keyID>4D5851D0B093D65DE0CF13D94877270468C0B65A6E42CA50D393AC9B99C457B5</keyID>
|
||||||
|
<result>HajrYudo7@Mamh</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_mb_masterPassword" parent="v0">
|
||||||
|
<masterPassword>⛄</masterPassword>
|
||||||
|
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
|
||||||
|
<result>MewmDini0]Meho</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_mb_siteName" parent="v0">
|
||||||
|
<siteName>⛄</siteName>
|
||||||
|
<result>HahiVana2@Nole</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_loginName" parent="v0">
|
||||||
|
<keyPurpose>Identification</keyPurpose>
|
||||||
|
<resultType>Name</resultType>
|
||||||
|
<result>lozwajave</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_securityAnswer" parent="v0">
|
||||||
|
<keyPurpose>Recovery</keyPurpose>
|
||||||
|
<resultType>Phrase</resultType>
|
||||||
|
<result>miy lirfijoja dubu</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_securityAnswer_context" parent="v0_securityAnswer">
|
||||||
|
<keyContext>question</keyContext>
|
||||||
|
<result>movm bex gevrica jaf</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_type_maximum" parent="v0">
|
||||||
|
<resultType>Maximum</resultType>
|
||||||
|
<result>w1!3bA3icmRAc)SS@lwl</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_type_medium" parent="v0">
|
||||||
|
<resultType>Medium</resultType>
|
||||||
|
<result>Fej7]Jug</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_type_basic" parent="v0">
|
||||||
|
<resultType>Basic</resultType>
|
||||||
|
<result>wvH7irC1</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_type_short" parent="v0">
|
||||||
|
<resultType>Short</resultType>
|
||||||
|
<result>Fej7</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_type_pin" parent="v0">
|
||||||
|
<resultType>PIN</resultType>
|
||||||
|
<result>2117</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_type_name" parent="v0">
|
||||||
|
<resultType>Name</resultType>
|
||||||
|
<result>fejrajugo</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_type_phrase" parent="v0">
|
||||||
|
<resultType>Phrase</resultType>
|
||||||
|
<result>fejr jug gabsibu bax</result>
|
||||||
|
</case>
|
||||||
|
<case id="v0_counter_ceiling" parent="v0">
|
||||||
|
<siteCounter>4294967295</siteCounter>
|
||||||
|
<result>QateDojh1@Hecn</result>
|
||||||
|
</case>
|
||||||
|
</tests>
|
||||||
|
|
||||||
6
gradle/.idea/runConfigurations/Android.xml
generated
6
gradle/.idea/runConfigurations/Android.xml
generated
@@ -6,20 +6,18 @@
|
|||||||
<option name="PM_INSTALL_OPTIONS" value="" />
|
<option name="PM_INSTALL_OPTIONS" value="" />
|
||||||
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
|
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
|
||||||
<option name="MODE" value="default_activity" />
|
<option name="MODE" value="default_activity" />
|
||||||
<option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
|
|
||||||
<option name="PREFERRED_AVD" value="" />
|
<option name="PREFERRED_AVD" value="" />
|
||||||
<option name="CLEAR_LOGCAT" value="false" />
|
<option name="CLEAR_LOGCAT" value="false" />
|
||||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||||
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
|
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
|
||||||
<option name="FORCE_STOP_RUNNING_APP" value="true" />
|
<option name="FORCE_STOP_RUNNING_APP" value="true" />
|
||||||
<option name="DEBUGGER_TYPE" value="Java" />
|
<option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
|
||||||
<option name="USE_LAST_SELECTED_DEVICE" value="false" />
|
<option name="USE_LAST_SELECTED_DEVICE" value="false" />
|
||||||
<option name="PREFERRED_AVD" value="" />
|
<option name="PREFERRED_AVD" value="" />
|
||||||
|
<option name="DEBUGGER_TYPE" value="Java" />
|
||||||
<Java />
|
<Java />
|
||||||
<Profilers>
|
<Profilers>
|
||||||
<option name="ENABLE_ADVANCED_PROFILING" value="false" />
|
<option name="ENABLE_ADVANCED_PROFILING" value="false" />
|
||||||
<option name="GAPID_ENABLED" value="false" />
|
|
||||||
<option name="GAPID_DISABLE_PCS" value="false" />
|
|
||||||
<option name="SUPPORT_LIB_ENABLED" value="true" />
|
<option name="SUPPORT_LIB_ENABLED" value="true" />
|
||||||
<option name="INSTRUMENTATION_ENABLED" value="true" />
|
<option name="INSTRUMENTATION_ENABLED" value="true" />
|
||||||
</Profilers>
|
</Profilers>
|
||||||
|
|||||||
4
gradle/.idea/runConfigurations/GUI.xml
generated
4
gradle/.idea/runConfigurations/GUI.xml
generated
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="GUI" type="Application" factoryName="Application">
|
<configuration default="false" name="GUI" type="Application" factoryName="Application" show_console_on_std_err="true">
|
||||||
<option name="MAIN_CLASS_NAME" value="com.lyndir.masterpassword.gui.GUI" />
|
<option name="MAIN_CLASS_NAME" value="com.lyndir.masterpassword.gui.GUI" />
|
||||||
<option name="VM_PARAMETERS" value="" />
|
<option name="VM_PARAMETERS" value="" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="" />
|
<option name="PROGRAM_PARAMETERS" value="" />
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<option name="ENABLE_SWING_INSPECTOR" value="false" />
|
<option name="ENABLE_SWING_INSPECTOR" value="false" />
|
||||||
<option name="ENV_VARIABLES" />
|
<option name="ENV_VARIABLES" />
|
||||||
<option name="PASS_PARENT_ENVS" value="true" />
|
<option name="PASS_PARENT_ENVS" value="true" />
|
||||||
<module name="gui" />
|
<module name="masterpassword-gui" />
|
||||||
<envs />
|
<envs />
|
||||||
<method />
|
<method />
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
6
gradle/.idea/runConfigurations/Tests.xml
generated
6
gradle/.idea/runConfigurations/Tests.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Tests" type="TestNG" factoryName="TestNG">
|
<configuration default="false" name="Tests" type="TestNG" factoryName="TestNG" show_console_on_std_err="true">
|
||||||
<module name="tests" />
|
<module name="" />
|
||||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||||
<option name="ALTERNATIVE_JRE_PATH" />
|
<option name="ALTERNATIVE_JRE_PATH" />
|
||||||
<option name="SUITE_NAME" value="" />
|
<option name="SUITE_NAME" value="" />
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<option name="ENV_VARIABLES" />
|
<option name="ENV_VARIABLES" />
|
||||||
<option name="PASS_PARENT_ENVS" value="true" />
|
<option name="PASS_PARENT_ENVS" value="true" />
|
||||||
<option name="TEST_SEARCH_SCOPE">
|
<option name="TEST_SEARCH_SCOPE">
|
||||||
<value defaultName="singleModule" />
|
<value defaultName="wholeProject" />
|
||||||
</option>
|
</option>
|
||||||
<option name="USE_DEFAULT_REPORTERS" value="false" />
|
<option name="USE_DEFAULT_REPORTERS" value="false" />
|
||||||
<option name="PROPERTIES_FILE" value="" />
|
<option name="PROPERTIES_FILE" value="" />
|
||||||
|
|||||||
2
gradle/.idea/scopes/masterpassword.xml
generated
2
gradle/.idea/scopes/masterpassword.xml
generated
@@ -1,3 +1,3 @@
|
|||||||
<component name="DependencyValidationManager">
|
<component name="DependencyValidationManager">
|
||||||
<scope name="masterpassword" pattern="com.lyndir.masterpassword.*" />
|
<scope name="masterpassword" pattern="com.lyndir.masterpassword..*" />
|
||||||
</component>
|
</component>
|
||||||
@@ -22,7 +22,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath group: 'com.android.tools.build', name: 'gradle', version: '2.2.3'
|
classpath group: 'com.android.tools.build', name: 'gradle', version: '2.3.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
<module>masterpassword-tests</module>
|
<module>masterpassword-tests</module>
|
||||||
<module>masterpassword-algorithm</module>
|
<module>masterpassword-algorithm</module>
|
||||||
<module>masterpassword-model</module>
|
<module>masterpassword-model</module>
|
||||||
<module>masterpassword-cli</module>
|
|
||||||
<module>masterpassword-gui</module>
|
<module>masterpassword-gui</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
rootProject.name = 'masterpassword'
|
rootProject.name = 'masterpassword'
|
||||||
|
|
||||||
|
def local = new Properties();
|
||||||
|
try {
|
||||||
|
local.load(file('local.properties').newDataInputStream())
|
||||||
|
} catch (FileNotFoundException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
include 'masterpassword-algorithm'
|
include 'masterpassword-algorithm'
|
||||||
project(':masterpassword-algorithm').projectDir = new File( '../core/java/algorithm' )
|
project(':masterpassword-algorithm').projectDir = new File( '../core/java/algorithm' )
|
||||||
|
|
||||||
@@ -9,11 +15,12 @@ project(':masterpassword-model').projectDir = new File( '../core/java/model' )
|
|||||||
include 'masterpassword-tests'
|
include 'masterpassword-tests'
|
||||||
project(':masterpassword-tests').projectDir = new File( '../core/java/tests' )
|
project(':masterpassword-tests').projectDir = new File( '../core/java/tests' )
|
||||||
|
|
||||||
include 'masterpassword-cli'
|
|
||||||
project(':masterpassword-cli').projectDir = new File( '../platform-independent/cli-java' )
|
|
||||||
|
|
||||||
include 'masterpassword-gui'
|
include 'masterpassword-gui'
|
||||||
project(':masterpassword-gui').projectDir = new File( '../platform-independent/gui-java' )
|
project(':masterpassword-gui').projectDir = new File( '../platform-independent/gui-java' )
|
||||||
|
|
||||||
include 'masterpassword-android'
|
if (local.containsKey('sdk.dir')) {
|
||||||
project(':masterpassword-android').projectDir = new File( '../platform-android' )
|
include 'masterpassword-android'
|
||||||
|
project(':masterpassword-android').projectDir = new File( '../platform-android' )
|
||||||
|
} else {
|
||||||
|
logger.warn( "Skipping masterpassword-android since sdk.dir is not defined in local.properties." )
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import android.view.WindowManager;
|
|||||||
import android.widget.*;
|
import android.widget.*;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import com.google.common.base.Throwables;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
import com.google.common.util.concurrent.*;
|
import com.google.common.util.concurrent.*;
|
||||||
@@ -52,12 +51,12 @@ public class EmergencyActivity extends Activity {
|
|||||||
private static final int PASSWORD_NOTIFICATION = 0;
|
private static final int PASSWORD_NOTIFICATION = 0;
|
||||||
public static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S;
|
public static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S;
|
||||||
|
|
||||||
private final Preferences preferences = Preferences.get( this );
|
private final Preferences preferences = Preferences.get( this );
|
||||||
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
||||||
private final ImmutableList<MPSiteType> allSiteTypes = ImmutableList.copyOf( MPSiteType.forClass( MPSiteTypeClass.Generated ) );
|
private final ImmutableList<MPResultType> allResultTypes = ImmutableList.copyOf( MPResultType.forClass( MPResultTypeClass.Template ) );
|
||||||
private final ImmutableList<MasterKey.Version> allVersions = ImmutableList.copyOf( MasterKey.Version.values() );
|
private final ImmutableList<MPMasterKey.Version> allVersions = ImmutableList.copyOf( MPMasterKey.Version.values() );
|
||||||
|
|
||||||
private ListenableFuture<MasterKey> masterKeyFuture;
|
private MPMasterKey masterKey;
|
||||||
|
|
||||||
@BindView(R.id.progressView)
|
@BindView(R.id.progressView)
|
||||||
ProgressBar progressView;
|
ProgressBar progressView;
|
||||||
@@ -71,8 +70,8 @@ public class EmergencyActivity extends Activity {
|
|||||||
@BindView(R.id.siteNameField)
|
@BindView(R.id.siteNameField)
|
||||||
EditText siteNameField;
|
EditText siteNameField;
|
||||||
|
|
||||||
@BindView(R.id.siteTypeButton)
|
@BindView(R.id.resultTypeButton)
|
||||||
Button siteTypeButton;
|
Button resultTypeButton;
|
||||||
|
|
||||||
@BindView(R.id.counterField)
|
@BindView(R.id.counterField)
|
||||||
Button siteCounterButton;
|
Button siteCounterButton;
|
||||||
@@ -97,7 +96,6 @@ public class EmergencyActivity extends Activity {
|
|||||||
|
|
||||||
private int id_userName;
|
private int id_userName;
|
||||||
private int id_masterPassword;
|
private int id_masterPassword;
|
||||||
private int id_version;
|
|
||||||
private String sitePassword;
|
private String sitePassword;
|
||||||
|
|
||||||
public static void start(final Context context) {
|
public static void start(final Context context) {
|
||||||
@@ -131,15 +129,15 @@ public class EmergencyActivity extends Activity {
|
|||||||
updateSitePassword();
|
updateSitePassword();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
siteTypeButton.setOnClickListener( new View.OnClickListener() {
|
resultTypeButton.setOnClickListener( new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final View v) {
|
public void onClick(final View v) {
|
||||||
@SuppressWarnings("SuspiciousMethodCalls")
|
@SuppressWarnings("SuspiciousMethodCalls")
|
||||||
MPSiteType siteType =
|
MPResultType resultType =
|
||||||
allSiteTypes.get( (allSiteTypes.indexOf( siteTypeButton.getTag() ) + 1) % allSiteTypes.size() );
|
allResultTypes.get( (allResultTypes.indexOf( resultTypeButton.getTag() ) + 1) % allResultTypes.size() );
|
||||||
preferences.setDefaultSiteType( siteType );
|
preferences.setDefaultResultType( resultType );
|
||||||
siteTypeButton.setTag( siteType );
|
resultTypeButton.setTag( resultType );
|
||||||
siteTypeButton.setText( siteType.getShortName() );
|
resultTypeButton.setText( resultType.getShortName() );
|
||||||
updateSitePassword();
|
updateSitePassword();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
@@ -156,7 +154,7 @@ public class EmergencyActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(final View v) {
|
public void onClick(final View v) {
|
||||||
@SuppressWarnings("SuspiciousMethodCalls")
|
@SuppressWarnings("SuspiciousMethodCalls")
|
||||||
MasterKey.Version siteVersion =
|
MPMasterKey.Version siteVersion =
|
||||||
allVersions.get( (allVersions.indexOf( siteVersionButton.getTag() ) + 1) % allVersions.size() );
|
allVersions.get( (allVersions.indexOf( siteVersionButton.getTag() ) + 1) % allVersions.size() );
|
||||||
preferences.setDefaultVersion( siteVersion );
|
preferences.setDefaultVersion( siteVersion );
|
||||||
siteVersionButton.setTag( siteVersion );
|
siteVersionButton.setTag( siteVersion );
|
||||||
@@ -213,17 +211,17 @@ public class EmergencyActivity extends Activity {
|
|||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
// FIXME: MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
||||||
|
|
||||||
fullNameField.setText( preferences.getFullName() );
|
fullNameField.setText( preferences.getFullName() );
|
||||||
rememberFullNameField.setChecked( preferences.isRememberFullName() );
|
rememberFullNameField.setChecked( preferences.isRememberFullName() );
|
||||||
forgetPasswordField.setChecked( preferences.isForgetPassword() );
|
forgetPasswordField.setChecked( preferences.isForgetPassword() );
|
||||||
maskPasswordField.setChecked( preferences.isMaskPassword() );
|
maskPasswordField.setChecked( preferences.isMaskPassword() );
|
||||||
sitePasswordField.setTransformationMethod( preferences.isMaskPassword()? new PasswordTransformationMethod(): null );
|
sitePasswordField.setTransformationMethod( preferences.isMaskPassword()? new PasswordTransformationMethod(): null );
|
||||||
MPSiteType defaultSiteType = preferences.getDefaultSiteType();
|
MPResultType defaultResultType = preferences.getDefaultResultType();
|
||||||
siteTypeButton.setTag( defaultSiteType );
|
resultTypeButton.setTag( defaultResultType );
|
||||||
siteTypeButton.setText( defaultSiteType.getShortName() );
|
resultTypeButton.setText( defaultResultType.getShortName() );
|
||||||
MasterKey.Version defaultVersion = preferences.getDefaultVersion();
|
MPMasterKey.Version defaultVersion = preferences.getDefaultVersion();
|
||||||
siteVersionButton.setTag( defaultVersion );
|
siteVersionButton.setTag( defaultVersion );
|
||||||
siteVersionButton.setText( defaultVersion.name() );
|
siteVersionButton.setText( defaultVersion.name() );
|
||||||
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
|
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
|
||||||
@@ -241,10 +239,8 @@ public class EmergencyActivity extends Activity {
|
|||||||
if (preferences.isForgetPassword()) {
|
if (preferences.isForgetPassword()) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
id_userName = id_masterPassword = 0;
|
id_userName = id_masterPassword = 0;
|
||||||
if (masterKeyFuture != null) {
|
if (masterKey != null)
|
||||||
masterKeyFuture.cancel( true );
|
masterKey = null;
|
||||||
masterKeyFuture = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
masterPasswordField.setText( "" );
|
masterPasswordField.setText( "" );
|
||||||
}
|
}
|
||||||
@@ -260,23 +256,17 @@ public class EmergencyActivity extends Activity {
|
|||||||
private synchronized void updateMasterKey() {
|
private synchronized void updateMasterKey() {
|
||||||
final String fullName = fullNameField.getText().toString();
|
final String fullName = fullNameField.getText().toString();
|
||||||
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
|
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
|
||||||
final MasterKey.Version version = (MasterKey.Version) siteVersionButton.getTag();
|
|
||||||
if ((id_userName == fullName.hashCode())
|
if ((id_userName == fullName.hashCode())
|
||||||
&& (id_masterPassword == Arrays.hashCode( masterPassword ))
|
&& (id_masterPassword == Arrays.hashCode( masterPassword )))
|
||||||
&& (id_version == version.ordinal()))
|
if (masterKey != null)
|
||||||
if ((masterKeyFuture != null) && !masterKeyFuture.isCancelled())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
id_userName = fullName.hashCode();
|
id_userName = fullName.hashCode();
|
||||||
id_masterPassword = Arrays.hashCode( masterPassword );
|
id_masterPassword = Arrays.hashCode( masterPassword );
|
||||||
id_version = version.ordinal();
|
|
||||||
|
|
||||||
if (preferences.isRememberFullName())
|
if (preferences.isRememberFullName())
|
||||||
preferences.setFullName( fullName );
|
preferences.setFullName( fullName );
|
||||||
|
|
||||||
if (masterKeyFuture != null)
|
|
||||||
masterKeyFuture.cancel( true );
|
|
||||||
|
|
||||||
if (fullName.isEmpty() || (masterPassword.length == 0)) {
|
if (fullName.isEmpty() || (masterPassword.length == 0)) {
|
||||||
sitePasswordField.setText( "" );
|
sitePasswordField.setText( "" );
|
||||||
progressView.setVisibility( View.INVISIBLE );
|
progressView.setVisibility( View.INVISIBLE );
|
||||||
@@ -285,43 +275,21 @@ public class EmergencyActivity extends Activity {
|
|||||||
|
|
||||||
sitePasswordField.setText( "" );
|
sitePasswordField.setText( "" );
|
||||||
progressView.setVisibility( View.VISIBLE );
|
progressView.setVisibility( View.VISIBLE );
|
||||||
(masterKeyFuture = executor.submit( new Callable<MasterKey>() {
|
masterKey = new MPMasterKey( fullName, masterPassword );
|
||||||
@Override
|
updateSitePassword();
|
||||||
public MasterKey call()
|
|
||||||
throws Exception {
|
|
||||||
try {
|
|
||||||
return MasterKey.create( version, fullName, masterPassword );
|
|
||||||
}
|
|
||||||
catch (final Exception e) {
|
|
||||||
sitePasswordField.setText( "" );
|
|
||||||
progressView.setVisibility( View.INVISIBLE );
|
|
||||||
logger.err( e, "While generating master key." );
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} )).addListener( new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
runOnUiThread( new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
updateSitePassword();
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}, executor );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSitePassword() {
|
private void updateSitePassword() {
|
||||||
final String siteName = siteNameField.getText().toString();
|
final String siteName = siteNameField.getText().toString();
|
||||||
final MPSiteType type = (MPSiteType) siteTypeButton.getTag();
|
final MPResultType type = (MPResultType) resultTypeButton.getTag();
|
||||||
final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() );
|
final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() );
|
||||||
|
final MPMasterKey.Version version = (MPMasterKey.Version) siteVersionButton.getTag();
|
||||||
|
|
||||||
if ((masterKeyFuture == null) || siteName.isEmpty() || (type == null)) {
|
if ((masterKey == null) || siteName.isEmpty() || (type == null)) {
|
||||||
sitePasswordField.setText( "" );
|
sitePasswordField.setText( "" );
|
||||||
progressView.setVisibility( View.INVISIBLE );
|
progressView.setVisibility( View.INVISIBLE );
|
||||||
|
|
||||||
if (masterKeyFuture == null)
|
if (masterKey == null)
|
||||||
updateMasterKey();
|
updateMasterKey();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -332,7 +300,7 @@ public class EmergencyActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
sitePassword = masterKeyFuture.get().encode( siteName, type, counter, MPSiteVariant.Password, null );
|
sitePassword = masterKey.siteResult( siteName, counter, MPKeyPurpose.Authentication, null, type, null, version );
|
||||||
|
|
||||||
runOnUiThread( new Runnable() {
|
runOnUiThread( new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -342,16 +310,10 @@ public class EmergencyActivity extends Activity {
|
|||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
catch (final InterruptedException ignored) {
|
catch (final MPInvalidatedException ignored) {
|
||||||
sitePasswordField.setText( "" );
|
sitePasswordField.setText( "" );
|
||||||
progressView.setVisibility( View.INVISIBLE );
|
progressView.setVisibility( View.INVISIBLE );
|
||||||
}
|
}
|
||||||
catch (final ExecutionException e) {
|
|
||||||
sitePasswordField.setText( "" );
|
|
||||||
progressView.setVisibility( View.INVISIBLE );
|
|
||||||
logger.err( e, "While generating site password." );
|
|
||||||
throw Throwables.propagate( e );
|
|
||||||
}
|
|
||||||
catch (final RuntimeException e) {
|
catch (final RuntimeException e) {
|
||||||
sitePasswordField.setText( "" );
|
sitePasswordField.setText( "" );
|
||||||
progressView.setVisibility( View.INVISIBLE );
|
progressView.setVisibility( View.INVISIBLE );
|
||||||
@@ -363,10 +325,9 @@ public class EmergencyActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void integrityTests(final View view) {
|
public void integrityTests(final View view) {
|
||||||
if (masterKeyFuture != null) {
|
if (masterKey != null)
|
||||||
masterKeyFuture.cancel( true );
|
masterKey = null;
|
||||||
masterKeyFuture = null;
|
|
||||||
}
|
|
||||||
TestActivity.startNoSkip( this );
|
TestActivity.startNoSkip( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public final class Preferences {
|
|||||||
private static final String PREF_FORGET_PASSWORD = "forgetPassword";
|
private static final String PREF_FORGET_PASSWORD = "forgetPassword";
|
||||||
private static final String PREF_MASK_PASSWORD = "maskPassword";
|
private static final String PREF_MASK_PASSWORD = "maskPassword";
|
||||||
private static final String PREF_FULL_NAME = "fullName";
|
private static final String PREF_FULL_NAME = "fullName";
|
||||||
private static final String PREF_SITE_TYPE = "siteType";
|
private static final String PREF_RESULT_TYPE = "resultType";
|
||||||
private static final String PREF_ALGORITHM_VERSION = "algorithmVersion";
|
private static final String PREF_ALGORITHM_VERSION = "algorithmVersion";
|
||||||
private static Preferences instance;
|
private static Preferences instance;
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ public final class Preferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllowNativeKDF() {
|
public boolean isAllowNativeKDF() {
|
||||||
return prefs().getBoolean( PREF_NATIVE_KDF, MasterKey.isAllowNativeByDefault() );
|
return prefs().getBoolean( PREF_NATIVE_KDF, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setTestsPassed(final Set<String> value) {
|
public boolean setTestsPassed(final Set<String> value) {
|
||||||
@@ -138,20 +138,20 @@ public final class Preferences {
|
|||||||
return prefs().getString( PREF_FULL_NAME, "" );
|
return prefs().getString( PREF_FULL_NAME, "" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setDefaultSiteType(@Nonnull final MPSiteType value) {
|
public boolean setDefaultResultType(final MPResultType value) {
|
||||||
if (getDefaultSiteType() == value)
|
if (getDefaultResultType() == value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
prefs().edit().putInt( PREF_SITE_TYPE, value.ordinal() ).apply();
|
prefs().edit().putInt( PREF_RESULT_TYPE, value.ordinal() ).apply();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public MPSiteType getDefaultSiteType() {
|
public MPResultType getDefaultResultType() {
|
||||||
return MPSiteType.values()[prefs().getInt( PREF_SITE_TYPE, MPSiteType.GeneratedLong.ordinal() )];
|
return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, MPResultType.DEFAULT.ordinal() )];
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setDefaultVersion(@Nonnull final MasterKey.Version value) {
|
public boolean setDefaultVersion(final MPMasterKey.Version value) {
|
||||||
if (getDefaultVersion() == value)
|
if (getDefaultVersion() == value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ public final class Preferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public MasterKey.Version getDefaultVersion() {
|
public MPMasterKey.Version getDefaultVersion() {
|
||||||
return MasterKey.Version.values()[prefs().getInt( PREF_ALGORITHM_VERSION, MasterKey.Version.CURRENT.ordinal() )];
|
return MPMasterKey.Version.values()[prefs().getInt( PREF_ALGORITHM_VERSION, MPMasterKey.Version.CURRENT.ordinal() )];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
|||||||
@Override
|
@Override
|
||||||
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
|
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
|
||||||
preferences.setNativeKDFEnabled( isChecked );
|
preferences.setNativeKDFEnabled( isChecked );
|
||||||
MasterKey.setAllowNativeByDefault( isChecked );
|
// TODO: MasterKey.setAllowNativeByDefault( isChecked );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
|||||||
if (testFuture != null)
|
if (testFuture != null)
|
||||||
testFuture.cancel( true );
|
testFuture.cancel( true );
|
||||||
|
|
||||||
MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
// TODO: MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
||||||
|
|
||||||
setStatus( R.string.tests_testing, R.string.tests_btn_testing, null );
|
setStatus( R.string.tests_testing, R.string.tests_btn_testing, null );
|
||||||
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() {
|
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() {
|
||||||
|
|||||||
@@ -105,7 +105,7 @@
|
|||||||
android:id="@id/sitePasswordField"
|
android:id="@id/sitePasswordField"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:nextFocusForward="@+id/siteTypeButton"
|
android:nextFocusForward="@+id/resultTypeButton"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:textColor="#FFFFFF"
|
android:textColor="#FFFFFF"
|
||||||
@@ -157,7 +157,7 @@
|
|||||||
android:gravity="center">
|
android:gravity="center">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@id/siteTypeButton"
|
android:id="@id/resultTypeButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
@@ -175,12 +175,12 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:labelFor="@id/siteTypeButton"
|
android:labelFor="@id/resultTypeButton"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:textColor="@android:color/tertiary_text_dark"
|
android:textColor="@android:color/tertiary_text_dark"
|
||||||
android:text="@string/siteType_hint" />
|
android:text="@string/resultType_hint" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<string name="masterPassword_hint">Your master password</string>
|
<string name="masterPassword_hint">Your master password</string>
|
||||||
<string name="siteName_hint">eg. google.com</string>
|
<string name="siteName_hint">eg. google.com</string>
|
||||||
<string name="sitePassword_hint">Tap to copy</string>
|
<string name="sitePassword_hint">Tap to copy</string>
|
||||||
<string name="siteType_hint">Type</string>
|
<string name="resultType_hint">Type</string>
|
||||||
<string name="siteCounter_hint">Counter</string>
|
<string name="siteCounter_hint">Counter</string>
|
||||||
<string name="siteVersion_hint">Algorithm</string>
|
<string name="siteVersion_hint">Algorithm</string>
|
||||||
<string name="empty" />
|
<string name="empty" />
|
||||||
|
|||||||
2
platform-darwin/External/Pearl
vendored
2
platform-darwin/External/Pearl
vendored
Submodule platform-darwin/External/Pearl updated: f513a4a63c...b713577cd6
@@ -20,7 +20,6 @@
|
|||||||
93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39D8508BF868907E9732E /* PearlHangDetector.h */; };
|
93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39D8508BF868907E9732E /* PearlHangDetector.h */; };
|
||||||
93D39392DEDA376F93C6C718 /* MPCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39BAA71DE51B4D8A1286C /* MPCell.m */; };
|
93D39392DEDA376F93C6C718 /* MPCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39BAA71DE51B4D8A1286C /* MPCell.m */; };
|
||||||
93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3957D76F71A652716EECC /* MPStoreViewController.m */; };
|
93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3957D76F71A652716EECC /* MPStoreViewController.m */; };
|
||||||
93D393AA69A1193401160418 /* UIView+AlphaScale.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39488AB33616661725929 /* UIView+AlphaScale.m */; };
|
|
||||||
93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39A4759186F6D2D34AA6B /* PearlSizedTextView.h */; };
|
93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39A4759186F6D2D34AA6B /* PearlSizedTextView.h */; };
|
||||||
93D3942C1B117EE4851AA7B6 /* UIView+Visible.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */; };
|
93D3942C1B117EE4851AA7B6 /* UIView+Visible.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */; };
|
||||||
93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */; };
|
93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */; };
|
||||||
@@ -32,7 +31,6 @@
|
|||||||
93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */; };
|
93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */; };
|
||||||
93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B381350802A194BF332 /* MPAvatarCell.m */; };
|
93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B381350802A194BF332 /* MPAvatarCell.m */; };
|
||||||
93D39577FD8BB0945DB2F0A3 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39FD9623E8D5571C0AEB3 /* MPAlgorithmV3.m */; };
|
93D39577FD8BB0945DB2F0A3 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39FD9623E8D5571C0AEB3 /* MPAlgorithmV3.m */; };
|
||||||
93D3959696396A91961C6148 /* UIView+AlphaScale.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D392D76C091DEA3319F11D /* UIView+AlphaScale.h */; };
|
|
||||||
93D395B715D15F2B56F2A2EE /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D392C5A6572DB0EB5B82C8 /* mpw-types.c */; };
|
93D395B715D15F2B56F2A2EE /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D392C5A6572DB0EB5B82C8 /* mpw-types.c */; };
|
||||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
|
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
|
||||||
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B050DD5F55E9794EFD4 /* MPPopdownSegue.m */; };
|
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B050DD5F55E9794EFD4 /* MPPopdownSegue.m */; };
|
||||||
@@ -40,9 +38,7 @@
|
|||||||
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3942A356B639724157982 /* PearlOverlay.h */; };
|
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3942A356B639724157982 /* PearlOverlay.h */; };
|
||||||
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */; };
|
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */; };
|
||||||
93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */; };
|
93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */; };
|
||||||
93D397FCAAC6FA885247A4F9 /* PearlLinks.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39FEFC296AF6E7DF8E468 /* PearlLinks.m */; };
|
|
||||||
93D3980046016EFD05B35BC5 /* PearlUICollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */; };
|
93D3980046016EFD05B35BC5 /* PearlUICollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */; };
|
||||||
93D39861AEE621B287EA93E9 /* PearlLinks.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D399C408B705172FA0FA02 /* PearlLinks.h */; };
|
|
||||||
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */; };
|
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */; };
|
||||||
93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */; };
|
93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */; };
|
||||||
93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; };
|
93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; };
|
||||||
@@ -134,8 +130,6 @@
|
|||||||
DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2C3D641BD9612F001137B3 /* libz.tbd */; };
|
DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2C3D641BD9612F001137B3 /* libz.tbd */; };
|
||||||
DA2CA4DD18D28859007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */; };
|
DA2CA4DD18D28859007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */; };
|
||||||
DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4DA18D28859007798F8 /* NSArray+Pearl.h */; };
|
DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4DA18D28859007798F8 /* NSArray+Pearl.h */; };
|
||||||
DA2CA4DF18D28859007798F8 /* NSTimer+PearlBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4DB18D28859007798F8 /* NSTimer+PearlBlock.m */; };
|
|
||||||
DA2CA4E018D28859007798F8 /* NSTimer+PearlBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4DC18D28859007798F8 /* NSTimer+PearlBlock.h */; };
|
|
||||||
DA2CA4E418D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4E218D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h */; };
|
DA2CA4E418D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4E218D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h */; };
|
||||||
DA2CA4E618D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E518D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m */; };
|
DA2CA4E618D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E518D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m */; };
|
||||||
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
|
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
|
||||||
@@ -165,7 +159,6 @@
|
|||||||
DA32D07C19D7D784004F3F0E /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D07919D7D784004F3F0E /* background.png */; };
|
DA32D07C19D7D784004F3F0E /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D07919D7D784004F3F0E /* background.png */; };
|
||||||
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3509FC15F101A500C14A8E /* PearlQueue.h */; };
|
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3509FC15F101A500C14A8E /* PearlQueue.h */; };
|
||||||
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3509FD15F101A500C14A8E /* PearlQueue.m */; };
|
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3509FD15F101A500C14A8E /* PearlQueue.m */; };
|
||||||
DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */; };
|
|
||||||
DA3BCFCB19BD09D5006B2681 /* SourceCodePro-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA3BCFCA19BD09D5006B2681 /* SourceCodePro-Regular.otf */; };
|
DA3BCFCB19BD09D5006B2681 /* SourceCodePro-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA3BCFCA19BD09D5006B2681 /* SourceCodePro-Regular.otf */; };
|
||||||
DA4522441902355C008F650A /* icon_book.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD370C1711E29500CF925C /* icon_book.png */; };
|
DA4522441902355C008F650A /* icon_book.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD370C1711E29500CF925C /* icon_book.png */; };
|
||||||
DA4522451902355C008F650A /* icon_book@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD370D1711E29500CF925C /* icon_book@2x.png */; };
|
DA4522451902355C008F650A /* icon_book@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD370D1711E29500CF925C /* icon_book@2x.png */; };
|
||||||
@@ -175,7 +168,6 @@
|
|||||||
DA45224A190628A1008F650A /* icon_wrench@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD386B1711E29700CF925C /* icon_wrench@2x.png */; };
|
DA45224A190628A1008F650A /* icon_wrench@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD386B1711E29700CF925C /* icon_wrench@2x.png */; };
|
||||||
DA45224B190628B2008F650A /* icon_gear.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37821711E29500CF925C /* icon_gear.png */; };
|
DA45224B190628B2008F650A /* icon_gear.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37821711E29500CF925C /* icon_gear.png */; };
|
||||||
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37831711E29500CF925C /* icon_gear@2x.png */; };
|
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37831711E29500CF925C /* icon_gear@2x.png */; };
|
||||||
DA45711D1F572F1E00D54152 /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */; };
|
|
||||||
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
|
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
|
||||||
DA4DA1DA1564471F00F6F596 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; };
|
DA4DA1DA1564471F00F6F596 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; };
|
||||||
DA5A09DF171A70E4005284AB /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DD171A70E4005284AB /* play.png */; };
|
DA5A09DF171A70E4005284AB /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DD171A70E4005284AB /* play.png */; };
|
||||||
@@ -212,7 +204,6 @@
|
|||||||
DA92614E1BE1A57500369DE5 /* MPAppDelegate_InApp.m in Sources */ = {isa = PBXBuildFile; fileRef = DA92614D1BE1A57500369DE5 /* MPAppDelegate_InApp.m */; };
|
DA92614E1BE1A57500369DE5 /* MPAppDelegate_InApp.m in Sources */ = {isa = PBXBuildFile; fileRef = DA92614D1BE1A57500369DE5 /* MPAppDelegate_InApp.m */; };
|
||||||
DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA945C8617E3F3FD0053236B /* Images.xcassets */; };
|
DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA945C8617E3F3FD0053236B /* Images.xcassets */; };
|
||||||
DA95B50C1C476B6A0067F5EF /* LocalAuthentication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA95B50B1C476B6A0067F5EF /* LocalAuthentication.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
DA95B50C1C476B6A0067F5EF /* LocalAuthentication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA95B50B1C476B6A0067F5EF /* LocalAuthentication.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||||
DA95B50F1C4776F00067F5EF /* NSMutableSet+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA95B50E1C4776F00067F5EF /* NSMutableSet+Pearl.m */; };
|
|
||||||
DA95D5F214DF0B2C008D1B94 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */; };
|
DA95D5F214DF0B2C008D1B94 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */; };
|
||||||
DAA141201922FF020032B392 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA1411C1922FF020032B392 /* PearlTween.m */; };
|
DAA141201922FF020032B392 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA1411C1922FF020032B392 /* PearlTween.m */; };
|
||||||
DAA141211922FF020032B392 /* PearlTween.h in Headers */ = {isa = PBXBuildFile; fileRef = DAA1411D1922FF020032B392 /* PearlTween.h */; };
|
DAA141211922FF020032B392 /* PearlTween.h in Headers */ = {isa = PBXBuildFile; fileRef = DAA1411D1922FF020032B392 /* PearlTween.h */; };
|
||||||
@@ -249,11 +240,26 @@
|
|||||||
DAA1765219D8B82B0044227B /* copy_pw.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763C19D8B82B0044227B /* copy_pw.png */; };
|
DAA1765219D8B82B0044227B /* copy_pw.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763C19D8B82B0044227B /* copy_pw.png */; };
|
||||||
DAA1765319D8B82B0044227B /* choose_type@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763D19D8B82B0044227B /* choose_type@2x.png */; };
|
DAA1765319D8B82B0044227B /* choose_type@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763D19D8B82B0044227B /* choose_type@2x.png */; };
|
||||||
DAA1765419D8B82B0044227B /* choose_type.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763E19D8B82B0044227B /* choose_type.png */; };
|
DAA1765419D8B82B0044227B /* choose_type.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763E19D8B82B0044227B /* choose_type.png */; };
|
||||||
DAA449D21EEC4B5800E7BDD5 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */; };
|
DAA449D21EEC4B5800E7BDD5 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D01EEC4B5800E7BDD5 /* mpw-marshal.c */; };
|
||||||
DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D3969393A3A46BD27D7078 /* mpw-algorithm.c */; };
|
DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D3969393A3A46BD27D7078 /* mpw-algorithm.c */; };
|
||||||
|
DAB07C9D1F7725C500CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9B1F7725C500CC6D43 /* aes.c */; };
|
||||||
|
DAB4FBC4202FDDDD002768FB /* NSInvocation+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBC2202FDDDC002768FB /* NSInvocation+Pearl.h */; };
|
||||||
|
DAB4FBC5202FDDDD002768FB /* NSInvocation+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBC3202FDDDD002768FB /* NSInvocation+Pearl.m */; };
|
||||||
|
DAB4FBC6202FDDEC002768FB /* NSMutableSet+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA95B50D1C4776F00067F5EF /* NSMutableSet+Pearl.h */; };
|
||||||
|
DAB4FBC7202FDDEF002768FB /* NSMutableSet+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA95B50E1C4776F00067F5EF /* NSMutableSet+Pearl.m */; };
|
||||||
|
DAB4FBC8202FDDF3002768FB /* NSNotificationCenter+PearlEasyCleanup.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D391AA32F24290C424438E /* NSNotificationCenter+PearlEasyCleanup.h */; };
|
||||||
|
DAB4FBC9202FDE0F002768FB /* PearlCryptUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DA45711C1F572F1E00D54152 /* PearlCryptUtils.h */; };
|
||||||
|
DAB4FBCA202FDE13002768FB /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */; };
|
||||||
|
DAB4FBD3202FDE48002768FB /* PearlLinks.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBCB202FDE47002768FB /* PearlLinks.m */; };
|
||||||
|
DAB4FBD4202FDE48002768FB /* UIView+PearlLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBCC202FDE47002768FB /* UIView+PearlLayout.h */; };
|
||||||
|
DAB4FBD5202FDE48002768FB /* UIView+PearlSize.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBCD202FDE47002768FB /* UIView+PearlSize.h */; };
|
||||||
|
DAB4FBD6202FDE48002768FB /* PearlLinks.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBCE202FDE47002768FB /* PearlLinks.h */; };
|
||||||
|
DAB4FBD7202FDE48002768FB /* UIView+PearlLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBCF202FDE47002768FB /* UIView+PearlLayout.m */; };
|
||||||
|
DAB4FBD8202FDE48002768FB /* WTFViews.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBD0202FDE47002768FB /* WTFViews.h */; };
|
||||||
|
DAB4FBD9202FDE48002768FB /* UIView+PearlSize.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBD1202FDE48002768FB /* UIView+PearlSize.m */; };
|
||||||
|
DAB4FBDA202FDE48002768FB /* WTFViews.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBD2202FDE48002768FB /* WTFViews.m */; };
|
||||||
DAB7AE5D1F3D752900C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE5C1F3D752900C856B1 /* libjson-c.a */; };
|
DAB7AE5D1F3D752900C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE5C1F3D752900C856B1 /* libjson-c.a */; };
|
||||||
DAB7AE771F3D755B00C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE761F3D755B00C856B1 /* libjson-c.a */; };
|
DAB7AE991F3DDEE000C856B1 /* mpw-marshal-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB7AE981F3DDEE000C856B1 /* mpw-marshal-util.c */; };
|
||||||
DAB7AE991F3DDEE000C856B1 /* mpw-marshall-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB7AE981F3DDEE000C856B1 /* mpw-marshall-util.c */; };
|
|
||||||
DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DABB981515100B4000B05417 /* SystemConfiguration.framework */; };
|
DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DABB981515100B4000B05417 /* SystemConfiguration.framework */; };
|
||||||
DABD39371711E29700CF925C /* avatar-0.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366C1711E29400CF925C /* avatar-0.png */; };
|
DABD39371711E29700CF925C /* avatar-0.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366C1711E29400CF925C /* avatar-0.png */; };
|
||||||
DABD39381711E29700CF925C /* avatar-0@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366D1711E29400CF925C /* avatar-0@2x.png */; };
|
DABD39381711E29700CF925C /* avatar-0@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366D1711E29400CF925C /* avatar-0@2x.png */; };
|
||||||
@@ -349,7 +355,6 @@
|
|||||||
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||||
DAC8DF47192831E100BA7D71 /* icon_key.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD379A1711E29600CF925C /* icon_key.png */; };
|
DAC8DF47192831E100BA7D71 /* icon_key.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD379A1711E29600CF925C /* icon_key.png */; };
|
||||||
DAC8DF48192831E100BA7D71 /* icon_key@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD379B1711E29600CF925C /* icon_key@2x.png */; };
|
DAC8DF48192831E100BA7D71 /* icon_key@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD379B1711E29600CF925C /* icon_key@2x.png */; };
|
||||||
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA29711705E1A8002C6C22 /* ciphers.plist */; };
|
|
||||||
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; };
|
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; };
|
||||||
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; };
|
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; };
|
||||||
DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA298C1705E2BD002C6C22 /* JRSwizzle.m */; };
|
DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA298C1705E2BD002C6C22 /* JRSwizzle.m */; };
|
||||||
@@ -504,7 +509,6 @@
|
|||||||
93D3924EE15017F8A12CB436 /* MPSitesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesViewController.m; sourceTree = "<group>"; };
|
93D3924EE15017F8A12CB436 /* MPSitesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesViewController.m; sourceTree = "<group>"; };
|
||||||
93D392876BE5C011DE73B43F /* MPPopdownSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPopdownSegue.h; sourceTree = "<group>"; };
|
93D392876BE5C011DE73B43F /* MPPopdownSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPopdownSegue.h; sourceTree = "<group>"; };
|
||||||
93D392C5A6572DB0EB5B82C8 /* mpw-types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-types.c"; sourceTree = "<group>"; };
|
93D392C5A6572DB0EB5B82C8 /* mpw-types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-types.c"; sourceTree = "<group>"; };
|
||||||
93D392D76C091DEA3319F11D /* UIView+AlphaScale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+AlphaScale.h"; sourceTree = "<group>"; };
|
|
||||||
93D393310223DDB35218467A /* MPCombinedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCombinedViewController.m; sourceTree = "<group>"; };
|
93D393310223DDB35218467A /* MPCombinedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCombinedViewController.m; sourceTree = "<group>"; };
|
||||||
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
|
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
|
||||||
93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; };
|
93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; };
|
||||||
@@ -512,7 +516,6 @@
|
|||||||
93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
|
93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
|
||||||
93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = "<group>"; };
|
93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = "<group>"; };
|
||||||
93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIResponder+PearlFirstResponder.h"; sourceTree = "<group>"; };
|
93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIResponder+PearlFirstResponder.h"; sourceTree = "<group>"; };
|
||||||
93D39488AB33616661725929 /* UIView+AlphaScale.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+AlphaScale.m"; sourceTree = "<group>"; };
|
|
||||||
93D394D73F5BC92297CE8D7B /* MPAlgorithmV3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithmV3.h; sourceTree = "<group>"; };
|
93D394D73F5BC92297CE8D7B /* MPAlgorithmV3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithmV3.h; sourceTree = "<group>"; };
|
||||||
93D395105935859D71679931 /* MPOverlayViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOverlayViewController.m; sourceTree = "<group>"; };
|
93D395105935859D71679931 /* MPOverlayViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOverlayViewController.m; sourceTree = "<group>"; };
|
||||||
93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Visible.m"; sourceTree = "<group>"; };
|
93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Visible.m"; sourceTree = "<group>"; };
|
||||||
@@ -540,7 +543,6 @@
|
|||||||
93D399A8E3181B442D347CD7 /* MPAlgorithmV2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV2.m; sourceTree = "<group>"; };
|
93D399A8E3181B442D347CD7 /* MPAlgorithmV2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV2.m; sourceTree = "<group>"; };
|
||||||
93D399B36CDB2004D7C51391 /* MPMessageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMessageViewController.m; sourceTree = "<group>"; };
|
93D399B36CDB2004D7C51391 /* MPMessageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMessageViewController.m; sourceTree = "<group>"; };
|
||||||
93D399C2F3D48E57C4803BDC /* NSPersistentStore+PearlMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSPersistentStore+PearlMigration.m"; sourceTree = "<group>"; };
|
93D399C2F3D48E57C4803BDC /* NSPersistentStore+PearlMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSPersistentStore+PearlMigration.m"; sourceTree = "<group>"; };
|
||||||
93D399C408B705172FA0FA02 /* PearlLinks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLinks.h; sourceTree = "<group>"; };
|
|
||||||
93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUsersViewController.m; sourceTree = "<group>"; };
|
93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUsersViewController.m; sourceTree = "<group>"; };
|
||||||
93D399F244BB522A317811BB /* MPFixable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFixable.h; sourceTree = "<group>"; };
|
93D399F244BB522A317811BB /* MPFixable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFixable.h; sourceTree = "<group>"; };
|
||||||
93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIResponder+PearlFirstResponder.m"; sourceTree = "<group>"; };
|
93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIResponder+PearlFirstResponder.m"; sourceTree = "<group>"; };
|
||||||
@@ -582,7 +584,6 @@
|
|||||||
93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; };
|
93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; };
|
||||||
93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSOrderedSetOrArray.h; sourceTree = "<group>"; };
|
93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSOrderedSetOrArray.h; sourceTree = "<group>"; };
|
||||||
93D39FD9623E8D5571C0AEB3 /* MPAlgorithmV3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV3.m; sourceTree = "<group>"; };
|
93D39FD9623E8D5571C0AEB3 /* MPAlgorithmV3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV3.m; sourceTree = "<group>"; };
|
||||||
93D39FEFC296AF6E7DF8E468 /* PearlLinks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlLinks.m; sourceTree = "<group>"; };
|
|
||||||
DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
|
DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
|
||||||
DA071BF1190187FE00179766 /* empty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "empty@2x.png"; sourceTree = "<group>"; };
|
DA071BF1190187FE00179766 /* empty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "empty@2x.png"; sourceTree = "<group>"; };
|
||||||
DA071BF2190187FE00179766 /* empty.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = empty.png; sourceTree = "<group>"; };
|
DA071BF2190187FE00179766 /* empty.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = empty.png; sourceTree = "<group>"; };
|
||||||
@@ -762,8 +763,6 @@
|
|||||||
DA2C3D641BD9612F001137B3 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
DA2C3D641BD9612F001137B3 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||||
DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = "<group>"; };
|
DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = "<group>"; };
|
||||||
DA2CA4DA18D28859007798F8 /* NSArray+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Pearl.h"; sourceTree = "<group>"; };
|
DA2CA4DA18D28859007798F8 /* NSArray+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Pearl.h"; sourceTree = "<group>"; };
|
||||||
DA2CA4DB18D28859007798F8 /* NSTimer+PearlBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+PearlBlock.m"; sourceTree = "<group>"; };
|
|
||||||
DA2CA4DC18D28859007798F8 /* NSTimer+PearlBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+PearlBlock.h"; sourceTree = "<group>"; };
|
|
||||||
DA2CA4E218D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSLayoutConstraint+PearlUIKit.h"; sourceTree = "<group>"; };
|
DA2CA4E218D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSLayoutConstraint+PearlUIKit.h"; sourceTree = "<group>"; };
|
||||||
DA2CA4E518D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSLayoutConstraint+PearlUIKit.m"; sourceTree = "<group>"; };
|
DA2CA4E518D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSLayoutConstraint+PearlUIKit.m"; sourceTree = "<group>"; };
|
||||||
DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; };
|
DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; };
|
||||||
@@ -790,7 +789,6 @@
|
|||||||
DA32D07919D7D784004F3F0E /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = background.png; path = ios/launch/background.png; sourceTree = "<group>"; };
|
DA32D07919D7D784004F3F0E /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = background.png; path = ios/launch/background.png; sourceTree = "<group>"; };
|
||||||
DA3509FC15F101A500C14A8E /* PearlQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlQueue.h; sourceTree = "<group>"; };
|
DA3509FC15F101A500C14A8E /* PearlQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlQueue.h; sourceTree = "<group>"; };
|
||||||
DA3509FD15F101A500C14A8E /* PearlQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlQueue.m; sourceTree = "<group>"; };
|
DA3509FD15F101A500C14A8E /* PearlQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlQueue.m; sourceTree = "<group>"; };
|
||||||
DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = "<group>"; };
|
|
||||||
DA3B844D190FC5DF00246EEA /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Crashlytics.framework; path = ../../../External/iOS/Crashlytics.framework; sourceTree = "<group>"; };
|
DA3B844D190FC5DF00246EEA /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Crashlytics.framework; path = ../../../External/iOS/Crashlytics.framework; sourceTree = "<group>"; };
|
||||||
DA3BCFCA19BD09D5006B2681 /* SourceCodePro-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Regular.otf"; sourceTree = "<group>"; };
|
DA3BCFCA19BD09D5006B2681 /* SourceCodePro-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Regular.otf"; sourceTree = "<group>"; };
|
||||||
DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlCryptUtils.m; sourceTree = "<group>"; };
|
DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlCryptUtils.m; sourceTree = "<group>"; };
|
||||||
@@ -871,9 +869,22 @@
|
|||||||
DAA1763C19D8B82B0044227B /* copy_pw.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = copy_pw.png; sourceTree = "<group>"; };
|
DAA1763C19D8B82B0044227B /* copy_pw.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = copy_pw.png; sourceTree = "<group>"; };
|
||||||
DAA1763D19D8B82B0044227B /* choose_type@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "choose_type@2x.png"; sourceTree = "<group>"; };
|
DAA1763D19D8B82B0044227B /* choose_type@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "choose_type@2x.png"; sourceTree = "<group>"; };
|
||||||
DAA1763E19D8B82B0044227B /* choose_type.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = choose_type.png; sourceTree = "<group>"; };
|
DAA1763E19D8B82B0044227B /* choose_type.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = choose_type.png; sourceTree = "<group>"; };
|
||||||
DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall.c"; sourceTree = "<group>"; };
|
DAA449D01EEC4B5800E7BDD5 /* mpw-marshal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal.c"; sourceTree = "<group>"; };
|
||||||
DAA449D11EEC4B5800E7BDD5 /* mpw-marshall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall.h"; sourceTree = "<group>"; };
|
DAA449D11EEC4B5800E7BDD5 /* mpw-marshal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal.h"; sourceTree = "<group>"; };
|
||||||
DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
|
DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
|
||||||
|
DAB07C9B1F7725C500CC6D43 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = "<group>"; };
|
||||||
|
DAB07C9C1F7725C500CC6D43 /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = "<group>"; };
|
||||||
|
DAB4FBC2202FDDDC002768FB /* NSInvocation+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSInvocation+Pearl.h"; sourceTree = "<group>"; };
|
||||||
|
DAB4FBC3202FDDDD002768FB /* NSInvocation+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSInvocation+Pearl.m"; sourceTree = "<group>"; };
|
||||||
|
DAB4FBCB202FDE47002768FB /* PearlLinks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlLinks.m; sourceTree = "<group>"; };
|
||||||
|
DAB4FBCC202FDE47002768FB /* UIView+PearlLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+PearlLayout.h"; sourceTree = "<group>"; };
|
||||||
|
DAB4FBCD202FDE47002768FB /* UIView+PearlSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+PearlSize.h"; sourceTree = "<group>"; };
|
||||||
|
DAB4FBCE202FDE47002768FB /* PearlLinks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLinks.h; sourceTree = "<group>"; };
|
||||||
|
DAB4FBCF202FDE47002768FB /* UIView+PearlLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+PearlLayout.m"; sourceTree = "<group>"; };
|
||||||
|
DAB4FBD0202FDE47002768FB /* WTFViews.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WTFViews.h; sourceTree = "<group>"; };
|
||||||
|
DAB4FBD1202FDE48002768FB /* UIView+PearlSize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+PearlSize.m"; sourceTree = "<group>"; };
|
||||||
|
DAB4FBD2202FDE48002768FB /* WTFViews.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WTFViews.m; sourceTree = "<group>"; };
|
||||||
|
DAB4FBDB202FDE5E002768FB /* Pearl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Pearl-Prefix.pch"; sourceTree = "<group>"; };
|
||||||
DAB7AE5C1F3D752900C856B1 /* libjson-c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libjson-c.a"; path = "External/libjson-c/libjson-c-ios/lib/libjson-c.a"; sourceTree = "<group>"; };
|
DAB7AE5C1F3D752900C856B1 /* libjson-c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libjson-c.a"; path = "External/libjson-c/libjson-c-ios/lib/libjson-c.a"; sourceTree = "<group>"; };
|
||||||
DAB7AE611F3D755B00C856B1 /* arraylist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arraylist.h; sourceTree = "<group>"; };
|
DAB7AE611F3D755B00C856B1 /* arraylist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arraylist.h; sourceTree = "<group>"; };
|
||||||
DAB7AE621F3D755B00C856B1 /* bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bits.h; sourceTree = "<group>"; };
|
DAB7AE621F3D755B00C856B1 /* bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bits.h; sourceTree = "<group>"; };
|
||||||
@@ -896,8 +907,8 @@
|
|||||||
DAB7AE731F3D755B00C856B1 /* strdup_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strdup_compat.h; sourceTree = "<group>"; };
|
DAB7AE731F3D755B00C856B1 /* strdup_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strdup_compat.h; sourceTree = "<group>"; };
|
||||||
DAB7AE741F3D755B00C856B1 /* vasprintf_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vasprintf_compat.h; sourceTree = "<group>"; };
|
DAB7AE741F3D755B00C856B1 /* vasprintf_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vasprintf_compat.h; sourceTree = "<group>"; };
|
||||||
DAB7AE761F3D755B00C856B1 /* libjson-c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libjson-c.a"; sourceTree = "<group>"; };
|
DAB7AE761F3D755B00C856B1 /* libjson-c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libjson-c.a"; sourceTree = "<group>"; };
|
||||||
DAB7AE971F3DDEE000C856B1 /* mpw-marshall-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall-util.h"; sourceTree = "<group>"; };
|
DAB7AE971F3DDEE000C856B1 /* mpw-marshal-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal-util.h"; sourceTree = "<group>"; };
|
||||||
DAB7AE981F3DDEE000C856B1 /* mpw-marshall-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall-util.c"; sourceTree = "<group>"; };
|
DAB7AE981F3DDEE000C856B1 /* mpw-marshal-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal-util.c"; sourceTree = "<group>"; };
|
||||||
DABB981515100B4000B05417 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
DABB981515100B4000B05417 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
||||||
DABD360F1711E29400CF925C /* ui_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ui_background.png; sourceTree = "<group>"; };
|
DABD360F1711E29400CF925C /* ui_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ui_background.png; sourceTree = "<group>"; };
|
||||||
DABD36101711E29400CF925C /* ui_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ui_background@2x.png"; sourceTree = "<group>"; };
|
DABD36101711E29400CF925C /* ui_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ui_background@2x.png"; sourceTree = "<group>"; };
|
||||||
@@ -1511,7 +1522,7 @@
|
|||||||
DABD38C11711E29700CF925C /* tip_location_teal@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tip_location_teal@2x.png"; sourceTree = "<group>"; };
|
DABD38C11711E29700CF925C /* tip_location_teal@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tip_location_teal@2x.png"; sourceTree = "<group>"; };
|
||||||
DABD38C21711E29700CF925C /* tip_location_wood.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tip_location_wood.png; sourceTree = "<group>"; };
|
DABD38C21711E29700CF925C /* tip_location_wood.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tip_location_wood.png; sourceTree = "<group>"; };
|
||||||
DABD38C31711E29700CF925C /* tip_location_wood@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tip_location_wood@2x.png"; sourceTree = "<group>"; };
|
DABD38C31711E29700CF925C /* tip_location_wood@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tip_location_wood@2x.png"; sourceTree = "<group>"; };
|
||||||
DABD38C81711E29700CF925C /* jquery-1.6.1.min.js */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = sourcecode.javascript; path = "jquery-1.6.1.min.js"; sourceTree = "<group>"; };
|
DABD38C81711E29700CF925C /* jquery-1.6.1.min.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "jquery-1.6.1.min.js"; sourceTree = "<group>"; };
|
||||||
DABD38C91711E29700CF925C /* keypad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = keypad.png; sourceTree = "<group>"; };
|
DABD38C91711E29700CF925C /* keypad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = keypad.png; sourceTree = "<group>"; };
|
||||||
DABD38CA1711E29700CF925C /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-bare.png"; sourceTree = "<group>"; };
|
DABD38CA1711E29700CF925C /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-bare.png"; sourceTree = "<group>"; };
|
||||||
DABD38CB1711E29700CF925C /* menu-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu-icon.png"; sourceTree = "<group>"; };
|
DABD38CB1711E29700CF925C /* menu-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu-icon.png"; sourceTree = "<group>"; };
|
||||||
@@ -1562,8 +1573,6 @@
|
|||||||
DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
||||||
DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Pearl-Prefix.pch"; path = "../../Source/Pearl/Pearl-Prefix.pch"; sourceTree = "<group>"; };
|
|
||||||
DACA29711705E1A8002C6C22 /* ciphers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = ciphers.plist; sourceTree = "<group>"; };
|
|
||||||
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
|
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
|
||||||
DACA29771705E2BD002C6C22 /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRSwizzle.h; sourceTree = "<group>"; };
|
DACA29771705E2BD002C6C22 /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRSwizzle.h; sourceTree = "<group>"; };
|
||||||
DACA298C1705E2BD002C6C22 /* JRSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JRSwizzle.m; sourceTree = "<group>"; };
|
DACA298C1705E2BD002C6C22 /* JRSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JRSwizzle.m; sourceTree = "<group>"; };
|
||||||
@@ -1680,7 +1689,6 @@
|
|||||||
DA95B50C1C476B6A0067F5EF /* LocalAuthentication.framework in Frameworks */,
|
DA95B50C1C476B6A0067F5EF /* LocalAuthentication.framework in Frameworks */,
|
||||||
DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */,
|
DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */,
|
||||||
DA2C3D631BD96126001137B3 /* libc++.tbd in Frameworks */,
|
DA2C3D631BD96126001137B3 /* libc++.tbd in Frameworks */,
|
||||||
DAB7AE771F3D755B00C856B1 /* libjson-c.a in Frameworks */,
|
|
||||||
DAA1761B19D86D0D0044227B /* libAttributedMarkdown.a in Frameworks */,
|
DAA1761B19D86D0D0044227B /* libAttributedMarkdown.a in Frameworks */,
|
||||||
DA0CC5421EB57BD4009A8ED9 /* Crashlytics.framework in Frameworks */,
|
DA0CC5421EB57BD4009A8ED9 /* Crashlytics.framework in Frameworks */,
|
||||||
DA32D03E19D11293004F3F0E /* libKCOrderedAccessorFix.a in Frameworks */,
|
DA32D03E19D11293004F3F0E /* libKCOrderedAccessorFix.a in Frameworks */,
|
||||||
@@ -1751,6 +1759,8 @@
|
|||||||
93D39A2239FFFE6BEC83E191 /* C */ = {
|
93D39A2239FFFE6BEC83E191 /* C */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
DAB07C9B1F7725C500CC6D43 /* aes.c */,
|
||||||
|
DAB07C9C1F7725C500CC6D43 /* aes.h */,
|
||||||
DA5B0B3E1F36469400B663F0 /* base64.c */,
|
DA5B0B3E1F36469400B663F0 /* base64.c */,
|
||||||
DA5B0B3F1F36469400B663F0 /* base64.h */,
|
DA5B0B3F1F36469400B663F0 /* base64.h */,
|
||||||
93D390A99850139D0FF0211E /* mpw-algorithm_v0.c */,
|
93D390A99850139D0FF0211E /* mpw-algorithm_v0.c */,
|
||||||
@@ -1759,10 +1769,10 @@
|
|||||||
93D39D4E713564B7654341B0 /* mpw-algorithm_v3.c */,
|
93D39D4E713564B7654341B0 /* mpw-algorithm_v3.c */,
|
||||||
93D3969393A3A46BD27D7078 /* mpw-algorithm.c */,
|
93D3969393A3A46BD27D7078 /* mpw-algorithm.c */,
|
||||||
93D3990D850D76A94C6B7A4D /* mpw-algorithm.h */,
|
93D3990D850D76A94C6B7A4D /* mpw-algorithm.h */,
|
||||||
DAB7AE981F3DDEE000C856B1 /* mpw-marshall-util.c */,
|
DAB7AE981F3DDEE000C856B1 /* mpw-marshal-util.c */,
|
||||||
DAB7AE971F3DDEE000C856B1 /* mpw-marshall-util.h */,
|
DAB7AE971F3DDEE000C856B1 /* mpw-marshal-util.h */,
|
||||||
DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */,
|
DAA449D01EEC4B5800E7BDD5 /* mpw-marshal.c */,
|
||||||
DAA449D11EEC4B5800E7BDD5 /* mpw-marshall.h */,
|
DAA449D11EEC4B5800E7BDD5 /* mpw-marshal.h */,
|
||||||
93D392C5A6572DB0EB5B82C8 /* mpw-types.c */,
|
93D392C5A6572DB0EB5B82C8 /* mpw-types.c */,
|
||||||
93D39AFD17CBE324D745DAB0 /* mpw-types.h */,
|
93D39AFD17CBE324D745DAB0 /* mpw-types.h */,
|
||||||
93D396C311C3725870343EE0 /* mpw-util.c */,
|
93D396C311C3725870343EE0 /* mpw-util.c */,
|
||||||
@@ -2993,7 +3003,6 @@
|
|||||||
93D39F556F2F142740A65E59 /* MPWebViewController.h */,
|
93D39F556F2F142740A65E59 /* MPWebViewController.h */,
|
||||||
93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */,
|
93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */,
|
||||||
DABD3BF91711E2DC00CF925C /* Settings.bundle */,
|
DABD3BF91711E2DC00CF925C /* Settings.bundle */,
|
||||||
DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */,
|
|
||||||
);
|
);
|
||||||
path = iOS;
|
path = iOS;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -3004,7 +3013,7 @@
|
|||||||
DAFE45D715039823003ABA7C /* Pearl */,
|
DAFE45D715039823003ABA7C /* Pearl */,
|
||||||
DAFE45FC15039823003ABA7C /* Pearl-Crypto */,
|
DAFE45FC15039823003ABA7C /* Pearl-Crypto */,
|
||||||
DAFE460715039823003ABA7C /* Pearl-UIKit */,
|
DAFE460715039823003ABA7C /* Pearl-UIKit */,
|
||||||
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */,
|
DAB4FBDB202FDE5E002768FB /* Pearl-Prefix.pch */,
|
||||||
);
|
);
|
||||||
path = Pearl;
|
path = Pearl;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -3039,7 +3048,6 @@
|
|||||||
DACA29701705E1A8002C6C22 /* Data */ = {
|
DACA29701705E1A8002C6C22 /* Data */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
DACA29711705E1A8002C6C22 /* ciphers.plist */,
|
|
||||||
DACA29721705E1A8002C6C22 /* dictionary.lst */,
|
DACA29721705E1A8002C6C22 /* dictionary.lst */,
|
||||||
);
|
);
|
||||||
path = Data;
|
path = Data;
|
||||||
@@ -3091,6 +3099,8 @@
|
|||||||
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */,
|
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */,
|
||||||
93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */,
|
93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */,
|
||||||
93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */,
|
93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */,
|
||||||
|
DAB4FBC2202FDDDC002768FB /* NSInvocation+Pearl.h */,
|
||||||
|
DAB4FBC3202FDDDD002768FB /* NSInvocation+Pearl.m */,
|
||||||
DAF4EF4F190A81E400023C90 /* NSManagedObject+Pearl.h */,
|
DAF4EF4F190A81E400023C90 /* NSManagedObject+Pearl.h */,
|
||||||
DAF4EF4E190A81E400023C90 /* NSManagedObject+Pearl.m */,
|
DAF4EF4E190A81E400023C90 /* NSManagedObject+Pearl.m */,
|
||||||
DA95B50D1C4776F00067F5EF /* NSMutableSet+Pearl.h */,
|
DA95B50D1C4776F00067F5EF /* NSMutableSet+Pearl.h */,
|
||||||
@@ -3100,14 +3110,14 @@
|
|||||||
DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */,
|
DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */,
|
||||||
DAFE4A63150399FF003ABA87 /* NSObject+PearlKVO.h */,
|
DAFE4A63150399FF003ABA87 /* NSObject+PearlKVO.h */,
|
||||||
DAFE4A63150399FF003ABA85 /* NSObject+PearlKVO.m */,
|
DAFE4A63150399FF003ABA85 /* NSObject+PearlKVO.m */,
|
||||||
|
93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */,
|
||||||
|
93D39789AAF49338F8AC8B02 /* NSOrderedSetOrArray.m */,
|
||||||
93D397F4BAFFF7CF3F1B21A4 /* NSPersistentStore+PearlMigration.h */,
|
93D397F4BAFFF7CF3F1B21A4 /* NSPersistentStore+PearlMigration.h */,
|
||||||
93D399C2F3D48E57C4803BDC /* NSPersistentStore+PearlMigration.m */,
|
93D399C2F3D48E57C4803BDC /* NSPersistentStore+PearlMigration.m */,
|
||||||
DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */,
|
DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */,
|
||||||
DAFE45DB15039823003ABA7C /* NSString+PearlNSArrayFormat.m */,
|
DAFE45DB15039823003ABA7C /* NSString+PearlNSArrayFormat.m */,
|
||||||
DAFE45DC15039823003ABA7C /* NSString+PearlSEL.h */,
|
DAFE45DC15039823003ABA7C /* NSString+PearlSEL.h */,
|
||||||
DAFE45DD15039823003ABA7C /* NSString+PearlSEL.m */,
|
DAFE45DD15039823003ABA7C /* NSString+PearlSEL.m */,
|
||||||
DA2CA4DC18D28859007798F8 /* NSTimer+PearlBlock.h */,
|
|
||||||
DA2CA4DB18D28859007798F8 /* NSTimer+PearlBlock.m */,
|
|
||||||
DAFE45DE15039823003ABA7C /* Pearl.h */,
|
DAFE45DE15039823003ABA7C /* Pearl.h */,
|
||||||
DA30E9CD15722ECA00A68B4C /* Pearl.m */,
|
DA30E9CD15722ECA00A68B4C /* Pearl.m */,
|
||||||
DAFE45DF15039823003ABA7C /* PearlAbstractStrings.h */,
|
DAFE45DF15039823003ABA7C /* PearlAbstractStrings.h */,
|
||||||
@@ -3118,6 +3128,8 @@
|
|||||||
DAFE45E615039823003ABA7C /* PearlConfig.m */,
|
DAFE45E615039823003ABA7C /* PearlConfig.m */,
|
||||||
DAFE45E715039823003ABA7C /* PearlDeviceUtils.h */,
|
DAFE45E715039823003ABA7C /* PearlDeviceUtils.h */,
|
||||||
DAFE45E815039823003ABA7C /* PearlDeviceUtils.m */,
|
DAFE45E815039823003ABA7C /* PearlDeviceUtils.m */,
|
||||||
|
93D39D8508BF868907E9732E /* PearlHangDetector.h */,
|
||||||
|
93D39BDA5DB85FCDE4E6450A /* PearlHangDetector.m */,
|
||||||
DAFE45E915039823003ABA7C /* PearlInfoPlist.h */,
|
DAFE45E915039823003ABA7C /* PearlInfoPlist.h */,
|
||||||
DAFE45EA15039823003ABA7C /* PearlInfoPlist.m */,
|
DAFE45EA15039823003ABA7C /* PearlInfoPlist.m */,
|
||||||
DA30E9D515723E6900A68B4C /* PearlLazy.h */,
|
DA30E9D515723E6900A68B4C /* PearlLazy.h */,
|
||||||
@@ -3141,10 +3153,6 @@
|
|||||||
DAA1411C1922FF020032B392 /* PearlTween.m */,
|
DAA1411C1922FF020032B392 /* PearlTween.m */,
|
||||||
DAFE45F815039823003ABA7C /* README */,
|
DAFE45F815039823003ABA7C /* README */,
|
||||||
DAFE45F915039823003ABA7C /* Resources */,
|
DAFE45F915039823003ABA7C /* Resources */,
|
||||||
93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */,
|
|
||||||
93D39789AAF49338F8AC8B02 /* NSOrderedSetOrArray.m */,
|
|
||||||
93D39BDA5DB85FCDE4E6450A /* PearlHangDetector.m */,
|
|
||||||
93D39D8508BF868907E9732E /* PearlHangDetector.h */,
|
|
||||||
);
|
);
|
||||||
path = Pearl;
|
path = Pearl;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -3193,6 +3201,8 @@
|
|||||||
DA32D01819D046E1004F3F0E /* PearlFixedTableView.m */,
|
DA32D01819D046E1004F3F0E /* PearlFixedTableView.m */,
|
||||||
DAFE461015039823003ABA7C /* PearlGradientView.h */,
|
DAFE461015039823003ABA7C /* PearlGradientView.h */,
|
||||||
DAFE461115039823003ABA7C /* PearlGradientView.m */,
|
DAFE461115039823003ABA7C /* PearlGradientView.m */,
|
||||||
|
DAB4FBCE202FDE47002768FB /* PearlLinks.h */,
|
||||||
|
DAB4FBCB202FDE47002768FB /* PearlLinks.m */,
|
||||||
DAFE461615039823003ABA7C /* PearlMessageView.h */,
|
DAFE461615039823003ABA7C /* PearlMessageView.h */,
|
||||||
DAFE461715039823003ABA7C /* PearlMessageView.m */,
|
DAFE461715039823003ABA7C /* PearlMessageView.m */,
|
||||||
DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */,
|
DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */,
|
||||||
@@ -3245,14 +3255,16 @@
|
|||||||
DACE2F6719BA6A2A0010F92E /* UIView+FontScale.m */,
|
DACE2F6719BA6A2A0010F92E /* UIView+FontScale.m */,
|
||||||
DAEFB01D19BCBD9E00525079 /* UIView+LayoutGone.h */,
|
DAEFB01D19BCBD9E00525079 /* UIView+LayoutGone.h */,
|
||||||
DAEFB01C19BCBD9E00525079 /* UIView+LayoutGone.m */,
|
DAEFB01C19BCBD9E00525079 /* UIView+LayoutGone.m */,
|
||||||
|
DAB4FBCC202FDE47002768FB /* UIView+PearlLayout.h */,
|
||||||
|
DAB4FBCF202FDE47002768FB /* UIView+PearlLayout.m */,
|
||||||
|
DAB4FBCD202FDE47002768FB /* UIView+PearlSize.h */,
|
||||||
|
DAB4FBD1202FDE48002768FB /* UIView+PearlSize.m */,
|
||||||
DAEC85B418E3DD9A007FC0DF /* UIView+Touches.h */,
|
DAEC85B418E3DD9A007FC0DF /* UIView+Touches.h */,
|
||||||
DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */,
|
DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */,
|
||||||
93D39488AB33616661725929 /* UIView+AlphaScale.m */,
|
|
||||||
93D392D76C091DEA3319F11D /* UIView+AlphaScale.h */,
|
|
||||||
93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */,
|
|
||||||
93D39B7B765546B1F1900CB7 /* UIView+Visible.h */,
|
93D39B7B765546B1F1900CB7 /* UIView+Visible.h */,
|
||||||
93D39FEFC296AF6E7DF8E468 /* PearlLinks.m */,
|
93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */,
|
||||||
93D399C408B705172FA0FA02 /* PearlLinks.h */,
|
DAB4FBD0202FDE47002768FB /* WTFViews.h */,
|
||||||
|
DAB4FBD2202FDE48002768FB /* WTFViews.m */,
|
||||||
);
|
);
|
||||||
path = "Pearl-UIKit";
|
path = "Pearl-UIKit";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -3295,10 +3307,12 @@
|
|||||||
DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
|
DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
|
||||||
DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
|
DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
|
||||||
DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
|
DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
|
||||||
|
DAB4FBD8202FDE48002768FB /* WTFViews.h in Headers */,
|
||||||
DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */,
|
DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */,
|
||||||
DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */,
|
DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */,
|
||||||
DAFE4A2415039824003ABA7C /* PearlInfoPlist.h in Headers */,
|
DAFE4A2415039824003ABA7C /* PearlInfoPlist.h in Headers */,
|
||||||
DA2CA4E418D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h in Headers */,
|
DA2CA4E418D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h in Headers */,
|
||||||
|
DAB4FBD5202FDE48002768FB /* UIView+PearlSize.h in Headers */,
|
||||||
DACE2F6D19BA6A2A0010F92E /* PearlMutableStaticTableViewController.h in Headers */,
|
DACE2F6D19BA6A2A0010F92E /* PearlMutableStaticTableViewController.h in Headers */,
|
||||||
DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */,
|
DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */,
|
||||||
DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */,
|
DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */,
|
||||||
@@ -3307,13 +3321,13 @@
|
|||||||
DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */,
|
DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */,
|
||||||
DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */,
|
DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */,
|
||||||
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
|
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
|
||||||
DA2CA4E018D28859007798F8 /* NSTimer+PearlBlock.h in Headers */,
|
|
||||||
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
|
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
|
||||||
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
|
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
|
||||||
DAE2726419CE9CB3007C5262 /* UITableViewCell+PearlDeque.h in Headers */,
|
DAE2726419CE9CB3007C5262 /* UITableViewCell+PearlDeque.h in Headers */,
|
||||||
DACE2F6E19BA6A2A0010F92E /* UIView+FontScale.h in Headers */,
|
DACE2F6E19BA6A2A0010F92E /* UIView+FontScale.h in Headers */,
|
||||||
DA32D01B19D046E1004F3F0E /* PearlFixedTableView.h in Headers */,
|
DA32D01B19D046E1004F3F0E /* PearlFixedTableView.h in Headers */,
|
||||||
DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */,
|
DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */,
|
||||||
|
DAB4FBD6202FDE48002768FB /* PearlLinks.h in Headers */,
|
||||||
DAEC85B818E3DD9A007FC0DF /* UIView+Touches.h in Headers */,
|
DAEC85B818E3DD9A007FC0DF /* UIView+Touches.h in Headers */,
|
||||||
DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */,
|
DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */,
|
||||||
DAFE4A3E15039824003ABA7C /* PearlAlert.h in Headers */,
|
DAFE4A3E15039824003ABA7C /* PearlAlert.h in Headers */,
|
||||||
@@ -3321,9 +3335,11 @@
|
|||||||
DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */,
|
DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */,
|
||||||
DAEFB01F19BCBD9E00525079 /* UIView+LayoutGone.h in Headers */,
|
DAEFB01F19BCBD9E00525079 /* UIView+LayoutGone.h in Headers */,
|
||||||
DAFE4A4415039824003ABA7C /* PearlGradientView.h in Headers */,
|
DAFE4A4415039824003ABA7C /* PearlGradientView.h in Headers */,
|
||||||
|
DAB4FBC6202FDDEC002768FB /* NSMutableSet+Pearl.h in Headers */,
|
||||||
DAFE4A4A15039824003ABA7C /* PearlMessageView.h in Headers */,
|
DAFE4A4A15039824003ABA7C /* PearlMessageView.h in Headers */,
|
||||||
DACE2F6619BA6A0A0010F92E /* PearlProfiler.h in Headers */,
|
DACE2F6619BA6A0A0010F92E /* PearlProfiler.h in Headers */,
|
||||||
DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */,
|
DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */,
|
||||||
|
DAB4FBC9202FDE0F002768FB /* PearlCryptUtils.h in Headers */,
|
||||||
DAFE4A4E15039824003ABA7C /* PearlSheet.h in Headers */,
|
DAFE4A4E15039824003ABA7C /* PearlSheet.h in Headers */,
|
||||||
DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */,
|
DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */,
|
||||||
DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */,
|
DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */,
|
||||||
@@ -3341,6 +3357,7 @@
|
|||||||
DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */,
|
DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */,
|
||||||
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */,
|
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */,
|
||||||
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */,
|
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */,
|
||||||
|
DAB4FBC8202FDDF3002768FB /* NSNotificationCenter+PearlEasyCleanup.h in Headers */,
|
||||||
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */,
|
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */,
|
||||||
DAEC85B718E3DD9A007FC0DF /* PearlUINavigationBar.h in Headers */,
|
DAEC85B718E3DD9A007FC0DF /* PearlUINavigationBar.h in Headers */,
|
||||||
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */,
|
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */,
|
||||||
@@ -3353,12 +3370,12 @@
|
|||||||
93D39536EB550E811CCD04BC /* UIResponder+PearlFirstResponder.h in Headers */,
|
93D39536EB550E811CCD04BC /* UIResponder+PearlFirstResponder.h in Headers */,
|
||||||
93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */,
|
93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */,
|
||||||
93D392A8777DC30C11361647 /* UITextView+PearlAttributes.h in Headers */,
|
93D392A8777DC30C11361647 /* UITextView+PearlAttributes.h in Headers */,
|
||||||
|
DAB4FBC4202FDDDD002768FB /* NSInvocation+Pearl.h in Headers */,
|
||||||
93D39A53D76CA70786423458 /* UICollectionView+PearlReloadItems.h in Headers */,
|
93D39A53D76CA70786423458 /* UICollectionView+PearlReloadItems.h in Headers */,
|
||||||
93D39AA4A0BE66A872CCC02E /* NSPersistentStore+PearlMigration.h in Headers */,
|
93D39AA4A0BE66A872CCC02E /* NSPersistentStore+PearlMigration.h in Headers */,
|
||||||
93D399E4BC1E092A8C8B12AE /* NSOrderedSetOrArray.h in Headers */,
|
93D399E4BC1E092A8C8B12AE /* NSOrderedSetOrArray.h in Headers */,
|
||||||
93D3959696396A91961C6148 /* UIView+AlphaScale.h in Headers */,
|
|
||||||
93D39BFB5F5F9337F6565DE3 /* UIView+Visible.h in Headers */,
|
93D39BFB5F5F9337F6565DE3 /* UIView+Visible.h in Headers */,
|
||||||
93D39861AEE621B287EA93E9 /* PearlLinks.h in Headers */,
|
DAB4FBD4202FDE48002768FB /* UIView+PearlLayout.h in Headers */,
|
||||||
93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */,
|
93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -3527,15 +3544,15 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
CLASSPREFIX = MP;
|
CLASSPREFIX = MP;
|
||||||
LastUpgradeCheck = 0820;
|
LastUpgradeCheck = 0920;
|
||||||
ORGANIZATIONNAME = Lyndir;
|
ORGANIZATIONNAME = Lyndir;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
DA32D01F19D111C6004F3F0E = {
|
DA32D01F19D111C6004F3F0E = {
|
||||||
CreatedOnToolsVersion = 6.0;
|
|
||||||
DevelopmentTeam = HL3Q45LX9N;
|
DevelopmentTeam = HL3Q45LX9N;
|
||||||
};
|
};
|
||||||
DA5BFA43147E415C00F98B1E = {
|
DA5BFA43147E415C00F98B1E = {
|
||||||
DevelopmentTeam = HL3Q45LX9N;
|
DevelopmentTeam = HL3Q45LX9N;
|
||||||
|
LastSwiftMigration = 0920;
|
||||||
ProvisioningStyle = Automatic;
|
ProvisioningStyle = Automatic;
|
||||||
SystemCapabilities = {
|
SystemCapabilities = {
|
||||||
com.apple.BackgroundModes = {
|
com.apple.BackgroundModes = {
|
||||||
@@ -3553,7 +3570,6 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
DAA1757C19D86BE70044227B = {
|
DAA1757C19D86BE70044227B = {
|
||||||
CreatedOnToolsVersion = 6.0;
|
|
||||||
DevelopmentTeam = HL3Q45LX9N;
|
DevelopmentTeam = HL3Q45LX9N;
|
||||||
};
|
};
|
||||||
DAB7AE3D1F3D464A00C856B1 = {
|
DAB7AE3D1F3D464A00C856B1 = {
|
||||||
@@ -3699,7 +3715,6 @@
|
|||||||
files = (
|
files = (
|
||||||
DAFE4A5A1503982E003ABA7C /* Pearl.strings in Resources */,
|
DAFE4A5A1503982E003ABA7C /* Pearl.strings in Resources */,
|
||||||
DA0CC53B1EB57B5C009A8ED9 /* Fabric.plist in Resources */,
|
DA0CC53B1EB57B5C009A8ED9 /* Fabric.plist in Resources */,
|
||||||
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */,
|
|
||||||
DA32D04F19D2F59B004F3F0E /* meter_fuel@2x.png in Resources */,
|
DA32D04F19D2F59B004F3F0E /* meter_fuel@2x.png in Resources */,
|
||||||
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
|
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
|
||||||
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */,
|
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */,
|
||||||
@@ -3869,7 +3884,6 @@
|
|||||||
DA8495311A93049300B3053D /* icon_down.png in Resources */,
|
DA8495311A93049300B3053D /* icon_down.png in Resources */,
|
||||||
DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */,
|
DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */,
|
||||||
DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */,
|
DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */,
|
||||||
DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */,
|
|
||||||
DA5A09DF171A70E4005284AB /* play.png in Resources */,
|
DA5A09DF171A70E4005284AB /* play.png in Resources */,
|
||||||
DA24EBEC19DAD6EE00FF010B /* Icon-Small@3x.png in Resources */,
|
DA24EBEC19DAD6EE00FF010B /* Icon-Small@3x.png in Resources */,
|
||||||
DA5A09E0171A70E4005284AB /* play@2x.png in Resources */,
|
DA5A09E0171A70E4005284AB /* play@2x.png in Resources */,
|
||||||
@@ -3970,7 +3984,7 @@
|
|||||||
DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */,
|
DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */,
|
||||||
DA0CC5941EB6B030009A8ED9 /* MPSiteEntity+CoreDataClass.m in Sources */,
|
DA0CC5941EB6B030009A8ED9 /* MPSiteEntity+CoreDataClass.m in Sources */,
|
||||||
DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */,
|
DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */,
|
||||||
DAA449D21EEC4B5800E7BDD5 /* mpw-marshall.c in Sources */,
|
DAA449D21EEC4B5800E7BDD5 /* mpw-marshal.c in Sources */,
|
||||||
DABD3C1E1711E2DC00CF925C /* MPPreferencesViewController.m in Sources */,
|
DABD3C1E1711E2DC00CF925C /* MPPreferencesViewController.m in Sources */,
|
||||||
DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */,
|
DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */,
|
||||||
DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */,
|
DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */,
|
||||||
@@ -3988,8 +4002,7 @@
|
|||||||
DA0CC58E1EB6B030009A8ED9 /* MPSiteQuestionEntity+CoreDataClass.m in Sources */,
|
DA0CC58E1EB6B030009A8ED9 /* MPSiteQuestionEntity+CoreDataClass.m in Sources */,
|
||||||
93D39A5FF670957C0AF8298D /* MPSiteCell.m in Sources */,
|
93D39A5FF670957C0AF8298D /* MPSiteCell.m in Sources */,
|
||||||
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */,
|
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */,
|
||||||
DAB7AE991F3DDEE000C856B1 /* mpw-marshall-util.c in Sources */,
|
DAB7AE991F3DDEE000C856B1 /* mpw-marshal-util.c in Sources */,
|
||||||
DA95B50F1C4776F00067F5EF /* NSMutableSet+Pearl.m in Sources */,
|
|
||||||
93D394B5036C882B33C71872 /* MPSitesSegue.m in Sources */,
|
93D394B5036C882B33C71872 /* MPSitesSegue.m in Sources */,
|
||||||
DA0CC5911EB6B030009A8ED9 /* MPStoredSiteEntity+CoreDataProperties.m in Sources */,
|
DA0CC5911EB6B030009A8ED9 /* MPStoredSiteEntity+CoreDataProperties.m in Sources */,
|
||||||
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */,
|
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */,
|
||||||
@@ -3998,12 +4011,12 @@
|
|||||||
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */,
|
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */,
|
||||||
DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */,
|
DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */,
|
||||||
DA0CC54E1EB6AD0E009A8ED9 /* MasterPassword.xcdatamodeld in Sources */,
|
DA0CC54E1EB6AD0E009A8ED9 /* MasterPassword.xcdatamodeld in Sources */,
|
||||||
|
DAB07C9D1F7725C500CC6D43 /* aes.c in Sources */,
|
||||||
93D39EAA4D064193074D3021 /* MPFixable.m in Sources */,
|
93D39EAA4D064193074D3021 /* MPFixable.m in Sources */,
|
||||||
93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */,
|
93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */,
|
||||||
93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */,
|
93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */,
|
||||||
93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */,
|
93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */,
|
||||||
93D390C1B93F9D3AE37DD0A5 /* MPAnswersViewController.m in Sources */,
|
93D390C1B93F9D3AE37DD0A5 /* MPAnswersViewController.m in Sources */,
|
||||||
DA45711D1F572F1E00D54152 /* PearlCryptUtils.m in Sources */,
|
|
||||||
93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */,
|
93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */,
|
||||||
93D39A27F2506C6FEEF9C588 /* MPAlgorithmV2.m in Sources */,
|
93D39A27F2506C6FEEF9C588 /* MPAlgorithmV2.m in Sources */,
|
||||||
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */,
|
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */,
|
||||||
@@ -4100,24 +4113,28 @@
|
|||||||
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */,
|
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */,
|
||||||
DAF4EF50190A81E400023C90 /* NSManagedObject+Pearl.m in Sources */,
|
DAF4EF50190A81E400023C90 /* NSManagedObject+Pearl.m in Sources */,
|
||||||
93D39262A8A97DB748213309 /* PearlEMail.m in Sources */,
|
93D39262A8A97DB748213309 /* PearlEMail.m in Sources */,
|
||||||
|
DAB4FBD9202FDE48002768FB /* UIView+PearlSize.m in Sources */,
|
||||||
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */,
|
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */,
|
||||||
|
DAB4FBDA202FDE48002768FB /* WTFViews.m in Sources */,
|
||||||
|
DAB4FBC7202FDDEF002768FB /* NSMutableSet+Pearl.m in Sources */,
|
||||||
93D3922A53E41A54832E90D9 /* PearlOverlay.m in Sources */,
|
93D3922A53E41A54832E90D9 /* PearlOverlay.m in Sources */,
|
||||||
DA32D01A19D046E1004F3F0E /* PearlFixedTableView.m in Sources */,
|
DA32D01A19D046E1004F3F0E /* PearlFixedTableView.m in Sources */,
|
||||||
93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */,
|
93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */,
|
||||||
93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */,
|
93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */,
|
||||||
DA2CA4DF18D28859007798F8 /* NSTimer+PearlBlock.m in Sources */,
|
|
||||||
93D3954E96236384AFA00453 /* UIScrollView+PearlAdjustInsets.m in Sources */,
|
93D3954E96236384AFA00453 /* UIScrollView+PearlAdjustInsets.m in Sources */,
|
||||||
|
DAB4FBCA202FDE13002768FB /* PearlCryptUtils.m in Sources */,
|
||||||
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */,
|
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */,
|
||||||
93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */,
|
93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */,
|
||||||
DAA141201922FF020032B392 /* PearlTween.m in Sources */,
|
DAA141201922FF020032B392 /* PearlTween.m in Sources */,
|
||||||
|
DAB4FBD7202FDE48002768FB /* UIView+PearlLayout.m in Sources */,
|
||||||
93D391ECBD9BD2C64115B5DD /* PearlSizedTextView.m in Sources */,
|
93D391ECBD9BD2C64115B5DD /* PearlSizedTextView.m in Sources */,
|
||||||
|
DAB4FBD3202FDE48002768FB /* PearlLinks.m in Sources */,
|
||||||
93D39E34FD28D24FE3442C48 /* UITextView+PearlAttributes.m in Sources */,
|
93D39E34FD28D24FE3442C48 /* UITextView+PearlAttributes.m in Sources */,
|
||||||
93D39D47FC623E91FC39D20C /* UICollectionView+PearlReloadItems.m in Sources */,
|
93D39D47FC623E91FC39D20C /* UICollectionView+PearlReloadItems.m in Sources */,
|
||||||
93D3928D629EA563F9EC4909 /* NSPersistentStore+PearlMigration.m in Sources */,
|
93D3928D629EA563F9EC4909 /* NSPersistentStore+PearlMigration.m in Sources */,
|
||||||
93D392A33CCE85431E910C7B /* NSOrderedSetOrArray.m in Sources */,
|
93D392A33CCE85431E910C7B /* NSOrderedSetOrArray.m in Sources */,
|
||||||
93D393AA69A1193401160418 /* UIView+AlphaScale.m in Sources */,
|
|
||||||
93D3942C1B117EE4851AA7B6 /* UIView+Visible.m in Sources */,
|
93D3942C1B117EE4851AA7B6 /* UIView+Visible.m in Sources */,
|
||||||
93D397FCAAC6FA885247A4F9 /* PearlLinks.m in Sources */,
|
DAB4FBC5202FDDDD002768FB /* NSInvocation+Pearl.m in Sources */,
|
||||||
93D395373A425B05C86B2268 /* PearlHangDetector.m in Sources */,
|
93D395373A425B05C86B2268 /* PearlHangDetector.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -4215,11 +4232,19 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||||
|
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
|
||||||
|
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
|
||||||
|
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
@@ -4230,19 +4255,25 @@
|
|||||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
DEVELOPMENT_TEAM = HL3Q45LX9N;
|
DEVELOPMENT_TEAM = HL3Q45LX9N;
|
||||||
DSTROOT = "/tmp/${PRODUCT_NAME}.dst";
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
@@ -4253,6 +4284,10 @@
|
|||||||
"NDEBUG=1",
|
"NDEBUG=1",
|
||||||
"NS_BLOCK_ASSERTIONS=1",
|
"NS_BLOCK_ASSERTIONS=1",
|
||||||
"CRASHLYTICS=1",
|
"CRASHLYTICS=1",
|
||||||
|
PEARL,
|
||||||
|
PEARL_UIKIT,
|
||||||
|
PEARL_CRYPTO,
|
||||||
|
PEARL_WITH_MESSAGEUI,
|
||||||
);
|
);
|
||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||||
@@ -4275,7 +4310,7 @@
|
|||||||
GCC_WARN_SIGN_COMPARE = NO;
|
GCC_WARN_SIGN_COMPARE = NO;
|
||||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
@@ -4288,6 +4323,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
OTHER_LDFLAGS = "-ObjC";
|
OTHER_LDFLAGS = "-ObjC";
|
||||||
PRODUCT_NAME = "${TARGET_NAME}";
|
PRODUCT_NAME = "${TARGET_NAME}";
|
||||||
PUBLIC_HEADERS_FOLDER_PATH = include;
|
PUBLIC_HEADERS_FOLDER_PATH = include;
|
||||||
@@ -4295,6 +4331,7 @@
|
|||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
STRIP_INSTALLED_PRODUCT = NO;
|
STRIP_INSTALLED_PRODUCT = NO;
|
||||||
|
STRIP_SWIFT_SYMBOLS = NO;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
WARNING_CFLAGS = "-Wno-float-conversion";
|
WARNING_CFLAGS = "-Wno-float-conversion";
|
||||||
@@ -4310,16 +4347,17 @@
|
|||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO;
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO;
|
||||||
CODE_SIGN_ENTITLEMENTS = Source/iOS/MasterPassword.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Source/iOS/MasterPassword.entitlements;
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
|
||||||
COPY_PHASE_STRIP = YES;
|
|
||||||
EXCLUDED_SOURCE_FILE_NAMES = libDCIntrospect.a;
|
EXCLUDED_SOURCE_FILE_NAMES = libDCIntrospect.a;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"\"$(SRCROOT)/External/iOS\"",
|
"\"$(SRCROOT)/External/iOS\"",
|
||||||
);
|
);
|
||||||
|
GCC_C_LANGUAGE_STANDARD = c11;
|
||||||
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
||||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
||||||
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
|
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
|
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
|
||||||
@@ -4332,7 +4370,10 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
|
||||||
SKIP_INSTALL = NO;
|
SKIP_INSTALL = NO;
|
||||||
STRIP_INSTALLED_PRODUCT = YES;
|
STRIP_INSTALLED_PRODUCT = YES;
|
||||||
TARGETED_DEVICE_FAMILY = 1;
|
STRIP_SWIFT_SYMBOLS = YES;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Source/iOS/MasterPassword-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
|
SWIFT_VERSION = 4.0;
|
||||||
};
|
};
|
||||||
name = Test;
|
name = Test;
|
||||||
};
|
};
|
||||||
@@ -4340,11 +4381,13 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch";
|
GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "External/Pearl/Pearl-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 4.0;
|
||||||
};
|
};
|
||||||
name = Test;
|
name = Test;
|
||||||
};
|
};
|
||||||
@@ -4403,10 +4446,18 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
|
||||||
|
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
|
||||||
|
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
@@ -4417,19 +4468,26 @@
|
|||||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
DEVELOPMENT_TEAM = HL3Q45LX9N;
|
DEVELOPMENT_TEAM = HL3Q45LX9N;
|
||||||
DSTROOT = "/tmp/${PRODUCT_NAME}.dst";
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
@@ -4440,6 +4498,10 @@
|
|||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"CRASHLYTICS=1",
|
"CRASHLYTICS=1",
|
||||||
|
PEARL,
|
||||||
|
PEARL_UIKIT,
|
||||||
|
PEARL_CRYPTO,
|
||||||
|
PEARL_WITH_MESSAGEUI,
|
||||||
);
|
);
|
||||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
@@ -4476,6 +4538,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
OTHER_LDFLAGS = "-ObjC";
|
OTHER_LDFLAGS = "-ObjC";
|
||||||
PRODUCT_NAME = "${TARGET_NAME}";
|
PRODUCT_NAME = "${TARGET_NAME}";
|
||||||
@@ -4483,6 +4546,8 @@
|
|||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
STRIP_INSTALLED_PRODUCT = NO;
|
STRIP_INSTALLED_PRODUCT = NO;
|
||||||
|
STRIP_SWIFT_SYMBOLS = NO;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
WARNING_CFLAGS = "-Wno-float-conversion";
|
WARNING_CFLAGS = "-Wno-float-conversion";
|
||||||
};
|
};
|
||||||
@@ -4493,11 +4558,19 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||||
|
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
|
||||||
|
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
|
||||||
|
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
@@ -4508,19 +4581,25 @@
|
|||||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
DEVELOPMENT_TEAM = HL3Q45LX9N;
|
DEVELOPMENT_TEAM = HL3Q45LX9N;
|
||||||
DSTROOT = "/tmp/${PRODUCT_NAME}.dst";
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
@@ -4531,6 +4610,10 @@
|
|||||||
"NDEBUG=1",
|
"NDEBUG=1",
|
||||||
"NS_BLOCK_ASSERTIONS=1",
|
"NS_BLOCK_ASSERTIONS=1",
|
||||||
"CRASHLYTICS=1",
|
"CRASHLYTICS=1",
|
||||||
|
PEARL,
|
||||||
|
PEARL_UIKIT,
|
||||||
|
PEARL_CRYPTO,
|
||||||
|
PEARL_WITH_MESSAGEUI,
|
||||||
);
|
);
|
||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||||
@@ -4553,7 +4636,7 @@
|
|||||||
GCC_WARN_SIGN_COMPARE = NO;
|
GCC_WARN_SIGN_COMPARE = NO;
|
||||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
@@ -4566,6 +4649,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
OTHER_LDFLAGS = "-ObjC";
|
OTHER_LDFLAGS = "-ObjC";
|
||||||
PRODUCT_NAME = "${TARGET_NAME}";
|
PRODUCT_NAME = "${TARGET_NAME}";
|
||||||
PUBLIC_HEADERS_FOLDER_PATH = include;
|
PUBLIC_HEADERS_FOLDER_PATH = include;
|
||||||
@@ -4573,6 +4657,7 @@
|
|||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
STRIP_INSTALLED_PRODUCT = NO;
|
STRIP_INSTALLED_PRODUCT = NO;
|
||||||
|
STRIP_SWIFT_SYMBOLS = NO;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
WARNING_CFLAGS = "-Wno-float-conversion";
|
WARNING_CFLAGS = "-Wno-float-conversion";
|
||||||
@@ -4592,44 +4677,12 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"\"$(SRCROOT)/External/iOS\"",
|
"\"$(SRCROOT)/External/iOS\"",
|
||||||
);
|
);
|
||||||
|
GCC_C_LANGUAGE_STANDARD = c11;
|
||||||
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
||||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
||||||
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
|
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
|
|
||||||
"$(PROJECT_DIR)/External/libjson-c/libjson-c-ios/lib",
|
|
||||||
);
|
|
||||||
OTHER_CFLAGS = (
|
|
||||||
"-DMPW_SODIUM=1",
|
|
||||||
"-DMPW_CPERCIVA=0",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
|
|
||||||
SKIP_INSTALL = NO;
|
|
||||||
TARGETED_DEVICE_FAMILY = 1;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
DA5BFA6F147E415C00F98B1E /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO;
|
|
||||||
CODE_SIGN_ENTITLEMENTS = Source/iOS/MasterPassword.entitlements;
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = YES;
|
|
||||||
EXCLUDED_SOURCE_FILE_NAMES = libDCIntrospect.a;
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"\"$(SRCROOT)/External/iOS\"",
|
|
||||||
);
|
|
||||||
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
|
||||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
|
||||||
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
|
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
|
||||||
@@ -4642,6 +4695,49 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
|
||||||
SKIP_INSTALL = NO;
|
SKIP_INSTALL = NO;
|
||||||
STRIP_INSTALLED_PRODUCT = YES;
|
STRIP_INSTALLED_PRODUCT = YES;
|
||||||
|
STRIP_SWIFT_SYMBOLS = YES;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Source/iOS/MasterPassword-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 4.0;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
DA5BFA6F147E415C00F98B1E /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Source/iOS/MasterPassword.entitlements;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
EXCLUDED_SOURCE_FILE_NAMES = libDCIntrospect.a;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"\"$(SRCROOT)/External/iOS\"",
|
||||||
|
);
|
||||||
|
GCC_C_LANGUAGE_STANDARD = c11;
|
||||||
|
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
||||||
|
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
||||||
|
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
|
||||||
|
"$(PROJECT_DIR)/External/libjson-c/libjson-c-ios/lib",
|
||||||
|
);
|
||||||
|
OTHER_CFLAGS = (
|
||||||
|
"-DMPW_SODIUM=1",
|
||||||
|
"-DMPW_CPERCIVA=0",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
|
||||||
|
SKIP_INSTALL = NO;
|
||||||
|
STRIP_INSTALLED_PRODUCT = YES;
|
||||||
|
STRIP_SWIFT_SYMBOLS = YES;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Source/iOS/MasterPassword-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
|
SWIFT_VERSION = 4.0;
|
||||||
TARGETED_DEVICE_FAMILY = 1;
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
@@ -4820,11 +4916,13 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch";
|
GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "External/Pearl/Pearl-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 4.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -4832,7 +4930,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch";
|
GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "0830"
|
LastUpgradeVersion = "0920"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
</Testables>
|
</Testables>
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
DA16B342170661E0000A0EAB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC632871486D95D0075AEA5 /* Security.framework */; };
|
DA16B342170661E0000A0EAB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC632871486D95D0075AEA5 /* Security.framework */; };
|
||||||
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; };
|
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; };
|
||||||
DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
|
DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
|
||||||
DA1C7AAA1F1A8F24009A3551 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */; };
|
DA1C7AAA1F1A8F24009A3551 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */; };
|
||||||
DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; };
|
DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; };
|
||||||
DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; };
|
DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; };
|
||||||
DA1C7AAD1F1A8F24009A3551 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; };
|
DA1C7AAD1F1A8F24009A3551 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; };
|
||||||
@@ -64,8 +64,6 @@
|
|||||||
DA2CA4EE18D323D3007798F8 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */; };
|
DA2CA4EE18D323D3007798F8 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */; };
|
||||||
DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */; };
|
DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */; };
|
||||||
DA2CA4F018D323D3007798F8 /* NSArray+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */; };
|
DA2CA4F018D323D3007798F8 /* NSArray+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */; };
|
||||||
DA2CA4F118D323D3007798F8 /* NSTimer+PearlBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4EB18D323D3007798F8 /* NSTimer+PearlBlock.m */; };
|
|
||||||
DA2CA4F218D323D3007798F8 /* NSTimer+PearlBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4EC18D323D3007798F8 /* NSTimer+PearlBlock.h */; };
|
|
||||||
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
|
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
|
||||||
DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */; };
|
DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */; };
|
||||||
DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9D515723E6900A68B4C /* PearlLazy.h */; };
|
DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9D515723E6900A68B4C /* PearlLazy.h */; };
|
||||||
@@ -77,7 +75,6 @@
|
|||||||
DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3B8451190FC86F00246EEA /* NSManagedObject+Pearl.h */; };
|
DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3B8451190FC86F00246EEA /* NSManagedObject+Pearl.h */; };
|
||||||
DA3B8456190FC89700246EEA /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3B8454190FC89700246EEA /* MPFixable.m */; };
|
DA3B8456190FC89700246EEA /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3B8454190FC89700246EEA /* MPFixable.m */; };
|
||||||
DA3BCFCD19BD09E0006B2681 /* SourceCodePro-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA3BCFCC19BD09E0006B2681 /* SourceCodePro-Regular.otf */; };
|
DA3BCFCD19BD09E0006B2681 /* SourceCodePro-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA3BCFCC19BD09E0006B2681 /* SourceCodePro-Regular.otf */; };
|
||||||
DA4571201F572F3200D54152 /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DA45711E1F572F3200D54152 /* PearlCryptUtils.m */; };
|
|
||||||
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
|
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
|
||||||
DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE921A7D8117003E5423 /* MPAlgorithmV3.m */; };
|
DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE921A7D8117003E5423 /* MPAlgorithmV3.m */; };
|
||||||
DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE931A7D8117003E5423 /* MPTypes.m */; };
|
DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE931A7D8117003E5423 /* MPTypes.m */; };
|
||||||
@@ -110,8 +107,8 @@
|
|||||||
DA6774431A474A3B004F356A /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; };
|
DA6774431A474A3B004F356A /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; };
|
||||||
DA6774451A474A3B004F356A /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; };
|
DA6774451A474A3B004F356A /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; };
|
||||||
DA6774461A474A3B004F356A /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; };
|
DA6774461A474A3B004F356A /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; };
|
||||||
DA7471A31F2B71AE005F3468 /* mpw-marshall-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshall-util.c */; };
|
DA7471A31F2B71AE005F3468 /* mpw-marshal-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */; };
|
||||||
DA7471A61F2B71B9005F3468 /* mpw-marshall-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshall-util.c */; };
|
DA7471A61F2B71B9005F3468 /* mpw-marshal-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */; };
|
||||||
DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = DA89D4EA1A51EABD00AC64D7 /* Pearl-Cocoa.h */; };
|
DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = DA89D4EA1A51EABD00AC64D7 /* Pearl-Cocoa.h */; };
|
||||||
DA89D4ED1A51EABD00AC64D7 /* Pearl-Cocoa.m in Sources */ = {isa = PBXBuildFile; fileRef = DA89D4EB1A51EABD00AC64D7 /* Pearl-Cocoa.m */; };
|
DA89D4ED1A51EABD00AC64D7 /* Pearl-Cocoa.m in Sources */ = {isa = PBXBuildFile; fileRef = DA89D4EB1A51EABD00AC64D7 /* Pearl-Cocoa.m */; };
|
||||||
DA8ED895192906920099B726 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8ED891192906920099B726 /* PearlTween.m */; };
|
DA8ED895192906920099B726 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8ED891192906920099B726 /* PearlTween.m */; };
|
||||||
@@ -121,7 +118,7 @@
|
|||||||
DA9261521BE1A86700369DE5 /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261501BE1A86700369DE5 /* Fabric.framework */; };
|
DA9261521BE1A86700369DE5 /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261501BE1A86700369DE5 /* Fabric.framework */; };
|
||||||
DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261531BE1A88900369DE5 /* libc++.tbd */; };
|
DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261531BE1A88900369DE5 /* libc++.tbd */; };
|
||||||
DA9261561BE1A89600369DE5 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261551BE1A89600369DE5 /* libz.tbd */; };
|
DA9261561BE1A89600369DE5 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261551BE1A89600369DE5 /* libz.tbd */; };
|
||||||
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */; };
|
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */; };
|
||||||
DAAA81B0195A8D1300FA30D9 /* gradient.png in Resources */ = {isa = PBXBuildFile; fileRef = DAAA81AF195A8D1300FA30D9 /* gradient.png */; };
|
DAAA81B0195A8D1300FA30D9 /* gradient.png in Resources */ = {isa = PBXBuildFile; fileRef = DAAA81AF195A8D1300FA30D9 /* gradient.png */; };
|
||||||
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */; };
|
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */; };
|
||||||
DAADCC4819FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */; };
|
DAADCC4819FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */; };
|
||||||
@@ -130,6 +127,20 @@
|
|||||||
DAADCC6919FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m in Sources */ = {isa = PBXBuildFile; fileRef = DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */; };
|
DAADCC6919FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m in Sources */ = {isa = PBXBuildFile; fileRef = DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */; };
|
||||||
DAADCC6A19FB00B500987B1D /* libKCOrderedAccessorFix.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAADCC5019FB006500987B1D /* libKCOrderedAccessorFix.a */; };
|
DAADCC6A19FB00B500987B1D /* libKCOrderedAccessorFix.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAADCC5019FB006500987B1D /* libKCOrderedAccessorFix.a */; };
|
||||||
DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */; };
|
DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */; };
|
||||||
|
DAB07CA01F7725D400CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
|
||||||
|
DAB07CA31F77261400CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
|
||||||
|
DAB07CA51F77261C00CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
|
||||||
|
DAB07CA61F77262400CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
|
||||||
|
DAB4FBE3202FF93E002768FB /* PearlHangDetector.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBDD202FF93D002768FB /* PearlHangDetector.h */; };
|
||||||
|
DAB4FBE4202FF93E002768FB /* PearlHangDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBDE202FF93D002768FB /* PearlHangDetector.m */; };
|
||||||
|
DAB4FBE5202FF93E002768FB /* NSInvocation+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBDF202FF93D002768FB /* NSInvocation+Pearl.h */; };
|
||||||
|
DAB4FBE6202FF93E002768FB /* NSInvocation+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBE0202FF93D002768FB /* NSInvocation+Pearl.m */; };
|
||||||
|
DAB4FBE7202FF93E002768FB /* NSOrderedSetOrArray.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBE1202FF93D002768FB /* NSOrderedSetOrArray.h */; };
|
||||||
|
DAB4FBE8202FF93E002768FB /* NSOrderedSetOrArray.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBE2202FF93D002768FB /* NSOrderedSetOrArray.m */; };
|
||||||
|
DAB4FBE9202FF94C002768FB /* NSMutableSet+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DACBFCDB1C59B22E007EF90F /* NSMutableSet+Pearl.h */; };
|
||||||
|
DAB4FBEA202FF951002768FB /* NSMutableSet+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DACBFCDC1C59B22E007EF90F /* NSMutableSet+Pearl.m */; };
|
||||||
|
DAB4FBEB202FF975002768FB /* PearlCryptUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DA45711F1F572F3200D54152 /* PearlCryptUtils.h */; };
|
||||||
|
DAB4FBEC202FF979002768FB /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DA45711E1F572F3200D54152 /* PearlCryptUtils.m */; };
|
||||||
DAB7AE5A1F3D74E700C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE591F3D74E700C856B1 /* libjson-c.a */; };
|
DAB7AE5A1F3D74E700C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE591F3D74E700C856B1 /* libjson-c.a */; };
|
||||||
DAB7AE5B1F3D750B00C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE591F3D74E700C856B1 /* libjson-c.a */; };
|
DAB7AE5B1F3D750B00C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE591F3D74E700C856B1 /* libjson-c.a */; };
|
||||||
DAB7AE941F3D757B00C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE901F3D757B00C856B1 /* libjson-c.a */; };
|
DAB7AE941F3D757B00C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE901F3D757B00C856B1 /* libjson-c.a */; };
|
||||||
@@ -177,11 +188,9 @@
|
|||||||
DACA27381705DF81002C6C22 /* menu-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA24581705DF7D002C6C22 /* menu-icon.png */; };
|
DACA27381705DF81002C6C22 /* menu-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA24581705DF7D002C6C22 /* menu-icon.png */; };
|
||||||
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */; };
|
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */; };
|
||||||
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */; };
|
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */; };
|
||||||
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA29711705E1A8002C6C22 /* ciphers.plist */; };
|
|
||||||
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; };
|
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; };
|
||||||
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; };
|
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; };
|
||||||
DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA298C1705E2BD002C6C22 /* JRSwizzle.m */; };
|
DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA298C1705E2BD002C6C22 /* JRSwizzle.m */; };
|
||||||
DACBFCDF1C59B22E007EF90F /* NSMutableSet+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DACBFCDC1C59B22E007EF90F /* NSMutableSet+Pearl.m */; };
|
|
||||||
DAD9B5F01762CAA4001835F9 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */; };
|
DAD9B5F01762CAA4001835F9 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */; };
|
||||||
DAD9B5F11762CAB9001835F9 /* MasterPassword-Mac-LoginHelper.app in Copy LoginHelper */ = {isa = PBXBuildFile; fileRef = DAD9B5E6176299BA001835F9 /* MasterPassword-Mac-LoginHelper.app */; };
|
DAD9B5F11762CAB9001835F9 /* MasterPassword-Mac-LoginHelper.app in Copy LoginHelper */ = {isa = PBXBuildFile; fileRef = DAD9B5E6176299BA001835F9 /* MasterPassword-Mac-LoginHelper.app */; };
|
||||||
DADD5DFA1EA173B0005E7D96 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0979571E9A824700F0BFE8 /* libsodium.a */; };
|
DADD5DFA1EA173B0005E7D96 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0979571E9A824700F0BFE8 /* libsodium.a */; };
|
||||||
@@ -480,8 +489,6 @@
|
|||||||
DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; };
|
DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; };
|
||||||
DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = "<group>"; };
|
DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = "<group>"; };
|
||||||
DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Pearl.h"; sourceTree = "<group>"; };
|
DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Pearl.h"; sourceTree = "<group>"; };
|
||||||
DA2CA4EB18D323D3007798F8 /* NSTimer+PearlBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+PearlBlock.m"; sourceTree = "<group>"; };
|
|
||||||
DA2CA4EC18D323D3007798F8 /* NSTimer+PearlBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+PearlBlock.h"; sourceTree = "<group>"; };
|
|
||||||
DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; };
|
DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; };
|
||||||
DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Pearl-Crypto.m"; sourceTree = "<group>"; };
|
DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Pearl-Crypto.m"; sourceTree = "<group>"; };
|
||||||
DA30E9D515723E6900A68B4C /* PearlLazy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLazy.h; sourceTree = "<group>"; };
|
DA30E9D515723E6900A68B4C /* PearlLazy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLazy.h; sourceTree = "<group>"; };
|
||||||
@@ -950,8 +957,8 @@
|
|||||||
DA6773C51A4746AF004F356A /* mpw-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-util.c"; sourceTree = "<group>"; };
|
DA6773C51A4746AF004F356A /* mpw-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-util.c"; sourceTree = "<group>"; };
|
||||||
DA6773C61A4746AF004F356A /* mpw-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-util.h"; sourceTree = "<group>"; };
|
DA6773C61A4746AF004F356A /* mpw-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-util.h"; sourceTree = "<group>"; };
|
||||||
DA67743B1A474A03004F356A /* mpw-test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "mpw-test"; sourceTree = BUILT_PRODUCTS_DIR; };
|
DA67743B1A474A03004F356A /* mpw-test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "mpw-test"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
DA7471A01F2B71A9005F3468 /* mpw-marshall-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall-util.c"; sourceTree = "<group>"; };
|
DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal-util.c"; sourceTree = "<group>"; };
|
||||||
DA7471A11F2B71A9005F3468 /* mpw-marshall-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall-util.h"; sourceTree = "<group>"; };
|
DA7471A11F2B71A9005F3468 /* mpw-marshal-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal-util.h"; sourceTree = "<group>"; };
|
||||||
DA771FE51E6E15A1004D7EDE /* MasterPassword-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MasterPassword-Prefix.pch"; sourceTree = "<group>"; };
|
DA771FE51E6E15A1004D7EDE /* MasterPassword-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MasterPassword-Prefix.pch"; sourceTree = "<group>"; };
|
||||||
DA831A271A6E1146000AC234 /* mpw-algorithm_v0.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v0.c"; sourceTree = "<group>"; };
|
DA831A271A6E1146000AC234 /* mpw-algorithm_v0.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v0.c"; sourceTree = "<group>"; };
|
||||||
DA831A281A6E1146000AC234 /* mpw-algorithm_v1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v1.c"; sourceTree = "<group>"; };
|
DA831A281A6E1146000AC234 /* mpw-algorithm_v1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v1.c"; sourceTree = "<group>"; };
|
||||||
@@ -966,8 +973,8 @@
|
|||||||
DA9261501BE1A86700369DE5 /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = "<group>"; };
|
DA9261501BE1A86700369DE5 /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = "<group>"; };
|
||||||
DA9261531BE1A88900369DE5 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
DA9261531BE1A88900369DE5 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||||
DA9261551BE1A89600369DE5 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
DA9261551BE1A89600369DE5 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||||
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall.c"; sourceTree = "<group>"; };
|
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal.c"; sourceTree = "<group>"; };
|
||||||
DAA449D41EEC4B6B00E7BDD5 /* mpw-marshall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall.h"; sourceTree = "<group>"; };
|
DAA449D41EEC4B6B00E7BDD5 /* mpw-marshal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal.h"; sourceTree = "<group>"; };
|
||||||
DAAA81AF195A8D1300FA30D9 /* gradient.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = gradient.png; sourceTree = "<group>"; };
|
DAAA81AF195A8D1300FA30D9 /* gradient.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = gradient.png; sourceTree = "<group>"; };
|
||||||
DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = "<group>"; };
|
DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = "<group>"; };
|
||||||
DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPersistentStore+PearlMigration.h"; sourceTree = "<group>"; };
|
DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPersistentStore+PearlMigration.h"; sourceTree = "<group>"; };
|
||||||
@@ -977,6 +984,15 @@
|
|||||||
DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObjectModel+KCOrderedAccessorFix.m"; sourceTree = "<group>"; };
|
DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObjectModel+KCOrderedAccessorFix.m"; sourceTree = "<group>"; };
|
||||||
DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-cli-util.c"; sourceTree = "<group>"; };
|
DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-cli-util.c"; sourceTree = "<group>"; };
|
||||||
DAAF16641F5897EA0013B8AE /* mpw-cli-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-cli-util.h"; sourceTree = "<group>"; };
|
DAAF16641F5897EA0013B8AE /* mpw-cli-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-cli-util.h"; sourceTree = "<group>"; };
|
||||||
|
DAB07C9E1F7725D400CC6D43 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = "<group>"; };
|
||||||
|
DAB07C9F1F7725D400CC6D43 /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = "<group>"; };
|
||||||
|
DAB4FBB3202FD60A002768FB /* Pearl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Pearl-Prefix.pch"; sourceTree = "<group>"; };
|
||||||
|
DAB4FBDD202FF93D002768FB /* PearlHangDetector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlHangDetector.h; sourceTree = "<group>"; };
|
||||||
|
DAB4FBDE202FF93D002768FB /* PearlHangDetector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlHangDetector.m; sourceTree = "<group>"; };
|
||||||
|
DAB4FBDF202FF93D002768FB /* NSInvocation+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSInvocation+Pearl.h"; sourceTree = "<group>"; };
|
||||||
|
DAB4FBE0202FF93D002768FB /* NSInvocation+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSInvocation+Pearl.m"; sourceTree = "<group>"; };
|
||||||
|
DAB4FBE1202FF93D002768FB /* NSOrderedSetOrArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSOrderedSetOrArray.h; sourceTree = "<group>"; };
|
||||||
|
DAB4FBE2202FF93D002768FB /* NSOrderedSetOrArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSOrderedSetOrArray.m; sourceTree = "<group>"; };
|
||||||
DAB7AE591F3D74E700C856B1 /* libjson-c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libjson-c.a"; path = "External/libjson-c/libjson-c-osx/lib/libjson-c.a"; sourceTree = "<group>"; };
|
DAB7AE591F3D74E700C856B1 /* libjson-c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libjson-c.a"; path = "External/libjson-c/libjson-c-osx/lib/libjson-c.a"; sourceTree = "<group>"; };
|
||||||
DAB7AE7B1F3D757B00C856B1 /* arraylist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arraylist.h; sourceTree = "<group>"; };
|
DAB7AE7B1F3D757B00C856B1 /* arraylist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arraylist.h; sourceTree = "<group>"; };
|
||||||
DAB7AE7C1F3D757B00C856B1 /* bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bits.h; sourceTree = "<group>"; };
|
DAB7AE7C1F3D757B00C856B1 /* bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bits.h; sourceTree = "<group>"; };
|
||||||
@@ -1003,7 +1019,6 @@
|
|||||||
DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
||||||
DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Pearl-Prefix.pch"; path = "../../Source/Pearl/Pearl-Prefix.pch"; sourceTree = "<group>"; };
|
|
||||||
DACA241C1705DF7D002C6C22 /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-bare.png"; sourceTree = "<group>"; };
|
DACA241C1705DF7D002C6C22 /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-bare.png"; sourceTree = "<group>"; };
|
||||||
DACA24321705DF7D002C6C22 /* avatar-13@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-13@2x.png"; sourceTree = "<group>"; };
|
DACA24321705DF7D002C6C22 /* avatar-13@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-13@2x.png"; sourceTree = "<group>"; };
|
||||||
DACA24331705DF7D002C6C22 /* avatar-3@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-3@2x.png"; sourceTree = "<group>"; };
|
DACA24331705DF7D002C6C22 /* avatar-3@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-3@2x.png"; sourceTree = "<group>"; };
|
||||||
@@ -1046,7 +1061,6 @@
|
|||||||
DACA24581705DF7D002C6C22 /* menu-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu-icon.png"; sourceTree = "<group>"; };
|
DACA24581705DF7D002C6C22 /* menu-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu-icon.png"; sourceTree = "<group>"; };
|
||||||
DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-ExtraLight.otf"; sourceTree = "<group>"; };
|
DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-ExtraLight.otf"; sourceTree = "<group>"; };
|
||||||
DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Black.otf"; sourceTree = "<group>"; };
|
DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Black.otf"; sourceTree = "<group>"; };
|
||||||
DACA29711705E1A8002C6C22 /* ciphers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = ciphers.plist; sourceTree = "<group>"; };
|
|
||||||
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
|
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
|
||||||
DACA29771705E2BD002C6C22 /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRSwizzle.h; sourceTree = "<group>"; };
|
DACA29771705E2BD002C6C22 /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRSwizzle.h; sourceTree = "<group>"; };
|
||||||
DACA298C1705E2BD002C6C22 /* JRSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JRSwizzle.m; sourceTree = "<group>"; };
|
DACA298C1705E2BD002C6C22 /* JRSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JRSwizzle.m; sourceTree = "<group>"; };
|
||||||
@@ -1878,6 +1892,8 @@
|
|||||||
DA6773291A4746AF004F356A /* C */ = {
|
DA6773291A4746AF004F356A /* C */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
DAB07C9E1F7725D400CC6D43 /* aes.c */,
|
||||||
|
DAB07C9F1F7725D400CC6D43 /* aes.h */,
|
||||||
DA5B0B381F36467300B663F0 /* base64.c */,
|
DA5B0B381F36467300B663F0 /* base64.c */,
|
||||||
DA5B0B391F36467300B663F0 /* base64.h */,
|
DA5B0B391F36467300B663F0 /* base64.h */,
|
||||||
DA1C7AB71F1A8F6E009A3551 /* cli */,
|
DA1C7AB71F1A8F6E009A3551 /* cli */,
|
||||||
@@ -1887,10 +1903,10 @@
|
|||||||
DA831A2A1A6E1146000AC234 /* mpw-algorithm_v3.c */,
|
DA831A2A1A6E1146000AC234 /* mpw-algorithm_v3.c */,
|
||||||
DA6773BB1A4746AF004F356A /* mpw-algorithm.c */,
|
DA6773BB1A4746AF004F356A /* mpw-algorithm.c */,
|
||||||
DA6773BC1A4746AF004F356A /* mpw-algorithm.h */,
|
DA6773BC1A4746AF004F356A /* mpw-algorithm.h */,
|
||||||
DA7471A01F2B71A9005F3468 /* mpw-marshall-util.c */,
|
DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */,
|
||||||
DA7471A11F2B71A9005F3468 /* mpw-marshall-util.h */,
|
DA7471A11F2B71A9005F3468 /* mpw-marshal-util.h */,
|
||||||
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */,
|
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */,
|
||||||
DAA449D41EEC4B6B00E7BDD5 /* mpw-marshall.h */,
|
DAA449D41EEC4B6B00E7BDD5 /* mpw-marshal.h */,
|
||||||
DA6773C21A4746AF004F356A /* mpw-types.c */,
|
DA6773C21A4746AF004F356A /* mpw-types.c */,
|
||||||
DA6773C31A4746AF004F356A /* mpw-types.h */,
|
DA6773C31A4746AF004F356A /* mpw-types.h */,
|
||||||
DA6773C51A4746AF004F356A /* mpw-util.c */,
|
DA6773C51A4746AF004F356A /* mpw-util.c */,
|
||||||
@@ -1987,7 +2003,7 @@
|
|||||||
DAFE45D715039823003ABA7C /* Pearl */,
|
DAFE45D715039823003ABA7C /* Pearl */,
|
||||||
DA89D4E51A51E53100AC64D7 /* Pearl-Cocoa */,
|
DA89D4E51A51E53100AC64D7 /* Pearl-Cocoa */,
|
||||||
DAFE45FC15039823003ABA7C /* Pearl-Crypto */,
|
DAFE45FC15039823003ABA7C /* Pearl-Crypto */,
|
||||||
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */,
|
DAB4FBB3202FD60A002768FB /* Pearl-Prefix.pch */,
|
||||||
);
|
);
|
||||||
path = Pearl;
|
path = Pearl;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -2095,7 +2111,6 @@
|
|||||||
DACA29701705E1A8002C6C22 /* Data */ = {
|
DACA29701705E1A8002C6C22 /* Data */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
DACA29711705E1A8002C6C22 /* ciphers.plist */,
|
|
||||||
DACA29721705E1A8002C6C22 /* dictionary.lst */,
|
DACA29721705E1A8002C6C22 /* dictionary.lst */,
|
||||||
);
|
);
|
||||||
path = Data;
|
path = Data;
|
||||||
@@ -2147,6 +2162,12 @@
|
|||||||
DAFE45D715039823003ABA7C /* Pearl */ = {
|
DAFE45D715039823003ABA7C /* Pearl */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
DAB4FBDF202FF93D002768FB /* NSInvocation+Pearl.h */,
|
||||||
|
DAB4FBE0202FF93D002768FB /* NSInvocation+Pearl.m */,
|
||||||
|
DAB4FBE1202FF93D002768FB /* NSOrderedSetOrArray.h */,
|
||||||
|
DAB4FBE2202FF93D002768FB /* NSOrderedSetOrArray.m */,
|
||||||
|
DAB4FBDD202FF93D002768FB /* PearlHangDetector.h */,
|
||||||
|
DAB4FBDE202FF93D002768FB /* PearlHangDetector.m */,
|
||||||
DA8ED893192906920099B726 /* include */,
|
DA8ED893192906920099B726 /* include */,
|
||||||
93D396D04E57792A54D437AC /* NSArray+Indexing.h */,
|
93D396D04E57792A54D437AC /* NSArray+Indexing.h */,
|
||||||
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */,
|
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */,
|
||||||
@@ -2173,8 +2194,6 @@
|
|||||||
DAFE45DB15039823003ABA7C /* NSString+PearlNSArrayFormat.m */,
|
DAFE45DB15039823003ABA7C /* NSString+PearlNSArrayFormat.m */,
|
||||||
DAFE45DC15039823003ABA7C /* NSString+PearlSEL.h */,
|
DAFE45DC15039823003ABA7C /* NSString+PearlSEL.h */,
|
||||||
DAFE45DD15039823003ABA7C /* NSString+PearlSEL.m */,
|
DAFE45DD15039823003ABA7C /* NSString+PearlSEL.m */,
|
||||||
DA2CA4EC18D323D3007798F8 /* NSTimer+PearlBlock.h */,
|
|
||||||
DA2CA4EB18D323D3007798F8 /* NSTimer+PearlBlock.m */,
|
|
||||||
DAFE45DE15039823003ABA7C /* Pearl.h */,
|
DAFE45DE15039823003ABA7C /* Pearl.h */,
|
||||||
DA30E9CD15722ECA00A68B4C /* Pearl.m */,
|
DA30E9CD15722ECA00A68B4C /* Pearl.m */,
|
||||||
DAFE45DF15039823003ABA7C /* PearlAbstractStrings.h */,
|
DAFE45DF15039823003ABA7C /* PearlAbstractStrings.h */,
|
||||||
@@ -2250,15 +2269,16 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */,
|
DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */,
|
||||||
DA2CA4F218D323D3007798F8 /* NSTimer+PearlBlock.h in Headers */,
|
|
||||||
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */,
|
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */,
|
||||||
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */,
|
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */,
|
||||||
DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */,
|
DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */,
|
||||||
DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */,
|
DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */,
|
||||||
DA8ED897192906920099B726 /* map-macro.h in Headers */,
|
DA8ED897192906920099B726 /* map-macro.h in Headers */,
|
||||||
DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
|
DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
|
||||||
|
DAB4FBE9202FF94C002768FB /* NSMutableSet+Pearl.h in Headers */,
|
||||||
DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
|
DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
|
||||||
DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
|
DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
|
||||||
|
DAB4FBE3202FF93E002768FB /* PearlHangDetector.h in Headers */,
|
||||||
DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */,
|
DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */,
|
||||||
DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */,
|
DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */,
|
||||||
DA8ED896192906920099B726 /* PearlTween.h in Headers */,
|
DA8ED896192906920099B726 /* PearlTween.h in Headers */,
|
||||||
@@ -2266,13 +2286,16 @@
|
|||||||
DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */,
|
DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */,
|
||||||
DA2CA4F018D323D3007798F8 /* NSArray+Pearl.h in Headers */,
|
DA2CA4F018D323D3007798F8 /* NSArray+Pearl.h in Headers */,
|
||||||
DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */,
|
DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */,
|
||||||
|
DAB4FBE7202FF93E002768FB /* NSOrderedSetOrArray.h in Headers */,
|
||||||
DAFE4A2A15039824003ABA7C /* PearlObjectUtils.h in Headers */,
|
DAFE4A2A15039824003ABA7C /* PearlObjectUtils.h in Headers */,
|
||||||
DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */,
|
DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */,
|
||||||
DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */,
|
DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */,
|
||||||
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
|
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
|
||||||
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
|
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
|
||||||
|
DAB4FBEB202FF975002768FB /* PearlCryptUtils.h in Headers */,
|
||||||
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
|
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
|
||||||
DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */,
|
DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */,
|
||||||
|
DAB4FBE5202FF93E002768FB /* NSInvocation+Pearl.h in Headers */,
|
||||||
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */,
|
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */,
|
||||||
DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */,
|
DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */,
|
||||||
DAFE4A63150399FF003ABA94 /* NSDateFormatter+RFC3339.h in Headers */,
|
DAFE4A63150399FF003ABA94 /* NSDateFormatter+RFC3339.h in Headers */,
|
||||||
@@ -2606,7 +2629,6 @@
|
|||||||
DACA27381705DF81002C6C22 /* menu-icon.png in Resources */,
|
DACA27381705DF81002C6C22 /* menu-icon.png in Resources */,
|
||||||
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */,
|
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */,
|
||||||
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */,
|
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */,
|
||||||
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */,
|
|
||||||
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
|
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
|
||||||
DA5E5D081724A667003798D8 /* MasterPassword.entitlements in Resources */,
|
DA5E5D081724A667003798D8 /* MasterPassword.entitlements in Resources */,
|
||||||
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */,
|
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */,
|
||||||
@@ -2670,13 +2692,14 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
DA1C7AAA1F1A8F24009A3551 /* mpw-marshall.c in Sources */,
|
DA1C7AAA1F1A8F24009A3551 /* mpw-marshal.c in Sources */,
|
||||||
DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */,
|
DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */,
|
||||||
DA5B0B3D1F36467900B663F0 /* base64.c in Sources */,
|
DA5B0B3D1F36467900B663F0 /* base64.c in Sources */,
|
||||||
|
DAB07CA31F77261400CC6D43 /* aes.c in Sources */,
|
||||||
DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */,
|
DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */,
|
||||||
DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */,
|
DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */,
|
||||||
DA1C7AC31F1A8FBA009A3551 /* mpw-cli.c in Sources */,
|
DA1C7AC31F1A8FBA009A3551 /* mpw-cli.c in Sources */,
|
||||||
DA7471A31F2B71AE005F3468 /* mpw-marshall-util.c in Sources */,
|
DA7471A31F2B71AE005F3468 /* mpw-marshal-util.c in Sources */,
|
||||||
DA1C7AAD1F1A8F24009A3551 /* mpw-algorithm.c in Sources */,
|
DA1C7AAD1F1A8F24009A3551 /* mpw-algorithm.c in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -2688,6 +2711,7 @@
|
|||||||
DA5B0B3C1F36467900B663F0 /* base64.c in Sources */,
|
DA5B0B3C1F36467900B663F0 /* base64.c in Sources */,
|
||||||
DA1C7ACA1F1A8FD8009A3551 /* mpw-types.c in Sources */,
|
DA1C7ACA1F1A8FD8009A3551 /* mpw-types.c in Sources */,
|
||||||
DA1C7ACB1F1A8FD8009A3551 /* mpw-util.c in Sources */,
|
DA1C7ACB1F1A8FD8009A3551 /* mpw-util.c in Sources */,
|
||||||
|
DAB07CA61F77262400CC6D43 /* aes.c in Sources */,
|
||||||
DA1C7AD71F1A8FE6009A3551 /* mpw-bench.c in Sources */,
|
DA1C7AD71F1A8FE6009A3551 /* mpw-bench.c in Sources */,
|
||||||
DA1C7ACD1F1A8FD8009A3551 /* mpw-algorithm.c in Sources */,
|
DA1C7ACD1F1A8FD8009A3551 /* mpw-algorithm.c in Sources */,
|
||||||
);
|
);
|
||||||
@@ -2701,13 +2725,12 @@
|
|||||||
DA5E5CF61724A667003798D8 /* MPAlgorithm.m in Sources */,
|
DA5E5CF61724A667003798D8 /* MPAlgorithm.m in Sources */,
|
||||||
DA2686201EBFD7A40001E37E /* MPSiteEntity+CoreDataProperties.m in Sources */,
|
DA2686201EBFD7A40001E37E /* MPSiteEntity+CoreDataProperties.m in Sources */,
|
||||||
DA5E5CF71724A667003798D8 /* MPAlgorithmV0.m in Sources */,
|
DA5E5CF71724A667003798D8 /* MPAlgorithmV0.m in Sources */,
|
||||||
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshall.c in Sources */,
|
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshal.c in Sources */,
|
||||||
DA26861E1EBFD7A40001E37E /* MPGeneratedSiteEntity+CoreDataProperties.m in Sources */,
|
DA26861E1EBFD7A40001E37E /* MPGeneratedSiteEntity+CoreDataProperties.m in Sources */,
|
||||||
DA5E5CF81724A667003798D8 /* MPAlgorithmV1.m in Sources */,
|
DA5E5CF81724A667003798D8 /* MPAlgorithmV1.m in Sources */,
|
||||||
DA2686231EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataClass.m in Sources */,
|
DA2686231EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataClass.m in Sources */,
|
||||||
DA2686221EBFD7A40001E37E /* MPSiteQuestionEntity+CoreDataProperties.m in Sources */,
|
DA2686221EBFD7A40001E37E /* MPSiteQuestionEntity+CoreDataProperties.m in Sources */,
|
||||||
DA4571201F572F3200D54152 /* PearlCryptUtils.m in Sources */,
|
DAB07CA01F7725D400CC6D43 /* aes.c in Sources */,
|
||||||
DACBFCDF1C59B22E007EF90F /* NSMutableSet+Pearl.m in Sources */,
|
|
||||||
DA2686241EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataProperties.m in Sources */,
|
DA2686241EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataProperties.m in Sources */,
|
||||||
DA6774311A4746AF004F356A /* mpw-util.c in Sources */,
|
DA6774311A4746AF004F356A /* mpw-util.c in Sources */,
|
||||||
DA5E5CF91724A667003798D8 /* MPAppDelegate_Key.m in Sources */,
|
DA5E5CF91724A667003798D8 /* MPAppDelegate_Key.m in Sources */,
|
||||||
@@ -2738,7 +2761,7 @@
|
|||||||
DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */,
|
DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */,
|
||||||
DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */,
|
DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */,
|
||||||
93D393A1646430FAAC73E7FE /* MPMacApplication.m in Sources */,
|
93D393A1646430FAAC73E7FE /* MPMacApplication.m in Sources */,
|
||||||
DA7471A61F2B71B9005F3468 /* mpw-marshall-util.c in Sources */,
|
DA7471A61F2B71B9005F3468 /* mpw-marshal-util.c in Sources */,
|
||||||
93D398D1F5D8CD5A22AF6929 /* MPGradientView.m in Sources */,
|
93D398D1F5D8CD5A22AF6929 /* MPGradientView.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -2749,6 +2772,7 @@
|
|||||||
files = (
|
files = (
|
||||||
DA1C7AD81F1A8FF4009A3551 /* mpw-tests-util.c in Sources */,
|
DA1C7AD81F1A8FF4009A3551 /* mpw-tests-util.c in Sources */,
|
||||||
DA6774451A474A3B004F356A /* mpw-types.c in Sources */,
|
DA6774451A474A3B004F356A /* mpw-types.c in Sources */,
|
||||||
|
DAB07CA51F77261C00CC6D43 /* aes.c in Sources */,
|
||||||
DA6774461A474A3B004F356A /* mpw-util.c in Sources */,
|
DA6774461A474A3B004F356A /* mpw-util.c in Sources */,
|
||||||
DA1C7AD91F1A8FF4009A3551 /* mpw-tests.c in Sources */,
|
DA1C7AD91F1A8FF4009A3551 /* mpw-tests.c in Sources */,
|
||||||
DA5B0B3B1F36467800B663F0 /* base64.c in Sources */,
|
DA5B0B3B1F36467800B663F0 /* base64.c in Sources */,
|
||||||
@@ -2778,6 +2802,7 @@
|
|||||||
files = (
|
files = (
|
||||||
DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */,
|
DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */,
|
||||||
DAADCC4919FAFFAD00987B1D /* NSPersistentStore+PearlMigration.m in Sources */,
|
DAADCC4919FAFFAD00987B1D /* NSPersistentStore+PearlMigration.m in Sources */,
|
||||||
|
DAB4FBE8202FF93E002768FB /* NSOrderedSetOrArray.m in Sources */,
|
||||||
DAFE4A1615039824003ABA7C /* NSString+PearlNSArrayFormat.m in Sources */,
|
DAFE4A1615039824003ABA7C /* NSString+PearlNSArrayFormat.m in Sources */,
|
||||||
DAFE4A1815039824003ABA7C /* NSString+PearlSEL.m in Sources */,
|
DAFE4A1815039824003ABA7C /* NSString+PearlSEL.m in Sources */,
|
||||||
DA2CA4ED18D323D3007798F8 /* NSError+PearlFullDescription.m in Sources */,
|
DA2CA4ED18D323D3007798F8 /* NSError+PearlFullDescription.m in Sources */,
|
||||||
@@ -2785,6 +2810,7 @@
|
|||||||
DAFE4A1F15039824003ABA7C /* PearlCodeUtils.m in Sources */,
|
DAFE4A1F15039824003ABA7C /* PearlCodeUtils.m in Sources */,
|
||||||
DAFE4A2115039824003ABA7C /* PearlConfig.m in Sources */,
|
DAFE4A2115039824003ABA7C /* PearlConfig.m in Sources */,
|
||||||
DAFE4A2315039824003ABA7C /* PearlDeviceUtils.m in Sources */,
|
DAFE4A2315039824003ABA7C /* PearlDeviceUtils.m in Sources */,
|
||||||
|
DAB4FBE6202FF93E002768FB /* NSInvocation+Pearl.m in Sources */,
|
||||||
DAFE4A2515039824003ABA7C /* PearlInfoPlist.m in Sources */,
|
DAFE4A2515039824003ABA7C /* PearlInfoPlist.m in Sources */,
|
||||||
DAFE4A2715039824003ABA7C /* PearlLogger.m in Sources */,
|
DAFE4A2715039824003ABA7C /* PearlLogger.m in Sources */,
|
||||||
DA2C3D691BD9665B001137B3 /* PearlProfiler.m in Sources */,
|
DA2C3D691BD9665B001137B3 /* PearlProfiler.m in Sources */,
|
||||||
@@ -2795,12 +2821,14 @@
|
|||||||
DA89D4ED1A51EABD00AC64D7 /* Pearl-Cocoa.m in Sources */,
|
DA89D4ED1A51EABD00AC64D7 /* Pearl-Cocoa.m in Sources */,
|
||||||
DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */,
|
DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */,
|
||||||
DA8ED895192906920099B726 /* PearlTween.m in Sources */,
|
DA8ED895192906920099B726 /* PearlTween.m in Sources */,
|
||||||
DA2CA4F118D323D3007798F8 /* NSTimer+PearlBlock.m in Sources */,
|
DAB4FBE4202FF93E002768FB /* PearlHangDetector.m in Sources */,
|
||||||
|
DAB4FBEC202FF979002768FB /* PearlCryptUtils.m in Sources */,
|
||||||
DA3B8452190FC86F00246EEA /* NSManagedObject+Pearl.m in Sources */,
|
DA3B8452190FC86F00246EEA /* NSManagedObject+Pearl.m in Sources */,
|
||||||
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */,
|
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */,
|
||||||
DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */,
|
DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */,
|
||||||
DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */,
|
DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */,
|
||||||
DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */,
|
DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */,
|
||||||
|
DAB4FBEA202FF951002768FB /* NSMutableSet+Pearl.m in Sources */,
|
||||||
DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */,
|
DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */,
|
||||||
DAFE4A63150399FF003ABA92 /* NSDateFormatter+RFC3339.m in Sources */,
|
DAFE4A63150399FF003ABA92 /* NSDateFormatter+RFC3339.m in Sources */,
|
||||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */,
|
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */,
|
||||||
@@ -2888,10 +2916,15 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||||
CLANG_WARN_BOOL_CONVERSION = NO;
|
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
@@ -2899,16 +2932,21 @@
|
|||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
@@ -2926,6 +2964,9 @@
|
|||||||
"NDEBUG=1",
|
"NDEBUG=1",
|
||||||
"NS_BLOCK_ASSERTIONS=1",
|
"NS_BLOCK_ASSERTIONS=1",
|
||||||
"CRASHLYTICS=1",
|
"CRASHLYTICS=1",
|
||||||
|
PEARL,
|
||||||
|
PEARL_COCOA,
|
||||||
|
PEARL_CRYPTO,
|
||||||
);
|
);
|
||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||||
@@ -2946,12 +2987,12 @@
|
|||||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||||
GCC_WARN_MISSING_PARENTHESES = YES;
|
GCC_WARN_MISSING_PARENTHESES = YES;
|
||||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
||||||
GCC_WARN_SIGN_COMPARE = YES;
|
GCC_WARN_SIGN_COMPARE = NO;
|
||||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||||
GCC_WARN_UNUSED_FUNCTION = NO;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
GCC_WARN_UNUSED_VALUE = YES;
|
GCC_WARN_UNUSED_VALUE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
@@ -3012,7 +3053,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch";
|
GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
|
||||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||||
@@ -3048,7 +3089,7 @@
|
|||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
|
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
|
||||||
"/usr/include//libxml2",
|
/usr/include/libxml2,
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
@@ -3231,10 +3272,14 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||||
CLANG_WARN_BOOL_CONVERSION = NO;
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
@@ -3242,16 +3287,21 @@
|
|||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
@@ -3268,6 +3318,10 @@
|
|||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
"CRASHLYTICS=1",
|
||||||
|
PEARL,
|
||||||
|
PEARL_COCOA,
|
||||||
|
PEARL_CRYPTO,
|
||||||
);
|
);
|
||||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
@@ -3289,12 +3343,12 @@
|
|||||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||||
GCC_WARN_MISSING_PARENTHESES = YES;
|
GCC_WARN_MISSING_PARENTHESES = YES;
|
||||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
||||||
GCC_WARN_SIGN_COMPARE = YES;
|
GCC_WARN_SIGN_COMPARE = NO;
|
||||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = NO;
|
GCC_WARN_UNINITIALIZED_AUTOS = NO;
|
||||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||||
GCC_WARN_UNUSED_FUNCTION = NO;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
GCC_WARN_UNUSED_VALUE = YES;
|
GCC_WARN_UNUSED_VALUE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
@@ -3315,6 +3369,7 @@
|
|||||||
PUBLIC_HEADERS_FOLDER_PATH = include;
|
PUBLIC_HEADERS_FOLDER_PATH = include;
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
@@ -3324,10 +3379,15 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
||||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||||
CLANG_WARN_BOOL_CONVERSION = NO;
|
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
@@ -3335,16 +3395,21 @@
|
|||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
@@ -3362,6 +3427,9 @@
|
|||||||
"NDEBUG=1",
|
"NDEBUG=1",
|
||||||
"NS_BLOCK_ASSERTIONS=1",
|
"NS_BLOCK_ASSERTIONS=1",
|
||||||
"CRASHLYTICS=1",
|
"CRASHLYTICS=1",
|
||||||
|
PEARL,
|
||||||
|
PEARL_COCOA,
|
||||||
|
PEARL_CRYPTO,
|
||||||
);
|
);
|
||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||||
@@ -3382,12 +3450,12 @@
|
|||||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||||
GCC_WARN_MISSING_PARENTHESES = YES;
|
GCC_WARN_MISSING_PARENTHESES = YES;
|
||||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
||||||
GCC_WARN_SIGN_COMPARE = YES;
|
GCC_WARN_SIGN_COMPARE = NO;
|
||||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||||
GCC_WARN_UNUSED_FUNCTION = NO;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
GCC_WARN_UNUSED_VALUE = YES;
|
GCC_WARN_UNUSED_VALUE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
@@ -3482,7 +3550,7 @@
|
|||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
|
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
|
||||||
"/usr/include//libxml2",
|
/usr/include/libxml2,
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
@@ -3502,7 +3570,7 @@
|
|||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
|
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
|
||||||
"/usr/include//libxml2",
|
/usr/include/libxml2,
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
@@ -3621,7 +3689,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch";
|
GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
|
||||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||||
@@ -3634,7 +3702,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch";
|
GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
|
||||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "0830"
|
LastUpgradeVersion = "0920"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
</Testables>
|
</Testables>
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "0830"
|
LastUpgradeVersion = "0920"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
</Testables>
|
</Testables>
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "0830"
|
LastUpgradeVersion = "0920"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
</Testables>
|
</Testables>
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "0830"
|
LastUpgradeVersion = "0920"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
</Testables>
|
</Testables>
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "YES"
|
useCustomWorkingDirectory = "YES"
|
||||||
customWorkingDirectory = "/Users/lhunath/Documents/workspace/lyndir/MasterPassword/platform-independent/cli-c"
|
customWorkingDirectory = "/Users/lhunath/Documents/workspace/lyndir/MasterPassword/platform-independent/cli-c"
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>MPGeneratedSiteEntity</key>
|
|
||||||
<dict>
|
|
||||||
<key>Login Name</key>
|
|
||||||
<array>
|
|
||||||
<string>cvccvcvcv</string>
|
|
||||||
</array>
|
|
||||||
<key>Phrase</key>
|
|
||||||
<array>
|
|
||||||
<string>cvcc cvc cvccvcv cvc</string>
|
|
||||||
<string>cvc cvccvcvcv cvcv</string>
|
|
||||||
<string>cv cvccv cvc cvcvccv</string>
|
|
||||||
</array>
|
|
||||||
<key>Maximum Security Password</key>
|
|
||||||
<array>
|
|
||||||
<string>anoxxxxxxxxxxxxxxxxx</string>
|
|
||||||
<string>axxxxxxxxxxxxxxxxxno</string>
|
|
||||||
</array>
|
|
||||||
<key>Long Password</key>
|
|
||||||
<array>
|
|
||||||
<string>CvcvnoCvcvCvcv</string>
|
|
||||||
<string>CvcvCvcvnoCvcv</string>
|
|
||||||
<string>CvcvCvcvCvcvno</string>
|
|
||||||
<string>CvccnoCvcvCvcv</string>
|
|
||||||
<string>CvccCvcvnoCvcv</string>
|
|
||||||
<string>CvccCvcvCvcvno</string>
|
|
||||||
<string>CvcvnoCvccCvcv</string>
|
|
||||||
<string>CvcvCvccnoCvcv</string>
|
|
||||||
<string>CvcvCvccCvcvno</string>
|
|
||||||
<string>CvcvnoCvcvCvcc</string>
|
|
||||||
<string>CvcvCvcvnoCvcc</string>
|
|
||||||
<string>CvcvCvcvCvccno</string>
|
|
||||||
<string>CvccnoCvccCvcv</string>
|
|
||||||
<string>CvccCvccnoCvcv</string>
|
|
||||||
<string>CvccCvccCvcvno</string>
|
|
||||||
<string>CvcvnoCvccCvcc</string>
|
|
||||||
<string>CvcvCvccnoCvcc</string>
|
|
||||||
<string>CvcvCvccCvccno</string>
|
|
||||||
<string>CvccnoCvcvCvcc</string>
|
|
||||||
<string>CvccCvcvnoCvcc</string>
|
|
||||||
<string>CvccCvcvCvccno</string>
|
|
||||||
</array>
|
|
||||||
<key>Medium Password</key>
|
|
||||||
<array>
|
|
||||||
<string>CvcnoCvc</string>
|
|
||||||
<string>CvcCvcno</string>
|
|
||||||
</array>
|
|
||||||
<key>Basic Password</key>
|
|
||||||
<array>
|
|
||||||
<string>aaanaaan</string>
|
|
||||||
<string>aannaaan</string>
|
|
||||||
<string>aaannaaa</string>
|
|
||||||
</array>
|
|
||||||
<key>Short Password</key>
|
|
||||||
<array>
|
|
||||||
<string>Cvcn</string>
|
|
||||||
</array>
|
|
||||||
<key>PIN</key>
|
|
||||||
<array>
|
|
||||||
<string>nnnn</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
<key>MPCharacterClasses</key>
|
|
||||||
<dict>
|
|
||||||
<key>V</key>
|
|
||||||
<string>AEIOU</string>
|
|
||||||
<key>C</key>
|
|
||||||
<string>BCDFGHJKLMNPQRSTVWXYZ</string>
|
|
||||||
<key>v</key>
|
|
||||||
<string>aeiou</string>
|
|
||||||
<key>c</key>
|
|
||||||
<string>bcdfghjklmnpqrstvwxyz</string>
|
|
||||||
<key>A</key>
|
|
||||||
<string>AEIOUBCDFGHJKLMNPQRSTVWXYZ</string>
|
|
||||||
<key>a</key>
|
|
||||||
<string>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz</string>
|
|
||||||
<key>n</key>
|
|
||||||
<string>0123456789</string>
|
|
||||||
<key>o</key>
|
|
||||||
<string>@&%?,=[]_:-+*$#!'^~;()/.</string>
|
|
||||||
<key>x</key>
|
|
||||||
<string>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()</string>
|
|
||||||
<key> </key>
|
|
||||||
<string> </string>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,11 +1,16 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
hash automake || { echo >&2 "Missing automake."; exit 1; }
|
||||||
|
hash autoreconf || { echo >&2 "Missing autoconf."; exit 1; }
|
||||||
|
hash libtool || hash glibtool || { echo >&2 "Missing libtool."; exit 1; }
|
||||||
|
|
||||||
cd "${BASH_SOURCE%/*}/../External/libjson-c"
|
cd "${BASH_SOURCE%/*}/../External/libjson-c"
|
||||||
|
[[ $1 = clean ]] && { [[ ! -e Makefile ]] || make -s distclean; exit; }
|
||||||
[[ -e "${prefix=$PWD/libjson-c-ios}/lib/libjson-c.a" ]] && exit
|
[[ -e "${prefix=$PWD/libjson-c-ios}/lib/libjson-c.a" ]] && exit
|
||||||
|
|
||||||
# Prepare
|
# Prepare
|
||||||
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
|
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
|
||||||
rm -rf "${prefix=$PWD/libjson-c-ios}"
|
rm -rf "${prefix=$PWD/libjson-c-ios}"
|
||||||
mkdir -p "$prefix/lib" \
|
mkdir -p "$prefix/lib" \
|
||||||
"${prefix_i386=$prefix/tmp/i386}" \
|
"${prefix_i386=$prefix/tmp/i386}" \
|
||||||
@@ -17,8 +22,8 @@ mkdir -p "$prefix/lib" \
|
|||||||
# Targets
|
# Targets
|
||||||
(
|
(
|
||||||
## ARCH: i386
|
## ARCH: i386
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||||
export CFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
export CFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||||
export LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
export LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
@@ -28,8 +33,8 @@ mkdir -p "$prefix/lib" \
|
|||||||
)
|
)
|
||||||
(
|
(
|
||||||
## ARCH: x86_64
|
## ARCH: x86_64
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
@@ -39,8 +44,8 @@ mkdir -p "$prefix/lib" \
|
|||||||
)
|
)
|
||||||
(
|
(
|
||||||
## ARCH: armv7
|
## ARCH: armv7
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||||
export CFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
export CFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||||
export LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
export LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
@@ -50,8 +55,8 @@ mkdir -p "$prefix/lib" \
|
|||||||
)
|
)
|
||||||
(
|
(
|
||||||
## ARCH: armv7s
|
## ARCH: armv7s
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||||
export CFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
export CFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||||
export LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
export LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
@@ -61,8 +66,8 @@ mkdir -p "$prefix/lib" \
|
|||||||
)
|
)
|
||||||
(
|
(
|
||||||
## ARCH: arm64
|
## ARCH: arm64
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||||
export CFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
export CFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||||
export LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
export LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
hash automake || { echo >&2 "Missing automake."; exit 1; }
|
||||||
|
hash autoreconf || { echo >&2 "Missing autoconf."; exit 1; }
|
||||||
|
hash libtool || hash glibtool || { echo >&2 "Missing libtool."; exit 1; }
|
||||||
|
|
||||||
cd "${BASH_SOURCE%/*}/../External/libjson-c"
|
cd "${BASH_SOURCE%/*}/../External/libjson-c"
|
||||||
|
[[ $1 = clean ]] && { [[ ! -e Makefile ]] || make -s distclean; exit; }
|
||||||
[[ -e "${prefix=$PWD/libjson-c-osx}/lib/libjson-c.a" ]] && exit
|
[[ -e "${prefix=$PWD/libjson-c-osx}/lib/libjson-c.a" ]] && exit
|
||||||
|
|
||||||
# Prepare
|
# Prepare
|
||||||
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
|
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
|
||||||
rm -rf "${prefix=$PWD/libjson-c-osx}"
|
rm -rf "${prefix=$PWD/libjson-c-osx}"
|
||||||
mkdir -p "$prefix"
|
mkdir -p "$prefix"
|
||||||
|
|
||||||
# Targets
|
# Targets
|
||||||
(
|
(
|
||||||
## ARCH: x86_64
|
## ARCH: x86_64
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
|
||||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -O2 -g $CFLAGS" # -flto
|
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -O2 -g $CFLAGS" # -flto
|
||||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $LDFLAGS" # -flto
|
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $LDFLAGS" # -flto
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
hash automake || { echo >&2 "Missing automake."; exit 1; }
|
||||||
|
hash autoreconf || { echo >&2 "Missing autoconf."; exit 1; }
|
||||||
|
hash libtool || hash glibtool || { echo >&2 "Missing libtool."; exit 1; }
|
||||||
|
|
||||||
cd "${BASH_SOURCE%/*}/../External/libsodium"
|
cd "${BASH_SOURCE%/*}/../External/libsodium"
|
||||||
|
[[ $1 = clean ]] && { [[ ! -e Makefile ]] || make -s distclean; exit; }
|
||||||
[[ -e "${prefix=$PWD/libsodium-ios}/lib/libsodium.a" ]] && exit
|
[[ -e "${prefix=$PWD/libsodium-ios}/lib/libsodium.a" ]] && exit
|
||||||
|
|
||||||
# Prepare
|
# Prepare
|
||||||
autoreconf --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
|
autoreconf --verbose --install --symlink 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
|
||||||
rm -rf "${prefix=$PWD/libsodium-ios}"
|
rm -rf "${prefix=$PWD/libsodium-ios}"
|
||||||
mkdir -p "$prefix/lib" \
|
mkdir -p "$prefix/lib" \
|
||||||
"${prefix_i386=$prefix/tmp/i386}" \
|
"${prefix_i386=$prefix/tmp/i386}" \
|
||||||
@@ -17,57 +22,57 @@ mkdir -p "$prefix/lib" \
|
|||||||
# Targets
|
# Targets
|
||||||
(
|
(
|
||||||
## ARCH: i386
|
## ARCH: i386
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||||
export CFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
export CFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||||
export LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
export LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
[[ -e Makefile ]] && make -s distclean
|
[[ -e Makefile ]] && make -s distclean
|
||||||
./configure --host=i686-apple --disable-shared --prefix="$prefix_i386"
|
./configure --host=i686-apple --disable-shared --enable-minimal --prefix="$prefix_i386"
|
||||||
make -j3 install
|
make -j3 install
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
## ARCH: x86_64
|
## ARCH: x86_64
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
[[ -e Makefile ]] && make -s distclean
|
[[ -e Makefile ]] && make -s distclean
|
||||||
./configure --host=x86_64-apple --disable-shared --prefix="$prefix_x86_64"
|
./configure --host=x86_64-apple --disable-shared --enable-minimal --prefix="$prefix_x86_64"
|
||||||
make -j3 install
|
make -j3 install
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
## ARCH: armv7
|
## ARCH: armv7
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||||
export CFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
export CFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||||
export LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
export LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
[[ -e Makefile ]] && make -s distclean
|
[[ -e Makefile ]] && make -s distclean
|
||||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7"
|
./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_armv7"
|
||||||
make -j3 install
|
make -j3 install
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
## ARCH: armv7s
|
## ARCH: armv7s
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||||
export CFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
export CFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||||
export LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
export LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
[[ -e Makefile ]] && make -s distclean
|
[[ -e Makefile ]] && make -s distclean
|
||||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7s"
|
./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_armv7s"
|
||||||
make -j3 install
|
make -j3 install
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
## ARCH: arm64
|
## ARCH: arm64
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||||
export CFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
export CFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||||
export LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
export LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
[[ -e Makefile ]] && make -s distclean
|
[[ -e Makefile ]] && make -s distclean
|
||||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_arm64"
|
./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_arm64"
|
||||||
make -j3 install
|
make -j3 install
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,30 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
hash automake || { echo >&2 "Missing automake."; exit 1; }
|
||||||
|
hash autoreconf || { echo >&2 "Missing autoconf."; exit 1; }
|
||||||
|
hash libtool || hash glibtool || { echo >&2 "Missing libtool."; exit 1; }
|
||||||
|
|
||||||
cd "${BASH_SOURCE%/*}/../External/libsodium"
|
cd "${BASH_SOURCE%/*}/../External/libsodium"
|
||||||
|
[[ $1 = clean ]] && { [[ ! -e Makefile ]] || make -s distclean; exit; }
|
||||||
[[ -e "${prefix=$PWD/libsodium-osx}/lib/libsodium.a" ]] && exit
|
[[ -e "${prefix=$PWD/libsodium-osx}/lib/libsodium.a" ]] && exit
|
||||||
|
|
||||||
# Inspired by libsodium/dist-build/osx.sh
|
# Inspired by libsodium/dist-build/osx.sh
|
||||||
# Prepare
|
# Prepare
|
||||||
autoreconf --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
|
autoreconf --verbose --install --symlink 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
|
||||||
rm -rf "${prefix=$PWD/libsodium-osx}"
|
rm -rf "${prefix=$PWD/libsodium-osx}"
|
||||||
mkdir -p "$prefix"
|
mkdir -p "$prefix"
|
||||||
|
|
||||||
# Targets
|
# Targets
|
||||||
(
|
(
|
||||||
## ARCH: x86_64
|
## ARCH: x86_64
|
||||||
export SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
|
SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
|
||||||
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
|
PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
|
||||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -O2 -g -flto $CFLAGS"
|
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -O2 -g -flto $CFLAGS"
|
||||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -flto $LDFLAGS"
|
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -flto $LDFLAGS"
|
||||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||||
[[ -e Makefile ]] && make -s distclean
|
[[ -e Makefile ]] && make -s distclean
|
||||||
./configure --disable-shared --prefix="$prefix"
|
./configure --disable-shared --enable-minimal --prefix="$prefix"
|
||||||
make -j3 check
|
make -j3 check
|
||||||
make -j3 install
|
make -j3 install
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
+ (BOOL)managedObjectContextForMainThreadPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *mainContext))mocBlock;
|
+ (BOOL)managedObjectContextForMainThreadPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *mainContext))mocBlock;
|
||||||
+ (BOOL)managedObjectContextPerformBlock:(void ( ^ )(NSManagedObjectContext *context))mocBlock;
|
+ (BOOL)managedObjectContextPerformBlock:(void ( ^ )(NSManagedObjectContext *context))mocBlock;
|
||||||
+ (BOOL)managedObjectContextPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *context))mocBlock;
|
+ (BOOL)managedObjectContextPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *context))mocBlock;
|
||||||
+ (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock;
|
- (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock;
|
||||||
|
|
||||||
- (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context;
|
- (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context;
|
||||||
- (void)deleteAndResetStore;
|
- (void)deleteAndResetStore;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#import "MPAppDelegate_Store.h"
|
#import "MPAppDelegate_Store.h"
|
||||||
#import "mpw-marshall.h"
|
#import "mpw-marshal.h"
|
||||||
#import "mpw-util.h"
|
#import "mpw-util.h"
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
@@ -133,12 +133,11 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock {
|
- (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock {
|
||||||
|
|
||||||
NSManagedObjectContext *privateManagedObjectContextIfReady = [[self get] privateManagedObjectContextIfReady];
|
NSManagedObjectContext *privateManagedObjectContextIfReady = [self privateManagedObjectContextIfReady];
|
||||||
if (!privateManagedObjectContextIfReady)
|
if (!privateManagedObjectContextIfReady)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
return PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, privateManagedObjectContextIfReady, nil,
|
return PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, privateManagedObjectContextIfReady, nil,
|
||||||
^(id host, NSNotification *note) {
|
^(id host, NSNotification *note) {
|
||||||
NSMutableDictionary *affectedObjects = [NSMutableDictionary new];
|
NSMutableDictionary *affectedObjects = [NSMutableDictionary new];
|
||||||
@@ -217,7 +216,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
|
|
||||||
self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
||||||
self.mainManagedObjectContext.parentContext = self.privateManagedObjectContext;
|
self.mainManagedObjectContext.parentContext = self.privateManagedObjectContext;
|
||||||
if ([self.mainManagedObjectContext respondsToSelector:@selector( automaticallyMergesChangesFromParent )]) // iOS 10+
|
if (@available(iOS 10.0, macOS 10.12, *))
|
||||||
self.mainManagedObjectContext.automaticallyMergesChangesFromParent = YES;
|
self.mainManagedObjectContext.automaticallyMergesChangesFromParent = YES;
|
||||||
else
|
else
|
||||||
// When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
|
// When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
|
||||||
@@ -566,10 +565,10 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
saveInContext:(NSManagedObjectContext *)context {
|
saveInContext:(NSManagedObjectContext *)context {
|
||||||
|
|
||||||
// Read metadata for the import file.
|
// Read metadata for the import file.
|
||||||
MPMarshallInfo *info = mpw_marshall_read_info( importData.UTF8String );
|
MPMarshalInfo *info = mpw_marshal_read_info( importData.UTF8String );
|
||||||
if (info->format == MPMarshallFormatNone)
|
if (info->format == MPMarshalFormatNone)
|
||||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{
|
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||||
@"type" : @(MPMarshallErrorFormat),
|
@"type" : @(MPMarshalErrorFormat),
|
||||||
NSLocalizedDescriptionKey: @"This is not a Master Password import file.",
|
NSLocalizedDescriptionKey: @"This is not a Master Password import file.",
|
||||||
}]), @"While importing sites." );
|
}]), @"While importing sites." );
|
||||||
|
|
||||||
@@ -589,13 +588,13 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
caseInsensitiveCompare:@(info->keyID)] != NSOrderedSame);
|
caseInsensitiveCompare:@(info->keyID)] != NSOrderedSame);
|
||||||
|
|
||||||
// Parse import data.
|
// Parse import data.
|
||||||
MPMarshallError importError = { .type = MPMarshallSuccess };
|
MPMarshalError importError = { .type = MPMarshalSuccess };
|
||||||
MPMarshalledUser *importUser = mpw_marshall_read( importData.UTF8String, info->format, importMasterPassword.UTF8String, &importError );
|
MPMarshalledUser *importUser = mpw_marshal_read( importData.UTF8String, info->format, importMasterPassword.UTF8String, &importError );
|
||||||
mpw_marshal_info_free( &info );
|
mpw_marshal_info_free( &info );
|
||||||
|
|
||||||
@try {
|
@try {
|
||||||
if (!importUser || importError.type != MPMarshallSuccess)
|
if (!importUser || importError.type != MPMarshalSuccess)
|
||||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{
|
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||||
@"type" : @(importError.type),
|
@"type" : @(importError.type),
|
||||||
NSLocalizedDescriptionKey: @(importError.description),
|
NSLocalizedDescriptionKey: @(importError.description),
|
||||||
}]), @"While importing sites." );
|
}]), @"While importing sites." );
|
||||||
@@ -707,7 +706,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
NSString *masterPassword = askImportPassword( user.name );
|
NSString *masterPassword = askImportPassword( user.name );
|
||||||
|
|
||||||
inf( @"Exporting sites, %@, for user: %@", revealPasswords? @"revealing passwords": @"omitting passwords", user.userID );
|
inf( @"Exporting sites, %@, for user: %@", revealPasswords? @"revealing passwords": @"omitting passwords", user.userID );
|
||||||
MPMarshalledUser *exportUser = mpw_marshall_user( user.name.UTF8String, masterPassword.UTF8String, user.algorithm.version );
|
MPMarshalledUser *exportUser = mpw_marshal_user( user.name.UTF8String, masterPassword.UTF8String, user.algorithm.version );
|
||||||
exportUser->redacted = !revealPasswords;
|
exportUser->redacted = !revealPasswords;
|
||||||
exportUser->avatar = (unsigned int)user.avatar;
|
exportUser->avatar = (unsigned int)user.avatar;
|
||||||
exportUser->defaultType = user.defaultType;
|
exportUser->defaultType = user.defaultType;
|
||||||
@@ -721,7 +720,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
? [site.algorithm exportPasswordForSite:site usingKey:self.key]
|
? [site.algorithm exportPasswordForSite:site usingKey:self.key]
|
||||||
: [site.algorithm resolvePasswordForSite:site usingKey:self.key];
|
: [site.algorithm resolvePasswordForSite:site usingKey:self.key];
|
||||||
|
|
||||||
MPMarshalledSite *exportSite = mpw_marshall_site( exportUser,
|
MPMarshalledSite *exportSite = mpw_marshal_site( exportUser,
|
||||||
site.name.UTF8String, site.type, counter, site.algorithm.version );
|
site.name.UTF8String, site.type, counter, site.algorithm.version );
|
||||||
exportSite->content = content.UTF8String;
|
exportSite->content = content.UTF8String;
|
||||||
exportSite->loginContent = site.loginName.UTF8String;
|
exportSite->loginContent = site.loginName.UTF8String;
|
||||||
@@ -735,15 +734,15 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *export = NULL;
|
char *export = NULL;
|
||||||
MPMarshallError exportError = (MPMarshallError){ .type= MPMarshallSuccess };
|
MPMarshalError exportError = (MPMarshalError){ .type= MPMarshalSuccess };
|
||||||
mpw_marshall_write( &export, MPMarshallFormatFlat, exportUser, &exportError );
|
mpw_marshal_write( &export, MPMarshalFormatFlat, exportUser, &exportError );
|
||||||
NSString *mpsites = nil;
|
NSString *mpsites = nil;
|
||||||
if (export && exportError.type == MPMarshallSuccess)
|
if (export && exportError.type == MPMarshalSuccess)
|
||||||
mpsites = [NSString stringWithCString:export encoding:NSUTF8StringEncoding];
|
mpsites = [NSString stringWithCString:export encoding:NSUTF8StringEncoding];
|
||||||
mpw_free_string( &export );
|
mpw_free_string( &export );
|
||||||
|
|
||||||
resultBlock( mpsites, exportError.type == MPMarshallSuccess? nil:
|
resultBlock( mpsites, exportError.type == MPMarshalSuccess? nil:
|
||||||
[NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{
|
[NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||||
@"type" : @(exportError.type),
|
@"type" : @(exportError.type),
|
||||||
NSLocalizedDescriptionKey: @(exportError.description),
|
NSLocalizedDescriptionKey: @(exportError.description),
|
||||||
}] );
|
}] );
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
extern NSString *const MPErrorDomain;
|
extern NSString *const MPErrorDomain;
|
||||||
extern NSInteger const MPErrorHangCode;
|
extern NSInteger const MPErrorHangCode;
|
||||||
extern NSInteger const MPErrorMarshallCode;
|
extern NSInteger const MPErrorMarshalCode;
|
||||||
|
|
||||||
extern NSString *const MPSignedInNotification;
|
extern NSString *const MPSignedInNotification;
|
||||||
extern NSString *const MPSignedOutNotification;
|
extern NSString *const MPSignedOutNotification;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
NSString *const MPErrorDomain = @"MPErrorDomain";
|
NSString *const MPErrorDomain = @"MPErrorDomain";
|
||||||
NSInteger const MPErrorHangCode = 1;
|
NSInteger const MPErrorHangCode = 1;
|
||||||
NSInteger const MPErrorMarshallCode = 1;
|
NSInteger const MPErrorMarshalCode = 1;
|
||||||
|
|
||||||
NSString *const MPSignedInNotification = @"MPSignedInNotification";
|
NSString *const MPSignedInNotification = @"MPSignedInNotification";
|
||||||
NSString *const MPSignedOutNotification = @"MPSignedOutNotification";
|
NSString *const MPSignedOutNotification = @"MPSignedOutNotification";
|
||||||
|
|||||||
@@ -166,41 +166,66 @@
|
|||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||||
COPY_PHASE_STRIP = YES;
|
COPY_PHASE_STRIP = YES;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||||
|
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
|
||||||
|
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES;
|
||||||
|
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
|
||||||
|
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||||
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
||||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||||
|
GCC_WARN_MISSING_PARENTHESES = YES;
|
||||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
||||||
GCC_WARN_SIGN_COMPARE = YES;
|
GCC_WARN_SIGN_COMPARE = NO;
|
||||||
|
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
|
GCC_WARN_UNUSED_VALUE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||||
PRODUCT_NAME = "${TARGET_NAME}";
|
PRODUCT_NAME = "${TARGET_NAME}";
|
||||||
@@ -231,17 +256,31 @@
|
|||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
@@ -259,20 +298,30 @@
|
|||||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||||
|
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
|
||||||
|
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES;
|
||||||
|
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
|
||||||
|
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||||
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
||||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||||
|
GCC_WARN_MISSING_PARENTHESES = YES;
|
||||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
||||||
GCC_WARN_SIGN_COMPARE = YES;
|
GCC_WARN_SIGN_COMPARE = NO;
|
||||||
|
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
GCC_WARN_UNINITIALIZED_AUTOS = NO;
|
||||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
|
GCC_WARN_UNUSED_VALUE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
@@ -292,41 +341,66 @@
|
|||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||||
COPY_PHASE_STRIP = YES;
|
COPY_PHASE_STRIP = YES;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||||
|
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
|
||||||
|
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES;
|
||||||
|
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
|
||||||
|
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||||
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
||||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||||
|
GCC_WARN_MISSING_PARENTHESES = YES;
|
||||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
||||||
GCC_WARN_SIGN_COMPARE = YES;
|
GCC_WARN_SIGN_COMPARE = NO;
|
||||||
|
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
|
GCC_WARN_UNUSED_VALUE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||||
PRODUCT_NAME = "${TARGET_NAME}";
|
PRODUCT_NAME = "${TARGET_NAME}";
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
#import <objc/NSObjCRuntime.h>
|
#import <objc/NSObjCRuntime.h>
|
||||||
#import <stdlib.h>
|
#import <stdlib.h>
|
||||||
|
|
||||||
#define log(level, format, ...) \
|
#define mpw_log(level, format, ...) \
|
||||||
do { \
|
do { \
|
||||||
void (*_sendMsg)(id, SEL, CFStringRef, NSInteger, CFStringRef, NSUInteger, CFStringRef) = (void *)objc_msgSend; \
|
void (*_sendMsg)(id, SEL, CFStringRef, NSInteger, CFStringRef, NSUInteger, CFStringRef) = (void *)objc_msgSend; \
|
||||||
char *_msg = NULL; \
|
char *_msg = NULL; \
|
||||||
@@ -64,11 +64,11 @@
|
|||||||
CFRelease( msgStr ); \
|
CFRelease( msgStr ); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define trc(format, ...) log( 0, format, ##__VA_ARGS__ );
|
#define trc(format, ...) mpw_log( 0, format, ##__VA_ARGS__ );
|
||||||
#define dbg(format, ...) log( 1, format, ##__VA_ARGS__ );
|
#define dbg(format, ...) mpw_log( 1, format, ##__VA_ARGS__ );
|
||||||
#define inf(format, ...) log( 2, format, ##__VA_ARGS__ );
|
#define inf(format, ...) mpw_log( 2, format, ##__VA_ARGS__ );
|
||||||
#define wrn(format, ...) log( 3, format, ##__VA_ARGS__ );
|
#define wrn(format, ...) mpw_log( 3, format, ##__VA_ARGS__ );
|
||||||
#define err(format, ...) log( 4, format, ##__VA_ARGS__ );
|
#define err(format, ...) mpw_log( 4, format, ##__VA_ARGS__ );
|
||||||
#define ftl(format, ...) log( 5, format, ##__VA_ARGS__ );
|
#define ftl(format, ...) mpw_log( 5, format, ##__VA_ARGS__ );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// Prefix header for all source files of the 'Pearl' target in the 'Pearl' project
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifdef __OBJC__
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#define PEARL_WITH_MESSAGEUI
|
|
||||||
|
|
||||||
#define PEARL
|
|
||||||
#define PEARL_CRYPTO
|
|
||||||
#if TARGET_OS_IOS
|
|
||||||
#define PEARL_UIKIT
|
|
||||||
#elif TARGET_OS_OSX
|
|
||||||
#define PEARL_COCOA
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#import "Pearl.h"
|
|
||||||
#import "Pearl-Crypto.h"
|
|
||||||
#if TARGET_OS_IOS
|
|
||||||
#import "Pearl-UIKit.h"
|
|
||||||
#elif TARGET_OS_OSX
|
|
||||||
#import "Pearl-Cocoa.h"
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@@ -225,7 +225,7 @@
|
|||||||
- (void)copyAnswer:(NSString *)answer {
|
- (void)copyAnswer:(NSString *)answer {
|
||||||
|
|
||||||
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
||||||
if ([pasteboard respondsToSelector:@selector( setItems:options: )]) {
|
if (@available(iOS 10.0, *)) {
|
||||||
[pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: answer } ]
|
[pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: answer } ]
|
||||||
options:@{
|
options:@{
|
||||||
UIPasteboardOptionLocalOnly : @NO,
|
UIPasteboardOptionLocalOnly : @NO,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user