2
0

Removed iCloud + added generated login names.

[REMOVED]   UbiquityStoreManager and iCloud support.  Now using simplified local Core Data store logic.
[ADDED]     Generating site login names.
[IMPROVED]  Some refactoring and interface improvements for optionally generated user names.
This commit is contained in:
Maarten Billemont 2014-09-15 01:00:23 -04:00
parent 9109a59410
commit 88fdc89f27
39 changed files with 684 additions and 988 deletions

View File

@ -38,15 +38,20 @@ void usage() {
fprintf(stderr, " -u name Specify the full name of the user.\n" fprintf(stderr, " -u name Specify the full name of the user.\n"
" Defaults to %s in env.\n\n", MP_env_username); " Defaults to %s in env.\n\n", MP_env_username);
fprintf(stderr, " -t type Specify the password's template.\n" fprintf(stderr, " -t type Specify the password's template.\n"
" Defaults to %s in env or 'long'.\n" " Defaults to %s in env or 'long' for password, 'name' for login.\n"
" x, max, maximum | 20 characters, contains symbols.\n" " x, max, maximum | 20 characters, contains symbols.\n"
" l, long | Copy-friendly, 14 characters, contains symbols.\n" " l, long | Copy-friendly, 14 characters, contains symbols.\n"
" m, med, medium | Copy-friendly, 8 characters, contains symbols.\n" " m, med, medium | Copy-friendly, 8 characters, contains symbols.\n"
" b, basic | 8 characters, no symbols.\n" " b, basic | 8 characters, no symbols.\n"
" s, short | Copy-friendly, 4 characters, no symbols.\n" " s, short | Copy-friendly, 4 characters, no symbols.\n"
" p, pin | 4 numbers.\n\n", MP_env_sitetype); " p, pin | 4 numbers.\n"
" n, name | 9 letter name.\n\n", MP_env_sitetype);
fprintf(stderr, " -c counter The value of the counter.\n" fprintf(stderr, " -c counter The value of the counter.\n"
" Defaults to %s in env or '1'.\n\n", MP_env_sitecounter); " Defaults to %s in env or '1'.\n\n", MP_env_sitecounter);
fprintf(stderr, " -v variant The kind of content to generate.\n"
" Defaults to 'password'.\n"
" p, password | The password to log in with.\n"
" l, login | The username to log in as.\n\n");
exit(0); exit(0);
} }
@ -86,12 +91,14 @@ int main(int argc, char *const argv[]) {
const char *siteName = NULL; const char *siteName = NULL;
MPElementType siteType = MPElementTypeGeneratedLong; MPElementType siteType = MPElementTypeGeneratedLong;
const char *siteTypeString = getenv( MP_env_sitetype ); const char *siteTypeString = getenv( MP_env_sitetype );
MPElementVariant siteVariant = MPElementVariantPassword;
const char *siteVariantString = NULL;
uint32_t siteCounter = 1; uint32_t siteCounter = 1;
const char *siteCounterString = getenv( MP_env_sitecounter ); const char *siteCounterString = getenv( MP_env_sitecounter );
// Read the options. // Read the options.
char opt; char opt;
while ((opt = getopt(argc, argv, "u:t:c:h")) != -1) while ((opt = getopt(argc, argv, "u:t:c:v:h")) != -1)
switch (opt) { switch (opt) {
case 'h': case 'h':
usage(); usage();
@ -102,6 +109,9 @@ int main(int argc, char *const argv[]) {
case 't': case 't':
siteTypeString = optarg; siteTypeString = optarg;
break; break;
case 'v':
siteVariantString = optarg;
break;
case 'c': case 'c':
siteCounterString = optarg; siteCounterString = optarg;
break; break;
@ -144,6 +154,11 @@ int main(int argc, char *const argv[]) {
return 1; return 1;
} }
trc("siteCounter: %d\n", siteCounter); trc("siteCounter: %d\n", siteCounter);
if (siteVariantString)
siteVariant = VariantWithName( siteVariantString );
trc("siteVariant: %d (%s)\n", siteVariant, siteVariantString);
if (siteVariant == MPElementVariantLogin)
siteType = MPElementTypeGeneratedName;
if (siteTypeString) if (siteTypeString)
siteType = TypeWithName( siteTypeString ); siteType = TypeWithName( siteTypeString );
trc("siteType: %d (%s)\n", siteType, siteTypeString); trc("siteType: %d (%s)\n", siteType, siteTypeString);
@ -176,9 +191,10 @@ int main(int argc, char *const argv[]) {
trc("masterPassword: %s\n", masterPassword); trc("masterPassword: %s\n", masterPassword);
// Calculate the master key salt. // Calculate the master key salt.
char *mpNameSpace = "com.lyndir.masterpassword"; const char *mpKeyScope = ScopeForVariant(MPElementVariantPassword);
trc("key scope: %s\n", mpKeyScope);
const uint32_t n_userNameLength = htonl(strlen(userName)); const uint32_t n_userNameLength = htonl(strlen(userName));
size_t masterKeySaltLength = strlen(mpNameSpace) + sizeof(n_userNameLength) + strlen(userName); size_t masterKeySaltLength = strlen(mpKeyScope) + sizeof(n_userNameLength) + strlen(userName);
char *masterKeySalt = malloc( masterKeySaltLength ); char *masterKeySalt = malloc( masterKeySaltLength );
if (!masterKeySalt) { if (!masterKeySalt) {
fprintf(stderr, "Could not allocate master key salt: %d\n", errno); fprintf(stderr, "Could not allocate master key salt: %d\n", errno);
@ -186,7 +202,7 @@ int main(int argc, char *const argv[]) {
} }
char *mKS = masterKeySalt; char *mKS = masterKeySalt;
memcpy(mKS, mpNameSpace, strlen(mpNameSpace)); mKS += strlen(mpNameSpace); memcpy(mKS, mpKeyScope, strlen(mpKeyScope)); mKS += strlen(mpKeyScope);
memcpy(mKS, &n_userNameLength, sizeof(n_userNameLength)); mKS += sizeof(n_userNameLength); memcpy(mKS, &n_userNameLength, sizeof(n_userNameLength)); mKS += sizeof(n_userNameLength);
memcpy(mKS, userName, strlen(userName)); mKS += strlen(userName); memcpy(mKS, userName, strlen(userName)); mKS += strlen(userName);
if (mKS - masterKeySalt != masterKeySaltLength) if (mKS - masterKeySalt != masterKeySaltLength)
@ -210,9 +226,11 @@ int main(int argc, char *const argv[]) {
trc("masterKey ID: %s\n", IDForBuf(masterKey, MP_dkLen)); trc("masterKey ID: %s\n", IDForBuf(masterKey, MP_dkLen));
// Calculate the site seed. // Calculate the site seed.
const char *mpSiteScope = ScopeForVariant(siteVariant);
trc("site scope: %s\n", mpSiteScope);
const uint32_t n_siteNameLength = htonl(strlen(siteName)); const uint32_t n_siteNameLength = htonl(strlen(siteName));
const uint32_t n_siteCounter = htonl(siteCounter); const uint32_t n_siteCounter = htonl(siteCounter);
size_t sitePasswordInfoLength = strlen(mpNameSpace) + sizeof(n_siteNameLength) + strlen(siteName) + sizeof(n_siteCounter); size_t sitePasswordInfoLength = strlen(mpSiteScope) + sizeof(n_siteNameLength) + strlen(siteName) + sizeof(n_siteCounter);
char *sitePasswordInfo = malloc( sitePasswordInfoLength ); char *sitePasswordInfo = malloc( sitePasswordInfoLength );
if (!sitePasswordInfo) { if (!sitePasswordInfo) {
fprintf(stderr, "Could not allocate site seed: %d\n", errno); fprintf(stderr, "Could not allocate site seed: %d\n", errno);
@ -220,13 +238,13 @@ int main(int argc, char *const argv[]) {
} }
char *sPI = sitePasswordInfo; char *sPI = sitePasswordInfo;
memcpy(sPI, mpNameSpace, strlen(mpNameSpace)); sPI += strlen(mpNameSpace); memcpy(sPI, mpSiteScope, strlen(mpSiteScope)); sPI += strlen(mpSiteScope);
memcpy(sPI, &n_siteNameLength, sizeof(n_siteNameLength)); sPI += sizeof(n_siteNameLength); memcpy(sPI, &n_siteNameLength, sizeof(n_siteNameLength)); sPI += sizeof(n_siteNameLength);
memcpy(sPI, siteName, strlen(siteName)); sPI += strlen(siteName); memcpy(sPI, siteName, strlen(siteName)); sPI += strlen(siteName);
memcpy(sPI, &n_siteCounter, sizeof(n_siteCounter)); sPI += sizeof(n_siteCounter); memcpy(sPI, &n_siteCounter, sizeof(n_siteCounter)); sPI += sizeof(n_siteCounter);
if (sPI - sitePasswordInfo != sitePasswordInfoLength) if (sPI - sitePasswordInfo != sitePasswordInfoLength)
abort(); abort();
trc("seed from: hmac-sha256(masterKey, 'com.lyndir.masterpassword' | %s | %s | %s)\n", Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter))); trc("seed from: hmac-sha256(masterKey, %s | %s | %s | %s)\n", mpSiteScope, Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter)));
trc("sitePasswordInfo ID: %s\n", IDForBuf(sitePasswordInfo, sitePasswordInfoLength)); trc("sitePasswordInfo ID: %s\n", IDForBuf(sitePasswordInfo, sitePasswordInfoLength));
uint8_t sitePasswordSeed[32]; uint8_t sitePasswordSeed[32];

View File

@ -33,6 +33,8 @@ const MPElementType TypeWithName(const char *typeName) {
return MPElementTypeGeneratedShort; return MPElementTypeGeneratedShort;
if (0 == strcmp(lowerTypeName, "p") || 0 == strcmp(lowerTypeName, "pin")) if (0 == strcmp(lowerTypeName, "p") || 0 == strcmp(lowerTypeName, "pin"))
return MPElementTypeGeneratedPIN; return MPElementTypeGeneratedPIN;
if (0 == strcmp(lowerTypeName, "n") || 0 == strcmp(lowerTypeName, "name"))
return MPElementTypeGeneratedName;
fprintf(stderr, "Not a generated type name: %s", lowerTypeName); fprintf(stderr, "Not a generated type name: %s", lowerTypeName);
abort(); abort();
@ -67,6 +69,9 @@ const char *CipherForType(MPElementType type, uint8_t seedByte) {
case MPElementTypeGeneratedPIN: { case MPElementTypeGeneratedPIN: {
return "nnnn"; return "nnnn";
} }
case MPElementTypeGeneratedName: {
return "cvccvcvcv";
}
default: { default: {
fprintf(stderr, "Unknown generated type: %d", type); fprintf(stderr, "Unknown generated type: %d", type);
abort(); abort();
@ -74,6 +79,36 @@ const char *CipherForType(MPElementType type, uint8_t seedByte) {
} }
} }
const MPElementVariant VariantWithName(const char *variantName) {
char lowerVariantName[strlen(variantName)];
strcpy(lowerVariantName, variantName);
for (char *vN = lowerVariantName; *vN; ++vN)
*vN = tolower(*vN);
if (0 == strcmp(lowerVariantName, "p") || 0 == strcmp(lowerVariantName, "password"))
return MPElementVariantPassword;
if (0 == strcmp(lowerVariantName, "l") || 0 == strcmp(lowerVariantName, "login"))
return MPElementVariantLogin;
fprintf(stderr, "Not a variant name: %s", lowerVariantName);
abort();
}
const char *ScopeForVariant(MPElementVariant variant) {
switch (variant) {
case MPElementVariantPassword: {
return "com.lyndir.masterpassword";
}
case MPElementVariantLogin: {
return "com.lyndir.masterpassword.login";
}
default: {
fprintf(stderr, "Unknown variant: %d", variant);
abort();
}
}
}
const char CharacterFromClass(char characterClass, uint8_t seedByte) { const char CharacterFromClass(char characterClass, uint8_t seedByte) {
const char *classCharacters; const char *classCharacters;
switch (characterClass) { switch (characterClass) {

View File

@ -7,10 +7,11 @@
// //
typedef enum { typedef enum {
MPElementContentTypePassword, /** Generate the password to log in with. */
MPElementContentTypeNote, MPElementVariantPassword,
MPElementContentTypePicture, /** Generate the login name to log in as. */
} MPElementContentType; MPElementVariantLogin,
} MPElementVariant;
typedef enum { typedef enum {
/** Generate the password. */ /** Generate the password. */
@ -33,6 +34,7 @@ typedef enum {
MPElementTypeGeneratedBasic = 0x4 | MPElementTypeClassGenerated | 0x0, MPElementTypeGeneratedBasic = 0x4 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedShort = 0x3 | MPElementTypeClassGenerated | 0x0, MPElementTypeGeneratedShort = 0x3 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedPIN = 0x5 | MPElementTypeClassGenerated | 0x0, MPElementTypeGeneratedPIN = 0x5 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedName = 0xF | MPElementTypeClassGenerated | 0x0,
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent, MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate, MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
@ -44,6 +46,8 @@ typedef enum {
#define trc(...) do {} while (0) #define trc(...) do {} while (0)
#endif #endif
const MPElementVariant VariantWithName(const char *variantName);
const char *ScopeForVariant(MPElementVariant variant);
const MPElementType TypeWithName(const char *typeName); const MPElementType TypeWithName(const char *typeName);
const char *CipherForType(MPElementType type, uint8_t seedByte); const char *CipherForType(MPElementType type, uint8_t seedByte);
const char CharacterFromClass(char characterClass, uint8_t seedByte); const char CharacterFromClass(char characterClass, uint8_t seedByte);

View File

@ -1,12 +1,12 @@
/** /**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
* *
* See the enclosed file LICENSE for license information (LGPLv3). If you did * See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
* *
* @author Maarten Billemont <lhunath@lyndir.com> * @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt * @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/ */
// //
// MPAlgorithm // MPAlgorithm
@ -50,6 +50,7 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack);
- (MPKey *)keyFromKeyData:(NSData *)keyData; - (MPKey *)keyFromKeyData:(NSData *)keyData;
- (NSData *)keyIDForKeyData:(NSData *)keyData; - (NSData *)keyIDForKeyData:(NSData *)keyData;
- (NSString *)scopeForVariant:(MPElementVariant)variant;
- (NSString *)nameOfType:(MPElementType)type; - (NSString *)nameOfType:(MPElementType)type;
- (NSString *)shortNameOfType:(MPElementType)type; - (NSString *)shortNameOfType:(MPElementType)type;
- (NSString *)classNameOfType:(MPElementType)type; - (NSString *)classNameOfType:(MPElementType)type;
@ -59,19 +60,30 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack);
- (MPElementType)nextType:(MPElementType)type; - (MPElementType)nextType:(MPElementType)type;
- (MPElementType)previousType:(MPElementType)type; - (MPElementType)previousType:(MPElementType)type;
- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key; - (NSString *)generateLoginForSiteNamed:(NSString *)name usingKey:(MPKey *)key;
- (NSString *)storedContentForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key; - (NSString *)generatePasswordForSiteNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter
usingKey:(MPKey *)key;
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter
variant:(MPElementVariant)variant usingKey:(MPKey *)key;
- (BOOL)saveContent:(NSString *)clearContent toElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey; - (NSString *)storedLoginForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key;
- (NSString *)resolveContentForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey; - (NSString *)storedPasswordForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key;
- (void)resolveContentForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey
result:(void (^)(NSString *result))resultBlock;
- (void)importProtectedContent:(NSString *)protectedContent protectedByKey:(MPKey *)importKey - (BOOL)savePassword:(NSString *)clearPassword toElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey;
- (NSString *)resolveLoginForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey;
- (NSString *)resolvePasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey;
- (void)resolveLoginForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey
result:(void ( ^ )(NSString *result))resultBlock;
- (void)resolvePasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey
result:(void ( ^ )(NSString *result))resultBlock;
- (void)importProtectedPassword:(NSString *)protectedPassword protectedByKey:(MPKey *)importKey
intoElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey; intoElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey;
- (void)importClearTextContent:(NSString *)clearContent intoElement:(MPElementEntity *)element - (void)importClearTextPassword:(NSString *)clearPassword intoElement:(MPElementEntity *)element
usingKey:(MPKey *)elementKey; usingKey:(MPKey *)elementKey;
- (NSString *)exportContentForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey; - (NSString *)exportPasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey;
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPElementType)type byAttacker:(MPAttacker)attacker; - (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPElementType)type byAttacker:(MPAttacker)attacker;
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordString:(NSString *)password byAttacker:(MPAttacker)attacker; - (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordString:(NSString *)password byAttacker:(MPAttacker)attacker;

View File

@ -136,6 +136,18 @@
return [keyData hashWith:MP_hash]; return [keyData hashWith:MP_hash];
} }
- (NSString *)scopeForVariant:(MPElementVariant)variant {
switch (variant) {
case MPElementVariantPassword:
return @"com.lyndir.masterpassword";
case MPElementVariantLogin:
return @"com.lyndir.masterpassword.login";
}
Throw( @"Unsupported variant: %ld", (long)variant );
}
- (NSString *)nameOfType:(MPElementType)type { - (NSString *)nameOfType:(MPElementType)type {
if (!type) if (!type)
@ -160,6 +172,9 @@
case MPElementTypeGeneratedPIN: case MPElementTypeGeneratedPIN:
return @"PIN"; return @"PIN";
case MPElementTypeGeneratedName:
return @"Login Name";
case MPElementTypeStoredPersonal: case MPElementTypeStoredPersonal:
return @"Personal Password"; return @"Personal Password";
@ -194,6 +209,9 @@
case MPElementTypeGeneratedPIN: case MPElementTypeGeneratedPIN:
return @"PIN"; return @"PIN";
case MPElementTypeGeneratedName:
return @"Name";
case MPElementTypeStoredPersonal: case MPElementTypeStoredPersonal:
return @"Personal"; return @"Personal";
@ -233,6 +251,9 @@
case MPElementTypeGeneratedPIN: case MPElementTypeGeneratedPIN:
return [MPElementGeneratedEntity class]; return [MPElementGeneratedEntity class];
case MPElementTypeGeneratedName:
return [MPElementGeneratedEntity class];
case MPElementTypeStoredPersonal: case MPElementTypeStoredPersonal:
return [MPElementStoredEntity class]; return [MPElementStoredEntity class];
@ -326,18 +347,35 @@
return [NSNullToNil( [NSNullToNil( [[self allCiphers] valueForKey:@"MPCharacterClasses"] ) valueForKey:cipherClass] ) copy]; return [NSNullToNil( [NSNullToNil( [[self allCiphers] valueForKey:@"MPCharacterClasses"] ) valueForKey:cipherClass] ) copy];
} }
- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key { - (NSString *)generateLoginForSiteNamed:(NSString *)name usingKey:(MPKey *)key {
return [self generateContentForSiteNamed:name ofType:MPElementTypeGeneratedName withCounter:1
variant:MPElementVariantLogin usingKey:key];
}
- (NSString *)generatePasswordForSiteNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter
usingKey:(MPKey *)key {
return [self generateContentForSiteNamed:name ofType:type withCounter:counter
variant:MPElementVariantPassword usingKey:key];
}
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter
variant:(MPElementVariant)variant usingKey:(MPKey *)key {
// Determine the seed whose bytes will be used for calculating a password // Determine the seed whose bytes will be used for calculating a password
uint32_t ncounter = htonl( counter ), nnameLength = htonl( name.length ); uint32_t ncounter = htonl( counter ), nnameLength = htonl( name.length );
NSData *counterBytes = [NSData dataWithBytes:&ncounter length:sizeof( ncounter )]; NSData *counterBytes = [NSData dataWithBytes:&ncounter length:sizeof( ncounter )];
NSData *nameLengthBytes = [NSData dataWithBytes:&nnameLength length:sizeof( nnameLength )]; NSData *nameLengthBytes = [NSData dataWithBytes:&nnameLength length:sizeof( nnameLength )];
trc( @"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %@ | %@ | %@)", [key.keyData encodeBase64], NSString *scope = [self scopeForVariant:variant];;
[nameLengthBytes encodeHex], name, [counterBytes encodeHex] ); trc( @"seed from: hmac-sha256(%@, %@ | %@ | %@ | %@)",
[key.keyData encodeBase64], scope, [nameLengthBytes encodeHex], name, [counterBytes encodeHex] );
NSData *seed = [[NSData dataByConcatenatingDatas: NSData *seed = [[NSData dataByConcatenatingDatas:
[@"com.lyndir.masterpassword" dataUsingEncoding:NSUTF8StringEncoding], [scope dataUsingEncoding:NSUTF8StringEncoding],
nameLengthBytes, [name dataUsingEncoding:NSUTF8StringEncoding], nameLengthBytes,
counterBytes, nil] [name dataUsingEncoding:NSUTF8StringEncoding],
counterBytes,
nil]
hmacWith:PearlHashSHA256 key:key.keyData]; hmacWith:PearlHashSHA256 key:key.keyData];
trc( @"seed is: %@", [seed encodeBase64] ); trc( @"seed is: %@", [seed encodeBase64] );
const char *seedBytes = seed.bytes; const char *seedBytes = seed.bytes;
@ -364,12 +402,17 @@
return content; return content;
} }
- (NSString *)storedContentForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key { - (NSString *)storedLoginForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key {
return nil;
}
- (NSString *)storedPasswordForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key {
return [self decryptContent:element.contentObject usingKey:key]; return [self decryptContent:element.contentObject usingKey:key];
} }
- (BOOL)saveContent:(NSString *)clearContent toElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey { - (BOOL)savePassword:(NSString *)clearContent toElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." ); NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
switch (element.type) { switch (element.type) {
@ -378,7 +421,8 @@
case MPElementTypeGeneratedMedium: case MPElementTypeGeneratedMedium:
case MPElementTypeGeneratedBasic: case MPElementTypeGeneratedBasic:
case MPElementTypeGeneratedShort: case MPElementTypeGeneratedShort:
case MPElementTypeGeneratedPIN: { case MPElementTypeGeneratedPIN:
case MPElementTypeGeneratedName: {
NSAssert( NO, @"Cannot save content to element with generated type %lu.", (long)element.type ); NSAssert( NO, @"Cannot save content to element with generated type %lu.", (long)element.type );
return NO; return NO;
} }
@ -425,12 +469,12 @@
Throw( @"Unsupported type: %ld", (long)element.type ); Throw( @"Unsupported type: %ld", (long)element.type );
} }
- (NSString *)resolveContentForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey { - (NSString *)resolveLoginForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
dispatch_group_t group = dispatch_group_create(); dispatch_group_t group = dispatch_group_create();
dispatch_group_enter( group ); dispatch_group_enter( group );
__block NSString *result = nil; __block NSString *result = nil;
[self resolveContentForElement:element usingKey:elementKey result:^(NSString *result_) { [self resolveLoginForElement:element usingKey:elementKey result:^(NSString *result_) {
result = result_; result = result_;
dispatch_group_leave( group ); dispatch_group_leave( group );
}]; }];
@ -439,7 +483,43 @@
return result; return result;
} }
- (void)resolveContentForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey result:(void ( ^ )(NSString *result))resultBlock { - (NSString *)resolvePasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter( group );
__block NSString *result = nil;
[self resolvePasswordForElement:element usingKey:elementKey result:^(NSString *result_) {
result = result_;
dispatch_group_leave( group );
}];
dispatch_group_wait( group, DISPATCH_TIME_FOREVER );
return result;
}
- (void)resolveLoginForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey result:(void ( ^ )(NSString *result))resultBlock {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
NSString *name = element.name;
BOOL loginGenerated = element.loginGenerated;
NSString *loginName = loginGenerated? nil: element.loginName;
id<MPAlgorithm> algorithm = nil;
if (!name.length)
err( @"Missing name." );
else if (!elementKey.keyData.length)
err( @"Missing key." );
else
algorithm = element.algorithm;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
if (loginGenerated)
resultBlock( [algorithm generateLoginForSiteNamed:name usingKey:elementKey] );
else
resultBlock( loginName );
} );
}
- (void)resolvePasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey result:(void ( ^ )(NSString *result))resultBlock {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." ); NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
switch (element.type) { switch (element.type) {
@ -448,7 +528,8 @@
case MPElementTypeGeneratedMedium: case MPElementTypeGeneratedMedium:
case MPElementTypeGeneratedBasic: case MPElementTypeGeneratedBasic:
case MPElementTypeGeneratedShort: case MPElementTypeGeneratedShort:
case MPElementTypeGeneratedPIN: { case MPElementTypeGeneratedPIN:
case MPElementTypeGeneratedName: {
if (![element isKindOfClass:[MPElementGeneratedEntity class]]) { if (![element isKindOfClass:[MPElementGeneratedEntity class]]) {
wrn( @"Element with generated type %lu is not an MPElementGeneratedEntity, but a %@.", wrn( @"Element with generated type %lu is not an MPElementGeneratedEntity, but a %@.",
(long)element.type, [element class] ); (long)element.type, [element class] );
@ -467,7 +548,7 @@
algorithm = element.algorithm; algorithm = element.algorithm;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
NSString *result = [algorithm generateContentNamed:name ofType:type withCounter:counter usingKey:elementKey]; NSString *result = [algorithm generatePasswordForSiteNamed:name ofType:type withCounter:counter usingKey:elementKey];
resultBlock( result ); resultBlock( result );
} ); } );
break; break;
@ -505,7 +586,7 @@
} }
} }
- (void)importProtectedContent:(NSString *)protectedContent protectedByKey:(MPKey *)importKey - (void)importProtectedPassword:(NSString *)protectedContent protectedByKey:(MPKey *)importKey
intoElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey { intoElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." ); NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
@ -516,6 +597,7 @@
case MPElementTypeGeneratedBasic: case MPElementTypeGeneratedBasic:
case MPElementTypeGeneratedShort: case MPElementTypeGeneratedShort:
case MPElementTypeGeneratedPIN: case MPElementTypeGeneratedPIN:
case MPElementTypeGeneratedName:
break; break;
case MPElementTypeStoredPersonal: { case MPElementTypeStoredPersonal: {
@ -529,7 +611,7 @@
else { else {
NSString *clearContent = [self decryptContent:[protectedContent decodeBase64] usingKey:importKey]; NSString *clearContent = [self decryptContent:[protectedContent decodeBase64] usingKey:importKey];
[self importClearTextContent:clearContent intoElement:element usingKey:elementKey]; [self importClearTextPassword:clearContent intoElement:element usingKey:elementKey];
} }
break; break;
} }
@ -539,7 +621,7 @@
} }
} }
- (void)importClearTextContent:(NSString *)clearContent intoElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey { - (void)importClearTextPassword:(NSString *)clearContent intoElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." ); NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
switch (element.type) { switch (element.type) {
@ -549,10 +631,11 @@
case MPElementTypeGeneratedBasic: case MPElementTypeGeneratedBasic:
case MPElementTypeGeneratedShort: case MPElementTypeGeneratedShort:
case MPElementTypeGeneratedPIN: case MPElementTypeGeneratedPIN:
case MPElementTypeGeneratedName:
break; break;
case MPElementTypeStoredPersonal: { case MPElementTypeStoredPersonal: {
[self saveContent:clearContent toElement:element usingKey:elementKey]; [self savePassword:clearContent toElement:element usingKey:elementKey];
break; break;
} }
@ -561,7 +644,7 @@
} }
} }
- (NSString *)exportContentForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey { - (NSString *)exportPasswordForElement:(MPElementEntity *)element usingKey:(MPKey *)elementKey {
NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." ); NSAssert( [elementKey.keyID isEqualToData:element.user.keyID], @"Element does not belong to current user." );
if (!(element.type & MPElementFeatureExportContent)) if (!(element.type & MPElementFeatureExportContent))
@ -574,7 +657,8 @@
case MPElementTypeGeneratedMedium: case MPElementTypeGeneratedMedium:
case MPElementTypeGeneratedBasic: case MPElementTypeGeneratedBasic:
case MPElementTypeGeneratedShort: case MPElementTypeGeneratedShort:
case MPElementTypeGeneratedPIN: { case MPElementTypeGeneratedPIN:
case MPElementTypeGeneratedName: {
result = nil; result = nil;
break; break;
} }

View File

@ -45,29 +45,31 @@
return YES; return YES;
} }
- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key { - (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter
variant:(MPElementVariant)variant usingKey:(MPKey *)key {
// Determine the seed whose bytes will be used for calculating a password // Determine the seed whose bytes will be used for calculating a password
uint32_t ncounter = htonl( counter ), nnameLength = htonl( name.length ); uint32_t ncounter = htonl( counter ), nnameLength = htonl( name.length );
NSData *counterBytes = [NSData dataWithBytes:&ncounter length:sizeof( ncounter )]; NSData *counterBytes = [NSData dataWithBytes:&ncounter length:sizeof( ncounter )];
NSData *nameLengthBytes = [NSData dataWithBytes:&nnameLength length:sizeof( nnameLength )]; NSData *nameLengthBytes = [NSData dataWithBytes:&nnameLength length:sizeof( nnameLength )];
trc( @"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %@ | %@ | %@)", [key.keyData encodeBase64], [nameLengthBytes encodeHex], NSString *scope = [self scopeForVariant:variant];
name, [counterBytes encodeHex] ); trc( @"seed from: hmac-sha256(%@, %@ | %@ | %@ | %@)",
[[key keyID] encodeHex], scope, [nameLengthBytes encodeHex], name, [counterBytes encodeHex] );
NSData *seed = [[NSData dataByConcatenatingDatas: NSData *seed = [[NSData dataByConcatenatingDatas:
[@"com.lyndir.masterpassword" dataUsingEncoding:NSUTF8StringEncoding], [scope dataUsingEncoding:NSUTF8StringEncoding],
nameLengthBytes, nameLengthBytes,
[name dataUsingEncoding:NSUTF8StringEncoding], [name dataUsingEncoding:NSUTF8StringEncoding],
counterBytes, counterBytes,
nil] nil]
hmacWith:PearlHashSHA256 key:key.keyData]; hmacWith:PearlHashSHA256 key:key.keyData];
trc( @"seed is: %@", [seed encodeBase64] ); trc( @"seed is: %@", [seed encodeHex] );
const unsigned char *seedBytes = seed.bytes; const unsigned char *seedBytes = seed.bytes;
// Determine the cipher from the first seed byte. // Determine the cipher from the first seed byte.
NSAssert( [seed length], @"Missing seed." ); NSAssert( [seed length], @"Missing seed." );
NSArray *typeCiphers = [self ciphersForType:type]; NSArray *typeCiphers = [self ciphersForType:type];
NSString *cipher = typeCiphers[seedBytes[0] % [typeCiphers count]]; NSString *cipher = typeCiphers[seedBytes[0] % [typeCiphers count]];
trc( @"type %@, ciphers: %@, selected: %@", [self nameOfType:type], typeCiphers, cipher ); trc( @"type %@ (%d), ciphers: %@, selected: %@", [self nameOfType:type], type, typeCiphers, cipher );
// Encode the content, character by character, using subsequent seed bytes and the cipher. // Encode the content, character by character, using subsequent seed bytes and the cipher.
NSAssert( [seed length] >= [cipher length] + 1, @"Insufficient seed bytes to encode cipher." ); NSAssert( [seed length] >= [cipher length] + 1, @"Insufficient seed bytes to encode cipher." );

View File

@ -173,7 +173,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
for (MPElementEntity *element in user.elements) { for (MPElementEntity *element in user.elements) {
if (element.type & MPElementTypeClassStored) { if (element.type & MPElementTypeClassStored) {
NSString *content; NSString *content;
while (!(content = [element.algorithm storedContentForElement:(MPElementStoredEntity *)element usingKey:recoverKey])) { while (!(content = [element.algorithm storedPasswordForElement:(MPElementStoredEntity *)element usingKey:recoverKey])) {
// Failed to decrypt element with the current recoveryKey. Ask user for a new one to use. // Failed to decrypt element with the current recoveryKey. Ask user for a new one to use.
__block NSString *masterPassword = nil; __block NSString *masterPassword = nil;
@ -210,7 +210,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
break; break;
if (![recoverKey isEqualToKey:newKey]) if (![recoverKey isEqualToKey:newKey])
[element.algorithm saveContent:content toElement:element usingKey:newKey]; [element.algorithm savePassword:content toElement:element usingKey:newKey];
} }
} }

View File

@ -8,7 +8,6 @@
#import "MPAppDelegate_Shared.h" #import "MPAppDelegate_Shared.h"
#import "UbiquityStoreManager.h"
#import "MPFixable.h" #import "MPFixable.h"
typedef NS_ENUM( NSUInteger, MPImportResult ) { typedef NS_ENUM( NSUInteger, MPImportResult ) {
@ -19,7 +18,7 @@ typedef NS_ENUM( NSUInteger, MPImportResult ) {
MPImportResultInternalError, MPImportResultInternalError,
}; };
@interface MPAppDelegate_Shared(Store)<UbiquityStoreManagerDelegate> @interface MPAppDelegate_Shared(Store)
+ (NSManagedObjectContext *)managedObjectContextForMainThreadIfReady; + (NSManagedObjectContext *)managedObjectContextForMainThreadIfReady;
+ (BOOL)managedObjectContextForMainThreadPerformBlock:(void (^)(NSManagedObjectContext *mainContext))mocBlock; + (BOOL)managedObjectContextForMainThreadPerformBlock:(void (^)(NSManagedObjectContext *mainContext))mocBlock;
@ -27,7 +26,6 @@ typedef NS_ENUM( NSUInteger, MPImportResult ) {
+ (BOOL)managedObjectContextPerformBlock:(void (^)(NSManagedObjectContext *context))mocBlock; + (BOOL)managedObjectContextPerformBlock:(void (^)(NSManagedObjectContext *context))mocBlock;
+ (BOOL)managedObjectContextPerformBlockAndWait:(void (^)(NSManagedObjectContext *context))mocBlock; + (BOOL)managedObjectContextPerformBlockAndWait:(void (^)(NSManagedObjectContext *context))mocBlock;
- (UbiquityStoreManager *)storeManager;
- (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context; - (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context;
/** @param completion The block to execute after adding the element, executed from the main thread with the new element in the main MOC. */ /** @param completion The block to execute after adding the element, executed from the main thread with the new element in the main MOC. */

View File

@ -14,27 +14,21 @@
#define STORE_OPTIONS #define STORE_OPTIONS
#endif #endif
#define MPCloudContainerIdentifier @"HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.shared" #define MPStoreMigrationLevelKey @"MPMigrationLevelLocalStoreKey"
#define MPMigrationLevelLocalStoreKey @"MPMigrationLevelLocalStoreKey"
#define MPMigrationLevelCloudStoreKey @"MPMigrationLevelCloudStoreKey"
typedef NS_ENUM( NSInteger, MPMigrationLevelLocalStore ) { typedef NS_ENUM( NSInteger, MPStoreMigrationLevel ) {
MPMigrationLevelLocalStoreV1, MPStoreMigrationLevelV1,
MPMigrationLevelLocalStoreV2, MPStoreMigrationLevelV2,
MPMigrationLevelLocalStoreCurrent = MPMigrationLevelLocalStoreV2, MPStoreMigrationLevelV3,
}; MPStoreMigrationLevelCurrent = MPStoreMigrationLevelV3,
typedef NS_ENUM( NSInteger, MPMigrationLevelCloudStore ) {
MPMigrationLevelCloudStoreV1,
MPMigrationLevelCloudStoreV2,
MPMigrationLevelCloudStoreV3,
MPMigrationLevelCloudStoreCurrent = MPMigrationLevelCloudStoreV3,
}; };
@implementation MPAppDelegate_Shared(Store) @implementation MPAppDelegate_Shared(Store)
PearlAssociatedObjectProperty( id, SaveObserver, saveObserver ); PearlAssociatedObjectProperty( id, SaveObserver, saveObserver );
PearlAssociatedObjectProperty( NSPersistentStoreCoordinator*, PersistentStoreCoordinator, persistentStoreCoordinator );
PearlAssociatedObjectProperty( NSManagedObjectContext*, PrivateManagedObjectContext, privateManagedObjectContext ); PearlAssociatedObjectProperty( NSManagedObjectContext*, PrivateManagedObjectContext, privateManagedObjectContext );
PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext, mainManagedObjectContext ); PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext, mainManagedObjectContext );
@ -109,47 +103,103 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
- (NSManagedObjectContext *)mainManagedObjectContextIfReady { - (NSManagedObjectContext *)mainManagedObjectContextIfReady {
[self storeManager]; [self loadStore];
return self.mainManagedObjectContext; return self.mainManagedObjectContext;
} }
- (NSManagedObjectContext *)privateManagedObjectContextIfReady { - (NSManagedObjectContext *)privateManagedObjectContextIfReady {
[self storeManager]; [self loadStore];
return self.privateManagedObjectContext; return self.privateManagedObjectContext;
} }
- (UbiquityStoreManager *)storeManager { - (NSURL *)localStoreURL {
static UbiquityStoreManager *storeManager = nil; NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
if (storeManager) inDomains:NSUserDomainMask] lastObject];
return storeManager; return [[[applicationSupportURL
URLByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier isDirectory:YES]
URLByAppendingPathComponent:@"UbiquityStore" isDirectory:NO]
URLByAppendingPathExtension:@"sqlite"];
}
storeManager = [[UbiquityStoreManager alloc] initStoreNamed:nil withManagedObjectModel:nil localStoreURL:nil - (void)loadStore {
containerIdentifier:MPCloudContainerIdentifier
storeConfiguration:nil storeOptions:@{ STORE_OPTIONS } @synchronized (self) {
delegate:self]; // Do nothing if already fully set up, otherwise (re-)load the store.
if (self.persistentStoreCoordinator && self.saveObserver && self.mainManagedObjectContext && self.privateManagedObjectContext)
return;
// Unregister any existing observers and contexts.
if (self.saveObserver)
[[NSNotificationCenter defaultCenter] removeObserver:self.saveObserver];
[self.mainManagedObjectContext performBlockAndWait:^{
[self.mainManagedObjectContext reset];
self.mainManagedObjectContext = nil;
}];
[self.privateManagedObjectContext performBlockAndWait:^{
[self.privateManagedObjectContext reset];
self.privateManagedObjectContext = nil;
}];
// Check if migration is necessary.
[self migrateStore];
// Create a new store coordinator.
self.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:
[NSManagedObjectModel mergedModelFromBundles:nil]];
NSError *error = nil;
[self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self localStoreURL]
options:@{
NSMigratePersistentStoresAutomaticallyOption : @YES,
NSInferMappingModelAutomaticallyOption : @YES,
STORE_OPTIONS
} error:&error];
// Create our contexts and observer.
self.privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[self.privateManagedObjectContext performBlockAndWait:^{
self.privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
self.privateManagedObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator;
}];
self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
self.mainManagedObjectContext.parentContext = self.privateManagedObjectContext;
self.saveObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification
object:self.privateManagedObjectContext queue:nil usingBlock:
^(NSNotification *note) {
// When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
[self.mainManagedObjectContext performBlock:^{
[self.mainManagedObjectContext mergeChangesFromContextDidSaveNotification:note];
}];
}];
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification object:UIApp [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification object:UIApp
queue:[NSOperationQueue mainQueue] usingBlock: queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) { ^(NSNotification *note) {
[[self mainManagedObjectContext] saveToStore]; [self.mainManagedObjectContext saveToStore];
}]; }];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:UIApp [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:UIApp
queue:[NSOperationQueue mainQueue] usingBlock: queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) { ^(NSNotification *note) {
[[self mainManagedObjectContext] saveToStore]; [self.mainManagedObjectContext saveToStore];
}]; }];
#else #else
[[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillTerminateNotification object:NSApp [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillTerminateNotification object:NSApp
queue:[NSOperationQueue mainQueue] usingBlock: queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) { ^(NSNotification *note) {
[self.mainManagedObjectContextIfReady saveToStore]; [self.mainManagedObjectContext saveToStore];
}]; }];
#endif #endif
return storeManager; // Perform a data sanity check on the newly loaded store to find and fix any issues.
if ([[MPConfig get].checkInconsistency boolValue])
[MPAppDelegate_Shared managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
[self findAndFixInconsistenciesSaveInContext:context];
}];
}
} }
- (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context { - (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context {
@ -187,103 +237,27 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
return result; return result;
} }
- (void)migrateStoreForManager:(UbiquityStoreManager *)manager isCloud:(BOOL)isCloudStore { - (void)migrateStore {
[self migrateLocalStore]; MPStoreMigrationLevel migrationLevel = (signed)[[NSUserDefaults standardUserDefaults] integerForKey:MPStoreMigrationLevelKey];
if (migrationLevel >= MPStoreMigrationLevelCurrent)
if (isCloudStore)
[self migrateCloudStore];
}
- (void)migrateLocalStore {
MPMigrationLevelLocalStore migrationLevel = (signed)[[NSUserDefaults standardUserDefaults] integerForKey:MPMigrationLevelLocalStoreKey];
if (migrationLevel >= MPMigrationLevelLocalStoreCurrent)
// Local store up-to-date. // Local store up-to-date.
return; return;
inf( @"Local store migration level: %d (current %d)", (signed)migrationLevel, (signed)MPMigrationLevelLocalStoreCurrent ); inf( @"Local store migration level: %d (current %d)", (signed)migrationLevel, (signed)MPStoreMigrationLevelCurrent );
if (migrationLevel <= MPMigrationLevelLocalStoreV1) if (![self migrateV1LocalStore]) { if (migrationLevel == MPStoreMigrationLevelV1 && ![self migrateV1LocalStore]) {
inf( @"Failed to migrate old V1 to new local store." ); inf( @"Failed to migrate old V1 to new local store." );
return; return;
} }
if (migrationLevel == MPStoreMigrationLevelV2 && ![self migrateV2LocalStore]) {
inf( @"Failed to migrate old V2 to new local store." );
return;
}
[[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelLocalStoreCurrent forKey:MPMigrationLevelLocalStoreKey]; [[NSUserDefaults standardUserDefaults] setInteger:MPStoreMigrationLevelCurrent forKey:MPStoreMigrationLevelKey];
inf( @"Successfully migrated old to new local store." ); inf( @"Successfully migrated old to new local store." );
} }
- (void)migrateCloudStore {
MPMigrationLevelCloudStore migrationLevel = (signed)[[NSUserDefaults standardUserDefaults] integerForKey:MPMigrationLevelCloudStoreKey];
if (migrationLevel >= MPMigrationLevelCloudStoreCurrent)
// Cloud store up-to-date.
return;
inf( @"Cloud store migration level: %d (current %d)", (signed)migrationLevel, (signed)MPMigrationLevelCloudStoreCurrent );
if (migrationLevel <= MPMigrationLevelCloudStoreV1) {
if (![self migrateV1CloudStore]) {
inf( @"Failed to migrate old V1 to new cloud store." );
return;
}
}
else if (migrationLevel <= MPMigrationLevelCloudStoreV2) {
if (![self migrateV2CloudStore]) {
inf( @"Failed to migrate old V2 to new cloud store." );
return;
}
}
[[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey];
inf( @"Successfully migrated old to new cloud store." );
}
- (BOOL)migrateV1CloudStore {
// Migrate cloud enabled preference.
NSNumber *oldCloudEnabled = [[NSUserDefaults standardUserDefaults] objectForKey:@"iCloudEnabledKey"];
if ([oldCloudEnabled boolValue])
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:USMCloudEnabledKey];
// Migrate cloud store.
NSString *uuid = [[NSUserDefaults standardUserDefaults] stringForKey:@"LocalUUIDKey"];
if (!uuid) {
inf( @"No V1 cloud store to migrate." );
return YES;
}
inf( @"Migrating V1 cloud store: %@ -> %@", uuid, [self.storeManager valueForKey:@"storeUUID"] );
NSURL *cloudContainerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:MPCloudContainerIdentifier];
NSURL *oldCloudContentURL = [[cloudContainerURL
URLByAppendingPathComponent:@"Data" isDirectory:YES]
URLByAppendingPathComponent:uuid isDirectory:YES];
NSURL *oldCloudStoreURL = [[[cloudContainerURL
URLByAppendingPathComponent:@"Database.nosync" isDirectory:YES]
URLByAppendingPathComponent:uuid isDirectory:NO] URLByAppendingPathExtension:@"sqlite"];
return [self migrateFromCloudStore:oldCloudStoreURL cloudContent:oldCloudContentURL];
}
- (BOOL)migrateV2CloudStore {
// Migrate cloud store.
NSString *uuid = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:@"USMStoreUUIDKey"];
if (!uuid) {
inf( @"No V2 cloud store to migrate." );
return YES;
}
inf( @"Migrating V2 cloud store: %@ -> %@", uuid, [self.storeManager valueForKey:@"storeUUID"] );
NSURL *cloudContainerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:MPCloudContainerIdentifier];
NSURL *oldCloudContentURL = [[cloudContainerURL
URLByAppendingPathComponent:@"CloudLogs" isDirectory:YES]
URLByAppendingPathComponent:uuid isDirectory:YES];
NSURL *oldCloudStoreURL = [[[cloudContainerURL
URLByAppendingPathComponent:@"CloudStore.nosync" isDirectory:YES]
URLByAppendingPathComponent:uuid isDirectory:NO] URLByAppendingPathExtension:@"sqlite"];
return [self migrateFromCloudStore:oldCloudStoreURL cloudContent:oldCloudContentURL];
}
- (BOOL)migrateV1LocalStore { - (BOOL)migrateV1LocalStore {
NSURL *applicationFilesDirectory = [[[NSFileManager defaultManager] NSURL *applicationFilesDirectory = [[[NSFileManager defaultManager]
@ -296,141 +270,58 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
} }
inf( @"Migrating V1 local store" ); inf( @"Migrating V1 local store" );
return [self migrateFromLocalStore:oldLocalStoreURL]; NSURL *newLocalStoreURL = [self localStoreURL];
} NSError *error = nil;
if (![[NSFileManager defaultManager] createDirectoryAtURL:[newLocalStoreURL URLByDeletingLastPathComponent]
- (BOOL)migrateFromLocalStore:(NSURL *)oldLocalStoreURL { withIntermediateDirectories:YES attributes:nil error:&error]) {
err( @"Couldn't create our application support directory: %@", [error fullDescription] );
NSURL *newLocalStoreURL = [self.storeManager URLForLocalStore]; return NO;
if ([[NSFileManager defaultManager] fileExistsAtPath:newLocalStoreURL.path isDirectory:NULL]) {
wrn( @"Can't migrate local store: A new local store already exists." );
return YES;
} }
if (![[NSFileManager defaultManager] moveItemAtURL:oldLocalStoreURL toURL:newLocalStoreURL error:&error]) {
if (![self.storeManager migrateStore:oldLocalStoreURL withOptions:nil err( @"Couldn't move the old store to the new location: %@", [error fullDescription] );
toStore:newLocalStoreURL withOptions:nil
strategy:0 error:nil cause:nil context:nil]) {
self.storeManager.localStoreURL = oldLocalStoreURL;
return NO; return NO;
} }
inf( @"Successfully migrated to new local store." );
return YES; return YES;
} }
- (BOOL)migrateFromCloudStore:(NSURL *)oldCloudStoreURL cloudContent:(NSURL *)oldCloudContentURL { - (BOOL)migrateV2LocalStore {
if (![self.storeManager cloudSafeForSeeding]) { NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
inf( @"Can't migrate cloud store: A new cloud store already exists." ); inDomains:NSUserDomainMask] lastObject];
NSURL *oldLocalStoreURL;
// On iOS, each app is in a sandbox so we don't need to app-scope this directory.
#if TARGET_OS_IPHONE
oldLocalStoreURL = [[applicationSupportURL
URLByAppendingPathComponent:@"UbiquityStore" isDirectory:NO]
URLByAppendingPathExtension:@"sqlite"];
#else
// The directory is shared between all apps on the system so we need to scope it for the running app.
oldLocalStoreURL = [[[applicationSupportURL
URLByAppendingPathComponent:[NSRunningApplication currentApplication].bundleIdentifier isDirectory:YES]
URLByAppendingPathComponent:@"UbiquityStore" isDirectory:NO]
URLByAppendingPathExtension:@"sqlite"];
#endif
if (![[NSFileManager defaultManager] fileExistsAtPath:oldLocalStoreURL.path isDirectory:NULL]) {
inf( @"No V2 local store to migrate." );
return YES; return YES;
} }
NSURL *newCloudStoreURL = [self.storeManager URLForCloudStore]; inf( @"Migrating V2 local store" );
if (![self.storeManager migrateStore:oldCloudStoreURL withOptions:nil NSURL *newLocalStoreURL = [self localStoreURL];
toStore:newCloudStoreURL withOptions:nil NSError *error = nil;
strategy:0 error:nil cause:nil context:nil]) if (![[NSFileManager defaultManager] createDirectoryAtURL:[newLocalStoreURL URLByDeletingLastPathComponent]
withIntermediateDirectories:YES attributes:nil error:&error]) {
err( @"Couldn't create our application support directory: %@", [error fullDescription] );
return NO;
}
if (![[NSFileManager defaultManager] moveItemAtURL:oldLocalStoreURL toURL:newLocalStoreURL error:&error]) {
err( @"Couldn't move the old store to the new location: %@", [error fullDescription] );
return NO; return NO;
inf( @"Successfully migrated to new cloud store." );
return YES;
}
#pragma mark - UbiquityStoreManagerDelegate
- (NSManagedObjectContext *)ubiquityStoreManager:(UbiquityStoreManager *)manager
managedObjectContextForUbiquityChanges:(NSNotification *)note {
return [self mainManagedObjectContextIfReady];
}
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager log:(NSString *)message {
inf( @"[StoreManager] %@", message );
}
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager willLoadStoreIsCloud:(BOOL)isCloudStore {
NSManagedObjectContext *moc = [self mainManagedObjectContextIfReady];
[moc performBlockAndWait:^{
[moc saveToStore];
[moc reset];
if (self.saveObserver) {
[[NSNotificationCenter defaultCenter] removeObserver:self.saveObserver];
self.saveObserver = nil;
} }
self.privateManagedObjectContext = nil; return YES;
self.mainManagedObjectContext = nil;
}];
[self migrateStoreForManager:manager isCloud:isCloudStore];
}
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didLoadStoreForCoordinator:(NSPersistentStoreCoordinator *)coordinator
isCloud:(BOOL)isCloudStore {
inf( @"Using iCloud? %@", @(isCloudStore) );
MPCheckpoint( MPCheckpointCloud, @{
@"enabled" : @(isCloudStore)
} );
// Create our contexts.
NSManagedObjectContext *privateManagedObjectContext =
[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[privateManagedObjectContext performBlockAndWait:^{
privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
privateManagedObjectContext.persistentStoreCoordinator = coordinator;
// dbg(@"===");
// NSError *error;
// for (NSEntityDescription *entityDescription in [coordinator.managedObjectModel entities]) {
// dbg(@"Entities: %@", entityDescription.name);
// NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:entityDescription.name];
// NSArray *entities = [privateManagedObjectContext executeFetchRequest:request error:&error];
// if (!entities)
// err(@" - Error: %@", error);
// else
// for (id entity in entities)
// dbg(@" - %@", [entity debugDescription]);
// }
// dbg(@"===");
}];
NSManagedObjectContext *mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
mainManagedObjectContext.parentContext = privateManagedObjectContext;
if (self.saveObserver)
[[NSNotificationCenter defaultCenter] removeObserver:self.saveObserver];
self.saveObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification
object:privateManagedObjectContext queue:nil usingBlock:
^(NSNotification *note) {
// When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
[mainManagedObjectContext performBlock:^{
[mainManagedObjectContext mergeChangesFromContextDidSaveNotification:note];
}];
}];
self.privateManagedObjectContext = privateManagedObjectContext;
self.mainManagedObjectContext = mainManagedObjectContext;
// Perform a data sanity check on the newly loaded store to find and fix any issues.
if ([[MPConfig get].checkInconsistency boolValue])
[MPAppDelegate_Shared managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
[self findAndFixInconsistenciesSaveInContext:context];
}];
}
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didEncounterError:(NSError *)error cause:(UbiquityStoreErrorCause)cause
context:(id)context {
err( @"[StoreManager] ERROR: cause=%@, context=%@, error=%@", NSStringFromUSMCause( cause ), context, error );
MPCheckpoint( MPCheckpointMPErrorUbiquity, @{
@"cause" : @(cause),
@"error.code" : @(error.code),
@"error.domain" : NilToNSNull( error.domain ),
@"error.reason" : NilToNSNull( [error localizedFailureReason]?: [error localizedDescription] ),
} );
} }
#pragma mark - Utilities #pragma mark - Utilities
@ -735,7 +626,8 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
if (importAvatar != NSNotFound) if (importAvatar != NSNotFound)
user.avatar = importAvatar; user.avatar = importAvatar;
dbg( @"Updating User: %@", [user debugDescription] ); dbg( @"Updating User: %@", [user debugDescription] );
} else { }
else {
user = [MPUserEntity insertNewObjectInContext:context]; user = [MPUserEntity insertNewObjectInContext:context];
user.name = importUserName; user.name = importUserName;
user.keyID = importKeyID; user.keyID = importKeyID;
@ -767,9 +659,9 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
element.version = version; element.version = version;
if ([exportContent length]) { if ([exportContent length]) {
if (clearText) if (clearText)
[element.algorithm importClearTextContent:exportContent intoElement:element usingKey:userKey]; [element.algorithm importClearTextPassword:exportContent intoElement:element usingKey:userKey];
else else
[element.algorithm importProtectedContent:exportContent protectedByKey:importKey intoElement:element usingKey:userKey]; [element.algorithm importProtectedPassword:exportContent protectedByKey:importKey intoElement:element usingKey:userKey];
} }
if ([element isKindOfClass:[MPElementGeneratedEntity class]] && counter != NSNotFound) if ([element isKindOfClass:[MPElementGeneratedEntity class]] && counter != NSNotFound)
((MPElementGeneratedEntity *)element).counter = counter; ((MPElementGeneratedEntity *)element).counter = counter;
@ -838,9 +730,9 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
// Determine the content to export. // Determine the content to export.
if (!(type & MPElementFeatureDevicePrivate)) { if (!(type & MPElementFeatureDevicePrivate)) {
if (revealPasswords) if (revealPasswords)
content = [element.algorithm resolveContentForElement:element usingKey:self.key]; content = [element.algorithm resolvePasswordForElement:element usingKey:self.key];
else if (type & MPElementFeatureExportContent) else if (type & MPElementFeatureExportContent)
content = [element.algorithm exportContentForElement:element usingKey:self.key]; content = [element.algorithm exportPasswordForElement:element usingKey:self.key];
} }
[export appendFormat:@"%@ %8ld %8s %25s\t%25s\t%@\n", [export appendFormat:@"%@ %8ld %8s %25s\t%25s\t%@\n",

View File

@ -2,25 +2,26 @@
// MPElementEntity.h // MPElementEntity.h
// MasterPassword-iOS // MasterPassword-iOS
// //
// Created by Maarten Billemont on 2013-01-29. // Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2013 Lyndir. All rights reserved. // Copyright (c) 2014 Lyndir. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <CoreData/CoreData.h> #import <CoreData/CoreData.h>
#import "MPFixable.h"
@class MPUserEntity; @class MPUserEntity;
@interface MPElementEntity : NSManagedObject <MPFixable> @interface MPElementEntity : NSManagedObject
@property(nonatomic, retain) NSDate *lastUsed; //@property (nonatomic, retain) id content; // Hide here, reveal in MPElementStoredEntity
@property(nonatomic, retain) NSString *loginName; @property (nonatomic, retain) NSDate * lastUsed;
@property(nonatomic, retain) NSString *name; @property (nonatomic, retain) NSString * loginName;
@property(nonatomic, retain) NSNumber *requiresExplicitMigration_; @property (nonatomic, retain) NSString * name;
@property(nonatomic, retain) NSNumber *type_; @property (nonatomic, retain) NSNumber * requiresExplicitMigration_;
@property(nonatomic, retain) NSNumber *uses_; @property (nonatomic, retain) NSNumber * type_;
@property(nonatomic, retain) NSNumber *version_; @property (nonatomic, retain) NSNumber * uses_;
@property(nonatomic, retain) MPUserEntity *user; @property (nonatomic, retain) NSNumber * version_;
@property (nonatomic, retain) NSNumber * loginGenerated_;
@property (nonatomic, retain) MPUserEntity *user;
@end @end

View File

@ -2,14 +2,17 @@
// MPElementEntity.m // MPElementEntity.m
// MasterPassword-iOS // MasterPassword-iOS
// //
// Created by Maarten Billemont on 2013-01-29. // Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2013 Lyndir. All rights reserved. // Copyright (c) 2014 Lyndir. All rights reserved.
// //
#import "MPElementEntity.h" #import "MPElementEntity.h"
#import "MPUserEntity.h"
@implementation MPElementEntity @implementation MPElementEntity
//@dynamic content;
@dynamic lastUsed; @dynamic lastUsed;
@dynamic loginName; @dynamic loginName;
@dynamic name; @dynamic name;
@ -17,11 +20,7 @@
@dynamic type_; @dynamic type_;
@dynamic uses_; @dynamic uses_;
@dynamic version_; @dynamic version_;
@dynamic loginGenerated_;
@dynamic user; @dynamic user;
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
return MPFixableResultNoProblems;
}
@end @end

View File

@ -2,16 +2,17 @@
// MPElementGeneratedEntity.h // MPElementGeneratedEntity.h
// MasterPassword-iOS // MasterPassword-iOS
// //
// Created by Maarten Billemont on 2013-01-29. // Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2013 Lyndir. All rights reserved. // Copyright (c) 2014 Lyndir. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <CoreData/CoreData.h> #import <CoreData/CoreData.h>
#import "MPElementEntity.h" #import "MPElementEntity.h"
@interface MPElementGeneratedEntity : MPElementEntity @interface MPElementGeneratedEntity : MPElementEntity
@property(nonatomic, retain) NSNumber *counter_; @property (nonatomic, retain) NSNumber * counter_;
@end @end

View File

@ -2,54 +2,15 @@
// MPElementGeneratedEntity.m // MPElementGeneratedEntity.m
// MasterPassword-iOS // MasterPassword-iOS
// //
// Created by Maarten Billemont on 2013-01-29. // Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2013 Lyndir. All rights reserved. // Copyright (c) 2014 Lyndir. All rights reserved.
// //
#import "MPElementGeneratedEntity.h" #import "MPElementGeneratedEntity.h"
#import "MPAppDelegate_Shared.h"
@implementation MPElementGeneratedEntity @implementation MPElementGeneratedEntity
@dynamic counter_; @dynamic counter_;
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
MPFixableResult result = [super findAndFixInconsistenciesInContext:context];
if (!self.type || self.type == (MPElementType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
// Invalid self.type
result = MPApplyFix( result, ^MPFixableResult {
wrn( @"Invalid type for: %@ of %@, type: %ld. Will use %ld instead.",
self.name, self.user.name, (long)self.type, (long)self.user.defaultType );
self.type = self.user.defaultType;
return MPFixableResultProblemsFixed;
} );
if (!self.type || self.type == (MPElementType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
// Invalid self.user.defaultType
result = MPApplyFix( result, ^MPFixableResult {
wrn( @"Invalid type for: %@ of %@, type: %ld. Will use %ld instead.",
self.name, self.user.name, (long)self.type, (long)MPElementTypeGeneratedLong );
self.type = MPElementTypeGeneratedLong;
return MPFixableResultProblemsFixed;
} );
if (![self isKindOfClass:[self.algorithm classOfType:self.type]])
// Mismatch between self.type and self.class
result = MPApplyFix( result, ^MPFixableResult {
for (MPElementType newType = self.type; self.type != (newType = [self.algorithm nextType:newType]);)
if ([self isKindOfClass:[self.algorithm classOfType:newType]]) {
wrn( @"Mismatching type for: %@ of %@, type: %lu, class: %@. Will use %ld instead.",
self.name, self.user.name, (long)self.type, self.class, (long)newType );
self.type = newType;
return MPFixableResultProblemsFixed;
}
err( @"Mismatching type for: %@ of %@, type: %lu, class: %@. Couldn't find a type to fix problem with.",
self.name, self.user.name, (long)self.type, self.class );
return MPFixableResultProblemsNotFixed;
} );
return result;
}
@end @end

View File

@ -2,16 +2,17 @@
// MPElementStoredEntity.h // MPElementStoredEntity.h
// MasterPassword-iOS // MasterPassword-iOS
// //
// Created by Maarten Billemont on 2013-01-29. // Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2013 Lyndir. All rights reserved. // Copyright (c) 2014 Lyndir. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <CoreData/CoreData.h> #import <CoreData/CoreData.h>
#import "MPElementEntity.h" #import "MPElementEntity.h"
@interface MPElementStoredEntity : MPElementEntity @interface MPElementStoredEntity : MPElementEntity
@property(nonatomic, retain) NSData *contentObject; @property (nonatomic, retain) NSData * contentObject;
@end @end

View File

@ -2,36 +2,15 @@
// MPElementStoredEntity.m // MPElementStoredEntity.m
// MasterPassword-iOS // MasterPassword-iOS
// //
// Created by Maarten Billemont on 2013-01-29. // Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2013 Lyndir. All rights reserved. // Copyright (c) 2014 Lyndir. All rights reserved.
// //
#import "MPElementStoredEntity.h" #import "MPElementStoredEntity.h"
#import "MPEntities.h"
#import "MPAppDelegate_Shared.h"
@implementation MPElementStoredEntity @implementation MPElementStoredEntity
@dynamic contentObject; @dynamic contentObject;
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
MPFixableResult result = [super findAndFixInconsistenciesInContext:context];
if (self.contentObject && ![self.contentObject isKindOfClass:[NSData class]])
result = MPApplyFix( result, ^MPFixableResult {
MPKey *key = [MPAppDelegate_Shared get].key;
if (key && [[MPAppDelegate_Shared get] activeUserInContext:context] == self.user) {
wrn( @"Content object not encrypted for: %@ of %@. Will re-encrypt.", self.name, self.user.name );
[self.algorithm saveContent:[self.contentObject description] toElement:self usingKey:key];
return MPFixableResultProblemsFixed;
}
err( @"Content object not encrypted for: %@ of %@. Couldn't fix, please sign in.", self.name, self.user.name );
return MPFixableResultProblemsNotFixed;
} );
return result;
}
@end @end

View File

@ -12,6 +12,7 @@
#import "MPElementGeneratedEntity.h" #import "MPElementGeneratedEntity.h"
#import "MPUserEntity.h" #import "MPUserEntity.h"
#import "MPAlgorithm.h" #import "MPAlgorithm.h"
#import "MPFixable.h"
#define MPAvatarCount 19 #define MPAvatarCount 19
@ -21,8 +22,9 @@
@end @end
@interface MPElementEntity(MP) @interface MPElementEntity(MP)<MPFixable>
@property(assign) BOOL loginGenerated;
@property(assign) MPElementType type; @property(assign) MPElementType type;
@property(readonly) NSString *typeName; @property(readonly) NSString *typeName;
@property(readonly) NSString *typeShortName; @property(readonly) NSString *typeShortName;
@ -35,8 +37,10 @@
- (NSUInteger)use; - (NSUInteger)use;
- (BOOL)migrateExplicitly:(BOOL)explicit; - (BOOL)migrateExplicitly:(BOOL)explicit;
- (NSString *)resolveContentUsingKey:(MPKey *)key; - (NSString *)resolveLoginUsingKey:(MPKey *)key;
- (void)resolveContentUsingKey:(MPKey *)key result:(void (^)(NSString *))result; - (NSString *)resolvePasswordUsingKey:(MPKey *)key;
- (void)resolveLoginUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result;
- (void)resolvePasswordUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result;
@end @end

View File

@ -36,11 +36,26 @@
@implementation MPElementEntity(MP) @implementation MPElementEntity(MP)
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
return MPFixableResultNoProblems;
}
- (MPElementType)type { - (MPElementType)type {
return (MPElementType)[self.type_ unsignedIntegerValue]; return (MPElementType)[self.type_ unsignedIntegerValue];
} }
- (void)setLoginGenerated:(BOOL)aLoginGenerated {
self.loginGenerated_ = @(aLoginGenerated);
}
- (BOOL)loginGenerated {
return [self.loginGenerated_ boolValue];
}
- (void)setType:(MPElementType)aType { - (void)setType:(MPElementType)aType {
self.type_ = @(aType); self.type_ = @(aType);
@ -135,20 +150,69 @@
return YES; return YES;
} }
- (NSString *)resolveContentUsingKey:(MPKey *)key { - (NSString *)resolveLoginUsingKey:(MPKey *)key {
return [self.algorithm resolveContentForElement:self usingKey:key]; return [self.algorithm resolveLoginForElement:self usingKey:key];
} }
- (void)resolveContentUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result { - (NSString *)resolvePasswordUsingKey:(MPKey *)key {
[self.algorithm resolveContentForElement:self usingKey:key result:result]; return [self.algorithm resolvePasswordForElement:self usingKey:key];
}
- (void)resolveLoginUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result {
[self.algorithm resolveLoginForElement:self usingKey:key result:result];
}
- (void)resolvePasswordUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result {
[self.algorithm resolvePasswordForElement:self usingKey:key result:result];
} }
@end @end
@implementation MPElementGeneratedEntity(MP) @implementation MPElementGeneratedEntity(MP)
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
MPFixableResult result = [super findAndFixInconsistenciesInContext:context];
if (!self.type || self.type == (MPElementType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
// Invalid self.type
result = MPApplyFix( result, ^MPFixableResult {
wrn( @"Invalid type for: %@ of %@, type: %ld. Will use %ld instead.",
self.name, self.user.name, (long)self.type, (long)self.user.defaultType );
self.type = self.user.defaultType;
return MPFixableResultProblemsFixed;
} );
if (!self.type || self.type == (MPElementType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
// Invalid self.user.defaultType
result = MPApplyFix( result, ^MPFixableResult {
wrn( @"Invalid type for: %@ of %@, type: %ld. Will use %ld instead.",
self.name, self.user.name, (long)self.type, (long)MPElementTypeGeneratedLong );
self.type = MPElementTypeGeneratedLong;
return MPFixableResultProblemsFixed;
} );
if (![self isKindOfClass:[self.algorithm classOfType:self.type]])
// Mismatch between self.type and self.class
result = MPApplyFix( result, ^MPFixableResult {
for (MPElementType newType = self.type; self.type != (newType = [self.algorithm nextType:newType]);)
if ([self isKindOfClass:[self.algorithm classOfType:newType]]) {
wrn( @"Mismatching type for: %@ of %@, type: %lu, class: %@. Will use %ld instead.",
self.name, self.user.name, (long)self.type, self.class, (long)newType );
self.type = newType;
return MPFixableResultProblemsFixed;
}
err( @"Mismatching type for: %@ of %@, type: %lu, class: %@. Couldn't find a type to fix problem with.",
self.name, self.user.name, (long)self.type, self.class );
return MPFixableResultProblemsNotFixed;
} );
return result;
}
- (NSUInteger)counter { - (NSUInteger)counter {
return [self.counter_ unsignedIntegerValue]; return [self.counter_ unsignedIntegerValue];
@ -163,6 +227,26 @@
@implementation MPElementStoredEntity(MP) @implementation MPElementStoredEntity(MP)
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
MPFixableResult result = [super findAndFixInconsistenciesInContext:context];
if (self.contentObject && ![self.contentObject isKindOfClass:[NSData class]])
result = MPApplyFix( result, ^MPFixableResult {
MPKey *key = [MPAppDelegate_Shared get].key;
if (key && [[MPAppDelegate_Shared get] activeUserInContext:context] == self.user) {
wrn( @"Content object not encrypted for: %@ of %@. Will re-encrypt.", self.name, self.user.name );
[self.algorithm savePassword:[self.contentObject description] toElement:self usingKey:key];
return MPFixableResultProblemsFixed;
}
err( @"Content object not encrypted for: %@ of %@. Couldn't fix, please sign in.", self.name, self.user.name );
return MPFixableResultProblemsNotFixed;
} );
return result;
}
@end @end
@implementation MPUserEntity(MP) @implementation MPUserEntity(MP)

View File

@ -8,12 +8,6 @@
#import "MPKey.h" #import "MPKey.h"
typedef NS_ENUM(NSUInteger, MPElementContentType) {
MPElementContentTypePassword,
MPElementContentTypeNote,
MPElementContentTypePicture,
};
typedef NS_ENUM(NSUInteger, MPElementTypeClass) { typedef NS_ENUM(NSUInteger, MPElementTypeClass) {
/** Generate the password. */ /** Generate the password. */
MPElementTypeClassGenerated = 1 << 4, MPElementTypeClassGenerated = 1 << 4,
@ -21,6 +15,13 @@ typedef NS_ENUM(NSUInteger, MPElementTypeClass) {
MPElementTypeClassStored = 1 << 5, MPElementTypeClassStored = 1 << 5,
}; };
typedef NS_ENUM(NSUInteger, MPElementVariant) {
/** Generate the password. */
MPElementVariantPassword,
/** Generate the login name. */
MPElementVariantLogin,
};
typedef NS_ENUM(NSUInteger, MPElementFeature) { typedef NS_ENUM(NSUInteger, MPElementFeature) {
/** Export the key-protected content data. */ /** Export the key-protected content data. */
MPElementFeatureExportContent = 1 << 10, MPElementFeatureExportContent = 1 << 10,
@ -35,6 +36,7 @@ typedef NS_ENUM(NSUInteger, MPElementType) {
MPElementTypeGeneratedBasic = 0x4 | MPElementTypeClassGenerated | 0x0, MPElementTypeGeneratedBasic = 0x4 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedShort = 0x3 | MPElementTypeClassGenerated | 0x0, MPElementTypeGeneratedShort = 0x3 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedPIN = 0x5 | MPElementTypeClassGenerated | 0x0, MPElementTypeGeneratedPIN = 0x5 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedName = 0xF | MPElementTypeClassGenerated | 0x0,
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent, MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate, MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,

View File

@ -2,8 +2,8 @@
// MPUserEntity.h // MPUserEntity.h
// MasterPassword-iOS // MasterPassword-iOS
// //
// Created by Maarten Billemont on 2013-01-29. // Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2013 Lyndir. All rights reserved. // Copyright (c) 2014 Lyndir. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@ -13,16 +13,16 @@
@interface MPUserEntity : NSManagedObject @interface MPUserEntity : NSManagedObject
@property(nonatomic, retain) NSNumber *avatar_; @property (nonatomic, retain) NSNumber * avatar_;
@property(nonatomic, retain) NSNumber *defaultType_; @property (nonatomic, retain) NSNumber * defaultType_;
@property(nonatomic, retain) NSData *keyID; @property (nonatomic, retain) NSData * keyID;
@property(nonatomic, retain) NSDate *lastUsed; @property (nonatomic, retain) NSDate * lastUsed;
@property(nonatomic, retain) NSString *name; @property (nonatomic, retain) NSString * name;
@property(nonatomic, retain) NSNumber *saveKey_; @property (nonatomic, retain) NSNumber * saveKey_;
@property(nonatomic, retain) NSSet *elements; @property (nonatomic, retain) NSSet *elements;
@end @end
@interface MPUserEntity(CoreDataGeneratedAccessors) @interface MPUserEntity (CoreDataGeneratedAccessors)
- (void)addElementsObject:(MPElementEntity *)value; - (void)addElementsObject:(MPElementEntity *)value;
- (void)removeElementsObject:(MPElementEntity *)value; - (void)removeElementsObject:(MPElementEntity *)value;

View File

@ -2,11 +2,13 @@
// MPUserEntity.m // MPUserEntity.m
// MasterPassword-iOS // MasterPassword-iOS
// //
// Created by Maarten Billemont on 2013-01-29. // Created by Maarten Billemont on 2014-09-14.
// Copyright (c) 2013 Lyndir. All rights reserved. // Copyright (c) 2014 Lyndir. All rights reserved.
// //
#import "MPUserEntity.h" #import "MPUserEntity.h"
#import "MPElementEntity.h"
@implementation MPUserEntity @implementation MPUserEntity

View File

@ -117,7 +117,7 @@
re_anyChar = [NSRegularExpression regularExpressionWithPattern:@"." options:0 error:nil]; re_anyChar = [NSRegularExpression regularExpressionWithPattern:@"." options:0 error:nil];
} ); } );
[entity resolveContentUsingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) { [entity resolvePasswordUsingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) {
NSString *displayResult = result; NSString *displayResult = result;
if ([[MPConfig get].hidePasswords boolValue] && !([NSEvent modifierFlags] & NSAlternateKeyMask)) if ([[MPConfig get].hidePasswords boolValue] && !([NSEvent modifierFlags] & NSAlternateKeyMask))
displayResult = [displayResult stringByReplacingMatchesOfExpression:re_anyChar withTemplate:@"●"]; displayResult = [displayResult stringByReplacingMatchesOfExpression:re_anyChar withTemplate:@"●"];

View File

@ -281,7 +281,7 @@
NSString *password = [(NSSecureTextField *)alert.accessoryView stringValue]; NSString *password = [(NSSecureTextField *)alert.accessoryView stringValue];
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPElementEntity *entity = [self.selectedElement entityInContext:context]; MPElementEntity *entity = [self.selectedElement entityInContext:context];
[entity.algorithm saveContent:password toElement:entity usingKey:[MPMacAppDelegate get].key]; [entity.algorithm savePassword:password toElement:entity usingKey:[MPMacAppDelegate get].key];
[context saveToStore]; [context saveToStore];
}]; }];
break; break;
@ -403,7 +403,7 @@
MPElementType type = [types[t] unsignedIntegerValue]; MPElementType type = [types[t] unsignedIntegerValue];
NSString *title = [element.algorithm nameOfType:type]; NSString *title = [element.algorithm nameOfType:type];
if (type & MPElementTypeClassGenerated) if (type & MPElementTypeClassGenerated)
title = [element.algorithm generateContentNamed:element.siteName ofType:type title = [element.algorithm generatePasswordForSiteNamed:element.siteName ofType:type
withCounter:element.counter usingKey:[MPMacAppDelegate get].key]; withCounter:element.counter usingKey:[MPMacAppDelegate get].key];
NSButtonCell *cell = [self.passwordTypesMatrix cellAtRow:(NSInteger)t column:0]; NSButtonCell *cell = [self.passwordTypesMatrix cellAtRow:(NSInteger)t column:0];

View File

@ -30,6 +30,7 @@
DA2508F119511D3600AC23F1 /* MPPasswordWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA2508F019511D3600AC23F1 /* MPPasswordWindowController.xib */; }; DA2508F119511D3600AC23F1 /* MPPasswordWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA2508F019511D3600AC23F1 /* MPPasswordWindowController.xib */; };
DA2508F719513C1400AC23F1 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; }; DA2508F719513C1400AC23F1 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; };
DA250925195148E200AC23F1 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; }; DA250925195148E200AC23F1 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
DA29992C19C6A89900AF7DF1 /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DA29992619C6A89900AF7DF1 /* MasterPassword.xcdatamodeld */; };
DA2CA4ED18D323D3007798F8 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */; }; DA2CA4ED18D323D3007798F8 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */; };
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 */; };
@ -71,7 +72,6 @@
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CC21724A667003798D8 /* InfoPlist.strings */; }; DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CC21724A667003798D8 /* InfoPlist.strings */; };
DA5E5D0B1724A667003798D8 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CC41724A667003798D8 /* MainMenu.xib */; }; DA5E5D0B1724A667003798D8 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CC41724A667003798D8 /* MainMenu.xib */; };
DA5E5D0C1724A667003798D8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CC61724A667003798D8 /* main.m */; }; DA5E5D0C1724A667003798D8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CC61724A667003798D8 /* main.m */; };
DA5E5D0D1724A667003798D8 /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CC71724A667003798D8 /* MasterPassword.xcdatamodeld */; };
DA60717C195D040500CA98B5 /* icon_gear.png in Resources */ = {isa = PBXBuildFile; fileRef = DA607092195D03E200CA98B5 /* icon_gear.png */; }; DA60717C195D040500CA98B5 /* icon_gear.png in Resources */ = {isa = PBXBuildFile; fileRef = DA607092195D03E200CA98B5 /* icon_gear.png */; };
DA60717D195D040500CA98B5 /* icon_gear@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA607093195D03E200CA98B5 /* icon_gear@2x.png */; }; DA60717D195D040500CA98B5 /* icon_gear@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA607093195D03E200CA98B5 /* icon_gear@2x.png */; };
DA6558A419A99609009A0BEB /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA6558A319A99609009A0BEB /* Images.xcassets */; }; DA6558A419A99609009A0BEB /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA6558A319A99609009A0BEB /* Images.xcassets */; };
@ -257,6 +257,11 @@
DA25090719513C1400AC23F1 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; DA25090719513C1400AC23F1 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
DA2509261951B86C00AC23F1 /* small-screen.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "small-screen.png"; sourceTree = "<group>"; }; DA2509261951B86C00AC23F1 /* small-screen.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "small-screen.png"; sourceTree = "<group>"; };
DA2509271951B86C00AC23F1 /* screen.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = screen.png; sourceTree = "<group>"; }; DA2509271951B86C00AC23F1 /* screen.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = screen.png; sourceTree = "<group>"; };
DA29992719C6A89900AF7DF1 /* MasterPassword 1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 1.xcdatamodel"; sourceTree = "<group>"; };
DA29992819C6A89900AF7DF1 /* MasterPassword 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 2.xcdatamodel"; sourceTree = "<group>"; };
DA29992919C6A89900AF7DF1 /* MasterPassword 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 3.xcdatamodel"; sourceTree = "<group>"; };
DA29992A19C6A89900AF7DF1 /* MasterPassword 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 4.xcdatamodel"; sourceTree = "<group>"; };
DA29992B19C6A89900AF7DF1 /* MasterPassword 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 5.xcdatamodel"; sourceTree = "<group>"; };
DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; }; DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; };
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>"; };
@ -320,10 +325,6 @@
DA5E5CC31724A667003798D8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; }; DA5E5CC31724A667003798D8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
DA5E5CC51724A667003798D8 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = "<group>"; }; DA5E5CC51724A667003798D8 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = "<group>"; };
DA5E5CC61724A667003798D8 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; DA5E5CC61724A667003798D8 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
DA5E5CC81724A667003798D8 /* MasterPassword 1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 1.xcdatamodel"; sourceTree = "<group>"; };
DA5E5CC91724A667003798D8 /* MasterPassword 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 2.xcdatamodel"; sourceTree = "<group>"; };
DA5E5CCA1724A667003798D8 /* MasterPassword 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 3.xcdatamodel"; sourceTree = "<group>"; };
DA5E5CCB1724A667003798D8 /* MasterPassword 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 4.xcdatamodel"; sourceTree = "<group>"; };
DA606FEA195D03E200CA98B5 /* icon_action.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_action.png; sourceTree = "<group>"; }; DA606FEA195D03E200CA98B5 /* icon_action.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_action.png; sourceTree = "<group>"; };
DA606FEB195D03E200CA98B5 /* icon_action@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_action@2x.png"; sourceTree = "<group>"; }; DA606FEB195D03E200CA98B5 /* icon_action@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_action@2x.png"; sourceTree = "<group>"; };
DA606FEC195D03E200CA98B5 /* icon_addressbook-person.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_addressbook-person.png"; sourceTree = "<group>"; }; DA606FEC195D03E200CA98B5 /* icon_addressbook-person.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_addressbook-person.png"; sourceTree = "<group>"; };
@ -1024,7 +1025,7 @@
DA5E5CAF1724A667003798D8 /* MPTypes.h */, DA5E5CAF1724A667003798D8 /* MPTypes.h */,
DA5E5CB01724A667003798D8 /* MPUserEntity.h */, DA5E5CB01724A667003798D8 /* MPUserEntity.h */,
DA5E5CB11724A667003798D8 /* MPUserEntity.m */, DA5E5CB11724A667003798D8 /* MPUserEntity.m */,
DA5E5CC71724A667003798D8 /* MasterPassword.xcdatamodeld */, DA29992619C6A89900AF7DF1 /* MasterPassword.xcdatamodeld */,
); );
name = ObjC; name = ObjC;
path = ..; path = ..;
@ -2146,6 +2147,7 @@
DA5E5CFD1724A667003798D8 /* MPElementEntity.m in Sources */, DA5E5CFD1724A667003798D8 /* MPElementEntity.m in Sources */,
DA5E5CFE1724A667003798D8 /* MPElementGeneratedEntity.m in Sources */, DA5E5CFE1724A667003798D8 /* MPElementGeneratedEntity.m in Sources */,
DA5E5CFF1724A667003798D8 /* MPElementStoredEntity.m in Sources */, DA5E5CFF1724A667003798D8 /* MPElementStoredEntity.m in Sources */,
DA29992C19C6A89900AF7DF1 /* MasterPassword.xcdatamodeld in Sources */,
DA3B8456190FC89700246EEA /* MPFixable.m in Sources */, DA3B8456190FC89700246EEA /* MPFixable.m in Sources */,
DA5E5D001724A667003798D8 /* MPEntities.m in Sources */, DA5E5D001724A667003798D8 /* MPEntities.m in Sources */,
DA5E5D011724A667003798D8 /* MPKey.m in Sources */, DA5E5D011724A667003798D8 /* MPKey.m in Sources */,
@ -2153,7 +2155,6 @@
DA5E5D031724A667003798D8 /* MPMacAppDelegate.m in Sources */, DA5E5D031724A667003798D8 /* MPMacAppDelegate.m in Sources */,
DA5E5D041724A667003798D8 /* MPMacConfig.m in Sources */, DA5E5D041724A667003798D8 /* MPMacConfig.m in Sources */,
DA5E5D0C1724A667003798D8 /* main.m in Sources */, DA5E5D0C1724A667003798D8 /* main.m in Sources */,
DA5E5D0D1724A667003798D8 /* MasterPassword.xcdatamodeld in Sources */,
93D39C5789EFA607CF788082 /* MPElementModel.m in Sources */, 93D39C5789EFA607CF788082 /* MPElementModel.m in Sources */,
93D39F833DEC1C89B2F795AC /* MPPasswordWindowController.m in Sources */, 93D39F833DEC1C89B2F795AC /* MPPasswordWindowController.m in Sources */,
93D390C676DF52DA7E459F19 /* MPPasswordWindow.m in Sources */, 93D390C676DF52DA7E459F19 /* MPPasswordWindow.m in Sources */,
@ -2782,15 +2783,16 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCVersionGroup section */ /* Begin XCVersionGroup section */
DA5E5CC71724A667003798D8 /* MasterPassword.xcdatamodeld */ = { DA29992619C6A89900AF7DF1 /* MasterPassword.xcdatamodeld */ = {
isa = XCVersionGroup; isa = XCVersionGroup;
children = ( children = (
DA5E5CC81724A667003798D8 /* MasterPassword 1.xcdatamodel */, DA29992719C6A89900AF7DF1 /* MasterPassword 1.xcdatamodel */,
DA5E5CC91724A667003798D8 /* MasterPassword 2.xcdatamodel */, DA29992819C6A89900AF7DF1 /* MasterPassword 2.xcdatamodel */,
DA5E5CCA1724A667003798D8 /* MasterPassword 3.xcdatamodel */, DA29992919C6A89900AF7DF1 /* MasterPassword 3.xcdatamodel */,
DA5E5CCB1724A667003798D8 /* MasterPassword 4.xcdatamodel */, DA29992A19C6A89900AF7DF1 /* MasterPassword 4.xcdatamodel */,
DA29992B19C6A89900AF7DF1 /* MasterPassword 5.xcdatamodel */,
); );
currentVersion = DA5E5CCB1724A667003798D8 /* MasterPassword 4.xcdatamodel */; currentVersion = DA29992B19C6A89900AF7DF1 /* MasterPassword 5.xcdatamodel */;
path = MasterPassword.xcdatamodeld; path = MasterPassword.xcdatamodeld;
sourceTree = "<group>"; sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel; versionGroupType = wrapper.xcdatamodel;

View File

@ -3,6 +3,6 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>_XCCurrentVersionName</key> <key>_XCCurrentVersionName</key>
<string>MasterPassword 4.xcdatamodel</string> <string>MasterPassword 5.xcdatamodel</string>
</dict> </dict>
</plist> </plist>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="6244" systemVersion="13E28" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="MPElementEntity" representedClassName="MPElementEntity" isAbstract="YES" syncable="YES">
<attribute name="content" optional="YES" transient="YES" attributeType="Transformable" syncable="YES"/>
<attribute name="lastUsed" attributeType="Date" indexed="YES" syncable="YES"/>
<attribute name="loginGenerated_" attributeType="Boolean" defaultValueString="NO" syncable="YES"/>
<attribute name="loginName" optional="YES" attributeType="String" elementID="A1B9F981-D33C-4BFE-9F94-C9D3E1F78E51" syncable="YES"/>
<attribute name="name" attributeType="String" minValueString="1" indexed="YES" syncable="YES"/>
<attribute name="requiresExplicitMigration_" attributeType="Boolean" defaultValueString="NO">
<userInfo/>
</attribute>
<attribute name="type_" attributeType="Integer 16" defaultValueString="17" syncable="YES"/>
<attribute name="uses_" attributeType="Integer 16" defaultValueString="0" indexed="YES" syncable="YES"/>
<attribute name="version_" attributeType="Integer 16" minValueString="0" defaultValueString="0" syncable="YES"/>
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements" inverseEntity="MPUserEntity" syncable="YES"/>
</entity>
<entity name="MPElementGeneratedEntity" representedClassName="MPElementGeneratedEntity" parentEntity="MPElementEntity" syncable="YES">
<attribute name="counter_" optional="YES" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
</entity>
<entity name="MPElementStoredEntity" representedClassName="MPElementStoredEntity" parentEntity="MPElementEntity" syncable="YES">
<attribute name="contentObject" optional="YES" attributeType="Transformable" storedInTruthFile="YES" syncable="YES"/>
</entity>
<entity name="MPUserEntity" representedClassName="MPUserEntity" syncable="YES">
<attribute name="avatar_" attributeType="Integer 16" defaultValueString="0" syncable="YES"/>
<attribute name="defaultType_" attributeType="Integer 16" defaultValueString="17" syncable="YES"/>
<attribute name="keyID" optional="YES" attributeType="Binary" syncable="YES"/>
<attribute name="lastUsed" optional="YES" attributeType="Date" syncable="YES"/>
<attribute name="name" attributeType="String" syncable="YES"/>
<attribute name="saveKey_" attributeType="Boolean" defaultValueString="NO">
<userInfo/>
</attribute>
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
</entity>
<elements>
<element name="MPElementEntity" positionX="-0" positionY="-286" width="128" height="193"/>
<element name="MPElementGeneratedEntity" positionX="216" positionY="-288" width="128" height="58"/>
<element name="MPElementStoredEntity" positionX="214" positionY="-171" width="128" height="58"/>
<element name="MPUserEntity" positionX="-218" positionY="-288" width="128" height="148"/>
</elements>
</model>

View File

@ -136,7 +136,7 @@
[_emergencyPasswordQueue addOperationWithBlock:^{ [_emergencyPasswordQueue addOperationWithBlock:^{
NSString *sitePassword = nil; NSString *sitePassword = nil;
if (_key && [siteName length]) if (_key && [siteName length])
sitePassword = [MPAlgorithmDefault generateContentNamed:siteName ofType:siteType withCounter:siteCounter usingKey:_key]; sitePassword = [MPAlgorithmDefault generatePasswordForSiteNamed:siteName ofType:siteType withCounter:siteCounter usingKey:_key];
PearlMainQueue( ^{ PearlMainQueue( ^{
[self.activity stopAnimating]; [self.activity stopAnimating];

View File

@ -23,7 +23,6 @@
@property (weak, nonatomic) IBOutlet UITextView *logView; @property (weak, nonatomic) IBOutlet UITextView *logView;
@property (weak, nonatomic) IBOutlet UISegmentedControl *levelControl; @property (weak, nonatomic) IBOutlet UISegmentedControl *levelControl;
- (IBAction)action:(id)sender;
- (IBAction)toggleLevelControl:(UISegmentedControl *)sender; - (IBAction)toggleLevelControl:(UISegmentedControl *)sender;
- (IBAction)refresh:(UIBarButtonItem *)sender; - (IBAction)refresh:(UIBarButtonItem *)sender;
- (IBAction)mail:(UIBarButtonItem *)sender; - (IBAction)mail:(UIBarButtonItem *)sender;

View File

@ -20,9 +20,7 @@
#import "MPiOSAppDelegate.h" #import "MPiOSAppDelegate.h"
#import "MPAppDelegate_Store.h" #import "MPAppDelegate_Store.h"
@implementation MPLogsViewController { @implementation MPLogsViewController
PearlOverlay *_switchCloudStoreProgress;
}
- (void)viewDidLoad { - (void)viewDidLoad {
@ -48,139 +46,6 @@
self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0; self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0;
} }
- (IBAction)action:(id)sender {
[PearlSheet showSheetWithTitle:@"Advanced Actions" viewStyle:UIActionSheetStyleAutomatic
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
if (buttonIndex == sheet.cancelButtonIndex)
return;
if (buttonIndex == sheet.firstOtherButtonIndex) {
// Switch
[PearlAlert showAlertWithTitle:@"Switching iCloud Store" message:
@"WARNING: This is an advanced operation and should only be done if you're having trouble with iCloud."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex_) {
if (buttonIndex_ == alert.cancelButtonIndex)
return;
_switchCloudStoreProgress = [PearlOverlay showProgressOverlayWithTitle:@"Enumerating Stores"];
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{
[self switchCloudStore];
} );
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil];
}
if (buttonIndex == sheet.firstOtherButtonIndex + 1) {
// Rebuild
[PearlAlert showAlertWithTitle:@"Rebuilding iCloud Store" message:
@"WARNING: This is an advanced operation and should only be done if you're having trouble with iCloud.\n"
@"Your local iCloud data will be removed and redownloaded from iCloud."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex_) {
if (buttonIndex_ == alert.cancelButtonIndex)
return;
[[MPiOSAppDelegate get].storeManager deleteCloudContainerLocalOnly:YES];
}
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil];
}
if (buttonIndex == sheet.firstOtherButtonIndex + 2) {
// Wipe
[PearlAlert showAlertWithTitle:@"Wiping iCloud Clean" message:
@"WARNING: This is an advanced operation and should only be done if you're having trouble with iCloud.\n"
@"All your iCloud data will be permanently lost. This is a clean slate!"
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex_) {
if (buttonIndex_ == alert.cancelButtonIndex)
return;
[[MPiOSAppDelegate get].storeManager deleteCloudContainerLocalOnly:NO];
}
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonContinue, nil];
}
} cancelTitle:[PearlStrings get].commonButtonCancel
destructiveTitle:nil otherTitles:@"Switch iCloud Store", @"Rebuild iCloud Container", @"Wipe iCloud Clean", nil];
}
- (void)switchCloudStore {
NSDictionary *cloudStores = [[MPiOSAppDelegate get].storeManager enumerateCloudStores];
if (!cloudStores) {
wrn( @"Failed enumerating cloud stores." );
return;
}
NSString *currentStoreUUID = nil;
NSMutableDictionary *stores = [NSMutableDictionary dictionary];
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *storePSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSFetchRequest *usersFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
NSFetchRequest *sitesFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
for (NSURL *cloudStoreURL in cloudStores) {
NSString *storeUUID = [[cloudStoreURL URLByDeletingPathExtension] lastPathComponent];
for (NSDictionary *cloudStoreOptions in cloudStores[cloudStoreURL]) {
NSError *error = nil;
NSPersistentStore *store = nil;
NSUInteger firstDash = [storeUUID rangeOfString:@"-" options:0].location;
NSString *storeDescription = strf( @"%@ v%@",
firstDash == NSNotFound? storeUUID: [storeUUID substringToIndex:firstDash],
cloudStoreOptions[USMCloudVersionKey] );
if ([cloudStoreOptions[USMCloudCurrentKey] boolValue])
currentStoreUUID = storeUUID;
@try {
if (!(store = [storePSC addPersistentStoreWithType:NSSQLiteStoreType configuration:nil
URL:cloudStoreURL options:cloudStoreOptions error:&error])) {
wrn(@"Couldn't describe store %@. While opening: %@", storeDescription, error);
continue;
}
NSUInteger userCount, siteCount;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
moc.persistentStoreCoordinator = storePSC;
if ((userCount = [moc countForFetchRequest:usersFetchRequest error:&error]) == NSNotFound) {
wrn(@"Couldn't describe store %@. While determining userCount: %@", storeDescription, error);
continue;
}
if ((siteCount = [moc countForFetchRequest:sitesFetchRequest error:&error]) == NSNotFound) {
wrn(@"Couldn't describe store %@. While determining siteCount: %@", storeDescription, error);
continue;
}
storeDescription = strf( @"%@: %luU, %luS", storeDescription, (unsigned long)userCount, (unsigned long)siteCount );
}
@catch (NSException *exception) {
wrn(@"Couldn't describe store %@: %@", storeDescription, exception);
}
@finally {
if (store && ![storePSC removePersistentStore:store error:&error]) {
wrn(@"Couldn't remove store %@: %@", storeDescription, error);
storePSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
}
stores[storeDescription] = cloudStoreOptions;
}
}
}
PearlArrayTVC *vc = [[PearlArrayTVC alloc] initWithStyle:UITableViewStylePlain];
NSUInteger firstDash = [currentStoreUUID rangeOfString:@"-" options:0].location;
vc.title = strf( @"Active: %@", firstDash == NSNotFound? currentStoreUUID: [currentStoreUUID substringToIndex:firstDash] );
[stores enumerateKeysAndObjectsUsingBlock:^(id storeDescription, id cloudStoreOptions, BOOL *stop) {
[vc addRowWithName:storeDescription style:PearlArrayTVCRowStyleLink toggled:[cloudStoreOptions[USMCloudCurrentKey] boolValue]
toSection:@"Cloud Stores" activationBlock:^BOOL(BOOL wasToggled) {
[[MPiOSAppDelegate get].storeManager switchToCloudStoreWithOptions:cloudStoreOptions];
[self.navigationController popToRootViewControllerAnimated:YES];
return YES;
}];
}];
dispatch_async( dispatch_get_main_queue(), ^{
[_switchCloudStoreProgress cancelOverlayAnimated:YES];
[self.navigationController pushViewController:vc animated:YES];
} );
}
- (IBAction)toggleLevelControl:(UISegmentedControl *)sender { - (IBAction)toggleLevelControl:(UISegmentedControl *)sender {
BOOL traceEnabled = (BOOL)self.levelControl.selectedSegmentIndex; BOOL traceEnabled = (BOOL)self.levelControl.selectedSegmentIndex;

View File

@ -19,6 +19,7 @@
#import "MPPasswordCell.h" #import "MPPasswordCell.h"
#import "MPiOSAppDelegate.h" #import "MPiOSAppDelegate.h"
#import "MPAppDelegate_Store.h" #import "MPAppDelegate_Store.h"
#import "UIColor+Expanded.h"
@interface MPPasswordCell() @interface MPPasswordCell()
@ -167,6 +168,11 @@
UICollectionView *collectionView = [UICollectionView findAsSuperviewOf:self]; UICollectionView *collectionView = [UICollectionView findAsSuperviewOf:self];
[collectionView scrollToItemAtIndexPath:[collectionView indexPathForCell:self] [collectionView scrollToItemAtIndexPath:[collectionView indexPathForCell:self]
atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES]; atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
if (textField == self.loginNameField)
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
if (![[self elementInContext:mainContext].loginName length])
self.loginNameField.text = nil;
}];
} }
- (IBAction)textFieldDidChange:(UITextField *)textField { - (IBAction)textFieldDidChange:(UITextField *)textField {
@ -199,7 +205,7 @@
return; return;
if (textField == self.passwordField) { if (textField == self.passwordField) {
if ([element.algorithm saveContent:text toElement:element usingKey:[MPiOSAppDelegate get].key]) if ([element.algorithm savePassword:text toElement:element usingKey:[MPiOSAppDelegate get].key])
[PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2]; [PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2];
} }
else if (textField == self.loginNameField && ![text isEqualToString:element.loginName]) { else if (textField == self.loginNameField && ![text isEqualToString:element.loginName]) {
@ -398,7 +404,12 @@
}]; }];
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
[self copyLoginOfElement:[self elementInContext:context] saveInContext:context]; MPElementEntity *element = [self elementInContext:context];
if (![self copyLoginOfElement:element saveInContext:context]) {
element.loginGenerated = YES;
[context saveToStore];
[self updateAnimated:YES];
}
PearlMainQueueAfter( .3f, ^{ PearlMainQueueAfter( .3f, ^{
[UIView animateWithDuration:.2f animations:^{ [UIView animateWithDuration:.2f animations:^{
@ -434,7 +445,9 @@
// UI // UI
self.upgradeButton.alpha = mainElement.requiresExplicitMigration? 1: 0; self.upgradeButton.alpha = mainElement.requiresExplicitMigration? 1: 0;
self.loginNameContainer.alpha = [mainElement.loginName length] || self.mode == MPPasswordCellModeSettings? 1: 0; self.loginNameContainer.alpha = self.mode == MPPasswordCellModeSettings ||
mainElement.loginGenerated || [mainElement.loginName length]? 0.7f: 0;
self.loginNameField.textColor = [UIColor colorWithHexString:[mainElement.loginName length]? @"6D5E63": @"5E636D"];
self.modeButton.alpha = self.transientSite? 0: self.mode == MPPasswordCellModePassword? 0.1f: 0.5f; self.modeButton.alpha = self.transientSite? 0: self.mode == MPPasswordCellModePassword? 0.1f: 0.5f;
self.counterLabel.alpha = self.counterButton.alpha = mainElement.type & MPElementTypeClassGenerated? 0.5f: 0; self.counterLabel.alpha = self.counterButton.alpha = mainElement.type & MPElementTypeClassGenerated? 0.5f: 0;
self.modeButton.selected = self.mode == MPPasswordCellModeSettings; self.modeButton.selected = self.mode == MPPasswordCellModeSettings;
@ -464,23 +477,27 @@
NSForegroundColorAttributeName : [UIColor whiteColor] NSForegroundColorAttributeName : [UIColor whiteColor]
} ); } );
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
NSString *password; MPElementEntity *element = [self elementInContext:context];
MPKey *key = [MPiOSAppDelegate get].key;
NSString *password, *loginName = [element resolveLoginUsingKey:key];
if (self.transientSite) if (self.transientSite)
password = [MPAlgorithmDefault generateContentNamed:self.transientSite ofType: password = [MPAlgorithmDefault generatePasswordForSiteNamed:self.transientSite ofType:
[[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPElementTypeGeneratedLong [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPElementTypeGeneratedLong
withCounter:1 usingKey:[MPiOSAppDelegate get].key]; withCounter:1 usingKey:key];
else else {
password = [[self elementInContext:context] resolveContentUsingKey:[MPiOSAppDelegate get].key]; password = [element resolvePasswordUsingKey:key];
}
TimeToCrack timeToCrack; TimeToCrack timeToCrack;
NSString *timeToCrackString = nil; NSString *timeToCrackString = nil;
id<MPAlgorithm> algorithm = mainElement.algorithm?: MPAlgorithmDefault; id<MPAlgorithm> algorithm = mainElement.algorithm?: MPAlgorithmDefault;
MPAttacker attackHardware = [[MPConfig get].siteAttacker unsignedIntegerValue]; MPAttacker attackHardware = [[MPConfig get].siteAttacker unsignedIntegerValue];
if ([algorithm timeToCrack:&timeToCrack passwordOfType:[self elementInContext:context].type byAttacker:attackHardware] || if ([algorithm timeToCrack:&timeToCrack passwordOfType:element.type byAttacker:attackHardware] ||
[algorithm timeToCrack:&timeToCrack passwordString:password byAttacker:attackHardware]) [algorithm timeToCrack:&timeToCrack passwordString:password byAttacker:attackHardware])
timeToCrackString = NSStringFromTimeToCrack( timeToCrack ); timeToCrackString = NSStringFromTimeToCrack( timeToCrack );
PearlMainQueue( ^{ PearlMainQueue( ^{
self.loginNameField.text = loginName;
self.passwordField.text = password; self.passwordField.text = password;
self.strengthLabel.text = timeToCrackString; self.strengthLabel.text = timeToCrackString;
@ -504,8 +521,7 @@
self.counterLabel.text = strf( @"%lu", (unsigned long)((MPElementGeneratedEntity *)mainElement).counter ); self.counterLabel.text = strf( @"%lu", (unsigned long)((MPElementGeneratedEntity *)mainElement).counter );
// Site Login Name // Site Login Name
self.loginNameField.text = mainElement.loginName; self.loginNameField.attributedPlaceholder = stra( self.loginNameField.placeholder, @{
self.loginNameField.attributedPlaceholder = stra( strl( @"Set login name" ), @{
NSForegroundColorAttributeName : [UIColor whiteColor] NSForegroundColorAttributeName : [UIColor whiteColor]
} ); } );
self.loginNameField.enabled = self.passwordField.enabled = // self.loginNameField.enabled = self.passwordField.enabled = //
@ -515,12 +531,12 @@
}]; }];
} }
- (void)copyContentOfElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context { - (BOOL)copyContentOfElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context {
inf( @"Copying password for: %@", element.name ); inf( @"Copying password for: %@", element.name );
NSString *password = [element resolveContentUsingKey:[MPAppDelegate_Shared get].key]; NSString *password = [element resolvePasswordUsingKey:[MPAppDelegate_Shared get].key];
if (![password length]) if (![password length])
return; return NO;
PearlMainQueue( ^{ PearlMainQueue( ^{
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Password Copied" ) dismissAfter:2]; [PearlOverlay showTemporaryOverlayWithTitle:strl( @"Password Copied" ) dismissAfter:2];
@ -529,14 +545,15 @@
[element use]; [element use];
[context saveToStore]; [context saveToStore];
return YES;
} }
- (void)copyLoginOfElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context { - (BOOL)copyLoginOfElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context {
inf( @"Copying login for: %@", element.name ); inf( @"Copying login for: %@", element.name );
NSString *loginName = element.loginName; NSString *loginName = [element.algorithm resolveLoginForElement:element usingKey:[MPiOSAppDelegate get].key];
if (![loginName length]) if (![loginName length])
return; return NO;
PearlMainQueue( ^{ PearlMainQueue( ^{
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Login Name Copied" ) dismissAfter:2]; [PearlOverlay showTemporaryOverlayWithTitle:strl( @"Login Name Copied" ) dismissAfter:2];
@ -545,6 +562,7 @@
[element use]; [element use];
[context saveToStore]; [context saveToStore];
return YES;
} }
- (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context { - (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context {

View File

@ -119,7 +119,7 @@ referenceSizeForHeaderInSection:(NSInteger)section {
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
if (![MPiOSAppDelegate get].activeUserOID) if (![MPiOSAppDelegate get].activeUserOID || !_fetchedResultsController)
return 0; return 0;
NSUInteger objects = ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[section]).numberOfObjects; NSUInteger objects = ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[section]).numberOfObjects;
@ -283,7 +283,7 @@ referenceSizeForHeaderInSection:(NSInteger)section {
_fetchedResultsController = nil; _fetchedResultsController = nil;
self.passwordsSearchBar.text = nil; self.passwordsSearchBar.text = nil;
[self updatePasswords]; [self.passwordCollectionView reloadData];
}], }],
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationDidBecomeActiveNotification object:nil addObserverForName:UIApplicationDidBecomeActiveNotification object:nil
@ -324,18 +324,19 @@ referenceSizeForHeaderInSection:(NSInteger)section {
}]; }];
if (!_storeChangingObserver) if (!_storeChangingObserver)
_storeChangingObserver = [[NSNotificationCenter defaultCenter] _storeChangingObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:USMStoreWillChangeNotification object:nil addObserverForName:NSPersistentStoreCoordinatorStoresWillChangeNotification object:nil
queue:nil usingBlock:^(NSNotification *note) {
Strongify( self );
if (self->_mocObserver)
[[NSNotificationCenter defaultCenter] removeObserver:self->_mocObserver];
}];
if (!_storeChangedObserver)
_storeChangedObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:USMStoreDidChangeNotification object:nil
queue:nil usingBlock:^(NSNotification *note) { queue:nil usingBlock:^(NSNotification *note) {
Strongify( self ); Strongify( self );
self->_fetchedResultsController = nil; self->_fetchedResultsController = nil;
if (self->_mocObserver)
[[NSNotificationCenter defaultCenter] removeObserver:self->_mocObserver];
[self.passwordCollectionView reloadData];
}];
if (!_storeChangedObserver)
_storeChangedObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:NSPersistentStoreCoordinatorStoresDidChangeNotification object:nil
queue:nil usingBlock:^(NSNotification *note) {
Strongify( self );
[self updatePasswords]; [self updatePasswords];
}]; }];
} }
@ -418,6 +419,7 @@ referenceSizeForHeaderInSection:(NSInteger)section {
- (NSFetchedResultsController *)fetchedResultsController { - (NSFetchedResultsController *)fetchedResultsController {
if (!_fetchedResultsController) { if (!_fetchedResultsController) {
_showTransientItem = NO;
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) { [MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )]; NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
fetchRequest.sortDescriptors = @[ fetchRequest.sortDescriptors = @[

View File

@ -80,7 +80,7 @@
counter = ((MPElementGeneratedEntity *)selectedElement).counter; counter = ((MPElementGeneratedEntity *)selectedElement).counter;
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{ dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{
NSString *typeContent = [MPAlgorithmDefault generateContentNamed:name ofType:cellType NSString *typeContent = [MPAlgorithmDefault generatePasswordForSiteNamed:name ofType:cellType
withCounter:counter usingKey:[MPiOSAppDelegate get].key]; withCounter:counter usingKey:[MPiOSAppDelegate get].key];
dispatch_async( dispatch_get_main_queue(), ^{ dispatch_async( dispatch_get_main_queue(), ^{

View File

@ -654,15 +654,16 @@ referenceSizeForFooterInSection:(NSInteger)section {
}]; }];
if (!_storeChangingObserver) if (!_storeChangingObserver)
_storeChangingObserver = [[NSNotificationCenter defaultCenter] _storeChangingObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:USMStoreWillChangeNotification object:nil addObserverForName:NSPersistentStoreCoordinatorStoresWillChangeNotification object:nil
queue:nil usingBlock:^(NSNotification *note) { queue:nil usingBlock:^(NSNotification *note) {
Strongify( self ); Strongify( self );
if (self->_mocObserver) if (self->_mocObserver)
[[NSNotificationCenter defaultCenter] removeObserver:self->_mocObserver]; [[NSNotificationCenter defaultCenter] removeObserver:self->_mocObserver];
self.userIDs = nil;
}]; }];
if (!_storeChangedObserver) if (!_storeChangedObserver)
_storeChangedObserver = [[NSNotificationCenter defaultCenter] _storeChangedObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:USMStoreDidChangeNotification object:nil addObserverForName:NSPersistentStoreCoordinatorStoresDidChangeNotification object:nil
queue:nil usingBlock:^(NSNotification *note) { queue:nil usingBlock:^(NSNotification *note) {
Strongify( self ); Strongify( self );
[self reloadUsers]; [self reloadUsers];
@ -683,7 +684,7 @@ referenceSizeForFooterInSection:(NSInteger)section {
[self afterUpdatesMainQueue:^{ [self afterUpdatesMainQueue:^{
[self observeStore]; [self observeStore];
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) { if (![MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
NSError *error = nil; NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )]; NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
fetchRequest.sortDescriptors = @[ fetchRequest.sortDescriptors = @[
@ -699,7 +700,8 @@ referenceSizeForFooterInSection:(NSInteger)section {
for (MPUserEntity *user in users) for (MPUserEntity *user in users)
[userIDs addObject:user.objectID]; [userIDs addObject:user.objectID];
self.userIDs = userIDs; self.userIDs = userIDs;
}]; }])
self.userIDs = nil;
}]; }];
} }

View File

@ -26,7 +26,7 @@
if ([self class] == [MPiOSAppDelegate class]) { if ([self class] == [MPiOSAppDelegate class]) {
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo; [PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
#ifdef DEBUG #ifdef DEBUG
[PearlLogger get].printLevel = PearlLogLevelDebug; //Trace; [PearlLogger get].printLevel = PearlLogLevelTrace;
#else #else
[PearlLogger get].printLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelDebug: PearlLogLevelInfo; [PearlLogger get].printLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelDebug: PearlLogLevelInfo;
#endif #endif
@ -455,73 +455,6 @@
- (void)updateConfigKey:(NSString *)key { - (void)updateConfigKey:(NSString *)key {
// iCloud enabled / disabled
BOOL iCloudEnabled = [[MPiOSConfig get].iCloudEnabled boolValue];
BOOL cloudEnabled = self.storeManager.cloudEnabled;
if (iCloudEnabled != cloudEnabled) {
if ([[MPiOSConfig get].iCloudEnabled boolValue])
[self.storeManager setCloudEnabledAndOverwriteCloudWithLocalIfConfirmed:^(void (^setConfirmationAnswer)(BOOL answer)) {
__block NSUInteger siteCount = NSNotFound;
[MPAppDelegate_Shared managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
NSError *error = nil;
if ((siteCount = [context countForFetchRequest:fetchRequest error:&error]) == NSNotFound) {
wrn( @"Couldn't count current sites: %@", error );
return;
}
}];
// If we currently have no sites, don't bother asking to copy them.
if (siteCount == 0) {
setConfirmationAnswer( NO );
return;
}
// The current store has sites, ask the user if he wants to copy them to the cloud
[PearlAlert showAlertWithTitle:@"Copy Sites To iCloud?"
message:@"You can either switch to your old iCloud sites "
@"or overwrite them with your current sites."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex])
setConfirmationAnswer( NO );
if (buttonIndex == [alert firstOtherButtonIndex])
setConfirmationAnswer( YES );
}
cancelTitle:@"Use Old" otherTitles:@"Overwrite", nil];
}];
else
[self.storeManager setCloudDisabledAndOverwriteLocalWithCloudIfConfirmed:^(void (^setConfirmationAnswer)(BOOL answer)) {
__block NSUInteger siteCount = NSNotFound;
[MPAppDelegate_Shared managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
NSError *error = nil;
if ((siteCount = [context countForFetchRequest:fetchRequest error:&error]) == NSNotFound) {
wrn( @"Couldn't count current sites: %@", error );
return;
}
}];
// If we currently have no sites, don't bother asking to copy them.
if (siteCount == 0) {
setConfirmationAnswer( NO );
return;
}
[PearlAlert showAlertWithTitle:@"Copy iCloud Sites?"
message:@"You can either switch to the old sites on your device "
@"or overwrite them with your current iCloud sites."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex])
setConfirmationAnswer( NO );
if (buttonIndex == [alert firstOtherButtonIndex])
setConfirmationAnswer( YES );
}
cancelTitle:@"Use Old" otherTitles:@"Overwrite", nil];
}];
}
// Trace mode // Trace mode
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo; [PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
@ -532,21 +465,18 @@
#ifdef CRASHLYTICS #ifdef CRASHLYTICS
[[Crashlytics sharedInstance] setBoolValue:[[MPConfig get].rememberLogin boolValue] forKey:@"rememberLogin"]; [[Crashlytics sharedInstance] setBoolValue:[[MPConfig get].rememberLogin boolValue] forKey:@"rememberLogin"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].iCloudEnabled boolValue] forKey:@"iCloudEnabled"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].sendInfo boolValue] forKey:@"sendInfo"]; [[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].sendInfo boolValue] forKey:@"sendInfo"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].helpHidden boolValue] forKey:@"helpHidden"]; [[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].helpHidden boolValue] forKey:@"helpHidden"];
[[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].showSetup boolValue] forKey:@"showQuickStart"]; [[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].showSetup boolValue] forKey:@"showQuickStart"];
[[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].firstRun boolValue] forKey:@"firstRun"]; [[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].firstRun boolValue] forKey:@"firstRun"];
[[Crashlytics sharedInstance] setIntValue:[[PearlConfig get].launchCount intValue] forKey:@"launchCount"]; [[Crashlytics sharedInstance] setIntValue:[[PearlConfig get].launchCount intValue] forKey:@"launchCount"];
[[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].askForReviews boolValue] forKey:@"askForReviews"]; [[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].askForReviews boolValue] forKey:@"askForReviews"];
[[Crashlytics sharedInstance] [[Crashlytics sharedInstance] setIntValue:[[PearlConfig get].reviewAfterLaunches intValue] forKey:@"reviewAfterLaunches"];
setIntValue:[[PearlConfig get].reviewAfterLaunches intValue] forKey:@"reviewAfterLaunches"];
[[Crashlytics sharedInstance] setObjectValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"]; [[Crashlytics sharedInstance] setObjectValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"];
#endif #endif
MPCheckpoint( MPCheckpointConfig, @{ MPCheckpoint( MPCheckpointConfig, @{
@"rememberLogin" : @([[MPConfig get].rememberLogin boolValue]), @"rememberLogin" : @([[MPConfig get].rememberLogin boolValue]),
@"iCloudEnabled" : @([[MPiOSConfig get].iCloudEnabled boolValue]),
@"sendInfo" : @([[MPiOSConfig get].sendInfo boolValue]), @"sendInfo" : @([[MPiOSConfig get].sendInfo boolValue]),
@"helpHidden" : @([[MPiOSConfig get].helpHidden boolValue]), @"helpHidden" : @([[MPiOSConfig get].helpHidden boolValue]),
@"showQuickStart" : @([[MPiOSConfig get].showSetup boolValue]), @"showQuickStart" : @([[MPiOSConfig get].showSetup boolValue]),
@ -559,123 +489,6 @@
} }
} }
#pragma mark - UbiquityStoreManager
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager willLoadStoreIsCloud:(BOOL)isCloudStore {
dispatch_async( dispatch_get_main_queue(), ^{
[self signOutAnimated:YES];
[self.handleCloudContentAlert cancelAlertAnimated:YES];
if (!self.storeLoadingOverlay)
self.storeLoadingOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Loading Sites"];
} );
[super ubiquityStoreManager:manager willLoadStoreIsCloud:isCloudStore];
}
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didLoadStoreForCoordinator:(NSPersistentStoreCoordinator *)coordinator
isCloud:(BOOL)isCloudStore {
[MPiOSConfig get].iCloudEnabled = @(isCloudStore);
[super ubiquityStoreManager:manager didLoadStoreForCoordinator:coordinator isCloud:isCloudStore];
[self.handleCloudContentAlert cancelAlertAnimated:YES];
[self.fixCloudContentAlert cancelAlertAnimated:YES];
[self.storeLoadingOverlay cancelOverlayAnimated:YES];
[self.handleCloudDisabledAlert cancelAlertAnimated:YES];
if (isCloudStore)
[PearlAlert showAlertWithTitle:@"iCloud Support Deprecated" message:
@"Master Password is moving away from iCloud due to limited platform support and reliability issues. "
@"\n\nMaster Password's generated passwords do not require syncing. "
@"Your sites will always have the same passwords on all your devices, even without iCloud. "
@"\n\niCloud continues to work for now but will be deactivated in a future update. "
@"Disable iCloud now to copy your iCloud sites to your device and avoid having to recreate them "
@"when iCloud becomes discontinued."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex])
return;
if (buttonIndex == [alert firstOtherButtonIndex])
[UIApp openURL:[NSURL URLWithString:
@"http://support.lyndir.com/topic/486731-why-doesnt-the-mac-version-have-icloud-support/#comment-755394"]];
if (buttonIndex == [alert firstOtherButtonIndex] + 1)
[MPiOSConfig get].iCloudEnabled = @NO;
}
cancelTitle:@"Ignore For Now" otherTitles:@"Why?", @"Disable iCloud", nil];
}
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager failedLoadingStoreWithCause:(UbiquityStoreErrorCause)cause context:(id)context
wasCloud:(BOOL)wasCloudStore {
[self.storeLoadingOverlay cancelOverlayAnimated:YES];
[self.handleCloudDisabledAlert cancelAlertAnimated:YES];
}
- (BOOL)ubiquityStoreManager:(UbiquityStoreManager *)manager handleCloudContentCorruptionWithHealthyStore:(BOOL)storeHealthy {
if (manager.cloudEnabled && !storeHealthy && !(self.handleCloudContentAlert || self.fixCloudContentAlert)) {
[self.storeLoadingOverlay cancelOverlayAnimated:YES];
[self.handleCloudDisabledAlert cancelAlertAnimated:YES];
[self showCloudContentAlert];
};
return NO;
}
- (BOOL)ubiquityStoreManagerHandleCloudDisabled:(UbiquityStoreManager *)manager {
if (!self.handleCloudDisabledAlert)
self.handleCloudDisabledAlert = [PearlAlert showAlertWithTitle:@"iCloud Login" message:
@"You haven't added an iCloud account to your device yet.\n"
@"To add one, go into Apple's Settings -> iCloud."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == alert.firstOtherButtonIndex) {
[MPiOSConfig get].iCloudEnabled = @NO;
return;
}
[self.storeManager reloadStore];
} cancelTitle:@"Try Again" otherTitles:@"Disable iCloud", nil];
return YES;
}
- (void)showCloudContentAlert {
__weak MPiOSAppDelegate *wSelf = self;
[self.handleCloudContentAlert cancelAlertAnimated:NO];
// TODO: Add the activity indicator back.
self.handleCloudContentAlert = [PearlAlert showAlertWithTitle:@"iCloud Sync Problem"
message:@"Waiting for your other device to autocorrect the problem..."
viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:
^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert firstOtherButtonIndex])
wSelf.fixCloudContentAlert = [PearlAlert showAlertWithTitle:@"Fix iCloud Now" message:
@"This problem can be autocorrected by opening the app on another device where you recently made changes.\n"
@"You can fix the problem from this device anyway, but recent changes from another device might get lost.\n\n"
@"You can also turn iCloud off for now."
viewStyle:UIAlertViewStyleDefault
initAlert:nil tappedButtonBlock:
^(UIAlertView *alert_, NSInteger buttonIndex_) {
if (buttonIndex_ == alert_.cancelButtonIndex)
[wSelf showCloudContentAlert];
if (buttonIndex_ == [alert_ firstOtherButtonIndex])
[wSelf.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:YES];
if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 1)
[MPiOSConfig get].iCloudEnabled = @NO;
}
cancelTitle:[PearlStrings get].commonButtonBack
otherTitles:@"Fix Anyway",
@"Turn Off", nil];
if (buttonIndex == [alert firstOtherButtonIndex] + 1)
[MPiOSConfig get].iCloudEnabled = @NO;
} cancelTitle:nil otherTitles:@"Fix Now", @"Turn Off", nil];
}
#pragma mark - Crashlytics #pragma mark - Crashlytics
- (NSDictionary *)crashlyticsInfo { - (NSDictionary *)crashlyticsInfo {

View File

@ -17,7 +17,6 @@
@property(nonatomic, retain) NSNumber *typeTipShown; @property(nonatomic, retain) NSNumber *typeTipShown;
@property(nonatomic, retain) NSNumber *loginNameTipShown; @property(nonatomic, retain) NSNumber *loginNameTipShown;
@property(nonatomic, retain) NSNumber *traceMode; @property(nonatomic, retain) NSNumber *traceMode;
@property(nonatomic, retain) NSNumber *iCloudEnabled;
@property(nonatomic, retain) NSNumber *dictationSearch; @property(nonatomic, retain) NSNumber *dictationSearch;
@end @end

View File

@ -8,7 +8,7 @@
@implementation MPiOSConfig @implementation MPiOSConfig
@dynamic helpHidden, siteInfoHidden, showSetup, actionsTipShown, typeTipShown, loginNameTipShown, traceMode, iCloudEnabled, dictationSearch; @dynamic helpHidden, siteInfoHidden, showSetup, actionsTipShown, typeTipShown, loginNameTipShown, traceMode, dictationSearch;
- (id)init { - (id)init {
@ -24,7 +24,6 @@
NSStringFromSelector( @selector(typeTipShown) ) : @(!self.firstRun), NSStringFromSelector( @selector(typeTipShown) ) : @(!self.firstRun),
NSStringFromSelector( @selector(loginNameTipShown) ) : @NO, NSStringFromSelector( @selector(loginNameTipShown) ) : @NO,
NSStringFromSelector( @selector(traceMode) ) : @NO, NSStringFromSelector( @selector(traceMode) ) : @NO,
NSStringFromSelector( @selector(iCloudEnabled) ) : @NO,
NSStringFromSelector( @selector(dictationSearch) ) : @NO NSStringFromSelector( @selector(dictationSearch) ) : @NO
}]; }];

View File

@ -33,7 +33,6 @@
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 */; };
93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; }; 93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; };
93D399BBC0A7EC746CB1B19B /* MPLogsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D391943675426839501BB8 /* MPLogsViewController.h */; };
93D39A53D76CA70786423458 /* UICollectionView+PearlReloadFromArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadFromArray.h */; }; 93D39A53D76CA70786423458 /* UICollectionView+PearlReloadFromArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadFromArray.h */; };
93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */; }; 93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */; };
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D8A953779B35403AF6E /* PearlUICollectionView.m */; }; 93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D8A953779B35403AF6E /* PearlUICollectionView.m */; };
@ -108,8 +107,6 @@
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 */; }; 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 */; };
DA4425CC1557BED40052177D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DA44260A1557D9E40052177D /* libUbiquityStoreManager.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */; };
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 */; };
DA45224719062899008F650A /* icon_settings.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38141711E29600CF925C /* icon_settings.png */; }; DA45224719062899008F650A /* icon_settings.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38141711E29600CF925C /* icon_settings.png */; };
@ -234,12 +231,8 @@
DABD3C011711E2DC00CF925C /* MPAppDelegate_Shared.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BA91711E2DC00CF925C /* MPAppDelegate_Shared.m */; }; DABD3C011711E2DC00CF925C /* MPAppDelegate_Shared.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BA91711E2DC00CF925C /* MPAppDelegate_Shared.m */; };
DABD3C021711E2DC00CF925C /* MPAppDelegate_Store.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BAB1711E2DC00CF925C /* MPAppDelegate_Store.m */; }; DABD3C021711E2DC00CF925C /* MPAppDelegate_Store.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BAB1711E2DC00CF925C /* MPAppDelegate_Store.m */; };
DABD3C031711E2DC00CF925C /* MPConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BAD1711E2DC00CF925C /* MPConfig.m */; }; DABD3C031711E2DC00CF925C /* MPConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BAD1711E2DC00CF925C /* MPConfig.m */; };
DABD3C041711E2DC00CF925C /* MPElementEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BAF1711E2DC00CF925C /* MPElementEntity.m */; };
DABD3C051711E2DC00CF925C /* MPElementGeneratedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BB11711E2DC00CF925C /* MPElementGeneratedEntity.m */; };
DABD3C061711E2DC00CF925C /* MPElementStoredEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BB31711E2DC00CF925C /* MPElementStoredEntity.m */; };
DABD3C071711E2DC00CF925C /* MPEntities.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BB51711E2DC00CF925C /* MPEntities.m */; }; DABD3C071711E2DC00CF925C /* MPEntities.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BB51711E2DC00CF925C /* MPEntities.m */; };
DABD3C081711E2DC00CF925C /* MPKey.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BB71711E2DC00CF925C /* MPKey.m */; }; DABD3C081711E2DC00CF925C /* MPKey.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BB71711E2DC00CF925C /* MPKey.m */; };
DABD3C091711E2DC00CF925C /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BBA1711E2DC00CF925C /* MPUserEntity.m */; };
DABD3C141711E2DC00CF925C /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BD01711E2DC00CF925C /* MasterPassword.xcdatamodeld */; }; DABD3C141711E2DC00CF925C /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BD01711E2DC00CF925C /* MasterPassword.xcdatamodeld */; };
DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BD91711E2DC00CF925C /* MPiOSAppDelegate.m */; }; DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BD91711E2DC00CF925C /* MPiOSAppDelegate.m */; };
DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BE71711E2DC00CF925C /* MPGuideViewController.m */; }; DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BE71711E2DC00CF925C /* MPGuideViewController.m */; };
@ -260,10 +253,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 */; };
DACA22BB1705DE7D002C6C22 /* UbiquityStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA22B71705DE7D002C6C22 /* UbiquityStoreManager.m */; };
DACA22BC1705DE7D002C6C22 /* NSError+UbiquityStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */; };
DACA22BD1705DE7D002C6C22 /* NSError+UbiquityStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA22B91705DE7D002C6C22 /* NSError+UbiquityStoreManager.m */; };
DACA22BE1705DE7D002C6C22 /* UbiquityStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA22BA1705DE7D002C6C22 /* UbiquityStoreManager.h */; };
DACA296F1705DF81002C6C22 /* Crashlytics.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA269A1705DF81002C6C22 /* Crashlytics.plist */; }; DACA296F1705DF81002C6C22 /* Crashlytics.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA269A1705DF81002C6C22 /* Crashlytics.plist */; };
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA29711705E1A8002C6C22 /* ciphers.plist */; }; 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 */; };
@ -279,6 +268,10 @@
DACE2F6D19BA6A2A0010F92E /* PearlMutableStaticTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */; }; DACE2F6D19BA6A2A0010F92E /* PearlMutableStaticTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */; };
DACE2F6E19BA6A2A0010F92E /* UIView+FontScale.h in Headers */ = {isa = PBXBuildFile; fileRef = DACE2F6A19BA6A2A0010F92E /* UIView+FontScale.h */; }; DACE2F6E19BA6A2A0010F92E /* UIView+FontScale.h in Headers */ = {isa = PBXBuildFile; fileRef = DACE2F6A19BA6A2A0010F92E /* UIView+FontScale.h */; };
DAD312C21552A22700A3F9ED /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD312C01552A20800A3F9ED /* libsqlite3.dylib */; }; DAD312C21552A22700A3F9ED /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD312C01552A20800A3F9ED /* libsqlite3.dylib */; };
DADB4EC719C66FB60065A78D /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DADB4EC619C66FB60065A78D /* MPUserEntity.m */; };
DADB4ECA19C66FB60065A78D /* MPElementEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DADB4EC919C66FB60065A78D /* MPElementEntity.m */; };
DADB4ECD19C66FB60065A78D /* MPElementGeneratedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DADB4ECC19C66FB60065A78D /* MPElementGeneratedEntity.m */; };
DADB4ED019C66FB70065A78D /* MPElementStoredEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DADB4ECF19C66FB70065A78D /* MPElementStoredEntity.m */; };
DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DAE1EF2417E942DE00BC0086 /* Localizable.strings */; }; DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DAE1EF2417E942DE00BC0086 /* Localizable.strings */; };
DAEBC45314F6364500987BF6 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; }; DAEBC45314F6364500987BF6 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
DAEC85B518E3DD9A007FC0DF /* UIView+Touches.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */; }; DAEC85B518E3DD9A007FC0DF /* UIView+Touches.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */; };
@ -496,7 +489,6 @@
DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; 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>"; };
DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libUbiquityStoreManager.a; sourceTree = BUILT_PRODUCTS_DIR; };
DA5A09DD171A70E4005284AB /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = "<group>"; }; DA5A09DD171A70E4005284AB /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = "<group>"; };
DA5A09DE171A70E4005284AB /* play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play@2x.png"; sourceTree = "<group>"; }; DA5A09DE171A70E4005284AB /* play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play@2x.png"; sourceTree = "<group>"; };
DA5A09E8171BB0F7005284AB /* unlocked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unlocked.png; sourceTree = "<group>"; }; DA5A09E8171BB0F7005284AB /* unlocked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unlocked.png; sourceTree = "<group>"; };
@ -507,6 +499,7 @@
DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
DA5BFA4E147E415C00F98B1E /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; DA5BFA4E147E415C00F98B1E /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
DA5E5C3C1723681B003798D8 /* Square-bottom.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Square-bottom.png"; path = "Dividers/Square-bottom.png"; sourceTree = "<group>"; }; DA5E5C3C1723681B003798D8 /* Square-bottom.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Square-bottom.png"; path = "Dividers/Square-bottom.png"; sourceTree = "<group>"; };
DA62140919C66A9700375240 /* MasterPassword 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 5.xcdatamodel"; sourceTree = "<group>"; };
DA6701B716406A4100B61001 /* Accounts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; }; DA6701B716406A4100B61001 /* Accounts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; };
DA6701DD16406B7300B61001 /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; }; DA6701DD16406B7300B61001 /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; };
DA6701DF16406BB400B61001 /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; }; DA6701DF16406BB400B61001 /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; };
@ -1208,10 +1201,6 @@
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 = "../../MasterPassword/ObjC/Pearl/Pearl-Prefix.pch"; sourceTree = "<group>"; }; DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Pearl-Prefix.pch"; path = "../../MasterPassword/ObjC/Pearl/Pearl-Prefix.pch"; sourceTree = "<group>"; };
DACA22B71705DE7D002C6C22 /* UbiquityStoreManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UbiquityStoreManager.m; sourceTree = "<group>"; };
DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+UbiquityStoreManager.h"; sourceTree = "<group>"; };
DACA22B91705DE7D002C6C22 /* NSError+UbiquityStoreManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+UbiquityStoreManager.m"; sourceTree = "<group>"; };
DACA22BA1705DE7D002C6C22 /* UbiquityStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UbiquityStoreManager.h; sourceTree = "<group>"; };
DACA269A1705DF81002C6C22 /* Crashlytics.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Crashlytics.plist; sourceTree = "<group>"; }; DACA269A1705DF81002C6C22 /* Crashlytics.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Crashlytics.plist; sourceTree = "<group>"; };
DACA29711705E1A8002C6C22 /* ciphers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = ciphers.plist; sourceTree = "<group>"; }; DACA29711705E1A8002C6C22 /* ciphers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = ciphers.plist; sourceTree = "<group>"; };
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; }; DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
@ -1228,6 +1217,14 @@
DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlMutableStaticTableViewController.h; sourceTree = "<group>"; }; DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlMutableStaticTableViewController.h; sourceTree = "<group>"; };
DACE2F6A19BA6A2A0010F92E /* UIView+FontScale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+FontScale.h"; sourceTree = "<group>"; }; DACE2F6A19BA6A2A0010F92E /* UIView+FontScale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+FontScale.h"; sourceTree = "<group>"; };
DAD312C01552A20800A3F9ED /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; DAD312C01552A20800A3F9ED /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
DADB4EC519C66FB50065A78D /* MPUserEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUserEntity.h; sourceTree = "<group>"; };
DADB4EC619C66FB60065A78D /* MPUserEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUserEntity.m; sourceTree = "<group>"; };
DADB4EC819C66FB60065A78D /* MPElementEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementEntity.h; sourceTree = "<group>"; };
DADB4EC919C66FB60065A78D /* MPElementEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementEntity.m; sourceTree = "<group>"; };
DADB4ECB19C66FB60065A78D /* MPElementGeneratedEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementGeneratedEntity.h; sourceTree = "<group>"; };
DADB4ECC19C66FB60065A78D /* MPElementGeneratedEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementGeneratedEntity.m; sourceTree = "<group>"; };
DADB4ECE19C66FB60065A78D /* MPElementStoredEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementStoredEntity.h; sourceTree = "<group>"; };
DADB4ECF19C66FB70065A78D /* MPElementStoredEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementStoredEntity.m; sourceTree = "<group>"; };
DADBB55918DB0CFC00D099FE /* keyboard-dark@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "keyboard-dark@2x.png"; sourceTree = "<group>"; }; DADBB55918DB0CFC00D099FE /* keyboard-dark@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "keyboard-dark@2x.png"; sourceTree = "<group>"; };
DAE1EF2317E942DE00BC0086 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; }; DAE1EF2317E942DE00BC0086 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
DAE8E65119867AB500416A0F /* libopensslcrypto-ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopensslcrypto-ios.a"; sourceTree = "<group>"; }; DAE8E65119867AB500416A0F /* libopensslcrypto-ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopensslcrypto-ios.a"; sourceTree = "<group>"; };
@ -1357,14 +1354,6 @@
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
DA4425C81557BED40052177D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DA4425CC1557BED40052177D /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DA5BFA41147E415C00F98B1E /* Frameworks */ = { DA5BFA41147E415C00F98B1E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -1373,7 +1362,6 @@
DA6701E016406BB400B61001 /* AdSupport.framework in Frameworks */, DA6701E016406BB400B61001 /* AdSupport.framework in Frameworks */,
DA6701DE16406B7300B61001 /* Social.framework in Frameworks */, DA6701DE16406B7300B61001 /* Social.framework in Frameworks */,
DA6701B816406A4100B61001 /* Accounts.framework in Frameworks */, DA6701B816406A4100B61001 /* Accounts.framework in Frameworks */,
DA44260A1557D9E40052177D /* libUbiquityStoreManager.a in Frameworks */,
DAD312C21552A22700A3F9ED /* libsqlite3.dylib in Frameworks */, DAD312C21552A22700A3F9ED /* libsqlite3.dylib in Frameworks */,
DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */, DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */,
DA672D3014F9413D004A189C /* libPearl.a in Frameworks */, DA672D3014F9413D004A189C /* libPearl.a in Frameworks */,
@ -1477,7 +1465,6 @@
DAC77CAD148291A600BCF976 /* libPearl.a */, DAC77CAD148291A600BCF976 /* libPearl.a */,
DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */, DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */,
DAC6326C148680650075AEA5 /* libjrswizzle.a */, DAC6326C148680650075AEA5 /* libjrswizzle.a */,
DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */,
DAFC5655172C573B00CB5CC5 /* libInAppSettingsKit.a */, DAFC5655172C573B00CB5CC5 /* libInAppSettingsKit.a */,
); );
name = Products; name = Products;
@ -2249,6 +2236,14 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DABD3BD71711E2DC00CF925C /* iOS */, DABD3BD71711E2DC00CF925C /* iOS */,
DADB4ECE19C66FB60065A78D /* MPElementStoredEntity.h */,
DADB4ECF19C66FB70065A78D /* MPElementStoredEntity.m */,
DADB4ECB19C66FB60065A78D /* MPElementGeneratedEntity.h */,
DADB4ECC19C66FB60065A78D /* MPElementGeneratedEntity.m */,
DADB4EC819C66FB60065A78D /* MPElementEntity.h */,
DADB4EC919C66FB60065A78D /* MPElementEntity.m */,
DADB4EC519C66FB50065A78D /* MPUserEntity.h */,
DADB4EC619C66FB60065A78D /* MPUserEntity.m */,
DABD3BA01711E2DC00CF925C /* MPAlgorithm.h */, DABD3BA01711E2DC00CF925C /* MPAlgorithm.h */,
DABD3BA11711E2DC00CF925C /* MPAlgorithm.m */, DABD3BA11711E2DC00CF925C /* MPAlgorithm.m */,
DABD3BA21711E2DC00CF925C /* MPAlgorithmV0.h */, DABD3BA21711E2DC00CF925C /* MPAlgorithmV0.h */,
@ -2359,24 +2354,11 @@
DAA141181922FED80032B392 /* iOS */, DAA141181922FED80032B392 /* iOS */,
DAFC5662172C57EC00CB5CC5 /* InAppSettingsKit */, DAFC5662172C57EC00CB5CC5 /* InAppSettingsKit */,
DAC77CAF148291A600BCF976 /* Pearl */, DAC77CAF148291A600BCF976 /* Pearl */,
DACA22B61705DE7D002C6C22 /* UbiquityStoreManager */,
); );
name = External; name = External;
path = ../../../External; path = ../../../External;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
DACA22B61705DE7D002C6C22 /* UbiquityStoreManager */ = {
isa = PBXGroup;
children = (
DACA22BA1705DE7D002C6C22 /* UbiquityStoreManager.h */,
DACA22B71705DE7D002C6C22 /* UbiquityStoreManager.m */,
DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */,
DACA22B91705DE7D002C6C22 /* NSError+UbiquityStoreManager.m */,
);
name = UbiquityStoreManager;
path = UbiquityStoreManager/UbiquityStoreManager;
sourceTree = "<group>";
};
DACA23B41705DF7D002C6C22 /* Resources */ = { DACA23B41705DF7D002C6C22 /* Resources */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -2673,16 +2655,6 @@
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */ /* Begin PBXHeadersBuildPhase section */
DA4425C91557BED40052177D /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
DACA22BC1705DE7D002C6C22 /* NSError+UbiquityStoreManager.h in Headers */,
DACA22BE1705DE7D002C6C22 /* UbiquityStoreManager.h in Headers */,
93D399BBC0A7EC746CB1B19B /* MPLogsViewController.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DAC6325B1486805C0075AEA5 /* Headers */ = { DAC6325B1486805C0075AEA5 /* Headers */ = {
isa = PBXHeadersBuildPhase; isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -2783,23 +2755,6 @@
/* End PBXHeadersBuildPhase section */ /* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
DA4425CA1557BED40052177D /* UbiquityStoreManager */ = {
isa = PBXNativeTarget;
buildConfigurationList = DA4425D31557BED40052177D /* Build configuration list for PBXNativeTarget "UbiquityStoreManager" */;
buildPhases = (
DA4425C71557BED40052177D /* Sources */,
DA4425C81557BED40052177D /* Frameworks */,
DA4425C91557BED40052177D /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = UbiquityStoreManager;
productName = iCloudStoreManager;
productReference = DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */;
productType = "com.apple.product-type.library.static";
};
DA5BFA43147E415C00F98B1E /* MasterPassword */ = { DA5BFA43147E415C00F98B1E /* MasterPassword */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword" */; buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword" */;
@ -3010,7 +2965,6 @@
DAC77CAC148291A600BCF976 /* Pearl */, DAC77CAC148291A600BCF976 /* Pearl */,
DAC6325C1486805C0075AEA5 /* uicolor-utilities */, DAC6325C1486805C0075AEA5 /* uicolor-utilities */,
DAC6326B148680650075AEA5 /* jrswizzle */, DAC6326B148680650075AEA5 /* jrswizzle */,
DA4425CA1557BED40052177D /* UbiquityStoreManager */,
DAFC5654172C573B00CB5CC5 /* InAppSettingsKit */, DAFC5654172C573B00CB5CC5 /* InAppSettingsKit */,
); );
}; };
@ -3206,15 +3160,6 @@
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
DA4425C71557BED40052177D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DACA22BB1705DE7D002C6C22 /* UbiquityStoreManager.m in Sources */,
DACA22BD1705DE7D002C6C22 /* NSError+UbiquityStoreManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DA5BFA40147E415C00F98B1E /* Sources */ = { DA5BFA40147E415C00F98B1E /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -3226,12 +3171,8 @@
DABD3C011711E2DC00CF925C /* MPAppDelegate_Shared.m in Sources */, DABD3C011711E2DC00CF925C /* MPAppDelegate_Shared.m in Sources */,
DABD3C021711E2DC00CF925C /* MPAppDelegate_Store.m in Sources */, DABD3C021711E2DC00CF925C /* MPAppDelegate_Store.m in Sources */,
DABD3C031711E2DC00CF925C /* MPConfig.m in Sources */, DABD3C031711E2DC00CF925C /* MPConfig.m in Sources */,
DABD3C041711E2DC00CF925C /* MPElementEntity.m in Sources */,
DABD3C051711E2DC00CF925C /* MPElementGeneratedEntity.m in Sources */,
DABD3C061711E2DC00CF925C /* MPElementStoredEntity.m in Sources */,
DABD3C071711E2DC00CF925C /* MPEntities.m in Sources */, DABD3C071711E2DC00CF925C /* MPEntities.m in Sources */,
DABD3C081711E2DC00CF925C /* MPKey.m in Sources */, DABD3C081711E2DC00CF925C /* MPKey.m in Sources */,
DABD3C091711E2DC00CF925C /* MPUserEntity.m in Sources */,
DABD3C141711E2DC00CF925C /* MasterPassword.xcdatamodeld in Sources */, DABD3C141711E2DC00CF925C /* MasterPassword.xcdatamodeld in Sources */,
DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */, DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */,
DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */, DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */,
@ -3239,11 +3180,14 @@
DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */, DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */,
DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */, DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */,
DABD3C271711E2DC00CF925C /* main.m in Sources */, DABD3C271711E2DC00CF925C /* main.m in Sources */,
DADB4EC719C66FB60065A78D /* MPUserEntity.m in Sources */,
93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */, 93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */,
DA095E75172F4CD8001C948B /* MPLogsViewController.m in Sources */, DA095E75172F4CD8001C948B /* MPLogsViewController.m in Sources */,
93D39D596A2E376D6F6F5DA1 /* MPCombinedViewController.m in Sources */, 93D39D596A2E376D6F6F5DA1 /* MPCombinedViewController.m in Sources */,
DADB4ECD19C66FB60065A78D /* MPElementGeneratedEntity.m in Sources */,
93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */, 93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */,
93D39B8F90F58A5D158DDBA3 /* MPPasswordsViewController.m in Sources */, 93D39B8F90F58A5D158DDBA3 /* MPPasswordsViewController.m in Sources */,
DADB4ED019C66FB70065A78D /* MPElementStoredEntity.m in Sources */,
93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */, 93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */,
93D39392DEDA376F93C6C718 /* MPCell.m in Sources */, 93D39392DEDA376F93C6C718 /* MPCell.m in Sources */,
93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */, 93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */,
@ -3253,6 +3197,7 @@
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */, 93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */,
93D39BA1EA3CAAC8A220B4A6 /* MPAppSettingsViewController.m in Sources */, 93D39BA1EA3CAAC8A220B4A6 /* MPAppSettingsViewController.m in Sources */,
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */, 93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */,
DADB4ECA19C66FB60065A78D /* MPElementEntity.m 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 */,
@ -3402,27 +3347,6 @@
/* End PBXVariantGroup section */ /* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
DA4425D41557BED40052177D /* Debug-iOS */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
};
name = "Debug-iOS";
};
DA4425D51557BED40052177D /* AdHoc-iOS */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
};
name = "AdHoc-iOS";
};
DA4425D61557BED40052177D /* AppStore-iOS */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
};
name = "AppStore-iOS";
};
DA5BFA6B147E415C00F98B1E /* Debug-iOS */ = { DA5BFA6B147E415C00F98B1E /* Debug-iOS */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
@ -3892,16 +3816,6 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
DA4425D31557BED40052177D /* Build configuration list for PBXNativeTarget "UbiquityStoreManager" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DA4425D41557BED40052177D /* Debug-iOS */,
DA4425D51557BED40052177D /* AdHoc-iOS */,
DA4425D61557BED40052177D /* AppStore-iOS */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = "AdHoc-iOS";
};
DA5BFA3E147E415C00F98B1E /* Build configuration list for PBXProject "MasterPassword-iOS" */ = { DA5BFA3E147E415C00F98B1E /* Build configuration list for PBXProject "MasterPassword-iOS" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
@ -3972,8 +3886,9 @@
DABD3BD21711E2DC00CF925C /* MasterPassword 2.xcdatamodel */, DABD3BD21711E2DC00CF925C /* MasterPassword 2.xcdatamodel */,
DABD3BD31711E2DC00CF925C /* MasterPassword 3.xcdatamodel */, DABD3BD31711E2DC00CF925C /* MasterPassword 3.xcdatamodel */,
DABD3BD41711E2DC00CF925C /* MasterPassword 4.xcdatamodel */, DABD3BD41711E2DC00CF925C /* MasterPassword 4.xcdatamodel */,
DA62140919C66A9700375240 /* MasterPassword 5.xcdatamodel */,
); );
currentVersion = DABD3BD41711E2DC00CF925C /* MasterPassword 4.xcdatamodel */; currentVersion = DA62140919C66A9700375240 /* MasterPassword 5.xcdatamodel */;
path = MasterPassword.xcdatamodeld; path = MasterPassword.xcdatamodeld;
sourceTree = "<group>"; sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel; versionGroupType = wrapper.xcdatamodel;

View File

@ -146,24 +146,6 @@ To see a site&apos;s password anyway, tap and hold your finger down for a while
<integer>2</integer> <integer>2</integer>
</array> </array>
</dict> </dict>
<dict>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>Title</key>
<string></string>
<key>FooterText</key>
<string>Synchronizes your sites with your other Apple devices. It&apos;s also a good way of keeping automatic backups.</string>
</dict>
<dict>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
<key>Title</key>
<string>iCloud</string>
<key>Key</key>
<string>iCloudEnabled</string>
<key>DefaultValue</key>
<false/>
</dict>
<dict> <dict>
<key>Type</key> <key>Type</key>
<string>PSGroupSpecifier</string> <string>PSGroupSpecifier</string>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6245" systemVersion="13E28" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="Q1S-vU-GGO"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6245" systemVersion="13E28" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="Q1S-vU-GGO">
<dependencies> <dependencies>
<deployment defaultVersion="1792" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
<capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/> <capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/> <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
@ -193,11 +192,11 @@
</collectionViewCell> </collectionViewCell>
</cells> </cells>
<collectionReusableView key="sectionHeaderView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPAvatarIndent" id="LD1-mt-htC"> <collectionReusableView key="sectionHeaderView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPAvatarIndent" id="LD1-mt-htC">
<rect key="frame" x="0.0" y="0.0" width="80" height="548"/> <rect key="frame" x="0.0" y="0.0" width="80" height="647"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
</collectionReusableView> </collectionReusableView>
<collectionReusableView key="sectionFooterView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPAvatarOutdent" id="G8v-Sb-ilL"> <collectionReusableView key="sectionFooterView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPAvatarOutdent" id="G8v-Sb-ilL">
<rect key="frame" x="240" y="0.0" width="80" height="548"/> <rect key="frame" x="295" y="0.0" width="80" height="647"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
</collectionReusableView> </collectionReusableView>
<connections> <connections>
@ -1061,9 +1060,16 @@
<action selector="doContent:" destination="W2g-yv-V3V" eventType="touchUpInside" id="ukg-D8-8O3"/> <action selector="doContent:" destination="W2g-yv-V3V" eventType="touchUpInside" id="ukg-D8-8O3"/>
</connections> </connections>
</button> </button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="w2g-zN-1wZ" userLabel="Login Container"> <view alpha="0.69999999999999996" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="w2g-zN-1wZ" userLabel="Login Container">
<rect key="frame" x="0.0" y="0.0" width="300" height="21"/> <rect key="frame" x="0.0" y="0.0" width="300" height="21"/>
<subviews> <subviews>
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="q3g-CJ-LbN" userLabel="Separator">
<rect key="frame" x="-1" y="20" width="300" height="1"/>
<color key="backgroundColor" red="0.14901960784313725" green="0.14901960784313725" blue="0.14901960784313725" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="jyk-dC-QLb"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Iwe-rQ-ma0" userLabel="Copy Login"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Iwe-rQ-ma0" userLabel="Copy Login">
<rect key="frame" x="0.0" y="0.0" width="300" height="29"/> <rect key="frame" x="0.0" y="0.0" width="300" height="29"/>
<color key="backgroundColor" red="0.18431372549019609" green="0.15686274509803921" blue="0.15686274509803921" alpha="0.01" colorSpace="calibratedRGB"/> <color key="backgroundColor" red="0.18431372549019609" green="0.15686274509803921" blue="0.15686274509803921" alpha="0.01" colorSpace="calibratedRGB"/>
@ -1071,26 +1077,19 @@
<action selector="doLoginName:" destination="W2g-yv-V3V" eventType="touchUpInside" id="Ex0-re-QrI"/> <action selector="doLoginName:" destination="W2g-yv-V3V" eventType="touchUpInside" id="Ex0-re-QrI"/>
</connections> </connections>
</button> </button>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="lhunath" textAlignment="center" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="3I9-vf-IZK" userLabel="Login"> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Tap to generate username" textAlignment="center" minimumFontSize="9" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="3I9-vf-IZK" userLabel="Login">
<rect key="frame" x="8" y="0.0" width="284" height="20"/> <rect key="frame" x="8" y="0.0" width="284" height="20"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="20" id="9gA-Ti-g1e"/> <constraint firstAttribute="height" constant="20" id="9gA-Ti-g1e"/>
</constraints> </constraints>
<color key="textColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.42745098039215684" green="0.36862745098039218" blue="0.38823529411764707" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" name="SourceCodePro-Regular" family="Source Code Pro" pointSize="14"/> <fontDescription key="fontDescription" name="SourceCodePro-Regular" family="Source Code Pro" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="alphabet" keyboardAppearance="alert" returnKeyType="done"/> <textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="alphabet" keyboardAppearance="alert" returnKeyType="done"/>
<connections> <connections>
<outlet property="delegate" destination="W2g-yv-V3V" id="z8b-Vd-dWe"/> <outlet property="delegate" destination="W2g-yv-V3V" id="z8b-Vd-dWe"/>
</connections> </connections>
</textField> </textField>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="q3g-CJ-LbN" userLabel="Separator">
<rect key="frame" x="0.0" y="20" width="300" height="1"/>
<color key="backgroundColor" red="0.14901960784313725" green="0.14901960784313725" blue="0.14901960784313725" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="jyk-dC-QLb"/>
</constraints>
</view>
</subviews> </subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints> <constraints>
@ -1110,7 +1109,7 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2tX-WK-ASq" userLabel="Password Container"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2tX-WK-ASq" userLabel="Password Container">
<rect key="frame" x="0.0" y="20" width="300" height="43"/> <rect key="frame" x="0.0" y="20" width="300" height="43"/>
<subviews> <subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="CuzaSasy3*Rimo" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="blw-Ou-8I8" userLabel="Password"> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="CuzaSasy3*Rimo" textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="blw-Ou-8I8" userLabel="Password">
<rect key="frame" x="0.0" y="0.0" width="300" height="31"/> <rect key="frame" x="0.0" y="0.0" width="300" height="31"/>
<color key="textColor" red="0.40000000600000002" green="0.80000001190000003" blue="1" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.40000000600000002" green="0.80000001190000003" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" name="SourceCodePro-Black" family="Source Code Pro" pointSize="24"/> <fontDescription key="fontDescription" name="SourceCodePro-Black" family="Source Code Pro" pointSize="24"/>
@ -1419,7 +1418,7 @@
</collectionViewCell> </collectionViewCell>
</cells> </cells>
<collectionReusableView key="sectionHeaderView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPPasswordHeader" id="yzh-hh-YjZ"> <collectionReusableView key="sectionHeaderView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPPasswordHeader" id="yzh-hh-YjZ">
<rect key="frame" x="0.0" y="0.0" width="320" height="108"/> <rect key="frame" x="0.0" y="0.0" width="375" height="108"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
</collectionReusableView> </collectionReusableView>
<connections> <connections>
@ -1463,7 +1462,7 @@
</toolbar> </toolbar>
<searchBar contentMode="redraw" barStyle="black" searchBarStyle="minimal" placeholder="eg. apple.com" translatesAutoresizingMaskIntoConstraints="NO" id="aGs-1S-aC3"> <searchBar contentMode="redraw" barStyle="black" searchBarStyle="minimal" placeholder="eg. apple.com" translatesAutoresizingMaskIntoConstraints="NO" id="aGs-1S-aC3">
<rect key="frame" x="0.0" y="64" width="375" height="44"/> <rect key="frame" x="0.0" y="64" width="375" height="44"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL"/> <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="URL"/>
<connections> <connections>
<outlet property="delegate" destination="nkY-z6-8jd" id="ENG-q5-XwX"/> <outlet property="delegate" destination="nkY-z6-8jd" id="ENG-q5-XwX"/>
</connections> </connections>
@ -2027,26 +2026,9 @@ CgoKCgoKCgoKCgoKCg
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<inset key="scrollIndicatorInsets" minX="0.0" minY="64" maxX="0.0" maxY="93"/> <inset key="scrollIndicatorInsets" minX="0.0" minY="64" maxX="0.0" maxY="93"/>
<string key="text">119-20:51:52 MPiOSAppDelegate.m:36 | INFO : Initializing TestFlight <string key="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis tortor leo, iaculis mollis elit dictum et. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In congue justo porta enim imperdiet, id luctus justo fringilla. Nunc nec sem id augue bibendum hendrerit eu ut eros. Ut fermentum augue quis nunc feugiat vehicula. Quisque in ultrices magna. Praesent quis mollis lectus. Sed fringilla massa vitae eros luctus, eget convallis justo pretium. Duis non tristique ante. Sed suscipit tortor ligula, sed fermentum eros sodales ut. Maecenas sed ante et orci posuere lobortis et sodales diam. Nunc non ullamcorper orci.
119-20:51:52 MPiOSAppDelegate.m:80 | INFO : Initializing Crashlytics
119-20:51:53 PearlAppDelegate.m:71 | INFO : Master Password (MasterPassword) 1.4 (1.4.0) (GIT: 1.4-0-g8a4eecd-dirty) Suspendisse potenti. Etiam ut nisi id augue tempor ultrices et sit amet sapien. Quisque fringilla ex dolor, at iaculis turpis facilisis et. Donec pellentesque quam vitae libero facilisis, quis scelerisque augue feugiat. Nam eros eros, posuere eget ultricies quis, maximus sodales velit. Aliquam euismod iaculis consectetur. Etiam dictum orci id dapibus fermentum. Vestibulum posuere tortor vitae viverra dictum. Morbi rutrum arcu mattis felis hendrerit pretium. Praesent rutrum euismod leo, in faucibus lectus rhoncus in. Vestibulum porttitor semper eros, eu dapibus risus tincidunt sed. Curabitur ex enim, ullamcorper nec laoreet id, consectetur et nisl. Etiam id pulvinar risus.</string>
119-20:51:53 MPiOSAppDelegate.m:257 | INFO : Started up with device identifier: A8C51CDA-6F60-4F0C-BFC9-68A08F2F2DD7
119-20:51:59 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] (Re)loading store...
119-20:51:59 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Will load cloud store: 0B3CA2DF-5796-44DF-B5E0-121EC3846464 (definite).
119-20:51:59 PearlConfig.m:193 | INFO : Lock screen will appear
119-20:51:59 MPiOSAppDelegate.m:412 | INFO : Re-activated
119-20:51:59 PearlConfig.m:180 | DEBUG : MPiOSConfig.launchCount = [70 -&gt;] 71
119-20:52:02 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Clearing stores...
119-20:52:03 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Loading store without seeding.
119-20:52:09 MPAppDelegate_Store.m:278 | DEBUG : [StoreManager] Cloud enabled and successfully loaded cloud store.
119-20:52:09 MPAppDelegate_Store.m:299 | INFO : Using iCloud? 1
119-20:52:12 MPAppDelegate_Key.m:28 | INFO : Found key in keychain for: b55911588b178466be1d6392597e899b8de46f9a
119-20:52:12 MPAppDelegate_Key.m:132 | INFO : Logged in: b55911588b178466be1d6392597e899b8de46f9a
119-20:52:13 MPUnlockViewController.m:229 | INFO : Lock screen will disappear
119-20:52:13 MPMainViewController.m:142 | INFO : Main will appear
119-20:52:16 MPMainViewController.m:734 | INFO : Action: Preferences
119-20:52:17 MPMainViewController.m:187 | INFO : Main will disappear.
</string>
<color key="textColor" cocoaTouchSystemColor="lightTextColor"/> <color key="textColor" cocoaTouchSystemColor="lightTextColor"/>
<fontDescription key="fontDescription" name="SourceCodePro-Black" family="Source Code Pro" pointSize="9"/> <fontDescription key="fontDescription" name="SourceCodePro-Black" family="Source Code Pro" pointSize="9"/>
<textInputTraits key="textInputTraits" autocorrectionType="no"/> <textInputTraits key="textInputTraits" autocorrectionType="no"/>
@ -2055,11 +2037,6 @@ CgoKCgoKCgoKCgoKCg
<toolbar contentMode="scaleToFill" barStyle="black" translatesAutoresizingMaskIntoConstraints="NO" id="WmH-JB-jp2"> <toolbar contentMode="scaleToFill" barStyle="black" translatesAutoresizingMaskIntoConstraints="NO" id="WmH-JB-jp2">
<rect key="frame" x="0.0" y="574" width="375" height="44"/> <rect key="frame" x="0.0" y="574" width="375" height="44"/>
<items> <items>
<barButtonItem systemItem="action" id="JjQ-rY-m2q">
<connections>
<action selector="action:" destination="C0Q-RC-szS" id="Vi3-CE-YmV"/>
</connections>
</barButtonItem>
<barButtonItem systemItem="compose" id="BSV-3i-01h"> <barButtonItem systemItem="compose" id="BSV-3i-01h">
<connections> <connections>
<action selector="mail:" destination="C0Q-RC-szS" id="i37-jS-UfO"/> <action selector="mail:" destination="C0Q-RC-szS" id="i37-jS-UfO"/>

View File

@ -4,6 +4,10 @@
<dict> <dict>
<key>MPElementGeneratedEntity</key> <key>MPElementGeneratedEntity</key>
<dict> <dict>
<key>Login Name</key>
<array>
<string>cvccvcvcv</string>
</array>
<key>Maximum Security Password</key> <key>Maximum Security Password</key>
<array> <array>
<string>anoxxxxxxxxxxxxxxxxx</string> <string>anoxxxxxxxxxxxxxxxxx</string>