Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2886e040a1 | ||
|
|
01cea659ca | ||
|
|
3a18e02a87 | ||
|
|
2de57984b2 | ||
|
|
c7201c7d90 | ||
|
|
d62c6b4594 | ||
|
|
57f275c471 | ||
|
|
b1d8296396 | ||
|
|
6d25463de0 | ||
|
|
029041dcf7 | ||
|
|
cfbf1f5cac | ||
|
|
acbd2dc2cc | ||
|
|
8fcac65fd5 | ||
|
|
9904f4c715 | ||
|
|
b51a3de32c | ||
|
|
9e91f0a9d6 | ||
|
|
7368b1be90 | ||
|
|
5db294bdb3 | ||
|
|
fee7bc7401 | ||
|
|
21968f4ba6 | ||
|
|
8582c934c2 | ||
|
|
7091e2ee1b | ||
|
|
d5d455ee57 | ||
|
|
e6ae06798b | ||
|
|
1cae4c754b | ||
|
|
93ad86e63c | ||
|
|
cf74dc5cc2 | ||
|
|
981bdb3ab4 | ||
|
|
9bea8bcbdf | ||
|
|
363d6f6639 | ||
|
|
eb1632cb62 | ||
|
|
73fadaef7f | ||
|
|
60200f6302 | ||
|
|
cce8db5c48 | ||
|
|
6f3da5ccf0 | ||
|
|
52c87eaeca | ||
|
|
1dccdd0a3c | ||
|
|
eb8d10ed05 | ||
|
|
d9e5f77bee | ||
|
|
60f60d087e | ||
|
|
df97dec2fe | ||
|
|
3bac8d9e0a | ||
|
|
3fa7e1e8a1 | ||
|
|
d1104e4028 | ||
|
|
e9f2a25c9c | ||
|
|
171a3f0978 | ||
|
|
8cfb9a83c5 | ||
|
|
5717375e75 | ||
|
|
cc2dca3bd0 | ||
|
|
7575924d80 | ||
|
|
8bedcedfaf | ||
|
|
10b205c541 | ||
|
|
774f183ac0 | ||
|
|
2279aacb5a | ||
|
|
1bd654621c | ||
|
|
c4f60e325d | ||
|
|
d4de3afb72 | ||
|
|
694b5ea227 | ||
|
|
66dd78797b | ||
|
|
61d1660560 | ||
|
|
c3568e4744 | ||
|
|
0c921d4318 | ||
|
|
0178efaaf7 | ||
|
|
14f919584b |
@@ -9,10 +9,12 @@ build_project:
|
||||
- "( ./lib/bin/build_libsodium-macos clean && ./lib/bin/build_libsodium-macos )"
|
||||
- "( ./lib/bin/build_libjson-c-macos clean && ./lib/bin/build_libjson-c-macos )"
|
||||
- "( cd ./platform-independent/c/cli && ./clean && targets=all ./build && ./mpw-tests && ./mpw-cli-tests )"
|
||||
- "( export JAVA_HOME=$(java_home -Fv 10 || java_home -Fv 9* ) && ./gradlew --stacktrace clean test )"
|
||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword iOS' -sdk iphonesimulator clean build )"
|
||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword macOS' clean build )"
|
||||
- "( ./gradlew --stacktrace --info clean test )"
|
||||
- "( cd platform-darwin && pod install )"
|
||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Release' -scheme 'MasterPassword iOS' -sdk iphonesimulator clean build )"
|
||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Release' -scheme 'MasterPassword macOS' clean build )"
|
||||
tags:
|
||||
- brew
|
||||
- java_9
|
||||
- xcode_9
|
||||
- java
|
||||
- cocoapods
|
||||
- xcode
|
||||
|
||||
3
.gitmodules
vendored
@@ -15,7 +15,6 @@
|
||||
url = https://github.com/json-c/json-c.git
|
||||
[submodule "public/site"]
|
||||
path = public/site
|
||||
url = https://github.com/Lyndir/MasterPassword.git
|
||||
url = https://gitlab.com/MasterPassword/MasterPassword.git
|
||||
branch = gh-pages
|
||||
shallow = true
|
||||
update = none
|
||||
|
||||
2
platform-darwin/External/Pearl
vendored
@@ -49,7 +49,6 @@
|
||||
93D39A5FF670957C0AF8298D /* MPSiteCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DEA995041A13DC9CAF7 /* MPSiteCell.m */; };
|
||||
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D8A953779B35403AF6E /* PearlUICollectionView.m */; };
|
||||
93D39AA4A0BE66A872CCC02E /* NSPersistentStore+PearlMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D397F4BAFFF7CF3F1B21A4 /* NSPersistentStore+PearlMigration.h */; };
|
||||
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399493FEDDE74DD1A0C15 /* MPRootSegue.m */; };
|
||||
93D39B76DD5AB108BA8928E8 /* UIScrollView+PearlAdjustInsets.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */; };
|
||||
93D39B842AB9A5D072810D76 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */; };
|
||||
93D39B8F90F58A5D158DDBA3 /* MPSitesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3924EE15017F8A12CB436 /* MPSitesViewController.m */; };
|
||||
@@ -77,11 +76,6 @@
|
||||
DA0CC5951EB6B030009A8ED9 /* MPSiteEntity+CoreDataProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC58B1EB6B030009A8ED9 /* MPSiteEntity+CoreDataProperties.m */; };
|
||||
DA24EBAE19DAD08900FF010B /* tip_basic_black_top.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38941711E29700CF925C /* tip_basic_black_top.png */; };
|
||||
DA24EBAF19DAD08C00FF010B /* tip_basic_black_top@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38951711E29700CF925C /* tip_basic_black_top@2x.png */; };
|
||||
DA24EBE819DAD6DE00FF010B /* Icon-320.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBE619DAD6DE00FF010B /* Icon-320.png */; };
|
||||
DA24EBE919DAD6DE00FF010B /* Icon-64.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBE719DAD6DE00FF010B /* Icon-64.png */; };
|
||||
DA24EBEA19DAD6EE00FF010B /* Icon-Small.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBBA19DAD4D000FF010B /* Icon-Small.png */; };
|
||||
DA24EBEB19DAD6EE00FF010B /* Icon-Small@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBBB19DAD4D000FF010B /* Icon-Small@2x.png */; };
|
||||
DA24EBEC19DAD6EE00FF010B /* Icon-Small@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBBC19DAD4D000FF010B /* Icon-Small@3x.png */; };
|
||||
DA250A17195665A100AC23F1 /* UITableView+PearlReloadItems.m in Sources */ = {isa = PBXBuildFile; fileRef = DA250A13195665A100AC23F1 /* UITableView+PearlReloadItems.m */; };
|
||||
DA250A18195665A100AC23F1 /* UITableView+PearlReloadItems.h in Headers */ = {isa = PBXBuildFile; fileRef = DA250A14195665A100AC23F1 /* UITableView+PearlReloadItems.h */; };
|
||||
DA250A19195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m in Sources */ = {isa = PBXBuildFile; fileRef = DA250A15195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m */; };
|
||||
@@ -155,6 +149,21 @@
|
||||
DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||
DA5BFA4D147E415C00F98B1E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */; };
|
||||
DA5BFA4F147E415C00F98B1E /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4E147E415C00F98B1E /* CoreData.framework */; };
|
||||
DA5E0E5524589C9B0007FBA7 /* Icon-Small@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E4624589C9A0007FBA7 /* Icon-Small@3x.png */; };
|
||||
DA5E0E5624589C9B0007FBA7 /* Icon-Small-40.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E4724589C9A0007FBA7 /* Icon-Small-40.png */; };
|
||||
DA5E0E5724589C9B0007FBA7 /* Icon-Small-20.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E4824589C9A0007FBA7 /* Icon-Small-20.png */; };
|
||||
DA5E0E5824589C9B0007FBA7 /* Icon-76.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E4924589C9A0007FBA7 /* Icon-76.png */; };
|
||||
DA5E0E5924589C9B0007FBA7 /* Icon-Small@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E4A24589C9A0007FBA7 /* Icon-Small@2x.png */; };
|
||||
DA5E0E5A24589C9B0007FBA7 /* Icon-Small-40@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E4B24589C9A0007FBA7 /* Icon-Small-40@2x.png */; };
|
||||
DA5E0E5B24589C9B0007FBA7 /* Icon-76@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E4C24589C9A0007FBA7 /* Icon-76@2x.png */; };
|
||||
DA5E0E5C24589C9B0007FBA7 /* Icon-Small-20@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E4D24589C9A0007FBA7 /* Icon-Small-20@3x.png */; };
|
||||
DA5E0E5D24589C9B0007FBA7 /* Icon-Small.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E4E24589C9A0007FBA7 /* Icon-Small.png */; };
|
||||
DA5E0E5E24589C9B0007FBA7 /* Icon-83@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E4F24589C9A0007FBA7 /* Icon-83@2x.png */; };
|
||||
DA5E0E5F24589C9B0007FBA7 /* Icon-Small-40@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E5024589C9A0007FBA7 /* Icon-Small-40@3x.png */; };
|
||||
DA5E0E6024589C9B0007FBA7 /* Icon-60@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E5124589C9A0007FBA7 /* Icon-60@3x.png */; };
|
||||
DA5E0E6124589C9B0007FBA7 /* iTunesArtwork@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E5224589C9B0007FBA7 /* iTunesArtwork@2x.png */; };
|
||||
DA5E0E6224589C9B0007FBA7 /* Icon-Small-20@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E5324589C9B0007FBA7 /* Icon-Small-20@2x.png */; };
|
||||
DA5E0E6324589C9B0007FBA7 /* Icon-60@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5E0E5424589C9B0007FBA7 /* Icon-60@2x.png */; };
|
||||
DA6701B816406A4100B61001 /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA6701B716406A4100B61001 /* Accounts.framework */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||
DA6701DE16406B7300B61001 /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA6701DD16406B7300B61001 /* Social.framework */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||
DA6701E016406BB400B61001 /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA6701DF16406BB400B61001 /* AdSupport.framework */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||
@@ -165,7 +174,7 @@
|
||||
DA67461018DE7F0C00DFE240 /* Exo2.0-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA67460C18DE7F0C00DFE240 /* Exo2.0-Bold.otf */; };
|
||||
DA69540617D975D900BF294E /* icon_gears.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37841711E29500CF925C /* icon_gears.png */; };
|
||||
DA69540717D975D900BF294E /* icon_gears@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37851711E29500CF925C /* icon_gears@2x.png */; };
|
||||
DA72BD7B19C1510C00E6ACFE /* UIView+FontScale.m in Sources */ = {isa = PBXBuildFile; fileRef = DACE2F6719BA6A2A0010F92E /* UIView+FontScale.m */; };
|
||||
DA72E2302453B91700676D4F /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA72E22F2453B91700676D4F /* WebKit.framework */; };
|
||||
DA73049D194E022700E72520 /* ui_spinner.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD36511711E29400CF925C /* ui_spinner.png */; };
|
||||
DA73049E194E022700E72520 /* ui_spinner@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD36521711E29400CF925C /* ui_spinner@2x.png */; };
|
||||
DA73049F194E022B00E72520 /* ui_textfield.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD365B1711E29400CF925C /* ui_textfield.png */; };
|
||||
@@ -323,7 +332,6 @@
|
||||
DABD3C1E1711E2DC00CF925C /* MPPreferencesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BEB1711E2DC00CF925C /* MPPreferencesViewController.m */; };
|
||||
DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BED1711E2DC00CF925C /* MPTypeViewController.m */; };
|
||||
DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BF11711E2DC00CF925C /* MPiOSConfig.m */; };
|
||||
DABD3C241711E2DC00CF925C /* MasterPassword.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BF81711E2DC00CF925C /* MasterPassword.entitlements */; };
|
||||
DABD3C251711E2DC00CF925C /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BF91711E2DC00CF925C /* Settings.bundle */; };
|
||||
DABD3C261711E2DC00CF925C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DABD3BFA1711E2DC00CF925C /* InfoPlist.strings */; };
|
||||
DABD3C271711E2DC00CF925C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD3BFC1711E2DC00CF925C /* main.m */; };
|
||||
@@ -465,7 +473,6 @@
|
||||
93D391943675426839501BB8 /* MPLogsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLogsViewController.h; sourceTree = "<group>"; };
|
||||
93D391AA32F24290C424438E /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = "<group>"; };
|
||||
93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadItems.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionView+PearlReloadItems.h"; sourceTree = "<group>"; };
|
||||
93D3924D6F77E6BF41AC32D3 /* MPRootSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootSegue.h; sourceTree = "<group>"; };
|
||||
93D3924EE15017F8A12CB436 /* MPSitesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesViewController.m; sourceTree = "<group>"; };
|
||||
93D392876BE5C011DE73B43F /* MPPopdownSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPopdownSegue.h; sourceTree = "<group>"; };
|
||||
93D392C5A6572DB0EB5B82C8 /* mpw-types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-types.c"; sourceTree = "<group>"; };
|
||||
@@ -494,7 +501,6 @@
|
||||
93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; };
|
||||
93D3990D850D76A94C6B7A4D /* mpw-algorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-algorithm.h"; sourceTree = "<group>"; };
|
||||
93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPWebViewController.m; sourceTree = "<group>"; };
|
||||
93D399493FEDDE74DD1A0C15 /* MPRootSegue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRootSegue.m; sourceTree = "<group>"; };
|
||||
93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCoachmarkViewController.m; sourceTree = "<group>"; };
|
||||
93D39975CE5AEC99E3F086C7 /* MPSiteCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteCell.h; sourceTree = "<group>"; };
|
||||
93D3999693660C89A7465F4E /* MPCoachmarkViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCoachmarkViewController.h; sourceTree = "<group>"; };
|
||||
@@ -573,19 +579,6 @@
|
||||
DA0CC5891EB6B030009A8ED9 /* MPSiteEntity+CoreDataClass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPSiteEntity+CoreDataClass.m"; sourceTree = "<group>"; };
|
||||
DA0CC58A1EB6B030009A8ED9 /* MPSiteEntity+CoreDataProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MPSiteEntity+CoreDataProperties.h"; sourceTree = "<group>"; };
|
||||
DA0CC58B1EB6B030009A8ED9 /* MPSiteEntity+CoreDataProperties.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPSiteEntity+CoreDataProperties.m"; sourceTree = "<group>"; };
|
||||
DA24EBB219DAD4D000FF010B /* Icon-60.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60.png"; sourceTree = "<group>"; };
|
||||
DA24EBB319DAD4D000FF010B /* Icon-60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60@2x.png"; sourceTree = "<group>"; };
|
||||
DA24EBB419DAD4D000FF010B /* Icon-60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60@3x.png"; sourceTree = "<group>"; };
|
||||
DA24EBB519DAD4D000FF010B /* Icon-76.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-76.png"; sourceTree = "<group>"; };
|
||||
DA24EBB619DAD4D000FF010B /* Icon-76@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-76@2x.png"; sourceTree = "<group>"; };
|
||||
DA24EBB719DAD4D000FF010B /* Icon-Small-40.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-40.png"; sourceTree = "<group>"; };
|
||||
DA24EBB819DAD4D000FF010B /* Icon-Small-40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-40@2x.png"; sourceTree = "<group>"; };
|
||||
DA24EBB919DAD4D000FF010B /* Icon-Small-40@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-40@3x.png"; sourceTree = "<group>"; };
|
||||
DA24EBBA19DAD4D000FF010B /* Icon-Small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small.png"; sourceTree = "<group>"; };
|
||||
DA24EBBB19DAD4D000FF010B /* Icon-Small@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small@2x.png"; sourceTree = "<group>"; };
|
||||
DA24EBBC19DAD4D000FF010B /* Icon-Small@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small@3x.png"; sourceTree = "<group>"; };
|
||||
DA24EBBD19DAD4D000FF010B /* iTunesArtwork.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = iTunesArtwork.png; sourceTree = "<group>"; };
|
||||
DA24EBBE19DAD4D000FF010B /* iTunesArtwork@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "iTunesArtwork@2x.png"; sourceTree = "<group>"; };
|
||||
DA24EBBF19DAD4D000FF010B /* icon.sketch */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = icon.sketch; sourceTree = "<group>"; };
|
||||
DA24EBC119DAD4D000FF010B /* 32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 32.png; sourceTree = "<group>"; };
|
||||
DA24EBC219DAD4D000FF010B /* 320-480.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "320-480.png"; sourceTree = "<group>"; };
|
||||
@@ -597,8 +590,6 @@
|
||||
DA24EBC819DAD4D000FF010B /* background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "background@2x.png"; sourceTree = "<group>"; };
|
||||
DA24EBC919DAD4D000FF010B /* background@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "background@3x.png"; sourceTree = "<group>"; };
|
||||
DA24EBCA19DAD4D000FF010B /* launch.sketch */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = launch.sketch; sourceTree = "<group>"; };
|
||||
DA24EBE619DAD6DE00FF010B /* Icon-320.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-320.png"; sourceTree = "<group>"; };
|
||||
DA24EBE719DAD6DE00FF010B /* Icon-64.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-64.png"; sourceTree = "<group>"; };
|
||||
DA250A13195665A100AC23F1 /* UITableView+PearlReloadItems.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+PearlReloadItems.m"; sourceTree = "<group>"; };
|
||||
DA250A14195665A100AC23F1 /* UITableView+PearlReloadItems.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+PearlReloadItems.h"; sourceTree = "<group>"; };
|
||||
DA250A15195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UICollectionReusableView+PearlDequeue.m"; sourceTree = "<group>"; };
|
||||
@@ -653,6 +644,21 @@
|
||||
DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.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; };
|
||||
DA5E0E4624589C9A0007FBA7 /* Icon-Small@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small@3x.png"; sourceTree = "<group>"; };
|
||||
DA5E0E4724589C9A0007FBA7 /* Icon-Small-40.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-40.png"; sourceTree = "<group>"; };
|
||||
DA5E0E4824589C9A0007FBA7 /* Icon-Small-20.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-20.png"; sourceTree = "<group>"; };
|
||||
DA5E0E4924589C9A0007FBA7 /* Icon-76.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-76.png"; sourceTree = "<group>"; };
|
||||
DA5E0E4A24589C9A0007FBA7 /* Icon-Small@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small@2x.png"; sourceTree = "<group>"; };
|
||||
DA5E0E4B24589C9A0007FBA7 /* Icon-Small-40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-40@2x.png"; sourceTree = "<group>"; };
|
||||
DA5E0E4C24589C9A0007FBA7 /* Icon-76@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-76@2x.png"; sourceTree = "<group>"; };
|
||||
DA5E0E4D24589C9A0007FBA7 /* Icon-Small-20@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-20@3x.png"; sourceTree = "<group>"; };
|
||||
DA5E0E4E24589C9A0007FBA7 /* Icon-Small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small.png"; sourceTree = "<group>"; };
|
||||
DA5E0E4F24589C9A0007FBA7 /* Icon-83@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-83@2x.png"; sourceTree = "<group>"; };
|
||||
DA5E0E5024589C9A0007FBA7 /* Icon-Small-40@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-40@3x.png"; sourceTree = "<group>"; };
|
||||
DA5E0E5124589C9A0007FBA7 /* Icon-60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60@3x.png"; sourceTree = "<group>"; };
|
||||
DA5E0E5224589C9B0007FBA7 /* iTunesArtwork@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "iTunesArtwork@2x.png"; sourceTree = "<group>"; };
|
||||
DA5E0E5324589C9B0007FBA7 /* Icon-Small-20@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-20@2x.png"; sourceTree = "<group>"; };
|
||||
DA5E0E5424589C9B0007FBA7 /* Icon-60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60@2x.png"; sourceTree = "<group>"; };
|
||||
DA5E5C3C1723681B003798D8 /* Square-bottom.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Square-bottom.png"; path = "Dividers/Square-bottom.png"; sourceTree = "<group>"; };
|
||||
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; };
|
||||
@@ -662,6 +668,7 @@
|
||||
DA67460B18DE7F0C00DFE240 /* Exo2.0-ExtraBold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo2.0-ExtraBold.otf"; sourceTree = "<group>"; };
|
||||
DA67460C18DE7F0C00DFE240 /* Exo2.0-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo2.0-Bold.otf"; sourceTree = "<group>"; };
|
||||
DA70EC7F1811B13C00F65DB2 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
|
||||
DA72E22F2453B91700676D4F /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
|
||||
DA771FE41E6E1595004D7EDE /* MasterPassword-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MasterPassword-Prefix.pch"; sourceTree = "<group>"; };
|
||||
DA854C8118D4CFBF00106317 /* avatar-add@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-add@2x.png"; sourceTree = "<group>"; };
|
||||
DA854C8218D4CFBF00106317 /* avatar-add.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-add.png"; sourceTree = "<group>"; };
|
||||
@@ -1597,6 +1604,7 @@
|
||||
DAE2725A19C93B8E007C5262 /* StoreKit.framework in Frameworks */,
|
||||
DA6701E016406BB400B61001 /* AdSupport.framework in Frameworks */,
|
||||
DA6701DE16406B7300B61001 /* Social.framework in Frameworks */,
|
||||
DA72E2302453B91700676D4F /* WebKit.framework in Frameworks */,
|
||||
DA6701B816406A4100B61001 /* Accounts.framework in Frameworks */,
|
||||
DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */,
|
||||
DA672D3014F9413D004A189C /* libPearl.a in Frameworks */,
|
||||
@@ -1685,21 +1693,21 @@
|
||||
DA24EBB119DAD4D000FF010B /* icon */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA24EBB219DAD4D000FF010B /* Icon-60.png */,
|
||||
DA24EBB319DAD4D000FF010B /* Icon-60@2x.png */,
|
||||
DA24EBB419DAD4D000FF010B /* Icon-60@3x.png */,
|
||||
DA24EBE719DAD6DE00FF010B /* Icon-64.png */,
|
||||
DA24EBB519DAD4D000FF010B /* Icon-76.png */,
|
||||
DA24EBB619DAD4D000FF010B /* Icon-76@2x.png */,
|
||||
DA24EBE619DAD6DE00FF010B /* Icon-320.png */,
|
||||
DA24EBB719DAD4D000FF010B /* Icon-Small-40.png */,
|
||||
DA24EBB819DAD4D000FF010B /* Icon-Small-40@2x.png */,
|
||||
DA24EBB919DAD4D000FF010B /* Icon-Small-40@3x.png */,
|
||||
DA24EBBA19DAD4D000FF010B /* Icon-Small.png */,
|
||||
DA24EBBB19DAD4D000FF010B /* Icon-Small@2x.png */,
|
||||
DA24EBBC19DAD4D000FF010B /* Icon-Small@3x.png */,
|
||||
DA24EBBD19DAD4D000FF010B /* iTunesArtwork.png */,
|
||||
DA24EBBE19DAD4D000FF010B /* iTunesArtwork@2x.png */,
|
||||
DA5E0E5424589C9B0007FBA7 /* Icon-60@2x.png */,
|
||||
DA5E0E5124589C9A0007FBA7 /* Icon-60@3x.png */,
|
||||
DA5E0E4924589C9A0007FBA7 /* Icon-76.png */,
|
||||
DA5E0E4C24589C9A0007FBA7 /* Icon-76@2x.png */,
|
||||
DA5E0E4F24589C9A0007FBA7 /* Icon-83@2x.png */,
|
||||
DA5E0E4824589C9A0007FBA7 /* Icon-Small-20.png */,
|
||||
DA5E0E5324589C9B0007FBA7 /* Icon-Small-20@2x.png */,
|
||||
DA5E0E4D24589C9A0007FBA7 /* Icon-Small-20@3x.png */,
|
||||
DA5E0E4724589C9A0007FBA7 /* Icon-Small-40.png */,
|
||||
DA5E0E4B24589C9A0007FBA7 /* Icon-Small-40@2x.png */,
|
||||
DA5E0E5024589C9A0007FBA7 /* Icon-Small-40@3x.png */,
|
||||
DA5E0E4E24589C9A0007FBA7 /* Icon-Small.png */,
|
||||
DA5E0E4A24589C9A0007FBA7 /* Icon-Small@2x.png */,
|
||||
DA5E0E4624589C9A0007FBA7 /* Icon-Small@3x.png */,
|
||||
DA5E0E5224589C9B0007FBA7 /* iTunesArtwork@2x.png */,
|
||||
);
|
||||
path = icon;
|
||||
sourceTree = "<group>";
|
||||
@@ -1775,6 +1783,7 @@
|
||||
DA5BFA47147E415C00F98B1E /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA72E22F2453B91700676D4F /* WebKit.framework */,
|
||||
DAFC1F6F2439795000D1CD66 /* CoreServices.framework */,
|
||||
DAB7AE5C1F3D752900C856B1 /* libjson-c.a */,
|
||||
DA6701B716406A4100B61001 /* Accounts.framework */,
|
||||
@@ -2770,8 +2779,6 @@
|
||||
93D39B050DD5F55E9794EFD4 /* MPPopdownSegue.m */,
|
||||
DABD3BEA1711E2DC00CF925C /* MPPreferencesViewController.h */,
|
||||
DABD3BEB1711E2DC00CF925C /* MPPreferencesViewController.m */,
|
||||
93D3924D6F77E6BF41AC32D3 /* MPRootSegue.h */,
|
||||
93D399493FEDDE74DD1A0C15 /* MPRootSegue.m */,
|
||||
93D39730673227EFF6DEFF19 /* MPSetupViewController.h */,
|
||||
93D39A28369954D147E239BA /* MPSetupViewController.m */,
|
||||
93D39975CE5AEC99E3F086C7 /* MPSiteCell.h */,
|
||||
@@ -3152,7 +3159,7 @@
|
||||
DA5BFA42147E415C00F98B1E /* Resources */,
|
||||
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */,
|
||||
4A87858EE3659604089E2F9F /* [CP] Embed Pods Frameworks */,
|
||||
DA3C4EB32439438B00A6C4A8 /* Upload Sentry dSYM */,
|
||||
DA3C4EB32439438B00A6C4A8 /* Sentry dSYM Upload */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -3286,6 +3293,7 @@
|
||||
DA69540617D975D900BF294E /* icon_gears.png in Resources */,
|
||||
DA67460D18DE7F0C00DFE240 /* Exo2.0-Thin.otf in Resources */,
|
||||
DA4522451902355C008F650A /* icon_book@2x.png in Resources */,
|
||||
DA5E0E5F24589C9B0007FBA7 /* Icon-Small-40@3x.png in Resources */,
|
||||
DA32D04919D2F417004F3F0E /* thumb_fuel@2x.png in Resources */,
|
||||
DAFC1F73243989FB00D1CD66 /* Launch Screen.storyboard in Resources */,
|
||||
DABD39371711E29700CF925C /* avatar-0.png in Resources */,
|
||||
@@ -3305,11 +3313,9 @@
|
||||
DA67461018DE7F0C00DFE240 /* Exo2.0-Bold.otf in Resources */,
|
||||
DABD39401711E29700CF925C /* avatar-13.png in Resources */,
|
||||
DA32D07C19D7D784004F3F0E /* background.png in Resources */,
|
||||
DA24EBE919DAD6DE00FF010B /* Icon-64.png in Resources */,
|
||||
DABD39411711E29700CF925C /* avatar-13@2x.png in Resources */,
|
||||
DABD39421711E29700CF925C /* avatar-14.png in Resources */,
|
||||
DABD39431711E29700CF925C /* avatar-14@2x.png in Resources */,
|
||||
DA24EBE819DAD6DE00FF010B /* Icon-320.png in Resources */,
|
||||
DAA1764419D8B82B0044227B /* personal_pw.png in Resources */,
|
||||
DABD39441711E29700CF925C /* avatar-15.png in Resources */,
|
||||
DABD39451711E29700CF925C /* avatar-15@2x.png in Resources */,
|
||||
@@ -3363,11 +3369,14 @@
|
||||
DA32D00919CF5C55004F3F0E /* icon_question.png in Resources */,
|
||||
DABD39561711E29700CF925C /* avatar-6@2x.png in Resources */,
|
||||
DA32D07B19D7D784004F3F0E /* background@2x.png in Resources */,
|
||||
DA5E0E6224589C9B0007FBA7 /* Icon-Small-20@2x.png in Resources */,
|
||||
DABD39571711E29700CF925C /* avatar-7.png in Resources */,
|
||||
DABD39581711E29700CF925C /* avatar-7@2x.png in Resources */,
|
||||
DA5E0E5C24589C9B0007FBA7 /* Icon-Small-20@3x.png in Resources */,
|
||||
DABD39591711E29700CF925C /* avatar-8.png in Resources */,
|
||||
DA32D00A19CF5C55004F3F0E /* icon_question@2x.png in Resources */,
|
||||
DAA1764019D8B82B0044227B /* site_new.png in Resources */,
|
||||
DA5E0E5924589C9B0007FBA7 /* Icon-Small@2x.png in Resources */,
|
||||
DABD395A1711E29700CF925C /* avatar-8@2x.png in Resources */,
|
||||
DABD395B1711E29700CF925C /* avatar-9.png in Resources */,
|
||||
DAA1765419D8B82B0044227B /* choose_type.png in Resources */,
|
||||
@@ -3377,23 +3386,30 @@
|
||||
DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */,
|
||||
DA32D04E19D2F59B004F3F0E /* meter_fuel@3x.png in Resources */,
|
||||
DA25C5FE197DBF200046CDCF /* icon_thumbs-up.png in Resources */,
|
||||
DA5E0E5624589C9B0007FBA7 /* Icon-Small-40.png in Resources */,
|
||||
DABD39871711E29700CF925C /* SourceCodePro-Black.otf in Resources */,
|
||||
DABD39881711E29700CF925C /* SourceCodePro-ExtraLight.otf in Resources */,
|
||||
DABD39A01711E29700CF925C /* icon_action.png in Resources */,
|
||||
DA5E0E5524589C9B0007FBA7 /* Icon-Small@3x.png in Resources */,
|
||||
DABD39A11711E29700CF925C /* icon_action@2x.png in Resources */,
|
||||
DABD39F21711E29700CF925C /* icon_cancel.png in Resources */,
|
||||
DA25C5FB197CCAE00046CDCF /* icon_delete@2x.png in Resources */,
|
||||
DA5E0E5724589C9B0007FBA7 /* Icon-Small-20.png in Resources */,
|
||||
DA29993219C9132F00AF7DF1 /* thumb_generated_login@3x.png in Resources */,
|
||||
DA29992F19C86F5700AF7DF1 /* thumb_generated_login@2x.png in Resources */,
|
||||
DA73049F194E022B00E72520 /* ui_textfield.png in Resources */,
|
||||
DABD39F31711E29700CF925C /* icon_cancel@2x.png in Resources */,
|
||||
DA5E0E5B24589C9B0007FBA7 /* Icon-76@2x.png in Resources */,
|
||||
DABD3A261711E29700CF925C /* icon_edit.png in Resources */,
|
||||
DABD3A271711E29700CF925C /* icon_edit@2x.png in Resources */,
|
||||
DA24EBAF19DAD08C00FF010B /* tip_basic_black_top@2x.png in Resources */,
|
||||
DABD3A3A1711E29700CF925C /* icon_find.png in Resources */,
|
||||
DA5E0E6324589C9B0007FBA7 /* Icon-60@2x.png in Resources */,
|
||||
DABD3A3B1711E29700CF925C /* icon_find@2x.png in Resources */,
|
||||
DAA1765319D8B82B0044227B /* choose_type@2x.png in Resources */,
|
||||
DA5E0E6124589C9B0007FBA7 /* iTunesArtwork@2x.png in Resources */,
|
||||
DABD3AA01711E29800CF925C /* icon_pause.png in Resources */,
|
||||
DA5E0E5A24589C9B0007FBA7 /* Icon-Small-40@2x.png in Resources */,
|
||||
DABD3AA11711E29800CF925C /* icon_pause@2x.png in Resources */,
|
||||
DAA1764219D8B82B0044227B /* settings.png in Resources */,
|
||||
DABD3AAA1711E29800CF925C /* icon_person.png in Resources */,
|
||||
@@ -3418,7 +3434,6 @@
|
||||
DABD3B951711E29800CF925C /* pull-down.png in Resources */,
|
||||
DABD3B961711E29800CF925C /* pull-down@2x.png in Resources */,
|
||||
DABD3B971711E29800CF925C /* pull-up.png in Resources */,
|
||||
DA24EBEA19DAD6EE00FF010B /* Icon-Small.png in Resources */,
|
||||
DA8495321A93049300B3053D /* icon_down@2x.png in Resources */,
|
||||
DABD3B981711E29800CF925C /* pull-up@2x.png in Resources */,
|
||||
DA7304A0194E022B00E72520 /* ui_textfield@2x.png in Resources */,
|
||||
@@ -3427,10 +3442,9 @@
|
||||
DA452249190628A1008F650A /* icon_wrench.png in Resources */,
|
||||
DAA1764519D8B82B0044227B /* name_new@2x.png in Resources */,
|
||||
DA45224819062899008F650A /* icon_settings@2x.png in Resources */,
|
||||
DA5E0E5E24589C9B0007FBA7 /* Icon-83@2x.png in Resources */,
|
||||
DA854C8418D4CFBF00106317 /* avatar-add.png in Resources */,
|
||||
DA24EBEB19DAD6EE00FF010B /* Icon-Small@2x.png in Resources */,
|
||||
DAA1764B19D8B82B0044227B /* login_name@2x.png in Resources */,
|
||||
DABD3C241711E2DC00CF925C /* MasterPassword.entitlements in Resources */,
|
||||
DABD3C251711E2DC00CF925C /* Settings.bundle in Resources */,
|
||||
DABD3C261711E2DC00CF925C /* InfoPlist.strings in Resources */,
|
||||
DA32D05119D3D107004F3F0E /* icon_meter.png in Resources */,
|
||||
@@ -3444,16 +3458,18 @@
|
||||
DAA1764619D8B82B0044227B /* name_new.png in Resources */,
|
||||
DA45224B190628B2008F650A /* icon_gear.png in Resources */,
|
||||
DAAA1D4123CD145000F3DF56 /* Storyboard.storyboard in Resources */,
|
||||
DA5E0E6024589C9B0007FBA7 /* Icon-60@3x.png in Resources */,
|
||||
DA8495311A93049300B3053D /* icon_down.png in Resources */,
|
||||
DA5E0E5D24589C9B0007FBA7 /* Icon-Small.png in Resources */,
|
||||
DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */,
|
||||
DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */,
|
||||
DA5A09DF171A70E4005284AB /* play.png in Resources */,
|
||||
DA24EBEC19DAD6EE00FF010B /* Icon-Small@3x.png in Resources */,
|
||||
DA5A09E0171A70E4005284AB /* play@2x.png in Resources */,
|
||||
DA5A09EA171BB0F7005284AB /* unlocked.png in Resources */,
|
||||
DAA1762819D89B610044227B /* thumb_ios_integration.png in Resources */,
|
||||
DA5A09EB171BB0F7005284AB /* unlocked@2x.png in Resources */,
|
||||
DAA1764F19D8B82B0044227B /* counter@2x.png in Resources */,
|
||||
DA5E0E5824589C9B0007FBA7 /* Icon-76.png in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -3499,7 +3515,7 @@
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
DA3C4EB32439438B00A6C4A8 /* Upload Sentry dSYM */ = {
|
||||
DA3C4EB32439438B00A6C4A8 /* Sentry dSYM Upload */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 8;
|
||||
files = (
|
||||
@@ -3507,15 +3523,16 @@
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}",
|
||||
);
|
||||
name = "Upload Sentry dSYM";
|
||||
name = "Sentry dSYM Upload";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
shellPath = "/bin/sh -e";
|
||||
shellScript = "if hash sentry-cli 2>/dev/null; then\n if ! ERROR=$(SENTRY_ORG=lyndir SENTRY_PROJECT=masterpassword-ios sentry-cli upload-dif --log-level info \"$DWARF_DSYM_FOLDER_PATH\" 2>&1 >/dev/null); then\n echo >&2 \"warning: sentry-cli: $ERROR\"\n fi\nelse\n echo >&2 \"warning: sentry-cli not installed: try brew install getsentry/tools/sentry-cli\"\nfi\n";
|
||||
shellScript = "if ! hash sentry-cli 2>/dev/null; then\n echo >&2 \"error: sentry-cli not installed. Try brew install getsentry/tools/sentry-cli\"\n exit 1\nfi\n\nSENTRY_ORG=lyndir SENTRY_PROJECT=masterpassword-ios sentry-cli upload-dif --log-level info \"$DWARF_DSYM_FOLDER_PATH\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */ = {
|
||||
@@ -3618,7 +3635,6 @@
|
||||
93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */,
|
||||
DA46021D23D5E30B00398FF4 /* MPSecrets.m in Sources */,
|
||||
93D39A27F2506C6FEEF9C588 /* MPAlgorithmV2.m in Sources */,
|
||||
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */,
|
||||
93D392FD5E2052F7D7DB3774 /* NSString+MPMarkDown.m in Sources */,
|
||||
93D395B715D15F2B56F2A2EE /* mpw-types.c in Sources */,
|
||||
93D39943D01E70DAC3B0DF76 /* mpw-util.c in Sources */,
|
||||
@@ -3664,7 +3680,6 @@
|
||||
DAFE4A2E15039824003ABA7C /* PearlStrings.m in Sources */,
|
||||
DAFE4A3015039824003ABA7C /* PearlStringUtils.m in Sources */,
|
||||
DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */,
|
||||
DA72BD7B19C1510C00E6ACFE /* UIView+FontScale.m in Sources */,
|
||||
DA250A17195665A100AC23F1 /* UITableView+PearlReloadItems.m in Sources */,
|
||||
DAFE4A4115039824003ABA7C /* PearlArrayTVC.m in Sources */,
|
||||
DAFE4A4315039824003ABA7C /* PearlBoxView.m in Sources */,
|
||||
@@ -3865,7 +3880,6 @@
|
||||
SKIP_INSTALL = YES;
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
STRIP_SWIFT_SYMBOLS = NO;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
WARNING_CFLAGS = "-Wno-float-conversion";
|
||||
};
|
||||
@@ -3994,10 +4008,6 @@
|
||||
"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
|
||||
);
|
||||
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(PROJECT_DIR)/../lib/libsodium/build-ios~/out/lib\"",
|
||||
@@ -4005,7 +4015,7 @@
|
||||
);
|
||||
OTHER_CFLAGS = (
|
||||
"-DMPW_SODIUM=1",
|
||||
"-DMPW_CPERCIVA=0",
|
||||
"-DMPW_JSON=1",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
|
||||
PRODUCT_NAME = MasterPassword;
|
||||
@@ -4013,9 +4023,6 @@
|
||||
SKIP_INSTALL = NO;
|
||||
STRIP_INSTALLED_PRODUCT = YES;
|
||||
STRIP_SWIFT_SYMBOLS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Source/iOS/MasterPassword-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -4028,7 +4035,6 @@
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO;
|
||||
CODE_SIGN_ENTITLEMENTS = Source/iOS/MasterPassword.entitlements;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
EXCLUDED_SOURCE_FILE_NAMES = libDCIntrospect.a;
|
||||
GCC_C_LANGUAGE_STANDARD = c11;
|
||||
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
|
||||
@@ -4038,10 +4044,6 @@
|
||||
"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
|
||||
);
|
||||
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(PROJECT_DIR)/../lib/libsodium/build-ios~/out/lib\"",
|
||||
@@ -4049,7 +4051,7 @@
|
||||
);
|
||||
OTHER_CFLAGS = (
|
||||
"-DMPW_SODIUM=1",
|
||||
"-DMPW_CPERCIVA=0",
|
||||
"-DMPW_JSON=1",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
|
||||
PRODUCT_NAME = MasterPassword;
|
||||
@@ -4057,10 +4059,6 @@
|
||||
SKIP_INSTALL = NO;
|
||||
STRIP_INSTALLED_PRODUCT = YES;
|
||||
STRIP_SWIFT_SYMBOLS = YES;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Source/iOS/MasterPassword-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -73,6 +73,13 @@
|
||||
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
||||
referenceType = "1">
|
||||
</LocationScenarioReference>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "TERM"
|
||||
value = "color"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Debug"
|
||||
|
||||
@@ -101,7 +101,6 @@
|
||||
DA5E5D011724A667003798D8 /* MPKey.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CAE1724A667003798D8 /* MPKey.m */; };
|
||||
DA5E5D031724A667003798D8 /* MPMacAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CB41724A667003798D8 /* MPMacAppDelegate.m */; };
|
||||
DA5E5D041724A667003798D8 /* MPMacConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CB61724A667003798D8 /* MPMacConfig.m */; };
|
||||
DA5E5D081724A667003798D8 /* MasterPassword.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CBF1724A667003798D8 /* MasterPassword.entitlements */; };
|
||||
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CC21724A667003798D8 /* InfoPlist.strings */; };
|
||||
DA5E5D0B1724A667003798D8 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CC41724A667003798D8 /* MainMenu.xib */; };
|
||||
DA5E5D0C1724A667003798D8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CC61724A667003798D8 /* main.m */; };
|
||||
@@ -2329,7 +2328,7 @@
|
||||
DAD9B5EE1762CA3A001835F9 /* Copy LoginHelper */,
|
||||
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */,
|
||||
43E5966C8C236E86824DDADE /* [CP] Embed Pods Frameworks */,
|
||||
DA3C4EB2243941AE00A6C4A8 /* Upload Sentry dSYM */,
|
||||
DA3C4EB2243941AE00A6C4A8 /* Sentry dSYM Upload */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -2388,7 +2387,7 @@
|
||||
CLASSPREFIX = MP;
|
||||
LastSwiftUpdateCheck = 0720;
|
||||
LastTestingUpgradeCheck = 0510;
|
||||
LastUpgradeCheck = 1140;
|
||||
LastUpgradeCheck = 1200;
|
||||
ORGANIZATIONNAME = Lyndir;
|
||||
TargetAttributes = {
|
||||
DA1C7AA61F1A8F24009A3551 = {
|
||||
@@ -2535,7 +2534,6 @@
|
||||
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */,
|
||||
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */,
|
||||
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
|
||||
DA5E5D081724A667003798D8 /* MasterPassword.entitlements in Resources */,
|
||||
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */,
|
||||
DA5E5D0B1724A667003798D8 /* MainMenu.xib in Resources */,
|
||||
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */,
|
||||
@@ -2585,7 +2583,7 @@
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
DA3C4EB2243941AE00A6C4A8 /* Upload Sentry dSYM */ = {
|
||||
DA3C4EB2243941AE00A6C4A8 /* Sentry dSYM Upload */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 8;
|
||||
files = (
|
||||
@@ -2593,15 +2591,16 @@
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}",
|
||||
);
|
||||
name = "Upload Sentry dSYM";
|
||||
name = "Sentry dSYM Upload";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
shellPath = "/bin/sh -e";
|
||||
shellScript = "if hash sentry-cli 2>/dev/null; then\n if ! ERROR=$(SENTRY_ORG=lyndir SENTRY_PROJECT=masterpassword-macos sentry-cli upload-dif --log-level info \"$DWARF_DSYM_FOLDER_PATH\" 2>&1 >/dev/null); then\n echo >&2 \"warning: sentry-cli: $ERROR\"\n fi\nelse\n echo >&2 \"warning: sentry-cli not installed: try brew install getsentry/tools/sentry-cli\"\nfi\n";
|
||||
shellScript = "if ! hash sentry-cli 2>/dev/null; then\n echo >&2 \"error: sentry-cli not installed. Try brew install getsentry/tools/sentry-cli\"\n exit 1\nfi\n\nSENTRY_ORG=lyndir SENTRY_PROJECT=masterpassword-macos sentry-cli upload-dif --log-level info \"$DWARF_DSYM_FOLDER_PATH\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
DA4EF9CB19FD4B600032ECB5 /* Run Script: genassets */ = {
|
||||
@@ -3025,6 +3024,7 @@
|
||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
@@ -3126,6 +3126,7 @@
|
||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
@@ -3201,6 +3202,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
||||
@@ -3240,6 +3242,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1140"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
@@ -27,15 +27,6 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
|
||||
BuildableName = "Master Password.app"
|
||||
BlueprintName = "MasterPassword-macOS"
|
||||
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
@@ -59,6 +50,17 @@
|
||||
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "TERM"
|
||||
value = "color"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<LocationScenarioReference
|
||||
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
||||
referenceType = "1">
|
||||
</LocationScenarioReference>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Debug"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1140"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
@@ -27,15 +27,6 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "DA1C7AC61F1A8FD8009A3551"
|
||||
BuildableName = "mpw-bench"
|
||||
BlueprintName = "mpw-bench"
|
||||
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
@@ -59,6 +50,17 @@
|
||||
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "TERM"
|
||||
value = "color"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<LocationScenarioReference
|
||||
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
||||
referenceType = "1">
|
||||
</LocationScenarioReference>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1140"
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -27,15 +27,6 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "DA1C7AA61F1A8F24009A3551"
|
||||
BuildableName = "mpw-cli"
|
||||
BlueprintName = "mpw-cli"
|
||||
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
@@ -81,6 +72,13 @@
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "TERM"
|
||||
value = "color"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<LocationScenarioReference
|
||||
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
||||
referenceType = "1">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1140"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
@@ -27,15 +27,6 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "DA67743A1A474A03004F356A"
|
||||
BuildableName = "mpw-test"
|
||||
BlueprintName = "mpw-test"
|
||||
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
@@ -60,6 +51,17 @@
|
||||
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "TERM"
|
||||
value = "color"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<LocationScenarioReference
|
||||
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
||||
referenceType = "1">
|
||||
</LocationScenarioReference>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Debug"
|
||||
|
||||
@@ -28,3 +28,14 @@ target 'MasterPassword-macOS' do
|
||||
pod 'KCOrderedAccessorFix'
|
||||
pod 'JRSwizzle'
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
if target.name == 'Countly-iOS' || target.name == 'Countly-macOS'
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'COUNTLY_EXCLUDE_IDFA=1'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
Before Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 843 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 236 KiB |
|
Before Width: | Height: | Size: 879 KiB After Width: | Height: | Size: 879 KiB |
@@ -34,7 +34,7 @@ icons=(
|
||||
# 57@1@iphone@:Icon.png
|
||||
# 29@1@iphone@:Icon-Small.png
|
||||
# iPad
|
||||
# 76@1@ipad@7.0:Icon-76.png
|
||||
76@1@ipad@7.0:Icon-76.png
|
||||
152@2@ipad@7.0:Icon-76@2x.png
|
||||
167@2@ipad@9.0:Icon-83@2x.png
|
||||
20@1@ipad@7.0:Icon-Small-20.png
|
||||
|
||||
@@ -46,9 +46,10 @@ esac
|
||||
description=$(git describe --always --dirty --long --match "*-$platform*")
|
||||
version=${description%-g*} build=${version##*-} version=${version%-$build}
|
||||
version=${version//-$platform/} version=${version//-/.} commit=${description##*-g}
|
||||
IFS=. read major minor build <<< "$version"
|
||||
|
||||
addPlistWithKey GITDescription string "$description"
|
||||
setPlistWithKey CFBundleVersion "$(hr "${version%%.*}" 14).${version#*.}"
|
||||
setPlistWithKey CFBundleVersion "$(hr "$major" 14)$(printf '%02d' "$minor")$(printf '%02d' "$build")"
|
||||
setPlistWithKey CFBundleShortVersionString "$version"
|
||||
|
||||
setSettingWithTitle "Build" "$commit"
|
||||
|
||||
@@ -621,7 +621,7 @@ static NSOperationQueue *_mpwQueue = nil;
|
||||
|
||||
- (NSString *)exportLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)key {
|
||||
|
||||
if (!(site.type & MPSiteFeatureExportContent) || site.loginGenerated || ![site.loginName length])
|
||||
if (site.loginGenerated || ![site.loginName length])
|
||||
return nil;
|
||||
|
||||
__block NSData *state = nil;
|
||||
|
||||
@@ -117,7 +117,7 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
|
||||
[self performPurchaseProductWithIdentifier:productIdentifier quantity:quantity];
|
||||
}]];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:controller animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:controller animated:YES completion:nil];
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -158,16 +158,16 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
|
||||
|
||||
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
|
||||
|
||||
MPError( error, @"StoreKit request (%@) failed.", request );
|
||||
MPError( error, @"StoreKit request failed." );
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Purchase Failed" message:
|
||||
strf( @"%@\n\n%@", error.localizedDescription,
|
||||
@"Ensure you are online and try logging out and back into iTunes from your device's Settings." )
|
||||
@"Could not reach Apple's iTunes Store. Make sure you're connected to the Internet and try again." )
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:controller animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:controller animated:YES completion:nil];
|
||||
} );
|
||||
#endif
|
||||
}
|
||||
@@ -197,18 +197,16 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
|
||||
forKey:transaction.payment.productIdentifier];
|
||||
[queue finishTransaction:transaction];
|
||||
|
||||
if ([[MPConfig get].sendInfo boolValue]) {
|
||||
SKProduct *product = self.products[transaction.payment.productIdentifier];
|
||||
[attributes addEntriesFromDictionary:@{
|
||||
@"id": product.productIdentifier,
|
||||
@"name": product.localizedTitle,
|
||||
@"price": product.price.description,
|
||||
@"currency": [product.priceLocale objectForKey:NSLocaleCurrencyCode],
|
||||
@"state" : @"success",
|
||||
@"quantity": @(transaction.payment.quantity).description,
|
||||
}];
|
||||
[Countly.sharedInstance recordEvent:@"purchase" segmentation:attributes];
|
||||
}
|
||||
SKProduct *product = self.products[transaction.payment.productIdentifier];
|
||||
[attributes addEntriesFromDictionary:@{
|
||||
@"id": product.productIdentifier,
|
||||
@"name": product.localizedTitle,
|
||||
@"price": product.price.description,
|
||||
@"currency": [product.priceLocale objectForKey:NSLocaleCurrencyCode],
|
||||
@"state" : @"success",
|
||||
@"quantity": @(transaction.payment.quantity).description,
|
||||
}];
|
||||
[Countly.sharedInstance recordEvent:@"purchase" segmentation:attributes];
|
||||
break;
|
||||
}
|
||||
case SKPaymentTransactionStateRestored: {
|
||||
@@ -224,18 +222,27 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
|
||||
MPError( transaction.error, @"Transaction failed: %@.", transaction.payment.productIdentifier );
|
||||
[queue finishTransaction:transaction];
|
||||
|
||||
if ([[MPConfig get].sendInfo boolValue]) {
|
||||
SKProduct *product = self.products[transaction.payment.productIdentifier];
|
||||
[Countly.sharedInstance recordEvent:@"purchase" segmentation:@{
|
||||
@"id": product.productIdentifier,
|
||||
@"name": product.localizedTitle,
|
||||
@"price": product.price.description,
|
||||
@"currency": [product.priceLocale objectForKey:NSLocaleCurrencyCode],
|
||||
@"state" : @"failed",
|
||||
@"quantity": @(transaction.payment.quantity).description,
|
||||
@"reason" : [transaction.error localizedFailureReason]?: [transaction.error localizedDescription],
|
||||
}];
|
||||
}
|
||||
#if TARGET_OS_IPHONE
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Purchase Failed" message:
|
||||
strf( @"%@\n\n%@", transaction.error.localizedDescription,
|
||||
@"Could not reach Apple's iTunes Store. Make sure you're connected to the Internet and try again." )
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.window.rootViewController presentViewController:controller animated:YES completion:nil];
|
||||
} );
|
||||
#endif
|
||||
|
||||
SKProduct *product = self.products[transaction.payment.productIdentifier];
|
||||
[Countly.sharedInstance recordEvent:@"purchase" segmentation:@{
|
||||
@"id": product.productIdentifier,
|
||||
@"name": product.localizedTitle,
|
||||
@"price": product.price.description,
|
||||
@"currency": [product.priceLocale objectForKey:NSLocaleCurrencyCode],
|
||||
@"state" : @"failed",
|
||||
@"quantity": @(transaction.payment.quantity).description,
|
||||
@"reason" : [transaction.error localizedFailureReason]?: [transaction.error localizedDescription],
|
||||
}];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,13 +173,11 @@
|
||||
else
|
||||
dbg( @"Automatic login failed for user: %@", user.userID );
|
||||
|
||||
if ([[MPConfig get].sendInfo boolValue]) {
|
||||
[Countly.sharedInstance recordEvent:@"login" segmentation:@{
|
||||
@"method" : password? @"Password": @"Automatic",
|
||||
@"state" : @"failed",
|
||||
@"algorithm": @(user.algorithm.version).description,
|
||||
}];
|
||||
}
|
||||
[Countly.sharedInstance recordEvent:@"login" segmentation:@{
|
||||
@"method" : password? @"Password": @"Automatic",
|
||||
@"state" : @"failed",
|
||||
@"algorithm": @(user.algorithm.version).description,
|
||||
}];
|
||||
|
||||
return NO;
|
||||
}
|
||||
@@ -203,15 +201,14 @@
|
||||
}
|
||||
|
||||
@try {
|
||||
if ([[MPConfig get].sendInfo boolValue]) {
|
||||
[Countly.sharedInstance userLoggedIn:user.userID];
|
||||
[SentrySDK setUser:[[SentryUser alloc] initWithUserId:user.userID]];
|
||||
[Countly.sharedInstance userLoggedIn:user.userID];
|
||||
|
||||
[Countly.sharedInstance recordEvent:@"login" segmentation:@{
|
||||
@"method" : password? @"Password": @"Automatic",
|
||||
@"state" : @"success",
|
||||
@"algorithm": @(user.algorithm.version).description,
|
||||
}];
|
||||
}
|
||||
[Countly.sharedInstance recordEvent:@"login" segmentation:@{
|
||||
@"method" : password? @"Password": @"Automatic",
|
||||
@"state" : @"success",
|
||||
@"algorithm": @(user.algorithm.version).description,
|
||||
}];
|
||||
}
|
||||
@catch (id exception) {
|
||||
err( @"While setting username: %@", exception );
|
||||
@@ -252,18 +249,18 @@
|
||||
masterPassword = PearlAwait( ^(void (^setResult)(id)) {
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Enter Old Master Password" message:
|
||||
strf( @"Your old master password is required to migrate the stored password for %@", site.name )
|
||||
strf( @"Your old master password is required to unlock the stored password for: <%@>", site.name )
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[controller addTextFieldWithConfigurationHandler:nil];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Migrate" style:UIAlertActionStyleDefault handler:
|
||||
^(UIAlertAction *_Nonnull action) {
|
||||
setResult( controller.textFields.firstObject.text );
|
||||
}]];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Don't Migrate" style:UIAlertActionStyleCancel handler:
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Leave It" style:UIAlertActionStyleCancel handler:
|
||||
^(UIAlertAction *_Nonnull action) {
|
||||
setResult( nil );
|
||||
}]];
|
||||
[self.navigationController presentViewController:controller animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:controller animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
@interface MPAppDelegate_Shared : PearlAppDelegate
|
||||
@interface MPAppDelegate_Shared : UIResponder<UIApplicationDelegate, PearlConfigDelegate>
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@@ -116,11 +116,9 @@ static MPAppDelegate_Shared *instance;
|
||||
if (self.activeUserOID == activeUserOID || [self.activeUserOID isEqual:activeUserOID])
|
||||
return;
|
||||
|
||||
if (self.key)
|
||||
self.key = nil;
|
||||
|
||||
if ([[MPConfig get].sendInfo boolValue])
|
||||
[Countly.sharedInstance userLoggedOut];
|
||||
self.key = nil;
|
||||
[SentrySDK setUser:nil];
|
||||
[Countly.sharedInstance userLoggedOut];
|
||||
|
||||
self.activeUserOID = activeUserOID;
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
- (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock;
|
||||
|
||||
- (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context;
|
||||
- (void)retryCorruptStore;
|
||||
- (void)deleteAndResetStore;
|
||||
|
||||
/** @param completion The block to execute after adding the site, executed from the main thread with the new site in the main MOC. */
|
||||
@@ -39,8 +40,9 @@
|
||||
askImportPassword:(NSString *( ^ )(NSString *userName))importPassword
|
||||
askUserPassword:(NSString *( ^ )(NSString *userName))userPassword
|
||||
result:(void ( ^ )(NSError *error))resultBlock;
|
||||
- (void)exportSitesRevealPasswords:(BOOL)revealPasswords
|
||||
askExportPassword:(NSString *( ^ )(NSString *userName))askImportPassword
|
||||
result:(void ( ^ )(NSString *exportedUser, NSError *error))resultBlock;
|
||||
- (NSString *)exportSitesFor:(MPUserEntity *)user
|
||||
revealPasswords:(BOOL)revealPasswords
|
||||
askExportPassword:(NSString *( ^ )(NSString *userName))askExportPassword
|
||||
error:(__autoreleasing NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "mpw-marshal.h"
|
||||
#import "mpw-util.h"
|
||||
#import "MPAppDelegate_InApp.h"
|
||||
#import "MPSecrets.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#define STORE_OPTIONS NSPersistentStoreFileProtectionKey : NSFileProtectionComplete,
|
||||
@@ -181,12 +183,12 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
} );
|
||||
|
||||
// Do nothing if already fully set up, otherwise (re-)load the store.
|
||||
if (self.storeCoordinator && self.mainManagedObjectContext && self.privateManagedObjectContext)
|
||||
if (self.mainManagedObjectContext && self.privateManagedObjectContext)
|
||||
return;
|
||||
|
||||
[self.storeQueue addOperationWithBlock:^{
|
||||
// Do nothing if already fully set up, otherwise (re-)load the store.
|
||||
if (self.storeCoordinator && self.mainManagedObjectContext && self.privateManagedObjectContext)
|
||||
if (self.mainManagedObjectContext && self.privateManagedObjectContext)
|
||||
return;
|
||||
|
||||
// Unregister any existing observers and contexts.
|
||||
@@ -199,6 +201,12 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
[self.privateManagedObjectContext reset];
|
||||
self.privateManagedObjectContext = nil;
|
||||
}];
|
||||
NSError *error = nil;
|
||||
for (NSPersistentStore *store in self.storeCoordinator.persistentStores)
|
||||
if (![self.storeCoordinator removePersistentStore:store error:&error] || error) {
|
||||
MPError( error, @"Couldn't remove persistence store from coordinator." );
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't load when the store is corrupted.
|
||||
if ([self.storeCorrupted boolValue])
|
||||
@@ -207,12 +215,36 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
// Check if migration is necessary.
|
||||
[self migrateStore];
|
||||
|
||||
// Create a new store coordinator.
|
||||
NSURL *localStoreURL = [self localStoreURL];
|
||||
if (![[NSFileManager defaultManager] createDirectoryAtURL:[localStoreURL URLByDeletingLastPathComponent]
|
||||
withIntermediateDirectories:YES attributes:nil error:&error]) {
|
||||
MPError( error, @"Couldn't create our application support directory." );
|
||||
PearlRemoveNotificationObserversFrom( self.mainManagedObjectContext );
|
||||
self.mainManagedObjectContext = nil;
|
||||
self.privateManagedObjectContext = nil;
|
||||
return;
|
||||
}
|
||||
if (![self.storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:localStoreURL
|
||||
options:@{
|
||||
NSMigratePersistentStoresAutomaticallyOption: @YES,
|
||||
NSInferMappingModelAutomaticallyOption : @YES,
|
||||
STORE_OPTIONS
|
||||
} error:&error]) {
|
||||
MPError( error, @"Failed to open store." );
|
||||
PearlRemoveNotificationObserversFrom( self.mainManagedObjectContext );
|
||||
self.mainManagedObjectContext = nil;
|
||||
self.privateManagedObjectContext = nil;
|
||||
self.storeCorrupted = @YES;
|
||||
[self handleCoordinatorError:error];
|
||||
return;
|
||||
}
|
||||
self.storeCorrupted = @NO;
|
||||
|
||||
// Install managed object contexts and observers.
|
||||
self.privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
|
||||
[self.privateManagedObjectContext performBlockAndWait:^{
|
||||
self.privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
|
||||
self.privateManagedObjectContext.persistentStoreCoordinator = self.storeCoordinator;
|
||||
}];
|
||||
self.privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
|
||||
self.privateManagedObjectContext.persistentStoreCoordinator = self.storeCoordinator;
|
||||
|
||||
self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
||||
self.mainManagedObjectContext.parentContext = self.privateManagedObjectContext;
|
||||
@@ -232,28 +264,6 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
}];
|
||||
} );
|
||||
|
||||
|
||||
// Create a new store coordinator.
|
||||
NSError *error = nil;
|
||||
NSURL *localStoreURL = [self localStoreURL];
|
||||
if (![[NSFileManager defaultManager] createDirectoryAtURL:[localStoreURL URLByDeletingLastPathComponent]
|
||||
withIntermediateDirectories:YES attributes:nil error:&error]) {
|
||||
MPError( error, @"Couldn't create our application support directory." );
|
||||
return;
|
||||
}
|
||||
if (![self.storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self localStoreURL]
|
||||
options:@{
|
||||
NSMigratePersistentStoresAutomaticallyOption: @YES,
|
||||
NSInferMappingModelAutomaticallyOption : @YES,
|
||||
STORE_OPTIONS
|
||||
} error:&error]) {
|
||||
MPError( error, @"Failed to open store." );
|
||||
self.storeCorrupted = @YES;
|
||||
[self handleCoordinatorError:error];
|
||||
return;
|
||||
}
|
||||
self.storeCorrupted = @NO;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
PearlAddNotificationObserver( UIApplicationWillResignActiveNotification, UIApp, [NSOperationQueue mainQueue],
|
||||
^(MPAppDelegate_Shared *self, NSNotification *note) {
|
||||
@@ -274,6 +284,12 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)retryCorruptStore {
|
||||
|
||||
self.storeCorrupted = @NO;
|
||||
[self loadStore];
|
||||
}
|
||||
|
||||
- (void)deleteAndResetStore {
|
||||
|
||||
@synchronized (self) {
|
||||
@@ -563,50 +579,46 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
|
||||
// Read metadata for the import file.
|
||||
MPMarshalledFile *file = mpw_marshal_read( NULL, importData.UTF8String );
|
||||
if (!file)
|
||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(MPMarshalErrorInternal),
|
||||
NSLocalizedDescriptionKey: @"Could not process Master Password import data.",
|
||||
}]), @"While importing sites." );
|
||||
if (file->error.type != MPMarshalSuccess) {
|
||||
MPMarshalErrorType type = file->error.type;
|
||||
mpw_marshal_file_free( &file );
|
||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(type),
|
||||
NSLocalizedDescriptionKey: @"Could not parse Master Password import data.",
|
||||
}]), @"While importing sites." );
|
||||
}
|
||||
if (file->info->format == MPMarshalFormatNone) {
|
||||
mpw_marshal_file_free( &file );
|
||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(MPMarshalErrorFormat),
|
||||
NSLocalizedDescriptionKey: @"This is not a Master Password import file.",
|
||||
}]), @"While importing sites." );
|
||||
}
|
||||
|
||||
// Get master password for import file.
|
||||
MPKey *importKey;
|
||||
NSString *importMasterPassword;
|
||||
do {
|
||||
importMasterPassword = askImportPassword( @(file->info->fullName) );
|
||||
if (!importMasterPassword) {
|
||||
inf( @"Import cancelled." );
|
||||
mpw_marshal_file_free( &file );
|
||||
return MPError( ([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]), @"" );
|
||||
MPMarshalledUser *importUser = nil;
|
||||
@try {
|
||||
if (!file)
|
||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(MPMarshalErrorInternal),
|
||||
NSLocalizedDescriptionKey: @"Could not process Master Password import data.",
|
||||
}]), @"While importing sites." );
|
||||
if (file->error.type != MPMarshalSuccess) {
|
||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(file->error.type),
|
||||
NSLocalizedDescriptionKey: strf( @"Could not parse Master Password import data:\n%@", @(file->error.message) ),
|
||||
}]), @"While importing sites." );
|
||||
}
|
||||
if (file->info->format == MPMarshalFormatNone) {
|
||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(MPMarshalErrorFormat),
|
||||
NSLocalizedDescriptionKey: @"This is not a Master Password import file.",
|
||||
}]), @"While importing sites." );
|
||||
}
|
||||
|
||||
importKey = [[MPKey alloc] initForFullName:@(file->info->fullName) withMasterPassword:importMasterPassword];
|
||||
} while ([[[importKey keyIDForAlgorithm:MPAlgorithmForVersion( file->info->algorithm )] encodeHex]
|
||||
caseInsensitiveCompare:@(file->info->keyID)] != NSOrderedSame);
|
||||
// Get master password for import file.
|
||||
MPKey *importKey;
|
||||
NSString *importMasterPassword;
|
||||
do {
|
||||
importMasterPassword = askImportPassword( @(file->info->fullName) );
|
||||
if (!importMasterPassword) {
|
||||
inf( @"Import cancelled." );
|
||||
return MPError( ([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]), @"" );
|
||||
}
|
||||
|
||||
// Parse import data.
|
||||
MPMarshalledUser *importUser = mpw_marshal_auth( file, mpw_masterKeyProvider_str( importMasterPassword.UTF8String ) );
|
||||
importKey = [[MPKey alloc] initForFullName:@(file->info->fullName) withMasterPassword:importMasterPassword];
|
||||
} while ([[[importKey keyIDForAlgorithm:MPAlgorithmForVersion( file->info->algorithm )] encodeHex]
|
||||
caseInsensitiveCompare:@(file->info->keyID)] != NSOrderedSame);
|
||||
|
||||
@try {
|
||||
// Parse import data.
|
||||
importUser = mpw_marshal_auth( file, mpw_masterKeyProvider_str( importMasterPassword.UTF8String ) );
|
||||
if (!importUser || file->error.type != MPMarshalSuccess)
|
||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(file->error.type),
|
||||
NSLocalizedDescriptionKey: @(file->error.message),
|
||||
NSLocalizedDescriptionKey: strf( @"Could not authenticate Master Password import:\n%@", @(file->error.message) ),
|
||||
}]), @"While importing sites." );
|
||||
|
||||
// Find an existing user to update.
|
||||
@@ -708,31 +720,45 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
site.lastUsed = [NSDate dateWithTimeIntervalSince1970:importSite->lastUsed];
|
||||
}
|
||||
|
||||
- (void)exportSitesRevealPasswords:(BOOL)revealPasswords
|
||||
askExportPassword:(NSString *( ^ )(NSString *userName))askImportPassword
|
||||
result:(void ( ^ )(NSString *exportedUser, NSError *error))resultBlock {
|
||||
|
||||
[MPAppDelegate_Shared managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPUserEntity *user = [self activeUserInContext:context];
|
||||
- (NSString *)exportSitesFor:(MPUserEntity *)user
|
||||
revealPasswords:(BOOL)revealPasswords
|
||||
askExportPassword:(NSString *( ^ )(NSString *userName))askExportPassword
|
||||
error:(__autoreleasing NSError **)error {
|
||||
|
||||
MPMarshalledUser *exportUser = NULL;
|
||||
MPMarshalledFile *exportFile = mpw_marshal_file( NULL, NULL, mpw_marshal_data_new() );
|
||||
@try {
|
||||
inf( @"Exporting sites, %@, for user: %@", revealPasswords? @"revealing passwords": @"omitting passwords", user.userID );
|
||||
MPMarshalledUser *exportUser = mpw_marshal_user( user.name.UTF8String,
|
||||
mpw_masterKeyProvider_str( askImportPassword( user.name ).UTF8String ), user.algorithm.version );
|
||||
NSString *masterPassword = askExportPassword( user.name );
|
||||
if (!masterPassword) {
|
||||
inf( @"Export cancelled." );
|
||||
return nil;
|
||||
}
|
||||
|
||||
for (NSString *feature in @[MPProductGenerateLogins, MPProductGenerateAnswers, MPProductOSIntegration, MPProductTouchID])
|
||||
if ([[MPAppDelegate_Shared get] isFeatureUnlocked:feature])
|
||||
mpw_marshal_data_set_str( digest( strf( @"%@/%@", user.name, feature )).UTF8String, exportFile->data,
|
||||
"user", "_ext_mpw", feature.UTF8String, nil );
|
||||
|
||||
MPKey *key = [[MPKey alloc] initForFullName:user.name withMasterPassword:masterPassword];
|
||||
exportUser = mpw_marshal_user( user.name.UTF8String,
|
||||
mpw_masterKeyProvider_str( masterPassword.UTF8String ), user.algorithm.version );
|
||||
exportUser->redacted = !revealPasswords;
|
||||
exportUser->avatar = (unsigned int)user.avatar;
|
||||
exportUser->keyID = mpw_strdup( [user.keyID encodeHex].UTF8String );
|
||||
exportUser->defaultType = user.defaultType;
|
||||
exportUser->lastUsed = (time_t)user.lastUsed.timeIntervalSince1970;
|
||||
|
||||
for (MPSiteEntity *site in user.sites) {
|
||||
for (MPSiteEntity *site in [user.sites sortedArrayUsingDescriptors:@[
|
||||
[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]
|
||||
]]) {
|
||||
MPCounterValue counter = MPCounterValueInitial;
|
||||
if ([site isKindOfClass:[MPGeneratedSiteEntity class]])
|
||||
counter = ((MPGeneratedSiteEntity *)site).counter;
|
||||
MPMarshalledSite *exportSite = mpw_marshal_site( exportUser,
|
||||
site.name.UTF8String, site.type, counter, site.algorithm.version );
|
||||
exportSite->resultState = mpw_strdup( [site.algorithm exportPasswordForSite:site usingKey:self.key].UTF8String );
|
||||
exportSite->loginState = mpw_strdup( [site.algorithm exportLoginForSite:site usingKey:self.key].UTF8String );
|
||||
exportSite->loginType = site.loginGenerated? MPResultTypeTemplateName: MPResultTypeStatefulPersonal;
|
||||
MPMarshalledSite *exportSite = mpw_marshal_site( exportUser, site.name.UTF8String, site.type, counter, site.algorithm.version );
|
||||
exportSite->resultState = mpw_strdup( [site.algorithm exportPasswordForSite:site usingKey:key].UTF8String );
|
||||
exportSite->loginState = mpw_strdup( [site.algorithm exportLoginForSite:site usingKey:key].UTF8String );
|
||||
exportSite->loginType = site.loginGenerated || !exportSite->loginState? MPResultTypeTemplateName: MPResultTypeStatefulPersonal;
|
||||
exportSite->url = mpw_strdup( site.url.UTF8String );
|
||||
exportSite->uses = (unsigned int)site.uses;
|
||||
exportSite->lastUsed = (time_t)site.lastUsed.timeIntervalSince1970;
|
||||
@@ -741,22 +767,26 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
mpw_marshal_question( exportSite, siteQuestion.keyword.UTF8String );
|
||||
}
|
||||
|
||||
MPMarshalledFile *exportFile = NULL;
|
||||
const char *export = mpw_marshal_write( MPMarshalFormatDefault, &exportFile, exportUser );
|
||||
NSString *exportedUser = nil;
|
||||
if (export && exportFile && exportFile->error.type == MPMarshalSuccess)
|
||||
exportedUser = [NSString stringWithCString:export encoding:NSUTF8StringEncoding];
|
||||
mpw_free_string( &export );
|
||||
|
||||
resultBlock( exportedUser, exportFile && exportFile->error.type == MPMarshalSuccess? nil:
|
||||
[NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(exportFile? exportFile->error.type: MPMarshalErrorInternal),
|
||||
NSLocalizedDescriptionKey: @(exportFile? exportFile->error.message: nil),
|
||||
}] );
|
||||
if (error)
|
||||
*error = exportFile && exportFile->error.type == MPMarshalSuccess? nil:
|
||||
[NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(exportFile? exportFile->error.type: MPMarshalErrorInternal),
|
||||
NSLocalizedDescriptionKey: @(exportFile? exportFile->error.message: nil),
|
||||
}];
|
||||
|
||||
return exportedUser;
|
||||
}
|
||||
@finally {
|
||||
mpw_marshal_file_free( &exportFile );
|
||||
mpw_marshal_user_free( &exportUser );
|
||||
mpw_masterKeyProvider_free();
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -21,11 +21,13 @@
|
||||
@interface MPConfig : PearlConfig
|
||||
|
||||
@property(nonatomic, retain) NSNumber *sendInfo;
|
||||
@property(nonatomic, retain) NSNumber *sendInfoDecided;
|
||||
@property(nonatomic, retain) NSNumber *notificationsDecided;
|
||||
|
||||
@property(nonatomic, retain) NSNumber *rememberLogin;
|
||||
@property(nonatomic, retain) NSNumber *hidePasswords;
|
||||
@property(nonatomic, strong) NSNumber *siteAttacker;
|
||||
|
||||
@property(nonatomic, retain) NSNumber *checkInconsistency;
|
||||
|
||||
@property(nonatomic, strong) NSNumber *siteAttacker;
|
||||
|
||||
@end
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
@implementation MPConfig
|
||||
|
||||
@dynamic sendInfo, rememberLogin, checkInconsistency, hidePasswords, siteAttacker;
|
||||
@dynamic sendInfo, sendInfoDecided, notificationsDecided, rememberLogin, hidePasswords, siteAttacker, checkInconsistency;
|
||||
|
||||
- (id)init {
|
||||
|
||||
@@ -29,13 +29,16 @@
|
||||
return nil;
|
||||
|
||||
[self.defaults registerDefaults:@{
|
||||
NSStringFromSelector( @selector( askForReviews ) ) : @YES,
|
||||
NSStringFromSelector( @selector( sendInfo ) ) : @NO,
|
||||
NSStringFromSelector( @selector( sendInfoDecided ) ) : @NO,
|
||||
NSStringFromSelector( @selector( notificationsDecided ) ): @NO,
|
||||
|
||||
NSStringFromSelector( @selector( sendInfo ) ) : @YES,
|
||||
NSStringFromSelector( @selector( rememberLogin ) ) : @NO,
|
||||
NSStringFromSelector( @selector( hidePasswords ) ) : @NO,
|
||||
NSStringFromSelector( @selector( checkInconsistency ) ): @NO,
|
||||
NSStringFromSelector( @selector( siteAttacker ) ) : @(MPAttacker1),
|
||||
NSStringFromSelector( @selector( rememberLogin ) ) : @NO,
|
||||
NSStringFromSelector( @selector( hidePasswords ) ) : @NO,
|
||||
NSStringFromSelector( @selector( siteAttacker ) ) : @(MPAttacker1),
|
||||
|
||||
NSStringFromSelector( @selector( checkInconsistency ) ) : @NO,
|
||||
NSStringFromSelector( @selector( askForReviews ) ) : @YES,
|
||||
}];
|
||||
|
||||
self.delegate = [MPAppDelegate_Shared get];
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
if ([self hasChanges])
|
||||
[self performBlockAndWait:^{
|
||||
@try {
|
||||
[self processPendingChanges];
|
||||
|
||||
NSError *error = nil;
|
||||
if (!(success = [self save:&error]))
|
||||
MPError( error, @"While saving." );
|
||||
|
||||
@@ -20,11 +20,19 @@
|
||||
#import "base64.h"
|
||||
|
||||
// printf <secret> | openssl enc -[ed] -aes-128-cbc -a -A -K <appSecret> -iv 0
|
||||
NSString *appSecret = @"";
|
||||
NSString *appSalt = @"";
|
||||
NSString *sentryDSN = @"";
|
||||
NSString *countlyKey = @"";
|
||||
NSString *countlySalt = @"";
|
||||
#if TARGET_OS_IOS
|
||||
NSString *appSecret = @"946a6b12e6e6e004cc35bad1ea11478c";
|
||||
NSString *appSalt = @"uBcsbZeTB8TfSS7dDw4yUq6wMZD/2nREvR0mqzqsNXvv9guh+62hkt99ly6QcJ5n";
|
||||
NSString *sentryDSN = @"tmVjdMN9DpZ+0EIrrvHi44hWfaBkwrlrxjBkdeau2rDk+zlvgSdAZkAvNj7m1V+5NUR7i8Y/NumNKOaYlWJvPynEMJ4ZBvPepSbivgVvmr8=";
|
||||
NSString *countlyKey = @"mDnMZyxwoq4ENgYnGYTzW8wsyiJQlmNKxkRLj88/nrs0mzE+zVjs6Y5LAT3+AYBB";
|
||||
NSString *countlySalt = @"2COFsZd+4FNAU6jvI/HUu297mkZALzRIyKv5mD3vs55BHXDowh62A7FursCYS+cG";
|
||||
#elif TARGET_OS_MAC
|
||||
NSString *appSecret = @"24fcbadccb5789b2a969c0c811f86702";
|
||||
NSString *appSalt = @"0N1fzSanIOCb7OQ4hEshXSjwEPXAXMhPBKQJeEcYPor8FWz76IpdB8ZHa3Wyb7o9";
|
||||
NSString *sentryDSN = @"2RbeS9wfzQEOKB9MG3EWLDe+N8iXYNtWc8tovMcBmhuMIeyAHYKqo5eclSEYyM6lA73Y7FFHqUyTLbEmOR6MAU2PtWAitLdxOZlq3VnbXjI=";
|
||||
NSString *countlyKey = @"uiasXoQNtkPQHvpvNqEE5N/tw/F1Hnzm+4ViSJ38EMeoWGvDQPJ+Kt9zPhb8Qans";
|
||||
NSString *countlySalt = @"/raQUNxKQdxXRR5VFmCDJdyyJE8f6SPrTO5Y4z0kJH+wCrjaZ1VvCq+JSmOsBkz2";
|
||||
#endif
|
||||
|
||||
NSString *decrypt(NSString *secret) {
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
MP_LIBS_BEGIN
|
||||
#import <Sentry/Sentry.h>
|
||||
MP_LIBS_END
|
||||
|
||||
__BEGIN_DECLS
|
||||
extern NSString *const MPErrorDomain;
|
||||
@@ -41,8 +43,9 @@ __END_DECLS
|
||||
\
|
||||
if (__error && [[MPConfig get].sendInfo boolValue]) { \
|
||||
SentryEvent *event = [[SentryEvent alloc] initWithLevel:kSentryLevelError]; \
|
||||
event.message = strf(@"%@: %@", message_, [__error localizedDescription]); \
|
||||
event.message = strf( message_ @": %@", ##__VA_ARGS__, [__error localizedDescription]); \
|
||||
event.logger = @"MPError"; \
|
||||
event.fingerprint = @[ message_, __error.domain, @(__error.code) ]; \
|
||||
[SentrySDK captureEvent:event]; \
|
||||
} \
|
||||
__error; \
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<menu title="AMainMenu" systemMenu="main" id="29">
|
||||
<point key="canvasLocation" x="139" y="155"/>
|
||||
</menu>
|
||||
<customObject id="494" customClass="MPMacAppDelegate">
|
||||
<connections>
|
||||
<outlet property="createUserItem" destination="757" id="763"/>
|
||||
@@ -241,6 +238,9 @@
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="494" id="Slu-zT-yO4"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="140" y="23"/>
|
||||
</menu>
|
||||
</objects>
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#import "MPSitesWindowController.h"
|
||||
#import "MPInitialWindowController.h"
|
||||
|
||||
@interface MPMacAppDelegate : MPAppDelegate_Shared<NSApplicationDelegate>
|
||||
@interface MPMacAppDelegate : MPAppDelegate_Shared<NSApplicationDelegate, NSMenuDelegate>
|
||||
|
||||
@property(nonatomic, strong) NSStatusItem *statusView;
|
||||
@property(nonatomic, strong) NSStatusItem *statusItem;
|
||||
@property(nonatomic, strong) MPSitesWindowController *sitesWindowController;
|
||||
@property(nonatomic, strong) MPInitialWindowController *initialWindowController;
|
||||
@property(nonatomic, weak) IBOutlet NSMenuItem *lockItem;
|
||||
|
||||
@@ -22,14 +22,15 @@
|
||||
#import "MPSecrets.h"
|
||||
#import "mpw-marshal.h"
|
||||
|
||||
MP_LIBS_BEGIN
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <ServiceManagement/ServiceManagement.h>
|
||||
#import <Sentry/Sentry.h>
|
||||
#import <Countly/Countly.h>
|
||||
MP_LIBS_END
|
||||
|
||||
#define LOGIN_HELPER_BUNDLE_ID @"com.lyndir.lhunath.MasterPassword.Mac.LoginHelper"
|
||||
|
||||
|
||||
@implementation MPMacAppDelegate
|
||||
|
||||
#pragma clang diagnostic push
|
||||
@@ -69,10 +70,10 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
|
||||
@try {
|
||||
// Sentry
|
||||
[SentrySDK initWithOptions:@{
|
||||
[SentrySDK startWithOptions:@{
|
||||
@"dsn" : NilToNSNull( decrypt( sentryDSN ) ),
|
||||
#ifdef DEBUG
|
||||
@"debug" : @(YES),
|
||||
@"debug" : @(NO),
|
||||
@"environment" : @"Development",
|
||||
#elif PUBLIC
|
||||
@"debug" : @(NO),
|
||||
@@ -81,12 +82,12 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
@"debug" : @(NO),
|
||||
@"environment" : @"Private",
|
||||
#endif
|
||||
@"enabled" : [MPMacConfig get].sendInfo,
|
||||
@"enabled" : @([[MPMacConfig get].sendInfo boolValue] || ![[MPMacConfig get].sendInfoDecided boolValue]),
|
||||
@"enableAutoSessionTracking": @(YES),
|
||||
}];
|
||||
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
||||
PearlLogLevel level = PearlLogLevelWarn;
|
||||
if ([[MPConfig get].sendInfo boolValue])
|
||||
if ([[MPMacConfig get].sendInfo boolValue])
|
||||
level = PearlLogLevelDebug;
|
||||
|
||||
if (message.level >= level) {
|
||||
@@ -134,7 +135,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
#if DEBUG
|
||||
countlyConfig.enableDebug = YES;
|
||||
countlyConfig.pushTestMode = CLYPushTestModeDevelopment;
|
||||
#elif ! PUBLIC
|
||||
#elif !PUBLIC
|
||||
countlyConfig.enableDebug = NO;
|
||||
countlyConfig.pushTestMode = CLYPushTestModeTestFlightOrAdHoc;
|
||||
#endif
|
||||
@@ -145,7 +146,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
}
|
||||
|
||||
// Setup delegates and listeners.
|
||||
[MPConfig get].delegate = self;
|
||||
[MPMacConfig get].delegate = self;
|
||||
__weak id weakSelf = self;
|
||||
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
||||
dispatch_async( dispatch_get_main_queue(), ^{
|
||||
@@ -159,12 +160,10 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
} forKeyPath:@"activeUser" options:0 context:nil];
|
||||
|
||||
// Status item.
|
||||
self.statusView = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
|
||||
self.statusView.image = [NSImage imageNamed:@"menu-icon"];
|
||||
self.statusView.image.template = YES;
|
||||
self.statusView.menu = self.statusMenu;
|
||||
self.statusView.target = self;
|
||||
self.statusView.action = @selector( showMenu );
|
||||
self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
|
||||
self.statusItem.menu = self.statusMenu;
|
||||
self.statusItem.button.image = [NSImage imageNamed:@"menu-icon"];
|
||||
self.statusItem.button.image.template = YES;
|
||||
|
||||
PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, self.storeCoordinator, nil,
|
||||
^(id self, NSNotification *note) {
|
||||
@@ -205,12 +204,12 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
[self enableNotifications];
|
||||
[self tryNotifications];
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(NSNotification *)notification {
|
||||
|
||||
if (![[MPConfig get].rememberLogin boolValue])
|
||||
if (![[MPMacConfig get].rememberLogin boolValue])
|
||||
[self lock:nil];
|
||||
}
|
||||
|
||||
@@ -231,7 +230,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
return NSTerminateNow;
|
||||
}
|
||||
|
||||
- (void)enableNotifications {
|
||||
- (void)tryNotifications {
|
||||
|
||||
[Countly.sharedInstance giveConsentForFeature:CLYConsentPushNotifications];
|
||||
if (@available( macOS 10.14, * )) {
|
||||
@@ -250,18 +249,19 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
|
||||
- (void)askNotifications {
|
||||
|
||||
if ([[MPMacConfig get].notificationsDecided boolValue])
|
||||
return;
|
||||
|
||||
PearlMainQueue( ^{
|
||||
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"notificationsDecided"]) {
|
||||
if (@available( macOS 10.14, * )) {
|
||||
[Countly.sharedInstance askForNotificationPermissionWithOptions:UNAuthorizationOptionAlert completionHandler:
|
||||
^(BOOL granted, NSError *error) {
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"notificationsDecided"];
|
||||
}];
|
||||
}
|
||||
else {
|
||||
[Countly.sharedInstance askForNotificationPermission];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"notificationsDecided"];
|
||||
}
|
||||
if (@available( macOS 10.14, * )) {
|
||||
[Countly.sharedInstance askForNotificationPermissionWithOptions:UNAuthorizationOptionAlert completionHandler:
|
||||
^(BOOL granted, NSError *error) {
|
||||
[MPMacConfig get].notificationsDecided = @(YES);
|
||||
}];
|
||||
}
|
||||
else {
|
||||
[Countly.sharedInstance askForNotificationPermission];
|
||||
[MPMacConfig get].notificationsDecided = @(YES);
|
||||
}
|
||||
} );
|
||||
}
|
||||
@@ -409,11 +409,11 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
- (IBAction)togglePreference:(id)sender {
|
||||
|
||||
if (sender == self.diagnosticsItem)
|
||||
[MPConfig get].sendInfo = @(self.diagnosticsItem.state != NSOnState);
|
||||
[MPMacConfig get].sendInfo = @(self.diagnosticsItem.state != NSOnState);
|
||||
if (sender == self.hidePasswordsItem)
|
||||
[MPConfig get].hidePasswords = @(self.hidePasswordsItem.state != NSOnState);
|
||||
[MPMacConfig get].hidePasswords = @(self.hidePasswordsItem.state != NSOnState);
|
||||
if (sender == self.rememberPasswordItem)
|
||||
[MPConfig get].rememberLogin = @(self.rememberPasswordItem.state != NSOnState);
|
||||
[MPMacConfig get].rememberLogin = @(self.rememberPasswordItem.state != NSOnState);
|
||||
if (sender == self.openAtLoginItem)
|
||||
[self setLoginItemEnabled:self.openAtLoginItem.state != NSOnState];
|
||||
if (sender == self.showFullScreenItem) {
|
||||
@@ -440,8 +440,8 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
NSAlert *alert = [NSAlert new];
|
||||
[alert setMessageText:@"New User"];
|
||||
[alert setInformativeText:@"To begin, enter your full name.\n\n"
|
||||
@"IMPORTANT: Enter your name correctly, including the right capitalization, "
|
||||
@"as you would on an official document."];
|
||||
@"IMPORTANT: Enter your name correctly, including the right capitalization, "
|
||||
@"as you would on an official document."];
|
||||
[alert addButtonWithTitle:@"Create User"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
NSTextField *nameField = [[NSTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
||||
@@ -502,7 +502,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
|
||||
- (IBAction)showPopup:(id)sender {
|
||||
|
||||
[self.statusView popUpStatusItemMenu:self.statusView.menu];
|
||||
[[self.statusItem button] performClick:sender];
|
||||
}
|
||||
|
||||
- (IBAction)showPasswordWindow:(id)sender {
|
||||
@@ -546,15 +546,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self.key) {
|
||||
NSAlert *alert = [NSAlert new];
|
||||
alert.messageText = @"User Locked";
|
||||
alert.informativeText = @"To export your sites, first unlock your user by opening Master Password.";
|
||||
[alert runModal];
|
||||
[self showPopup:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
||||
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
||||
|
||||
@@ -579,43 +570,46 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
if ([savePanel runModal] == NSFileHandlingPanelCancelButton)
|
||||
return;
|
||||
|
||||
[self exportSitesRevealPasswords:revealPasswords
|
||||
askExportPassword:^NSString *(NSString *userName) {
|
||||
return PearlMainQueueAwait( ^id {
|
||||
NSAlert *alert = [NSAlert new];
|
||||
[alert addButtonWithTitle:@"Import"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
alert.messageText = strf( @"Master Password For\n%@", userName );
|
||||
alert.informativeText = @"Enter the current master password for this user.";
|
||||
alert.accessoryView = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
||||
[alert layout];
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn)
|
||||
return ((NSTextField *)alert.accessoryView).stringValue;
|
||||
else
|
||||
return nil;
|
||||
} );
|
||||
} result:^(NSString *mpsites, NSError *error) {
|
||||
if (!mpsites || error) {
|
||||
PearlMainQueue( ^{
|
||||
[[NSAlert alertWithError:MPError( error, @"Failed to export mpsites." )] runModal];
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
NSError *error = nil;
|
||||
NSString *exportedUser = [self exportSitesFor:[self activeUserInContext:context] revealPasswords:revealPasswords askExportPassword:
|
||||
^NSString *(NSString *userName) {
|
||||
return PearlMainQueueAwait( ^id {
|
||||
NSAlert *alert = [NSAlert new];
|
||||
[alert addButtonWithTitle:@"Export"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
alert.messageText = strf( @"Master Password For\n%@", userName );
|
||||
alert.informativeText = @"Enter the current master password for this user.";
|
||||
alert.accessoryView = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
||||
[alert layout];
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn)
|
||||
return ((NSTextField *)alert.accessoryView).stringValue;
|
||||
else
|
||||
return nil;
|
||||
} );
|
||||
return;
|
||||
}
|
||||
} error:&error];
|
||||
|
||||
NSError *coordinateError = nil;
|
||||
[[[NSFileCoordinator alloc] initWithFilePresenter:nil]
|
||||
coordinateWritingItemAtURL:savePanel.URL options:0 error:&coordinateError byAccessor:^(NSURL *newURL) {
|
||||
NSError *writeError = nil;
|
||||
if (![mpsites writeToURL:newURL atomically:NO encoding:NSUTF8StringEncoding error:&writeError])
|
||||
PearlMainQueue( ^{
|
||||
[[NSAlert alertWithError:MPError( writeError, @"Could not write to the export file." )] runModal];
|
||||
} );
|
||||
}];
|
||||
if (coordinateError)
|
||||
PearlMainQueue( ^{
|
||||
[[NSAlert alertWithError:MPError( coordinateError, @"Could not gain access to the export file." )] runModal];
|
||||
} );
|
||||
}];
|
||||
if (error)
|
||||
PearlMainQueue( ^{
|
||||
[[NSAlert alertWithError:MPError( error, @"Failed to export mpsites." )] runModal];
|
||||
} );
|
||||
if (!exportedUser)
|
||||
return;
|
||||
|
||||
NSError *coordinateError = nil;
|
||||
[[[NSFileCoordinator alloc] initWithFilePresenter:nil]
|
||||
coordinateWritingItemAtURL:savePanel.URL options:0 error:&coordinateError byAccessor:^(NSURL *newURL) {
|
||||
NSError *writeError = nil;
|
||||
if (![exportedUser writeToURL:newURL atomically:NO encoding:NSUTF8StringEncoding error:&writeError])
|
||||
PearlMainQueue( ^{
|
||||
[[NSAlert alertWithError:MPError( writeError, @"Could not write to the export file." )] runModal];
|
||||
} );
|
||||
}];
|
||||
if (coordinateError)
|
||||
PearlMainQueue( ^{
|
||||
[[NSAlert alertWithError:MPError( coordinateError, @"Could not gain access to the export file." )] runModal];
|
||||
} );
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateUsers {
|
||||
@@ -688,13 +682,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
[self updateMenuItems];
|
||||
}
|
||||
|
||||
- (void)showMenu {
|
||||
|
||||
[self updateMenuItems];
|
||||
|
||||
[self.statusView popUpStatusItemMenu:self.statusView.menu];
|
||||
}
|
||||
|
||||
- (void)updateMenuItems {
|
||||
|
||||
MPUserEntity *activeUser = [self activeUserForMainThread];
|
||||
@@ -749,6 +736,13 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSMenuDelegate
|
||||
|
||||
- (void)menuNeedsUpdate:(NSMenu *)menu {
|
||||
|
||||
[self updateMenuItems];
|
||||
}
|
||||
|
||||
#pragma mark - PearlConfigDelegate
|
||||
|
||||
- (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)oldValue {
|
||||
@@ -760,26 +754,25 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
|
||||
PearlMainQueue( ^{
|
||||
if (!key || [key isEqualToString:NSStringFromSelector( @selector( sendInfo ) )])
|
||||
self.diagnosticsItem.state = [[MPConfig get].sendInfo boolValue]? NSOnState: NSOffState;
|
||||
self.diagnosticsItem.state = [[MPMacConfig get].sendInfo boolValue]? NSOnState: NSOffState;
|
||||
if (!key || [key isEqualToString:NSStringFromSelector( @selector( hidePasswords ) )])
|
||||
self.hidePasswordsItem.state = [[MPConfig get].hidePasswords boolValue]? NSOnState: NSOffState;
|
||||
self.hidePasswordsItem.state = [[MPMacConfig get].hidePasswords boolValue]? NSOnState: NSOffState;
|
||||
if (!key || [key isEqualToString:NSStringFromSelector( @selector( rememberLogin ) )])
|
||||
self.rememberPasswordItem.state = [[MPConfig get].rememberLogin boolValue]? NSOnState: NSOffState;
|
||||
self.rememberPasswordItem.state = [[MPMacConfig get].rememberLogin boolValue]? NSOnState: NSOffState;
|
||||
} );
|
||||
|
||||
// Send info
|
||||
NSArray *countlyFeatures = @[
|
||||
CLYConsentSessions, CLYConsentEvents, CLYConsentUserDetails, CLYConsentCrashReporting, CLYConsentViewTracking, CLYConsentStarRating
|
||||
];
|
||||
if ([[MPConfig get].sendInfo boolValue]) {
|
||||
[Countly.sharedInstance giveConsentForFeatures:countlyFeatures];
|
||||
if ([[MPMacConfig get].sendInfo boolValue] || ![[MPMacConfig get].sendInfoDecided boolValue]) {
|
||||
if ([PearlLogger get].printLevel > PearlLogLevelInfo)
|
||||
[PearlLogger get].printLevel = PearlLogLevelInfo;
|
||||
|
||||
[SentrySDK.currentHub getClient].options.enabled = @YES;
|
||||
[SentrySDK configureScope:^(SentryScope *scope) {
|
||||
[scope setExtraValue:[MPConfig get].rememberLogin forKey:@"rememberLogin"];
|
||||
[scope setExtraValue:[MPConfig get].sendInfo forKey:@"sendInfo"];
|
||||
[scope setExtraValue:[MPMacConfig get].rememberLogin forKey:@"rememberLogin"];
|
||||
[scope setExtraValue:[MPMacConfig get].sendInfo forKey:@"sendInfo"];
|
||||
[scope setExtraValue:[MPMacConfig get].fullScreen forKey:@"fullScreen"];
|
||||
[scope setExtraValue:[PearlConfig get].firstRun forKey:@"firstRun"];
|
||||
[scope setExtraValue:[PearlConfig get].launchCount forKey:@"launchCount"];
|
||||
@@ -790,10 +783,12 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
||||
[scope setExtraValue:@([PearlDeviceUtils isAppEncrypted]) forKey:@"encrypted"];
|
||||
[scope setExtraValue:[PearlDeviceUtils platform] forKey:@"platform"];
|
||||
}];
|
||||
|
||||
[Countly.sharedInstance giveConsentForFeatures:countlyFeatures];
|
||||
}
|
||||
else {
|
||||
[SentrySDK.currentHub getClient].options.enabled = @NO;
|
||||
[Countly.sharedInstance cancelConsentForFeatures:countlyFeatures];
|
||||
[SentrySDK.currentHub getClient].options.enabled = @NO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
@property(nonatomic, readonly) BOOL stored;
|
||||
@property(nonatomic, readonly) BOOL transient;
|
||||
|
||||
- (instancetype)initWithEntity:(MPSiteEntity *)entity fuzzyGroups:(NSArray *)fuzzyGroups;
|
||||
- (instancetype)initWithEntity:(MPSiteEntity *)entity queryGroups:(NSArray *)queryGroups;
|
||||
- (instancetype)initWithName:(NSString *)siteName forUser:(MPUserEntity *)user;
|
||||
- (MPSiteEntity *)entityInContext:(NSManagedObjectContext *)moc;
|
||||
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
|
||||
@implementation MPSiteModel
|
||||
|
||||
- (instancetype)initWithEntity:(MPSiteEntity *)entity fuzzyGroups:(NSArray *)fuzzyGroups {
|
||||
- (instancetype)initWithEntity:(MPSiteEntity *)entity queryGroups:(NSArray *)queryGroups {
|
||||
|
||||
if (!(self = [super init]))
|
||||
return nil;
|
||||
|
||||
[self setEntity:entity fuzzyGroups:fuzzyGroups];
|
||||
[self setEntity:entity queryGroups:queryGroups];
|
||||
self.initialized = YES;
|
||||
|
||||
return self;
|
||||
@@ -53,23 +53,25 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setEntity:(MPSiteEntity *)entity fuzzyGroups:(NSArray *)fuzzyGroups {
|
||||
- (void)setEntity:(MPSiteEntity *)entity queryGroups:(NSArray *)queryGroups {
|
||||
|
||||
if ([self.entityOID isEqual:entity.permanentObjectID])
|
||||
return;
|
||||
self.entityOID = entity.permanentObjectID;
|
||||
|
||||
NSString *siteName = entity.name;
|
||||
NSMutableAttributedString *attributedSiteName = [[NSMutableAttributedString alloc] initWithString:siteName];
|
||||
for (NSUInteger f = 0, s = (NSUInteger)-1; f < [fuzzyGroups count]; ++f) {
|
||||
s = [siteName rangeOfString:fuzzyGroups[f] options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch
|
||||
range:NSMakeRange( s + 1, [siteName length] - (s + 1) )].location;
|
||||
if (s == NSNotFound)
|
||||
break;
|
||||
NSMutableAttributedString *attributedSiteName = [[NSMutableAttributedString alloc] initWithString:siteName?: @""];
|
||||
if ([attributedSiteName length])
|
||||
for (NSUInteger f = 0, s = 0; f < [queryGroups count]; ++f, ++s) {
|
||||
s = [siteName rangeOfString:queryGroups[f] options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch
|
||||
range:NSMakeRange( s, [siteName length] - s )].location;
|
||||
if (s == NSNotFound)
|
||||
break;
|
||||
|
||||
[attributedSiteName addAttribute:NSBackgroundColorAttributeName value:[NSColor alternateSelectedControlColor]
|
||||
range:NSMakeRange( s, [queryGroups[f] length] )];
|
||||
}
|
||||
|
||||
[attributedSiteName addAttribute:NSBackgroundColorAttributeName value:[NSColor alternateSelectedControlColor]
|
||||
range:NSMakeRange( s, [fuzzyGroups[f] length] )];
|
||||
}
|
||||
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
|
||||
paragraphStyle.alignment = NSCenterTextAlignment;
|
||||
[attributedSiteName addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange( 0, [siteName length] )];
|
||||
@@ -179,7 +181,8 @@
|
||||
if (algorithmVersion == self.algorithm.version)
|
||||
return;
|
||||
[self willChangeValueForKey:@"outdated"];
|
||||
self.algorithm = MPAlgorithmForVersion( algorithmVersion )?: self.algorithm;
|
||||
self.algorithm =
|
||||
MPAlgorithmForVersion( MIN( MPAlgorithmVersionLast, MAX( MPAlgorithmVersionFirst, algorithmVersion ) ) )?: self.algorithm;
|
||||
[self didChangeValueForKey:@"outdated"];
|
||||
|
||||
if (self.entityOID)
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
//==============================================================================
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <Countly/Countly.h>
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#import "MPSitesWindowController.h"
|
||||
#import "MPMacAppDelegate.h"
|
||||
#import "MPAppDelegate_Store.h"
|
||||
@@ -42,13 +44,27 @@
|
||||
prof_rewind( @"replaceFonts" );
|
||||
|
||||
PearlAddNotificationObserver( NSWindowDidBecomeKeyNotification, self.window, [NSOperationQueue mainQueue],
|
||||
^(id host, NSNotification *note) {
|
||||
(^(id host, NSNotification *note) {
|
||||
prof_new( @"didBecomeKey" );
|
||||
[self.window makeKeyAndOrderFront:nil];
|
||||
prof_rewind( @"fadeIn" );
|
||||
[self updateUser];
|
||||
prof_finish( @"updateUser" );
|
||||
} );
|
||||
prof_rewind( @"updateUser" );
|
||||
|
||||
if (![[MPMacConfig get].sendInfoDecided boolValue]) {
|
||||
NSAlert *alert = [NSAlert new];
|
||||
alert.messageText = @"Diagnostics";
|
||||
alert.informativeText = @"We look for bugs, sudden crashes, runtime issues & statistics.\n\n"
|
||||
@"Diagnostics are scrubbed and personal details will never leave your device.";
|
||||
[alert addButtonWithTitle:@"Engage"];
|
||||
[alert addButtonWithTitle:@"Disable"];
|
||||
[alert beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) {
|
||||
[MPMacConfig get].sendInfo = @(returnCode != NSAlertSecondButtonReturn);
|
||||
[MPMacConfig get].sendInfoDecided = @(YES);
|
||||
}];
|
||||
}
|
||||
prof_finish( @"sendInfoDecided" );
|
||||
}) );
|
||||
PearlAddNotificationObserver( NSWindowWillCloseNotification, self.window, [NSOperationQueue mainQueue],
|
||||
^(id host, NSNotification *note) {
|
||||
NSWindow *sheet = [self.window attachedSheet];
|
||||
@@ -81,7 +97,16 @@
|
||||
self.siteTable.superview.superview.layer.mask = self.siteGradient;
|
||||
|
||||
self.siteTable.controller = self;
|
||||
prof_finish( @"ui" );
|
||||
prof_rewind( @"ui" );
|
||||
|
||||
if (@available( macOS 10.14, * )) {
|
||||
[[UNUserNotificationCenter currentNotificationCenter]
|
||||
requestAuthorizationWithOptions:UNAuthorizationOptionAlert completionHandler:^(BOOL granted, NSError *error) {
|
||||
if (!granted)
|
||||
err( @"Couldn't obtain notification authorization: %@", error );
|
||||
}];
|
||||
}
|
||||
prof_finish( @"notifications" );
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
@@ -376,7 +401,52 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (IBAction)changeType:(id)sender {
|
||||
- (IBAction)changeDefaultType:(id)sender {
|
||||
|
||||
MPSiteModel *site = self.selectedSite;
|
||||
MPUserEntity *user = [MPMacAppDelegate get].activeUserForMainThread;
|
||||
NSArray *types = [user.algorithm allTypes];
|
||||
[self.passwordTypesMatrix renewRows:(NSInteger)[types count] columns:1];
|
||||
for (NSUInteger t = 0; t < [types count]; ++t) {
|
||||
MPResultType type = (MPResultType)[types[t] unsignedIntegerValue];
|
||||
NSString *title = [user.algorithm nameOfType:type];
|
||||
if (type & MPResultTypeClassTemplate)
|
||||
title = strf( @"%@ – %@", [user.algorithm mpwTemplateForSiteNamed:site.name?: @"masterpassword.app" ofType:type
|
||||
withCounter:site.counter?: MPCounterValueDefault
|
||||
usingKey:[MPMacAppDelegate get].key], title );
|
||||
|
||||
NSButtonCell *cell = [self.passwordTypesMatrix cellAtRow:(NSInteger)t column:0];
|
||||
cell.tag = type;
|
||||
cell.state = type == site.type? NSOnState: NSOffState;
|
||||
cell.title = title;
|
||||
}
|
||||
|
||||
self.passwordTypesBox.title = strf( @"Choose a password type for new sites of %@:", user.name );
|
||||
|
||||
NSAlert *alert = [NSAlert new];
|
||||
[alert addButtonWithTitle:@"Save"];
|
||||
[alert addButtonWithTitle:@"Cancel"];
|
||||
[alert setMessageText:@"Change Default Type"];
|
||||
[alert setAccessoryView:self.passwordTypesBox];
|
||||
[alert layout];
|
||||
[alert beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) {
|
||||
switch (returnCode) {
|
||||
case NSAlertFirstButtonReturn: {
|
||||
// "Save" button.
|
||||
MPResultType type = (MPResultType)[self.passwordTypesMatrix.selectedCell tag];
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
[[MPMacAppDelegate get] activeUserInContext:context].defaultType = type;
|
||||
[context saveToStore];
|
||||
}];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (IBAction)changeSiteType:(id)sender {
|
||||
|
||||
MPSiteModel *site = self.selectedSite;
|
||||
NSArray *types = [site.algorithm allTypes];
|
||||
@@ -487,13 +557,19 @@
|
||||
[self copyContent:self.shiftPressed? selectedSite.loginName: selectedSite.content];
|
||||
[NSApp hide:nil];
|
||||
|
||||
NSUserNotification *notification = [NSUserNotification new];
|
||||
notification.title = @"Password Copied";
|
||||
if (selectedSite.loginName.length)
|
||||
notification.subtitle = strf( @"%@ at %@", selectedSite.loginName, selectedSite.name );
|
||||
else
|
||||
notification.subtitle = selectedSite.name;
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
|
||||
if (@available( macOS 10.14, * )) {
|
||||
UNMutableNotificationContent *notification = [UNMutableNotificationContent new];
|
||||
notification.title = self.shiftPressed? @"Login Copied": @"Password Copied";
|
||||
if (selectedSite.loginName.length)
|
||||
notification.subtitle = strf( @"%@ at %@", selectedSite.loginName, selectedSite.name );
|
||||
else
|
||||
notification.subtitle = selectedSite.name;
|
||||
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:
|
||||
[UNNotificationRequest requestWithIdentifier:selectedSite.name content:notification trigger:nil]
|
||||
withCompletionHandler:^(NSError *error) {
|
||||
dbg( @"notification: %@, completed w/errror: %@", notification, error );
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateUser {
|
||||
@@ -535,22 +611,20 @@
|
||||
return;
|
||||
}
|
||||
|
||||
static NSRegularExpression *fuzzyRE;
|
||||
static dispatch_once_t once = 0;
|
||||
dispatch_once( &once, ^{
|
||||
fuzzyRE = [NSRegularExpression regularExpressionWithPattern:@"(.)" options:0 error:nil];
|
||||
} );
|
||||
|
||||
prof_new( @"updateSites" );
|
||||
NSString *queryString = self.siteField.stringValue;
|
||||
NSString *queryPattern = [[queryString stringByReplacingMatchesOfExpression:fuzzyRE withTemplate:@"*$1"] stringByAppendingString:@"*"];
|
||||
NSMutableArray *queryGroups = [NSMutableArray new];
|
||||
NSMutableString *queryPattern = [NSMutableString new];
|
||||
[queryString enumerateSubstringsInRange: NSMakeRange(0, [queryString length]) options: NSStringEnumerationByComposedCharacterSequences
|
||||
usingBlock: ^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
|
||||
if (substringRange.location < 20) {
|
||||
[queryGroups addObject:substring];
|
||||
[queryPattern appendString:@"*"];
|
||||
}
|
||||
[queryPattern appendString:substring];
|
||||
}];
|
||||
[queryPattern appendString:@"*"];
|
||||
prof_rewind( @"queryPattern" );
|
||||
NSMutableArray *fuzzyGroups = [NSMutableArray new];
|
||||
[fuzzyRE enumerateMatchesInString:queryString options:0 range:NSMakeRange( 0, queryString.length )
|
||||
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
||||
[fuzzyGroups addObject:[queryString substringWithRange:result.range]];
|
||||
}];
|
||||
prof_rewind( @"fuzzyRE" );
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
prof_rewind( @"moc" );
|
||||
|
||||
@@ -572,7 +646,7 @@
|
||||
BOOL exact = NO;
|
||||
NSMutableArray *newSites = [NSMutableArray arrayWithCapacity:[siteResults count]];
|
||||
for (MPSiteEntity *site in siteResults) {
|
||||
[newSites addObject:[[MPSiteModel alloc] initWithEntity:site fuzzyGroups:fuzzyGroups]];
|
||||
[newSites addObject:[[MPSiteModel alloc] initWithEntity:site queryGroups:queryGroups]];
|
||||
exact |= [site.name isEqualToString:queryString];
|
||||
}
|
||||
prof_rewind( @"newSites: %u, exact: %d", (uint)[siteResults count], exact );
|
||||
|
||||
@@ -31,26 +31,26 @@
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="640" height="577"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ" userLabel="Root">
|
||||
<rect key="frame" x="0.0" y="0.0" width="640" height="557"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="738" height="553"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<visualEffectView blendingMode="behindWindow" material="popover" state="followsWindowActiveState" translatesAutoresizingMaskIntoConstraints="NO" id="eRe-Ef-AZx">
|
||||
<rect key="frame" x="0.0" y="0.0" width="640" height="557"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="738" height="553"/>
|
||||
</visualEffectView>
|
||||
<progressIndicator hidden="YES" wantsLayer="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" maxValue="100" displayedWhenStopped="NO" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="oSh-Ec-8Nf" userLabel="Progress Spinner">
|
||||
<rect key="frame" x="312" y="521" width="16" height="16"/>
|
||||
<rect key="frame" x="361" y="517" width="16" height="16"/>
|
||||
</progressIndicator>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="NGk-Io-Buc" userLabel="Top Box">
|
||||
<rect key="frame" x="20" y="381" width="600" height="132"/>
|
||||
<rect key="frame" x="20" y="377" width="698" height="132"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ond-dT-x5d" userLabel="Site Password Label">
|
||||
<rect key="frame" x="157" y="98" width="287" height="14"/>
|
||||
<rect key="frame" x="206" y="98" width="287" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Your password for apple.com (hit <⏎ enter> to copy):" id="CgJ-XZ-6Hy">
|
||||
<font key="font" metaFont="menu" size="11"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -72,13 +72,13 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ia6-7b-dFr">
|
||||
<rect key="frame" x="127" y="59" width="347" height="14"/>
|
||||
<rect key="frame" x="176" y="59" width="347" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="No password set. Click "Set Password" on the bottom to set one." id="eDQ-iz-97a">
|
||||
<font key="font" metaFont="menu" size="11"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -108,13 +108,13 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OaQ-of-zmb" userLabel="Initial Help">
|
||||
<rect key="frame" x="39" y="109" width="522" height="18"/>
|
||||
<rect key="frame" x="113" y="109" width="473" height="17"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Master Password generates passwords for your sites (and other things)." id="YyD-hd-wi3">
|
||||
<font key="font" size="16" name="HelveticaNeue"/>
|
||||
<font key="font" metaFont="menu" size="14"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -136,18 +136,18 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="sYt-eL-uwt" userLabel="Initial Tip">
|
||||
<rect key="frame" x="-26" y="31" width="652" height="70"/>
|
||||
<rect key="frame" x="-2" y="31" width="702" height="70"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" id="9c4-NI-NM0">
|
||||
<font key="font" size="12" name="HelveticaNeue"/>
|
||||
<string key="title">– When you create an account with a site, use Master Password to create a password for it.
|
||||
– For accounts you already have, change the password to that created by Master Password for it.
|
||||
– To get a password, enter the site's bare domain name in the "site name" field (eg. apple.com).
|
||||
– For your master password, think of a strong password (eg. a short sentence). Tell *nobody*.
|
||||
– It's OK to share your site passwords. They can be changed if necessary.</string>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<string key="title">⑴ When you create an account on a site, open Master Password to create your account password.
|
||||
⑵ Consider changing all your existing account passwords to the password Master Password creates for those sites.
|
||||
⑶ To get the password for a site, just enter its domain name in the "site name" field (eg. "apple.com").
|
||||
⑷ When chosing a master password, make it easy but long (eg. a short sentence).
|
||||
⑸ Tell *nobody* your master password. It's OK to share your site passwords with people you trust: they can be changed if necessary.</string>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -169,7 +169,7 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="XUV-zU-Y9c" userLabel="Site Password">
|
||||
<rect key="frame" x="-2" y="26" width="604" height="80"/>
|
||||
<rect key="frame" x="-2" y="26" width="702" height="80"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
@@ -202,6 +202,7 @@
|
||||
<constraint firstItem="XUV-zU-Y9c" firstAttribute="leading" secondItem="NGk-Io-Buc" secondAttribute="leading" id="6Kl-7u-r90"/>
|
||||
<constraint firstAttribute="centerY" secondItem="XUV-zU-Y9c" secondAttribute="centerY" id="6Qf-5O-Cvk"/>
|
||||
<constraint firstAttribute="centerX" secondItem="XUV-zU-Y9c" secondAttribute="centerX" id="7sl-qi-HY9"/>
|
||||
<constraint firstItem="sYt-eL-uwt" firstAttribute="width" secondItem="NGk-Io-Buc" secondAttribute="width" id="Beb-mW-KDP"/>
|
||||
<constraint firstItem="Ond-dT-x5d" firstAttribute="top" secondItem="NGk-Io-Buc" secondAttribute="top" constant="20" symbolic="YES" id="IX4-cd-VkJ"/>
|
||||
<constraint firstItem="Ia6-7b-dFr" firstAttribute="centerY" secondItem="XUV-zU-Y9c" secondAttribute="centerY" id="KqM-uR-Obm"/>
|
||||
<constraint firstItem="Ia6-7b-dFr" firstAttribute="centerX" secondItem="XUV-zU-Y9c" secondAttribute="centerX" id="NFQ-aw-8tm"/>
|
||||
@@ -209,14 +210,13 @@
|
||||
<constraint firstAttribute="trailing" secondItem="XUV-zU-Y9c" secondAttribute="trailing" id="TdB-QV-9JK"/>
|
||||
<constraint firstItem="Ond-dT-x5d" firstAttribute="bottom" secondItem="XUV-zU-Y9c" secondAttribute="top" constant="8" symbolic="YES" id="UgV-J6-B5T"/>
|
||||
<constraint firstItem="Ond-dT-x5d" firstAttribute="centerX" secondItem="XUV-zU-Y9c" secondAttribute="centerX" id="UhT-LQ-aZ8"/>
|
||||
<constraint firstItem="sYt-eL-uwt" firstAttribute="leading" secondItem="NGk-Io-Buc" secondAttribute="leading" constant="-24" id="eaC-ow-ren"/>
|
||||
<constraint firstItem="sYt-eL-uwt" firstAttribute="top" secondItem="OaQ-of-zmb" secondAttribute="bottom" constant="8" symbolic="YES" id="hjJ-f1-mFv"/>
|
||||
<constraint firstItem="sYt-eL-uwt" firstAttribute="centerX" secondItem="OaQ-of-zmb" secondAttribute="centerX" id="mu2-se-Mtn"/>
|
||||
<constraint firstAttribute="centerY" secondItem="sYt-eL-uwt" secondAttribute="centerY" id="zLS-QG-MKS"/>
|
||||
</constraints>
|
||||
</customView>
|
||||
<scrollView focusRingType="none" borderType="none" autohidesScrollers="YES" horizontalLineScroll="34" horizontalPageScroll="10" verticalLineScroll="34" verticalPageScroll="10" hasHorizontalScroller="NO" hasVerticalScroller="NO" horizontalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="Bme-XK-MMc" userLabel="Sites Table">
|
||||
<rect key="frame" x="64" y="40" width="512" height="177"/>
|
||||
<rect key="frame" x="113" y="40" width="512" height="177"/>
|
||||
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="e11-59-xSS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="177"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
@@ -251,7 +251,7 @@
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" alignment="center" title="apple.com" id="o0g-Zv-pH4">
|
||||
<font key="font" size="24" name="HelveticaNeue-Thin"/>
|
||||
<font key="font" metaFont="systemUltraLight" size="24"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -310,7 +310,7 @@
|
||||
</connections>
|
||||
</scrollView>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="nM8-O3-spM" customClass="MPGradientView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="640" height="212"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="738" height="238"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="color" keyPath="startingColor">
|
||||
<color key="value" red="0.11764705882352941" green="0.11764705882352941" blue="0.11764705882352941" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -324,7 +324,7 @@
|
||||
</userDefinedRuntimeAttributes>
|
||||
</customView>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="Aue-Zx-6Mf" userLabel="Settings Gear">
|
||||
<rect key="frame" x="585" y="493" width="35" height="44"/>
|
||||
<rect key="frame" x="683" y="489" width="35" height="44"/>
|
||||
<shadow key="shadow">
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
@@ -339,13 +339,13 @@
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gAU-xs-aae">
|
||||
<rect key="frame" x="594" y="479" width="18" height="14"/>
|
||||
<rect key="frame" x="692" y="475" width="18" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘," id="Xm1-qb-6EP">
|
||||
<font key="font" metaFont="menu" size="11"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -358,7 +358,7 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OnR-s6-d4P" userLabel="Site Name Label">
|
||||
<rect key="frame" x="209" y="308" width="223" height="16"/>
|
||||
<rect key="frame" x="258" y="306" width="223" height="16"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -370,7 +370,7 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<secureTextField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="iGR-wo-ual" userLabel="Secure Master Password">
|
||||
<rect key="frame" x="18" y="257" width="604" height="43"/>
|
||||
<rect key="frame" x="18" y="255" width="702" height="43"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -405,7 +405,7 @@
|
||||
</connections>
|
||||
</secureTextField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="v80-wd-hUR" userLabel="Revealed Master Password">
|
||||
<rect key="frame" x="18" y="257" width="604" height="43"/>
|
||||
<rect key="frame" x="18" y="255" width="702" height="43"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -444,13 +444,13 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="lW3-2z-cEa" userLabel="Master Password Tip">
|
||||
<rect key="frame" x="195" y="237" width="251" height="12"/>
|
||||
<rect key="frame" x="248" y="236" width="243" height="11"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Hold alt ⌥ to reveal tips and unmask ●●●●●●●●." id="4Ep-xX-Ky8">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -471,13 +471,13 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Oy5-B7-hdN" userLabel="Revealed Master Password Tip">
|
||||
<rect key="frame" x="195" y="237" width="250" height="12"/>
|
||||
<rect key="frame" x="258" y="236" width="222" height="11"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Hold alt ⌥ to reveal tips and unmask passwords." id="bQ4-AN-S1A">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -499,7 +499,7 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<searchField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="CnS-iI-dhr" userLabel="Site Name">
|
||||
<rect key="frame" x="62" y="257" width="516" height="43"/>
|
||||
<rect key="frame" x="111" y="255" width="516" height="43"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="512" id="rW7-Vq-4Xy"/>
|
||||
</constraints>
|
||||
@@ -508,7 +508,7 @@
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<searchFieldCell key="cell" selectable="YES" editable="YES" focusRingType="none" alignment="center" placeholderString="Site Name" sendsSearchStringImmediately="YES" id="ppl-2c-1E9">
|
||||
<font key="font" size="36" name="HelveticaNeue-Thin"/>
|
||||
<font key="font" metaFont="system" size="36"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</searchFieldCell>
|
||||
@@ -519,13 +519,13 @@
|
||||
</connections>
|
||||
</searchField>
|
||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="npC-Kk-gUM" userLabel="Site Name Tip">
|
||||
<rect key="frame" x="101" y="237" width="438" height="12"/>
|
||||
<rect key="frame" x="172" y="236" width="395" height="11"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Type the name of your site (eg. apple.com), then hit enter ⏎ to create a password for it." id="QTI-cz-Onx">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -542,13 +542,13 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="rhm-sC-xFS" userLabel="Site Name Tip">
|
||||
<rect key="frame" x="138" y="225" width="365" height="24"/>
|
||||
<rect key="frame" x="206" y="225" width="326" height="22"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" id="n3W-XU-dya">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<string key="title">Hit enter ⏎ to copy the site's password, hold shift ⇧ for the login name.
|
||||
Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -568,7 +568,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</connections>
|
||||
</textField>
|
||||
<stackView distribution="fill" orientation="horizontal" alignment="bottom" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pHt-gg-ZNX">
|
||||
<rect key="frame" x="73" y="20" width="495" height="152"/>
|
||||
<rect key="frame" x="122" y="20" width="495" height="178"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1Qo-iG-CQt">
|
||||
<rect key="frame" x="0.0" y="-1" width="85" height="19"/>
|
||||
@@ -591,16 +591,16 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</connections>
|
||||
</button>
|
||||
<stackView distribution="fill" orientation="vertical" alignment="centerX" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DT0-RU-3LT">
|
||||
<rect key="frame" x="93" y="0.0" width="177" height="152"/>
|
||||
<rect key="frame" x="93" y="0.0" width="177" height="178"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="uol-dE-I8H">
|
||||
<rect key="frame" x="77" y="138" width="22" height="14"/>
|
||||
<rect key="frame" x="77" y="164" width="22" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘P" id="MyN-x6-dMk">
|
||||
<font key="font" metaFont="menu" size="11"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -631,7 +631,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</connections>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="brI-fg-Kav">
|
||||
<rect key="frame" x="40" y="111" width="96" height="19"/>
|
||||
<rect key="frame" x="40" y="137" width="96" height="19"/>
|
||||
<shadow key="shadow">
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
@@ -659,6 +659,35 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</binding>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="jl4-sS-xbm">
|
||||
<rect key="frame" x="12" y="111" width="153" height="19"/>
|
||||
<shadow key="shadow">
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<buttonCell key="cell" type="recessed" title="Default Password Type" bezelStyle="recessed" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Ah6-gK-Rm7" customClass="MPNoStateButtonCell">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
|
||||
<font key="font" metaFont="systemBold" size="12"/>
|
||||
<string key="keyEquivalent">p</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="changeDefaultType:" target="-2" id="3Qg-xV-ewc"/>
|
||||
<binding destination="-2" name="hidden2" keyPath="alternatePressed" previousBinding="2Mv-lM-iXB" id="6QO-NJ-Uyo">
|
||||
<dictionary key="options">
|
||||
<integer key="NSMultipleValuesPlaceholder" value="-1"/>
|
||||
<integer key="NSNoSelectionPlaceholder" value="-1"/>
|
||||
<integer key="NSNotApplicablePlaceholder" value="-1"/>
|
||||
<integer key="NSNullPlaceholder" value="-1"/>
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
<binding destination="mcS-ik-b0n" name="hidden" keyPath="canRemove" id="2Mv-lM-iXB">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="R46-fx-n14">
|
||||
<rect key="frame" x="0.0" y="85" width="177" height="19"/>
|
||||
<shadow key="shadow">
|
||||
@@ -686,26 +715,26 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</connections>
|
||||
</button>
|
||||
<stackView distribution="fill" orientation="horizontal" alignment="top" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Bgn-Ne-fQ7" userLabel="Version Container">
|
||||
<rect key="frame" x="70" y="56" width="36" height="22"/>
|
||||
<rect key="frame" x="71" y="56" width="34" height="22"/>
|
||||
<subviews>
|
||||
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mcq-qD-yte">
|
||||
<rect key="frame" x="-3" y="-3" width="19" height="28"/>
|
||||
<shadow key="shadow">
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<stepperCell key="cell" continuous="YES" alignment="left" minValue="1" maxValue="1000" doubleValue="1" id="73y-03-zHt"/>
|
||||
<stepperCell key="cell" continuous="YES" alignment="left" maxValue="4294967295" doubleValue="1" valueWraps="YES" id="73y-03-zHt"/>
|
||||
<connections>
|
||||
<binding destination="mcS-ik-b0n" name="value" keyPath="selection.algorithmVersion" id="GyA-hK-6cD"/>
|
||||
</connections>
|
||||
</stepper>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gyg-Fh-yn7">
|
||||
<rect key="frame" x="19" y="7" width="19" height="15"/>
|
||||
<rect key="frame" x="19" y="8" width="17" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="V1" id="Pjy-Fm-zwB">
|
||||
<font key="font" size="12" name="HelveticaNeue-Medium"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="calibratedRGB"/>
|
||||
</textFieldCell>
|
||||
@@ -740,26 +769,26 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</connections>
|
||||
</stackView>
|
||||
<stackView distribution="fill" orientation="horizontal" alignment="centerY" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6II-KA-cNi" userLabel="Counter Container">
|
||||
<rect key="frame" x="74" y="26" width="28" height="22"/>
|
||||
<rect key="frame" x="75" y="26" width="27" height="22"/>
|
||||
<subviews>
|
||||
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="XgA-Vl-CKh" userLabel="Counter Stepper">
|
||||
<rect key="frame" x="-3" y="-3" width="19" height="28"/>
|
||||
<shadow key="shadow">
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<stepperCell key="cell" continuous="YES" alignment="left" minValue="1" maxValue="1000" doubleValue="1" id="ikF-n4-xiI"/>
|
||||
<stepperCell key="cell" continuous="YES" alignment="left" minValue="1" maxValue="4294967295" doubleValue="1" valueWraps="YES" id="ikF-n4-xiI"/>
|
||||
<connections>
|
||||
<binding destination="mcS-ik-b0n" name="value" keyPath="selection.counter" id="qmm-6z-boy"/>
|
||||
</connections>
|
||||
</stepper>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="NvO-kt-eZ2" userLabel="Counter Field">
|
||||
<rect key="frame" x="19" y="4" width="11" height="15"/>
|
||||
<rect key="frame" x="19" y="4" width="10" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="1" id="dhQ-bJ-rn3">
|
||||
<font key="font" size="12" name="HelveticaNeue-Medium"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="calibratedRGB"/>
|
||||
</textFieldCell>
|
||||
@@ -805,7 +834,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="changeType:" target="-2" id="6Jj-7p-da9"/>
|
||||
<action selector="changeSiteType:" target="-2" id="6Jj-7p-da9"/>
|
||||
<binding destination="mcS-ik-b0n" name="hidden" keyPath="canRemove" id="Hat-GU-hcQ">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
@@ -821,6 +850,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
</visibilityPriorities>
|
||||
<customSpacing>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
@@ -829,6 +859,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
</stackView>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="whJ-Bw-pr4">
|
||||
@@ -886,13 +917,13 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</customSpacing>
|
||||
</stackView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="luC-0j-BeV">
|
||||
<rect key="frame" x="135" y="50" width="103" height="14"/>
|
||||
<rect key="frame" x="185" y="50" width="103" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Password Number:" id="weR-33-U49">
|
||||
<font key="font" metaFont="menu" size="11"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -923,13 +954,13 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gjx-bt-fKM">
|
||||
<rect key="frame" x="134" y="80" width="100" height="14"/>
|
||||
<rect key="frame" x="184" y="80" width="100" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Password Version:" id="E77-5t-EKJ">
|
||||
<font key="font" metaFont="menu" size="11"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -960,13 +991,13 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="dbM-ja-dKO" userLabel="Version Tip">
|
||||
<rect key="frame" x="88" y="106" width="332" height="14"/>
|
||||
<rect key="frame" x="137" y="106" width="332" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Upgrade your site's algorithm version for maximum protection:" id="3ds-qG-YNd">
|
||||
<font key="font" metaFont="menu" size="11"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -988,13 +1019,13 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ido-NQ-3MY">
|
||||
<rect key="frame" x="104" y="4" width="22" height="12"/>
|
||||
<rect key="frame" x="154" y="2" width="21" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘L" id="fUB-rF-7x8">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -1016,13 +1047,13 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="9b3-wy-KBb">
|
||||
<rect key="frame" x="243" y="2" width="22" height="14"/>
|
||||
<rect key="frame" x="292" y="2" width="22" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘T" id="HFM-Bk-akx">
|
||||
<font key="font" metaFont="menu" size="11"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -1044,13 +1075,13 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="qal-PP-YtO">
|
||||
<rect key="frame" x="516" y="4" width="23" height="12"/>
|
||||
<rect key="frame" x="565" y="2" width="23" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘D" id="PPC-be-w4E">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -1072,13 +1103,13 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="qLF-A6-ThX">
|
||||
<rect key="frame" x="404" y="4" width="23" height="12"/>
|
||||
<rect key="frame" x="453" y="2" width="22" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||
</shadow>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘S" id="qh6-k2-MUr">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -1178,7 +1209,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kCO-1M-Wz1">
|
||||
<rect key="frame" x="10" y="12" width="390" height="92"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" id="kl0-P1-6ZY">
|
||||
<font key="font" metaFont="menu" size="11"/>
|
||||
<font key="font" metaFont="message" size="11"/>
|
||||
<string key="title">"Personal password" allows you to store your own password. It cannot be regenerated in the event of loss. "Device private password" is similar but will never leave your device: it cannot be synced, backed up or exported.</string>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
CLASSPREFIX = MP;
|
||||
LastUpgradeCheck = 1140;
|
||||
LastUpgradeCheck = 1200;
|
||||
ORGANIZATIONNAME = "Maarten Billemont";
|
||||
TargetAttributes = {
|
||||
DAD9B5C0176299B9001835F9 = {
|
||||
@@ -185,6 +185,7 @@
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
@@ -271,6 +272,7 @@
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSBackgroundOnly</key>
|
||||
<true/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2013 Maarten Billemont. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.productivity</string>
|
||||
<key>LSBackgroundOnly</key>
|
||||
<true/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2013 Maarten Billemont. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -58,22 +58,6 @@ const long MPAvatarAdd = 10000;
|
||||
self.avatarImageView.layer.masksToBounds = NO;
|
||||
self.avatarImageView.backgroundColor = [UIColor clearColor];
|
||||
|
||||
[self observeKeyPath:@"bounds" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *self) {
|
||||
self.contentView.frame = self.bounds;
|
||||
}];
|
||||
[self observeKeyPath:@"selected" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *self) {
|
||||
[self updateAnimated:self.superview != nil];
|
||||
}];
|
||||
[self observeKeyPath:@"highlighted" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *self) {
|
||||
[self updateAnimated:self.superview != nil];
|
||||
}];
|
||||
PearlAddNotificationObserver( UIKeyboardWillShowNotification, nil, [NSOperationQueue mainQueue],
|
||||
^(MPAvatarCell *self, NSNotification *note) {
|
||||
CGRect keyboardRect = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
CGFloat keyboardHeight = CGRectGetHeight( self.window.screen.bounds ) - CGRectGetMinY( keyboardRect );
|
||||
[self.keyboardHeightConstraint updateConstant:keyboardHeight];
|
||||
} );
|
||||
|
||||
CABasicAnimation *toShadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
|
||||
toShadowOpacityAnimation.toValue = @0.2f;
|
||||
toShadowOpacityAnimation.duration = 0.5f;
|
||||
@@ -91,6 +75,22 @@ const long MPAvatarAdd = 10000;
|
||||
self.targetedShadowAnimation.duration = MAXFLOAT;
|
||||
self.avatarImageView.layer.shadowColor = [UIColor whiteColor].CGColor;
|
||||
self.avatarImageView.layer.shadowOffset = CGSizeZero;
|
||||
|
||||
[self observeKeyPath:@"bounds" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *self) {
|
||||
self.contentView.frame = self.bounds;
|
||||
}];
|
||||
[self observeKeyPath:@"selected" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *self) {
|
||||
[self updateAnimated:self.superview != nil];
|
||||
}];
|
||||
[self observeKeyPath:@"highlighted" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *self) {
|
||||
[self updateAnimated:self.superview != nil];
|
||||
}];
|
||||
PearlAddNotificationObserver( UIKeyboardWillShowNotification, nil, [NSOperationQueue mainQueue],
|
||||
^(MPAvatarCell *self, NSNotification *note) {
|
||||
CGRect keyboardRect = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
CGFloat keyboardHeight = CGRectGetHeight( self.window.screen.bounds ) - CGRectGetMinY( keyboardRect );
|
||||
[self.keyboardHeightConstraint updateConstant:keyboardHeight];
|
||||
} );
|
||||
}
|
||||
|
||||
- (void)prepareForReuse {
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
[super viewDidLoad];
|
||||
|
||||
self.mode = MPCombinedModeUserSelection;
|
||||
[self performSegueWithIdentifier:@"users" sender:self];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
@property(weak, nonatomic) IBOutlet UIActivityIndicatorView *activity;
|
||||
@property(weak, nonatomic) IBOutlet UIButton *passwordButton;
|
||||
@property(weak, nonatomic) IBOutlet UIView *tipContainer;
|
||||
@property(weak, nonatomic) IBOutlet UIButton *deviceButton;
|
||||
|
||||
- (IBAction)controlChanged:(UIControl *)control;
|
||||
- (IBAction)copyPassword:(UITapGestureRecognizer *)recognizer;
|
||||
- (IBAction)copyDevice:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
|
||||
self.view.backgroundColor = [UIColor clearColor];
|
||||
self.dialogView.layer.cornerRadius = 5;
|
||||
|
||||
[self.deviceButton setTitle:[PearlKeyChain deviceIdentifier] forState:UIControlStateNormal];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
@@ -112,6 +114,11 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (IBAction)copyDevice:(id)sender {
|
||||
[UIPasteboard generalPasteboard].string = [PearlKeyChain deviceIdentifier];
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Device Identifier Copied" ) dismissAfter:2];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)updateKey {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
//==============================================================================
|
||||
|
||||
#import "MPGuideViewController.h"
|
||||
#import "markdown_lib.h"
|
||||
#import "NSString+MPMarkDown.h"
|
||||
|
||||
@interface MPGuideStep : NSObject
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#import "MPNavigationController.h"
|
||||
#import "MPWebViewController.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
|
||||
@implementation MPNavigationController
|
||||
|
||||
@@ -29,6 +30,16 @@
|
||||
[self performSegueWithIdentifier:@"setup" sender:self];
|
||||
}
|
||||
|
||||
- (void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
|
||||
|
||||
if ([identifier isEqualToString:@"web"] && [[(NSURL *)sender scheme] isEqualToString:@"masterpassword"]) {
|
||||
[[MPiOSAppDelegate get] openURL:sender];
|
||||
return;
|
||||
}
|
||||
|
||||
[super performSegueWithIdentifier:identifier sender:sender];
|
||||
}
|
||||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
|
||||
if ([segue.identifier isEqualToString:@"web"])
|
||||
|
||||
@@ -33,13 +33,6 @@
|
||||
self.dismissSegueByButton = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
|
||||
[super viewDidLoad];
|
||||
|
||||
[self performSegueWithIdentifier:@"root" sender:self];
|
||||
}
|
||||
|
||||
- (UIViewController *)childViewControllerForStatusBarStyle {
|
||||
|
||||
return [self.childViewControllers lastObject];
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MPRootSegue : UIStoryboardSegue
|
||||
|
||||
@end
|
||||
@@ -1,35 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
#import "MPRootSegue.h"
|
||||
|
||||
@implementation MPRootSegue
|
||||
|
||||
- (void)perform {
|
||||
|
||||
UIViewController *sourceViewController = self.sourceViewController;
|
||||
UIViewController *destinationViewController = self.destinationViewController;
|
||||
[sourceViewController addChildViewController:destinationViewController];
|
||||
destinationViewController.view.frame = sourceViewController.view.bounds;
|
||||
destinationViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[sourceViewController.view addSubview:destinationViewController.view];
|
||||
[destinationViewController didMoveToParentViewController:sourceViewController];
|
||||
[sourceViewController setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -27,7 +27,7 @@ typedef NS_ENUM ( NSUInteger, MPSiteCellMode ) {
|
||||
|
||||
@interface MPSiteCell : MPCell<UIScrollViewDelegate, UITextFieldDelegate>
|
||||
|
||||
@property(nonatomic) NSArray *fuzzyGroups;
|
||||
@property(nonatomic) NSArray *queryGroups;
|
||||
|
||||
- (void)setSite:(MPSiteEntity *)site animated:(BOOL)animated;
|
||||
- (void)setTransientSite:(NSString *)siteName animated:(BOOL)animated;
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
[super prepareForReuse];
|
||||
|
||||
self.siteOID = nil;
|
||||
self.fuzzyGroups = nil;
|
||||
self.queryGroups = nil;
|
||||
self.transientSite = nil;
|
||||
self.mode = MPPasswordCellModePassword;
|
||||
[self updateAnimated:NO];
|
||||
@@ -150,11 +150,11 @@
|
||||
|
||||
#pragma mark - State
|
||||
|
||||
- (void)setFuzzyGroups:(NSArray *)fuzzyGroups {
|
||||
- (void)setQueryGroups:(NSArray *)queryGroups {
|
||||
|
||||
if (self.fuzzyGroups == fuzzyGroups)
|
||||
if (self.queryGroups == queryGroups)
|
||||
return;
|
||||
_fuzzyGroups = fuzzyGroups;
|
||||
_queryGroups = queryGroups;
|
||||
|
||||
[self updateSiteName:[self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]];
|
||||
}
|
||||
@@ -263,6 +263,7 @@
|
||||
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Delete %@?", site.name ) message:nil
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
[controller.popoverPresentationController setSourceView:sender];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Delete Site" style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
@@ -284,6 +285,7 @@
|
||||
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Change Password Type" message:nil
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
[controller.popoverPresentationController setSourceView:sender];
|
||||
for (NSNumber *typeNumber in [mainSite.algorithm allTypes]) {
|
||||
MPResultType type = (MPResultType)[typeNumber unsignedIntegerValue];
|
||||
NSString *typeName = [mainSite.algorithm nameOfType:type];
|
||||
@@ -425,7 +427,7 @@
|
||||
if (!site || ![site isKindOfClass:[MPGeneratedSiteEntity class]])
|
||||
return;
|
||||
|
||||
((MPGeneratedSiteEntity *)site).counter = 1;
|
||||
((MPGeneratedSiteEntity *)site).counter = MPCounterValueInitial;
|
||||
[context saveToStore];
|
||||
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Counter Reset" dismissAfter:2];
|
||||
@@ -433,7 +435,7 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (IBAction)doContent:(id)sender {
|
||||
- (IBAction)doContent:(UIButton *)sender {
|
||||
|
||||
[UIView animateWithDuration:.2f animations:^{
|
||||
self.contentButton.selected = YES;
|
||||
@@ -444,6 +446,7 @@
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Create Site" message:
|
||||
strf( @"Remember site named:\n%@", self.transientSite )
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
[controller.popoverPresentationController setSourceView:sender];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:
|
||||
^(UIAlertAction *_Nonnull action) {
|
||||
[[MPiOSAppDelegate get]
|
||||
@@ -534,13 +537,13 @@
|
||||
|
||||
// UI
|
||||
//self.backgroundColor = mainSite.url? [UIColor greenColor]: [UIColor redColor];
|
||||
self.upgradeButton.gone = !mainSite.requiresExplicitMigration && ![[MPiOSConfig get].allowDowngrade boolValue];
|
||||
self.answersButton.gone = ![[MPiOSAppDelegate get] isFeatureUnlocked:MPProductGenerateAnswers];
|
||||
self.upgradeButton.visible = mainSite.requiresExplicitMigration || [[MPiOSConfig get].allowDowngrade boolValue];
|
||||
self.answersButton.visible = [[MPiOSAppDelegate get] isFeatureUnlocked:MPProductGenerateAnswers];
|
||||
BOOL settingsMode = self.mode == MPPasswordCellModeSettings;
|
||||
self.loginNameContainer.visible = settingsMode || mainSite.loginGenerated || [mainSite.loginName length];
|
||||
self.modeButton.visible = !self.transientSite;
|
||||
self.modeButton.alpha = settingsMode? 0.5f: 0.1f;
|
||||
self.counterLabel.visible = self.counterButton.visible = mainSite.type & MPResultTypeClassTemplate;
|
||||
self.counterLabel.visible = self.counterButton.visible = (mainSite.type & MPResultTypeClassTemplate) == MPResultTypeClassTemplate;
|
||||
self.modeButton.selected = settingsMode;
|
||||
self.strengthLabel.gone = !settingsMode;
|
||||
self.modeScrollView.scrollEnabled = !self.transientSite;
|
||||
@@ -653,14 +656,14 @@
|
||||
NSString *siteName = self.transientSite?: site.name;
|
||||
NSMutableAttributedString *attributedSiteName = [[NSMutableAttributedString alloc] initWithString:siteName?: @""];
|
||||
if ([attributedSiteName length])
|
||||
for (NSUInteger f = 0, s = (NSUInteger)-1; f < [self.fuzzyGroups count]; ++f) {
|
||||
s = [siteName rangeOfString:self.fuzzyGroups[f] options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch
|
||||
range:NSMakeRange( s + 1, [siteName length] - (s + 1) )].location;
|
||||
for (NSUInteger f = 0, s = 0; f < [self.queryGroups count]; ++f, ++s) {
|
||||
s = [siteName rangeOfString:self.queryGroups[f] options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch
|
||||
range:NSMakeRange( s, [siteName length] - s )].location;
|
||||
if (s == NSNotFound)
|
||||
break;
|
||||
|
||||
[attributedSiteName addAttribute:NSBackgroundColorAttributeName value:[UIColor redColor]
|
||||
range:NSMakeRange( s, [self.fuzzyGroups[f] length] )];
|
||||
range:NSMakeRange( s, [self.queryGroups[f] length] )];
|
||||
}
|
||||
|
||||
if (self.transientSite)
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
UIView *sitesView = sitesVC.view;
|
||||
sitesView.frame = combinedVC.view.bounds;
|
||||
sitesView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[combinedVC.view insertSubview:sitesView belowSubview:combinedVC.usersVC.view];
|
||||
[combinedVC.view insertSubview:sitesView belowSubview:combinedVC.usersVC.view.superview];
|
||||
|
||||
[sitesVC setActive:YES animated:self.animated completion:^(BOOL finished) {
|
||||
if (!finished)
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
@property(nonatomic, strong) IBOutlet UIView *badNameTipContainer;
|
||||
@property(nonatomic, strong) IBOutlet UIView *popdownView;
|
||||
@property(nonatomic, strong) IBOutlet UIView *popdownContainer;
|
||||
@property(nonatomic, strong) IBOutlet UIView *voltoInstallAlert;
|
||||
@property(nonatomic, strong) IBOutlet UIView *voltoMigrateAlert;
|
||||
@property(nonatomic, strong) IBOutlet UIView *spectreInstallAlert;
|
||||
@property(nonatomic, strong) IBOutlet UIView *spectreMigrateAlert;
|
||||
|
||||
@property(assign, nonatomic) BOOL active;
|
||||
|
||||
@@ -39,6 +39,6 @@
|
||||
- (void)reloadSites;
|
||||
|
||||
- (IBAction)dismissPopdown:(id)sender;
|
||||
- (IBAction)upgradeVolto:(UIButton *)sender;
|
||||
- (IBAction)upgradeSpectre:(UIButton *)sender;
|
||||
|
||||
@end
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
MP_LIBS_BEGIN
|
||||
#import <StoreKit/StoreKit.h>
|
||||
MP_LIBS_END
|
||||
|
||||
#import "MPSitesViewController.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
@@ -33,11 +35,10 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
MPPasswordsBadNameTip = 1 << 0,
|
||||
};
|
||||
|
||||
@interface MPSitesViewController()<NSFetchedResultsControllerDelegate, SKStoreProductViewControllerDelegate>
|
||||
@interface MPSitesViewController()<NSFetchedResultsControllerDelegate>
|
||||
|
||||
@property(nonatomic, strong) SKStoreProductViewController *voltoViewController;
|
||||
@property(nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
|
||||
@property(nonatomic, strong) NSArray *fuzzyGroups;
|
||||
@property(nonatomic, strong) NSArray *queryGroups;
|
||||
@property(nonatomic, strong) NSCharacterSet *siteNameAcceptableCharactersSet;
|
||||
@property(nonatomic, strong) NSMutableArray<NSMutableArray *> *dataSource;
|
||||
@property(nonatomic, weak) UIViewController *popdownVC;
|
||||
@@ -73,7 +74,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
|
||||
[self registerObservers];
|
||||
[self updateConfigKey:nil];
|
||||
[self updateVoltoAlerts];
|
||||
[self updateSpectreAlerts];
|
||||
|
||||
static NSRegularExpression *bareHostRE = nil;
|
||||
static dispatch_once_t once = 0;
|
||||
@@ -121,12 +122,14 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
PearlRemoveNotificationObservers();
|
||||
}
|
||||
|
||||
- (void)viewWillLayoutSubviews {
|
||||
- (void)viewDidLayoutSubviews {
|
||||
|
||||
self.collectionView.contentInset = [self.collectionView occludedInsets];
|
||||
self.collectionView.scrollIndicatorInsets = self.collectionView.contentInset;
|
||||
[super viewDidLayoutSubviews];
|
||||
|
||||
[super viewWillLayoutSubviews];
|
||||
if (@available( iOS 11, * )) {
|
||||
self.collectionView.layoutMargins =
|
||||
UIEdgeInsetsMake( [self.collectionView occludedInsets].top - self.view.safeAreaInsets.top, 0, 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
@@ -161,7 +164,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
MPSiteCell *cell = [MPSiteCell dequeueFromCollectionView:collectionView indexPath:indexPath];
|
||||
[cell setFuzzyGroups:self.fuzzyGroups];
|
||||
[cell setQueryGroups:self.queryGroups];
|
||||
id item = self.dataSource[(NSUInteger)indexPath.section][(NSUInteger)indexPath.item];
|
||||
if ([item isKindOfClass:[MPSiteEntity class]])
|
||||
[cell setSite:item animated:NO];
|
||||
@@ -171,6 +174,19 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDelegateFlowLayout
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout
|
||||
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)collectionViewLayout;
|
||||
CGFloat availableWidth = collectionView.bounds.size.width
|
||||
- collectionView.layoutMargins.left - collectionView.layoutMargins.right
|
||||
- layout.sectionInset.left - layout.sectionInset.right;
|
||||
CGFloat cells = MAX( 1, (int)((availableWidth + layout.minimumInteritemSpacing) / (318 + layout.minimumInteritemSpacing)) );
|
||||
return CGSizeMake( (availableWidth - layout.minimumInteritemSpacing * (cells - 1)) / cells, 100 );
|
||||
}
|
||||
|
||||
#pragma mark - UIScrollDelegate
|
||||
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
|
||||
@@ -185,11 +201,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
|
||||
|
||||
if (controller == self.fetchedResultsController)
|
||||
PearlMainQueue( ^{
|
||||
[self.collectionView updateDataSource:self.dataSource
|
||||
toSections:[self createDataSource]
|
||||
reloadItems:nil completion:nil];
|
||||
} );
|
||||
[self updateSites];
|
||||
}
|
||||
|
||||
#pragma mark - UISearchBarDelegate
|
||||
@@ -306,7 +318,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
PearlAddNotificationObserver( UIApplicationWillEnterForegroundNotification, nil, [NSOperationQueue mainQueue],
|
||||
^(MPSitesViewController *self, NSNotification *note) {
|
||||
[self viewWillAppear:YES];
|
||||
[self updateVoltoAlerts];
|
||||
[self updateSpectreAlerts];
|
||||
} );
|
||||
PearlAddNotificationObserver( MPSignedOutNotification, nil, nil,
|
||||
^(MPSitesViewController *self, NSNotification *note) {
|
||||
@@ -354,39 +366,42 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
- (void)reloadSites {
|
||||
|
||||
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
||||
static NSRegularExpression *fuzzyRE;
|
||||
static dispatch_once_t once = 0;
|
||||
dispatch_once( &once, ^{
|
||||
fuzzyRE = [NSRegularExpression regularExpressionWithPattern:@"(.)" options:0 error:nil];
|
||||
} );
|
||||
|
||||
NSString *queryString = self.query;
|
||||
NSString *queryPattern = [[queryString stringByReplacingMatchesOfExpression:fuzzyRE withTemplate:@"*$1"]
|
||||
stringByAppendingString:@"*"];
|
||||
NSMutableArray *fuzzyGroups = [NSMutableArray new];
|
||||
[fuzzyRE enumerateMatchesInString:queryString options:0 range:NSMakeRange( 0, queryString.length )
|
||||
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
||||
[fuzzyGroups addObject:[queryString substringWithRange:result.range]];
|
||||
}];
|
||||
self.fuzzyGroups = fuzzyGroups;
|
||||
NSMutableArray *queryGroups = [NSMutableArray new];
|
||||
NSMutableString *queryPattern = [NSMutableString new];
|
||||
[queryString enumerateSubstringsInRange: NSMakeRange(0, [queryString length]) options: NSStringEnumerationByComposedCharacterSequences
|
||||
usingBlock: ^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
|
||||
if (substringRange.location < 20) {
|
||||
[queryGroups addObject:substring];
|
||||
[queryPattern appendString:@"*"];
|
||||
}
|
||||
[queryPattern appendString:substring];
|
||||
}];
|
||||
[queryPattern appendString:@"*"];
|
||||
self.queryGroups = queryGroups;
|
||||
|
||||
NSError *error = nil;
|
||||
self.fetchedResultsController.fetchRequest.predicate =
|
||||
[NSPredicate predicateWithFormat:@"name LIKE[cd] %@ AND user == %@", queryPattern, [MPiOSAppDelegate get].activeUserOID];
|
||||
if (![self.fetchedResultsController performFetch:&error])
|
||||
if (![self.fetchedResultsController performFetch:&error] || error)
|
||||
MPError( error, @"Couldn't fetch sites." );
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[self.collectionView updateDataSource:self.dataSource
|
||||
toSections:[self createDataSource]
|
||||
reloadItems:@[ MPTransientPasswordItem ] completion:^(BOOL finished) {
|
||||
for (MPSiteCell *cell in self.collectionView.visibleCells)
|
||||
[cell setFuzzyGroups:self.fuzzyGroups];
|
||||
}];
|
||||
} );
|
||||
[self updateSites];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateSites {
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[self.collectionView updateDataSource:self.dataSource
|
||||
toSections:[self createDataSource]
|
||||
reloadItems:@[ MPTransientPasswordItem ] completion:^(BOOL finished) {
|
||||
for (MPSiteCell *cell in self.collectionView.visibleCells)
|
||||
[cell setQueryGroups:self.queryGroups];
|
||||
}];
|
||||
} );
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (NSString *)query {
|
||||
@@ -404,14 +419,19 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
|
||||
if (!_fetchedResultsController) {
|
||||
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
|
||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
|
||||
NSFetchRequest *fetchRequest = [MPSiteEntity fetchRequest];
|
||||
fetchRequest.sortDescriptors = @[
|
||||
[[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO]
|
||||
];
|
||||
fetchRequest.fetchBatchSize = 10;
|
||||
|
||||
(self.fetchedResultsController = [[NSFetchedResultsController alloc]
|
||||
initWithFetchRequest:fetchRequest managedObjectContext:mainContext
|
||||
sectionNameKeyPath:nil cacheName:nil]).delegate = self;
|
||||
|
||||
NSError *error = nil;
|
||||
if (![self.fetchedResultsController performFetch:&error] || error)
|
||||
MPError( error, @"Couldn't fetch sites." );
|
||||
[self updateSites];
|
||||
}];
|
||||
[self registerObservers];
|
||||
}
|
||||
@@ -435,13 +455,6 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
} completion:completion];
|
||||
}
|
||||
|
||||
#pragma mark - SKStoreProductViewControllerDelegate
|
||||
|
||||
- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController {
|
||||
|
||||
[viewController dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)dismissPopdown:(id)sender {
|
||||
@@ -452,76 +465,23 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
self.popdownToTopConstraint.priority = UILayoutPriorityDefaultHigh;
|
||||
}
|
||||
|
||||
- (IBAction)upgradeVolto:(UIButton *)sender {
|
||||
- (IBAction)upgradeSpectre:(UIButton *)sender {
|
||||
|
||||
if ([UIApp canOpenURL:[[NSURL alloc] initWithString:@"volto:"]]) {
|
||||
[[MPiOSAppDelegate get] exportSitesRevealPasswords:NO askExportPassword:^NSString *(NSString *userName) {
|
||||
return PearlAwait( ^(void (^setResult)(id)) {
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Master Password For:\n%@", userName )
|
||||
message:@"Enter your master password to export the user."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
||||
textField.secureTextEntry = YES;
|
||||
}];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Export" style:UIAlertActionStyleDefault handler:
|
||||
^(UIAlertAction *action) { setResult( alert.textFields.firstObject.text ); }]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:
|
||||
^(UIAlertAction *action) { setResult( nil ); }]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
} result:^(NSString *exportedUser, NSError *error) {
|
||||
if (!exportedUser || error) {
|
||||
MPError( error, @"Failed to export user." );
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Error"
|
||||
message:[error localizedDescription]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
NSURLComponents *components = [NSURLComponents new];
|
||||
components.scheme = @"volto";
|
||||
components.path = @"import";
|
||||
components.queryItems = @[ [[NSURLQueryItem alloc] initWithName:@"data" value:exportedUser] ];
|
||||
[UIApp openURL:components.URL];
|
||||
}];
|
||||
}
|
||||
else if (self.voltoViewController)
|
||||
[self presentViewController:self.voltoViewController animated:YES completion:nil];
|
||||
[[MPiOSAppDelegate get] migrateFor:[MPiOSAppDelegate get].activeUserForMainThread];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)updateVoltoAlerts {
|
||||
- (void)updateSpectreAlerts {
|
||||
|
||||
BOOL voltoInstalled = [UIApp canOpenURL:[[NSURL alloc] initWithString:@"volto:"]];
|
||||
if (voltoInstalled) {
|
||||
self.voltoInstallAlert.visible = NO;
|
||||
self.voltoMigrateAlert.visible = YES;
|
||||
BOOL spectreInstalled = [UIApp canOpenURL:[[NSURL alloc] initWithString:@"spectre:"]];
|
||||
if (spectreInstalled) {
|
||||
self.spectreInstallAlert.visible = NO;
|
||||
self.spectreMigrateAlert.visible = YES;
|
||||
}
|
||||
else {
|
||||
self.voltoInstallAlert.visible = NO;
|
||||
self.voltoMigrateAlert.visible = NO;
|
||||
self.voltoViewController = [SKStoreProductViewController new];
|
||||
self.voltoViewController.delegate = self;
|
||||
[self.voltoViewController loadProductWithParameters:@{
|
||||
SKStoreProductParameterCampaignToken : @"app-masterpassword.ios", /* Campaign: From MasterPassword iOS */
|
||||
SKStoreProductParameterProviderToken : @153897, /* Provider: Maarten Billemont */
|
||||
SKStoreProductParameterITunesItemIdentifier: @510296984, /* Application: MasterPassword iOS */
|
||||
//SKStoreProductParameterITunesItemIdentifier: @1500430196, /* Application: Volto iOS */
|
||||
} completionBlock:^(BOOL result, NSError *error) {
|
||||
if (error)
|
||||
err( @"Failed loading Volto product information: %@", error );
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.voltoInstallAlert.visible = result;
|
||||
}];
|
||||
}];
|
||||
self.spectreInstallAlert.visible = [MPiOSAppDelegate get].spectreViewController != nil;
|
||||
self.spectreMigrateAlert.visible = NO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,13 @@
|
||||
|
||||
#import "MPStoreViewController.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
#import "UIColor+Expanded.h"
|
||||
#import "MPAppDelegate_InApp.h"
|
||||
#import "MPSitesViewController.h"
|
||||
|
||||
MP_LIBS_BEGIN
|
||||
#import "UIColor+Expanded.h"
|
||||
MP_LIBS_END
|
||||
|
||||
PearlEnum( MPDevelopmentFuelConsumption,
|
||||
MPDevelopmentFuelConsumptionQuarterly, MPDevelopmentFuelConsumptionMonthly, MPDevelopmentFuelWeekly );
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
|
||||
MPActiveUserStateMinimized,
|
||||
};
|
||||
|
||||
@interface MPUsersViewController()
|
||||
@interface MPUsersViewController()<NSFetchedResultsControllerDelegate>
|
||||
|
||||
@property(nonatomic) MPActiveUserState activeUserState;
|
||||
@property(nonatomic, strong) NSArray *userIDs;
|
||||
@@ -57,7 +57,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
|
||||
@property(nonatomic) NSUInteger marqueeTipTextIndex;
|
||||
@property(nonatomic, copy) NSString *masterPasswordChoice;
|
||||
@property(nonatomic, strong) NSOperationQueue *afterUpdates;
|
||||
@property(nonatomic, weak) id contextChangedObserver;
|
||||
@property(nonatomic, strong) NSFetchedResultsController *userResultsController;
|
||||
|
||||
@end
|
||||
|
||||
@@ -91,6 +91,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
self.userSelectionContainer.visible = NO;
|
||||
[self.storeLoadingActivity startAnimating];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
@@ -231,12 +232,10 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
|
||||
user.avatar = newUserAvatar;
|
||||
user.name = newUserName;
|
||||
|
||||
if ([[MPConfig get].sendInfo boolValue]) {
|
||||
[Countly.sharedInstance recordEvent:@"new-user" segmentation:@{
|
||||
@"algorithm": @(user.algorithm.version).description,
|
||||
@"avatar" : @(user.avatar).description,
|
||||
}];
|
||||
}
|
||||
[Countly.sharedInstance recordEvent:@"new-user" segmentation:@{
|
||||
@"algorithm": @(user.algorithm.version).description,
|
||||
@"avatar" : @(user.avatar).description,
|
||||
}];
|
||||
}
|
||||
|
||||
BOOL signedIn = [[MPiOSAppDelegate get] signInAsUser:user saveInContext:context
|
||||
@@ -434,6 +433,7 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
|
||||
NSManagedObjectID *userID = user.permanentObjectID;
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:user.name message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
[controller.popoverPresentationController setSourceView:avatarCell];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
|
||||
UIAlertController *controller_ = [UIAlertController alertControllerWithTitle:@"Deleting User" message:
|
||||
@"The user and its sites will be deleted." preferredStyle:UIAlertControllerStyleAlert];
|
||||
@@ -643,7 +643,6 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
|
||||
[self removeKeyPathObservers];
|
||||
PearlRemoveNotificationObservers();
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self.contextChangedObserver];
|
||||
}
|
||||
|
||||
- (void)registerObservers {
|
||||
@@ -675,24 +674,6 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
[self.keyboardHeightConstraint updateConstant:keyboardHeight];
|
||||
} );
|
||||
|
||||
if ((self.contextChangedObserver
|
||||
= [[MPiOSAppDelegate get] managedObjectContextChanged:^(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects) {
|
||||
if ([[[affectedObjects allKeys] filteredArrayUsingPredicate:
|
||||
[NSPredicate predicateWithBlock:^BOOL(NSManagedObjectID *objectID, NSDictionary *bindings) {
|
||||
return [objectID.entity.name isEqualToString:NSStringFromClass( [MPUserEntity class] )];
|
||||
}]] count])
|
||||
[self reloadUsers];
|
||||
}]))
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.avatarCollectionView.visible = YES;
|
||||
[self.storeLoadingActivity stopAnimating];
|
||||
}];
|
||||
else
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.avatarCollectionView.visible = NO;
|
||||
[self.storeLoadingActivity startAnimating];
|
||||
}];
|
||||
|
||||
PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, [MPiOSAppDelegate get].storeCoordinator, nil,
|
||||
^(MPUsersViewController *self, NSNotification *note) {
|
||||
self.userIDs = nil;
|
||||
@@ -704,32 +685,54 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
[self reloadUsers];
|
||||
} );
|
||||
} );
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.avatarCollectionView.visible = YES;
|
||||
[self.storeLoadingActivity stopAnimating];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)reloadUsers {
|
||||
|
||||
[self afterUpdatesMainQueue:^{
|
||||
if (![MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
|
||||
NSError *error = nil;
|
||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
|
||||
fetchRequest.sortDescriptors = @[
|
||||
[NSSortDescriptor sortDescriptorWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO]
|
||||
];
|
||||
NSArray *users = [mainContext executeFetchRequest:fetchRequest error:&error];
|
||||
if (!users) {
|
||||
MPError( error, @"Failed to load users." );
|
||||
self.userIDs = nil;
|
||||
}
|
||||
self.userResultsController = [[NSFetchedResultsController alloc]
|
||||
initWithFetchRequest:fetchRequest managedObjectContext:mainContext
|
||||
sectionNameKeyPath:nil cacheName:nil];
|
||||
self.userResultsController.delegate = self;
|
||||
|
||||
NSMutableArray *userIDs = [NSMutableArray arrayWithCapacity:[users count]];
|
||||
for (MPUserEntity *user in users)
|
||||
[userIDs addObject:user.permanentObjectID];
|
||||
self.userIDs = userIDs;
|
||||
NSError *error = nil;
|
||||
if (![self.userResultsController performFetch:&error])
|
||||
MPError( error, @"Failed to load users." );
|
||||
|
||||
[self updateUsers];
|
||||
}])
|
||||
self.userIDs = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateUsers {
|
||||
|
||||
[self.userResultsController.managedObjectContext performBlock:^{
|
||||
NSArray *users = self.userResultsController.fetchedObjects;
|
||||
NSMutableArray *userIDs = [NSMutableArray arrayWithCapacity:[users count]];
|
||||
for (MPUserEntity *user in users)
|
||||
[userIDs addObject:user.permanentObjectID];
|
||||
self.userIDs = userIDs;
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - NSFetchedResultsControllerDelegate
|
||||
|
||||
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
|
||||
|
||||
[self updateUsers];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setActive:(BOOL)active animated:(BOOL)animated {
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
//==============================================================================
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
@interface MPWebViewController : UIViewController<UIWebViewDelegate>
|
||||
@interface MPWebViewController : UIViewController<WKNavigationDelegate>
|
||||
|
||||
@property(nonatomic) IBOutlet UIWebView *webView;
|
||||
@property(nonatomic) IBOutlet WKWebView *webView;
|
||||
@property(nonatomic) IBOutlet UINavigationBar *webNavigationBar;
|
||||
@property(nonatomic) IBOutlet UINavigationItem *webNavigationItem;
|
||||
|
||||
@property(nonatomic) NSURL *initialURL;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#import "MPWebViewController.h"
|
||||
#import "MPiOSAppDelegate.h"
|
||||
|
||||
@implementation MPWebViewController
|
||||
|
||||
@@ -24,20 +25,30 @@
|
||||
|
||||
[super viewDidLoad];
|
||||
|
||||
[self.webView.scrollView insetOcclusion];
|
||||
if (!self.initialURL)
|
||||
self.initialURL = [NSURL URLWithString:@"https://masterpassword.app"];
|
||||
self.webNavigationItem.title = self.initialURL.host;
|
||||
|
||||
// WKWebView can't be on the storyboard for iOS pre 11 due to an NSCoding bug.
|
||||
[self.view insertSubview:self.webView = [WKWebView new] atIndex:0];
|
||||
[self.webView setNavigationDelegate:self];
|
||||
[self.webView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[self.webView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
|
||||
[self.webView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
|
||||
[self.webView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
|
||||
[self.webView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
|
||||
|
||||
[self.webView loadRequest:[[NSURLRequest alloc] initWithURL:self.initialURL]];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
|
||||
[super viewWillAppear:animated];
|
||||
}
|
||||
|
||||
if (!self.initialURL)
|
||||
self.initialURL = [NSURL URLWithString:@"https://masterpassword.app"];
|
||||
|
||||
self.webNavigationItem.title = self.initialURL.host;
|
||||
|
||||
self.webView.visible = NO;
|
||||
[self.webView loadRequest:[[NSURLRequest alloc] initWithURL:self.initialURL]];
|
||||
- (void)viewDidLayoutSubviews {
|
||||
[self.webView.scrollView insetOcclusion];
|
||||
[super viewDidLayoutSubviews];
|
||||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||
@@ -45,26 +56,24 @@
|
||||
return UIStatusBarStyleLightContent;
|
||||
}
|
||||
|
||||
#pragma mark - UIWebViewDelegate
|
||||
#pragma mark - WKNavigationDelegate
|
||||
|
||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
|
||||
navigationType:(UIWebViewNavigationType)navigationType {
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
|
||||
decisionHandler:(void ( ^ )(WKNavigationActionPolicy))decisionHandler {
|
||||
|
||||
if ([[request.URL absoluteString] rangeOfString:@"thanks.lhunath.com"].location != NSNotFound) {
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"tipped.thanks"];
|
||||
if (![[NSUserDefaults standardUserDefaults] synchronize])
|
||||
wrn( @"Couldn't synchronize thanks tip." );
|
||||
if ([navigationAction.request.mainDocumentURL.scheme isEqualToString:@"masterpassword"]) {
|
||||
[[MPiOSAppDelegate get] openURL:navigationAction.request.mainDocumentURL];
|
||||
decisionHandler( WKNavigationActionPolicyCancel );
|
||||
return;
|
||||
}
|
||||
|
||||
if ([request.URL isEqual:request.mainDocumentURL]) {
|
||||
self.webNavigationItem.title = request.URL.host;
|
||||
self.webNavigationItem.prompt = strl( @"Loading" );
|
||||
}
|
||||
|
||||
return YES;
|
||||
decisionHandler( WKNavigationActionPolicyAllow );
|
||||
}
|
||||
|
||||
- (void)webViewDidStartLoad:(UIWebView *)webView {
|
||||
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
|
||||
|
||||
self.webNavigationItem.title = webView.URL.host;
|
||||
self.webNavigationItem.prompt = strl( @"Loading" );
|
||||
|
||||
UIActivityIndicatorView *activityView =
|
||||
[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
|
||||
@@ -72,19 +81,57 @@
|
||||
[activityView startAnimating];
|
||||
}
|
||||
|
||||
- (void)webViewDidFinishLoad:(UIWebView *)webView {
|
||||
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
|
||||
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.webView.visible = YES;
|
||||
if ([[webView.URL absoluteString] rangeOfString:@"thanks.lhunath.com"].location != NSNotFound) {
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"tipped.thanks"];
|
||||
if (![[NSUserDefaults standardUserDefaults] synchronize])
|
||||
wrn( @"Couldn't synchronize thanks tip." );
|
||||
}
|
||||
|
||||
[self.webNavigationItem setLeftBarButtonItem:[[UIBarButtonItem alloc]
|
||||
initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector( action: )]];
|
||||
[webView evaluateJavaScript:@"document.title" completionHandler:^(id o, NSError *error) {
|
||||
self.webNavigationItem.prompt = [o description];
|
||||
}];
|
||||
|
||||
[self.webNavigationItem setLeftBarButtonItem:[webView canGoBack]? [[UIBarButtonItem alloc]
|
||||
initWithTitle:@"⬅︎" style:UIBarButtonItemStylePlain target:webView action:@selector( goBack )]: nil];
|
||||
self.webNavigationItem.prompt = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)action:(UIBarButtonItem *)sender {
|
||||
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:self.webView.URL.host
|
||||
message:self.webView.URL.absoluteString
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
[controller.popoverPresentationController setBarButtonItem:sender];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Safari" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[UIApp openURL:self.webView.URL];
|
||||
}]];
|
||||
if ([UIApp canOpenURL:[NSURL URLWithString:@"firefox:"]]) {
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Firefox" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[UIApp openURL:[NSURL URLWithString:strf( @"firefox://open-url?url=%@",
|
||||
[self.webView.URL.absoluteString stringByAddingPercentEncodingWithAllowedCharacters:
|
||||
[NSCharacterSet URLQueryAllowedCharacterSet]] )]];
|
||||
}]];
|
||||
}
|
||||
if ([UIApp canOpenURL:[NSURL URLWithString:@"googlechrome:"]]) {
|
||||
NSURL *url = [[NSURL alloc] initWithScheme:[self.webView.URL.scheme isEqualToString:@"http"]? @"googlechrome": @"googlechromes"
|
||||
host:self.webView.URL.host path:self.webView.URL.path];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Chrome" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[UIApp openURL:url];
|
||||
}]];
|
||||
}
|
||||
if ([UIApp canOpenURL:[NSURL URLWithString:@"opera-http:"]]) {
|
||||
NSURL *url = [[NSURL alloc] initWithScheme:[self.webView.URL.scheme isEqualToString:@"http"]? @"opera-http": @"opera-https"
|
||||
host:self.webView.URL.host path:self.webView.URL.path];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Opera" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[UIApp openURL:url];
|
||||
}]];
|
||||
}
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:controller animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (IBAction)done:(id)sender {
|
||||
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
|
||||
@@ -17,15 +17,23 @@
|
||||
//==============================================================================
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <StoreKit/StoreKit.h>
|
||||
|
||||
#import "MPAppDelegate_Shared.h"
|
||||
|
||||
@interface MPiOSAppDelegate : MPAppDelegate_Shared
|
||||
@interface MPiOSAppDelegate : MPAppDelegate_Shared <SKStoreProductViewControllerDelegate>
|
||||
|
||||
@property(nonatomic, strong) UIWindow *window;
|
||||
@property(nonatomic, strong) SKStoreProductViewController *spectreViewController;
|
||||
|
||||
- (void)openURL:(NSURL *)url;
|
||||
|
||||
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController;
|
||||
- (void)openFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController;
|
||||
|
||||
- (void)showExportForVC:(UIViewController *)viewController;
|
||||
- (void)migrateFor:(MPUserEntity *)user;
|
||||
|
||||
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset;
|
||||
|
||||
@end
|
||||
|
||||
@@ -23,8 +23,24 @@
|
||||
#import "mpw-marshal.h"
|
||||
#import "MPSecrets.h"
|
||||
|
||||
MP_LIBS_BEGIN
|
||||
#import <Sentry/Sentry.h>
|
||||
#import <Countly/Countly.h>
|
||||
MP_LIBS_END
|
||||
|
||||
@interface CountlyPushNotifications
|
||||
@end
|
||||
|
||||
@interface CountlyPushNotifications(MPNotifications)
|
||||
@end
|
||||
|
||||
@implementation CountlyPushNotifications(MPNotifications)
|
||||
|
||||
- (void)openURL:(NSString *)URLString {
|
||||
[[MPiOSAppDelegate get].window.rootViewController performSegueWithIdentifier:@"web" sender:[NSURL URLWithString:URLString]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface MPiOSAppDelegate()<UIDocumentInteractionControllerDelegate>
|
||||
|
||||
@@ -34,6 +50,8 @@
|
||||
|
||||
@implementation MPiOSAppDelegate
|
||||
|
||||
@synthesize window;
|
||||
|
||||
+ (void)initialize {
|
||||
|
||||
[MPiOSConfig get];
|
||||
@@ -43,10 +61,10 @@
|
||||
|
||||
@try {
|
||||
// Sentry
|
||||
[SentrySDK initWithOptions:@{
|
||||
[SentrySDK startWithOptions:@{
|
||||
@"dsn" : NilToNSNull( decrypt( sentryDSN ) ),
|
||||
#ifdef DEBUG
|
||||
@"debug" : @(YES),
|
||||
@"debug" : @(NO), //@(YES),
|
||||
@"environment" : @"Development",
|
||||
#elif PUBLIC
|
||||
@"debug" : @(NO),
|
||||
@@ -55,7 +73,7 @@
|
||||
@"debug" : @(NO),
|
||||
@"environment" : @"Private",
|
||||
#endif
|
||||
@"enabled" : [MPiOSConfig get].sendInfo,
|
||||
@"enabled" : @([[MPiOSConfig get].sendInfo boolValue] || ![[MPiOSConfig get].sendInfoDecided boolValue]),
|
||||
@"enableAutoSessionTracking": @(YES),
|
||||
}];
|
||||
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
||||
@@ -106,7 +124,7 @@
|
||||
countlyConfig.deviceID = [PearlKeyChain deviceIdentifier];
|
||||
countlyConfig.secretSalt = decrypt( countlySalt );
|
||||
#if DEBUG
|
||||
countlyConfig.enableDebug = YES;
|
||||
//countlyConfig.enableDebug = YES;
|
||||
countlyConfig.pushTestMode = CLYPushTestModeDevelopment;
|
||||
#elif ! PUBLIC
|
||||
countlyConfig.enableDebug = NO;
|
||||
@@ -136,12 +154,6 @@
|
||||
@catch (id exception) {
|
||||
err( @"During Config Test: %@", exception );
|
||||
}
|
||||
@try {
|
||||
[super application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
}
|
||||
@catch (id exception) {
|
||||
err( @"During Pearl Application Launch: %@", exception );
|
||||
}
|
||||
@try {
|
||||
inf( @"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier] );
|
||||
|
||||
@@ -172,11 +184,29 @@
|
||||
}
|
||||
} );
|
||||
|
||||
SKStoreProductViewController *migrateVC = [SKStoreProductViewController new];
|
||||
[migrateVC loadProductWithParameters:@{
|
||||
SKStoreProductParameterCampaignToken : @"app-masterpassword.ios", /* Campaign: From MasterPassword iOS */
|
||||
SKStoreProductParameterProviderToken : @153897, /* Provider: Maarten Billemont */
|
||||
// SKStoreProductParameterITunesItemIdentifier: @510296984, /* Application: MasterPassword iOS */
|
||||
SKStoreProductParameterITunesItemIdentifier: @1500430196, /* Application: Spectre iOS */
|
||||
} completionBlock:^(BOOL result, NSError *error) {
|
||||
if (error)
|
||||
err( @"Failed loading Spectre product information: %@", error );
|
||||
|
||||
if (result) {
|
||||
self.spectreViewController = migrateVC;
|
||||
self.spectreViewController.delegate = self;
|
||||
} else {
|
||||
self.spectreViewController = nil;
|
||||
}
|
||||
}];
|
||||
|
||||
PearlMainQueueOperation( ^{
|
||||
if ([[MPiOSConfig get].showSetup boolValue])
|
||||
[self.navigationController performSegueWithIdentifier:@"setup" sender:self];
|
||||
[self.window.rootViewController performSegueWithIdentifier:@"setup" sender:self];
|
||||
|
||||
[self enableNotifications];
|
||||
[self consentFeatures];
|
||||
} );
|
||||
}
|
||||
@catch (id exception) {
|
||||
@@ -193,6 +223,12 @@
|
||||
if (!url)
|
||||
return NO;
|
||||
|
||||
// masterpassword: URLs.
|
||||
if ([url.scheme isEqualToString:@"masterpassword"]) {
|
||||
[self openURL:url];
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Arbitrary URL to mpsites data.
|
||||
[[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:
|
||||
^(NSData *importedSitesData, NSURLResponse *response, NSError *error) {
|
||||
@@ -206,7 +242,7 @@
|
||||
(id)[error localizedDescription]?: error )
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
return;
|
||||
}
|
||||
@@ -218,7 +254,7 @@
|
||||
@"Master Password couldn't understand the import file."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
return;
|
||||
}
|
||||
@@ -229,7 +265,42 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)enableNotifications {
|
||||
- (void)consentFeatures {
|
||||
if ([self askDiagnostics])
|
||||
return;
|
||||
|
||||
[self tryNotifications];
|
||||
}
|
||||
|
||||
- (BOOL)askDiagnostics {
|
||||
|
||||
if ([[MPiOSConfig get].sendInfoDecided boolValue])
|
||||
return NO;
|
||||
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Diagnostics" message:
|
||||
@"We look for bugs, sudden crashes, runtime issues & statistics.\n\n"
|
||||
@"Diagnostics are scrubbed and personal details will never leave your device."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Disable" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
||||
[MPiOSConfig get].sendInfo = @(NO);
|
||||
[MPiOSConfig get].sendInfoDecided = @(YES);
|
||||
[self consentFeatures];
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Engage" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[MPiOSConfig get].sendInfo = @(YES);
|
||||
[MPiOSConfig get].sendInfoDecided = @(YES);
|
||||
[self consentFeatures];
|
||||
}]];
|
||||
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)tryNotifications {
|
||||
|
||||
[Countly.sharedInstance giveConsentForFeature:CLYConsentPushNotifications];
|
||||
if (@available( iOS 12, * )) {
|
||||
@@ -240,35 +311,35 @@
|
||||
|
||||
[self askNotifications];
|
||||
}];
|
||||
return;
|
||||
}
|
||||
else {
|
||||
[self askNotifications];
|
||||
}
|
||||
|
||||
[self askNotifications];
|
||||
}
|
||||
|
||||
- (void)askNotifications {
|
||||
|
||||
if ([[MPiOSConfig get].notificationsDecided boolValue])
|
||||
return;
|
||||
|
||||
PearlMainQueue( ^{
|
||||
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"notificationsDecided"]) {
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Coming Soon" message:
|
||||
@"Master Password is rolling out a new modern personal security platform and we're excited to bring you along.\n\n"
|
||||
@"When it's time, we'll send you a notification to help you make an effortless transition."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Thanks" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
if (@available( iOS 12, * )) {
|
||||
[Countly.sharedInstance askForNotificationPermissionWithOptions:UNAuthorizationOptionAlert completionHandler:
|
||||
^(BOOL granted, NSError *error) {
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"notificationsDecided"];
|
||||
}];
|
||||
}
|
||||
else {
|
||||
[Countly.sharedInstance askForNotificationPermission];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"notificationsDecided"];
|
||||
}
|
||||
}]];
|
||||
[(self.navigationController.presentedViewController?: (UIViewController *)self.navigationController)
|
||||
presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Coming Soon" message:
|
||||
@"Master Password is rolling out a brand new, updated version and we're excited to bring you along.\n\n"
|
||||
@"When it's time, we'll send you a notification to help you make an effortless transition."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Thanks" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
if (@available( iOS 12, * )) {
|
||||
[Countly.sharedInstance askForNotificationPermissionWithOptions:UNAuthorizationOptionAlert completionHandler:
|
||||
^(BOOL granted, NSError *error) {
|
||||
[MPiOSConfig get].notificationsDecided = @(YES);
|
||||
}];
|
||||
}
|
||||
else {
|
||||
[Countly.sharedInstance askForNotificationPermission];
|
||||
[MPiOSConfig get].notificationsDecided = @(YES);
|
||||
}
|
||||
}]];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
}
|
||||
|
||||
@@ -297,7 +368,7 @@
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
||||
setResult( nil );
|
||||
}]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
} askUserPassword:^NSString *(NSString *userName) {
|
||||
@@ -315,7 +386,7 @@
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
||||
setResult( nil );
|
||||
}]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
} result:^(NSError *error) {
|
||||
@@ -326,7 +397,7 @@
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:[error localizedDescription]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:controller animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:controller animated:YES completion:nil];
|
||||
}
|
||||
} );
|
||||
}];
|
||||
@@ -336,15 +407,7 @@
|
||||
|
||||
inf( @"Will foreground" );
|
||||
|
||||
[super applicationWillEnterForeground:application];
|
||||
|
||||
[self.hangDetector start];
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
|
||||
inf( @"Re-activated" );
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
|
||||
|
||||
PearlNotMainQueue( ^{
|
||||
NSString *importData = [UIPasteboard generalPasteboard].string;
|
||||
@@ -360,20 +423,22 @@
|
||||
[UIPasteboard generalPasteboard].string = @"";
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
}
|
||||
mpw_marshal_file_free( &importFile );
|
||||
} );
|
||||
}
|
||||
|
||||
[super applicationDidBecomeActive:application];
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
|
||||
inf( @"Re-activated" );
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
|
||||
|
||||
inf( @"Received memory warning." );
|
||||
|
||||
[super applicationDidReceiveMemoryWarning:application];
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
||||
@@ -386,12 +451,46 @@
|
||||
}
|
||||
|
||||
[self.hangDetector stop];
|
||||
|
||||
[super applicationDidEnterBackground:application];
|
||||
}
|
||||
|
||||
#pragma mark - Behavior
|
||||
|
||||
- (void)openURL:(NSURL *)url {
|
||||
if ([url.scheme isEqualToString:@"masterpassword"]) {
|
||||
if ([url.host isEqualToString:@"open-url"]) {
|
||||
for (NSURLQueryItem *item in [NSURLComponents componentsWithString:[url absoluteString]].queryItems)
|
||||
if ([item.name isEqualToString:@"url"]) {
|
||||
[UIApp openURL:[NSURL URLWithString:item.value]];
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ([url.host isEqualToString:@"show-url"]) {
|
||||
for (NSURLQueryItem *item in [NSURLComponents componentsWithString:[url absoluteString]].queryItems)
|
||||
if ([item.name isEqualToString:@"url"]) {
|
||||
[self.window.rootViewController performSegueWithIdentifier:@"web" sender:[NSURL URLWithString:item.value]];
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ([url.host isEqualToString:@"migrate"]) {
|
||||
for (NSURLQueryItem *item in [NSURLComponents componentsWithString:[url absoluteString]].queryItems)
|
||||
if ([item.name isEqualToString:@"fullName"]) {
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
NSFetchRequest
|
||||
*fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
|
||||
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", item.value];
|
||||
NSArray *users = [context executeFetchRequest:fetchRequest error:nil];
|
||||
[self migrateFor:users.firstObject];
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
[self migrateFor:nil];
|
||||
return;
|
||||
}
|
||||
} else
|
||||
[UIApp openURL:url];
|
||||
}
|
||||
|
||||
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController {
|
||||
|
||||
if (![PearlEMail canSendMail]) {
|
||||
@@ -401,7 +500,7 @@
|
||||
@"help@masterpassword.app"
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
else if (logs) {
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Feedback" message:
|
||||
@@ -415,7 +514,7 @@
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"No Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[self openFeedbackWithLogs:NO forVC:viewController];
|
||||
}]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
else
|
||||
[self openFeedbackWithLogs:NO forVC:viewController];
|
||||
@@ -461,15 +560,16 @@
|
||||
@"This may be due to corruption. You can either reset Master Password and "
|
||||
@"recreate your user, or E-Mail us your logs and leave your corrupt store as-is for now."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"E-Mail Logs" style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
[self openFeedbackWithLogs:YES forVC:nil];
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Try Again" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[self retryCorruptStore];
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Send Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[self openFeedbackWithLogs:YES forVC:nil];
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[self deleteAndResetStore];
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Ignore" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
}
|
||||
@@ -486,7 +586,7 @@
|
||||
@"Would you like to make all your passwords visible in the export file?\n\n"
|
||||
@"A safe export will include all sites but make their passwords invisible.\n"
|
||||
@"It is great as a backup and remains safe when fallen in the wrong hands."
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[sheet addAction:[UIAlertAction actionWithTitle:@"Safe Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[self showExportRevealPasswords:NO forVC:viewController];
|
||||
}]];
|
||||
@@ -494,10 +594,10 @@
|
||||
[self showExportRevealPasswords:YES forVC:viewController];
|
||||
}]];
|
||||
[sheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:sheet animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:sheet animated:YES completion:nil];
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)showExportRevealPasswords:(BOOL)revealPasswords forVC:(UIViewController *)viewController {
|
||||
@@ -508,93 +608,172 @@
|
||||
@"Close Master Password, go into Settings and add a Mail account."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
[self exportSitesRevealPasswords:revealPasswords askExportPassword:^NSString *(NSString *userName) {
|
||||
return PearlAwait( ^(void (^setResult)(id)) {
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Master Password For:\n%@", userName )
|
||||
message:@"Enter your master password to export the user."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
||||
textField.secureTextEntry = YES;
|
||||
}];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
setResult( alert.textFields.firstObject.text );
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
||||
setResult( nil );
|
||||
}]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
} result:^(NSString *exportedUser, NSError *error) {
|
||||
if (!exportedUser || error) {
|
||||
MPError( error, @"Failed to export mpsites." );
|
||||
PearlMainQueue( ^{
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
NSError *error = nil;
|
||||
NSString *exportedUser = [self exportSitesFor:[self activeUserInContext:context] revealPasswords:revealPasswords askExportPassword:
|
||||
^NSString *(NSString *userName) {
|
||||
return PearlAwait( ^(void (^setResult)(id)) {
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf(
|
||||
@"Master Password For:\n%@", userName )
|
||||
message:@"Enter your master password to export the user."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
||||
textField.secureTextEntry = YES;
|
||||
}];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Export" style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
setResult( alert.textFields.firstObject.text );
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *action) {
|
||||
setResult( nil );
|
||||
}]];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
} error:&error];
|
||||
|
||||
PearlMainQueue( ^{
|
||||
if (error) {
|
||||
MPError( error, @"Failed to export mpsites." );
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Error" message:[error localizedDescription]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
if (!exportedUser)
|
||||
return;
|
||||
|
||||
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
||||
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
||||
NSString *exportFileName = strf( @"%@ (%@).mpsites",
|
||||
[self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
|
||||
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Destination" message:nil
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Send As E-Mail" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
NSString *message;
|
||||
if (revealPasswords)
|
||||
message = strf( @"Export of Master Password sites with passwords included.\n\n"
|
||||
@"REMINDER: Make sure nobody else sees this file! Passwords are visible!\n\n\n"
|
||||
@"--\n"
|
||||
@"%@\n"
|
||||
@"Master Password %@, build %@",
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
else
|
||||
message = strf( @"Backup of Master Password sites.\n\n\n"
|
||||
@"--\n"
|
||||
@"%@\n"
|
||||
@"Master Password %@, build %@",
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
|
||||
[PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
|
||||
attachments:[[PearlEMailAttachment alloc] initWithContent:[exportedUser dataUsingEncoding:NSUTF8StringEncoding]
|
||||
mimeType:@"text/plain"
|
||||
fileName:exportFileName], nil];
|
||||
return;
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Share / Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
|
||||
inDomains:NSUserDomainMask] lastObject];
|
||||
NSURL *exportURL = [[applicationSupportURL
|
||||
URLByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier isDirectory:YES]
|
||||
URLByAppendingPathComponent:exportFileName isDirectory:NO];
|
||||
NSError *writeError = nil;
|
||||
if (![[exportedUser dataUsingEncoding:NSUTF8StringEncoding]
|
||||
writeToURL:exportURL options:NSDataWritingFileProtectionComplete error:&writeError])
|
||||
MPError( writeError, @"Failed to write export data to URL %@.", exportURL );
|
||||
else {
|
||||
self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:exportURL];
|
||||
self.interactionController.UTI = @"com.lyndir.masterpassword.sites";
|
||||
self.interactionController.delegate = self;
|
||||
[self.interactionController presentOpenInMenuFromRect:CGRectZero inView:viewController.view animated:YES];
|
||||
}
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)migrateFor:(MPUserEntity *)user {
|
||||
|
||||
if ([UIApp canOpenURL:[[NSURL alloc] initWithString:@"spectre:"]]) {
|
||||
if (!user) {
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
|
||||
NSArray *users = [context executeFetchRequest:fetchRequest error:nil];
|
||||
if (![users count])
|
||||
return;
|
||||
|
||||
UIAlertController *usersSheet = [UIAlertController alertControllerWithTitle:@"Migrate User"
|
||||
message:@"Choose a user to migrate out to Spectre."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[usersSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
for (MPUserEntity *user_ in users)
|
||||
[usersSheet addAction:[UIAlertAction actionWithTitle:user_.name style:UIAlertActionStyleDefault handler:
|
||||
^(UIAlertAction *action) { [self migrateFor:user_]; }]];
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[self.window.rootViewController presentViewController:usersSheet animated:YES completion:nil];
|
||||
} );
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
||||
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
||||
NSString *exportFileName = strf( @"%@ (%@).mpsites",
|
||||
[self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
|
||||
[MPAppDelegate_Shared managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
NSError *error = nil;
|
||||
NSString *exportedUser = [[MPAppDelegate_Shared get] exportSitesFor:[MPUserEntity existingObjectWithID:user.objectID inContext:context]
|
||||
revealPasswords:NO askExportPassword:^NSString *(NSString *userName) {
|
||||
return PearlAwait( ^(void (^setResult)(id)) {
|
||||
PearlMainQueue( ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Master Password For:\n%@", userName )
|
||||
message:@"Enter your master password to export the user."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
||||
textField.secureTextEntry = YES;
|
||||
}];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Export" style:UIAlertActionStyleDefault handler:
|
||||
^(UIAlertAction *action) { setResult( alert.textFields.firstObject.text ); }]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:
|
||||
^(UIAlertAction *action) { setResult( nil ); }]];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
} );
|
||||
} error:&error];
|
||||
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Destination" message:nil
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Send As E-Mail" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
NSString *message;
|
||||
if (revealPasswords)
|
||||
message = strf( @"Export of Master Password sites with passwords included.\n\n"
|
||||
@"REMINDER: Make sure nobody else sees this file! Passwords are visible!\n\n\n"
|
||||
@"--\n"
|
||||
@"%@\n"
|
||||
@"Master Password %@, build %@",
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
else
|
||||
message = strf( @"Backup of Master Password sites.\n\n\n"
|
||||
@"--\n"
|
||||
@"%@\n"
|
||||
@"Master Password %@, build %@",
|
||||
[self activeUserForMainThread].name,
|
||||
[PearlInfoPlist get].CFBundleShortVersionString,
|
||||
[PearlInfoPlist get].CFBundleVersion );
|
||||
PearlMainQueue( ^{
|
||||
if (error) {
|
||||
MPError( error, @"Failed to export user." );
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Error"
|
||||
message:[error localizedDescription]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
if (!exportedUser)
|
||||
return;
|
||||
|
||||
[PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
|
||||
attachments:[[PearlEMailAttachment alloc] initWithContent:[exportedUser dataUsingEncoding:NSUTF8StringEncoding]
|
||||
mimeType:@"text/plain"
|
||||
fileName:exportFileName], nil];
|
||||
return;
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Share / Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
|
||||
inDomains:NSUserDomainMask] lastObject];
|
||||
NSURL *exportURL = [[applicationSupportURL
|
||||
URLByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier isDirectory:YES]
|
||||
URLByAppendingPathComponent:exportFileName isDirectory:NO];
|
||||
NSError *writeError = nil;
|
||||
if (![[exportedUser dataUsingEncoding:NSUTF8StringEncoding]
|
||||
writeToURL:exportURL options:NSDataWritingFileProtectionComplete error:&writeError])
|
||||
MPError( writeError, @"Failed to write export data to URL %@.", exportURL );
|
||||
else {
|
||||
self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:exportURL];
|
||||
self.interactionController.UTI = @"com.lyndir.masterpassword.sites";
|
||||
self.interactionController.delegate = self;
|
||||
[self.interactionController presentOpenInMenuFromRect:CGRectZero inView:viewController.view animated:YES];
|
||||
}
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
}];
|
||||
NSURLComponents *components = [NSURLComponents new];
|
||||
components.scheme = @"spectre";
|
||||
components.path = @"import";
|
||||
components.queryItems = @[ [[NSURLQueryItem alloc] initWithName:@"data" value:exportedUser] ];
|
||||
[UIApp openURL:components.URL];
|
||||
} );
|
||||
}];
|
||||
}
|
||||
|
||||
else if (self.spectreViewController)
|
||||
[self.window.rootViewController presentViewController:self.spectreViewController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset {
|
||||
@@ -605,7 +784,7 @@
|
||||
@"Changing your master password will cause all your generated passwords to change!\n"
|
||||
@"Changing the master password back to the old one will cause your passwords to revert as well."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[moc performBlockAndWait:^{
|
||||
inf( @"Clearing keyID for user: %@.", user.userID );
|
||||
user.keyID = nil;
|
||||
@@ -618,10 +797,17 @@
|
||||
didReset();
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
||||
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||
} );
|
||||
}
|
||||
|
||||
#pragma mark - SKStoreProductViewControllerDelegate
|
||||
|
||||
- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController {
|
||||
|
||||
[viewController dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - UIDocumentInteractionControllerDelegate
|
||||
|
||||
- (void)documentInteractionController:(UIDocumentInteractionController *)controller didEndSendingToApplication:(NSString *)application {
|
||||
@@ -645,15 +831,14 @@
|
||||
NSArray *countlyFeatures = @[
|
||||
CLYConsentSessions, CLYConsentEvents, CLYConsentUserDetails, CLYConsentCrashReporting, CLYConsentViewTracking, CLYConsentStarRating
|
||||
];
|
||||
if ([[MPConfig get].sendInfo boolValue]) {
|
||||
[Countly.sharedInstance giveConsentForFeatures:countlyFeatures];
|
||||
if ([[MPiOSConfig get].sendInfo boolValue] || ![[MPiOSConfig get].sendInfoDecided boolValue]) {
|
||||
if ([PearlLogger get].printLevel > PearlLogLevelInfo)
|
||||
[PearlLogger get].printLevel = PearlLogLevelInfo;
|
||||
|
||||
[SentrySDK.currentHub getClient].options.enabled = @YES;
|
||||
[SentrySDK configureScope:^(SentryScope *scope) {
|
||||
[scope setExtraValue:[MPConfig get].rememberLogin forKey:@"rememberLogin"];
|
||||
[scope setExtraValue:[MPConfig get].sendInfo forKey:@"sendInfo"];
|
||||
[scope setExtraValue:[MPiOSConfig get].rememberLogin forKey:@"rememberLogin"];
|
||||
[scope setExtraValue:[MPiOSConfig get].sendInfo forKey:@"sendInfo"];
|
||||
[scope setExtraValue:[MPiOSConfig get].helpHidden forKey:@"helpHidden"];
|
||||
[scope setExtraValue:[MPiOSConfig get].showSetup forKey:@"showQuickStart"];
|
||||
[scope setExtraValue:[PearlConfig get].firstRun forKey:@"firstRun"];
|
||||
@@ -671,10 +856,11 @@
|
||||
[scope setExtraValue:@(NO) forKey:@"reviewedVersion"];
|
||||
#endif
|
||||
}];
|
||||
[Countly.sharedInstance giveConsentForFeatures:countlyFeatures];
|
||||
}
|
||||
else {
|
||||
[SentrySDK.currentHub getClient].options.enabled = @NO;
|
||||
[Countly.sharedInstance cancelConsentForFeatures:countlyFeatures];
|
||||
[SentrySDK.currentHub getClient].options.enabled = @NO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
NSStringFromSelector( @selector( siteInfoHidden ) ) : @YES,
|
||||
NSStringFromSelector( @selector( showSetup ) ) : @YES,
|
||||
NSStringFromSelector( @selector( appleID ) ) : @"510296984",
|
||||
NSStringFromSelector( @selector( actionsTipShown ) ) : @(!self.firstRun),
|
||||
NSStringFromSelector( @selector( typeTipShown ) ) : @(!self.firstRun),
|
||||
NSStringFromSelector( @selector( actionsTipShown ) ) : @(![self.firstRun boolValue]),
|
||||
NSStringFromSelector( @selector( typeTipShown ) ) : @(![self.firstRun boolValue]),
|
||||
NSStringFromSelector( @selector( loginNameTipShown ) ): @NO,
|
||||
NSStringFromSelector( @selector( traceMode ) ) : @NO,
|
||||
NSStringFromSelector( @selector( dictationSearch ) ) : @NO,
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
<dict>
|
||||
<key>CFBundleTypeIconFiles</key>
|
||||
<array>
|
||||
<string>Icon-Small</string>
|
||||
<string>Icon-64.png</string>
|
||||
<string>Icon-320.png</string>
|
||||
<string>Icon-Small-40.png</string>
|
||||
<string>Icon-Small-40@2x.png</string>
|
||||
<string>Icon-Small-40@3x.png</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Master Password sites</string>
|
||||
@@ -21,6 +21,7 @@
|
||||
<string>Alternate</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>com.lyndir.masterpassword.json</string>
|
||||
<string>com.lyndir.masterpassword.sites</string>
|
||||
</array>
|
||||
</dict>
|
||||
@@ -37,8 +38,30 @@
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>[auto]</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLIconFile</key>
|
||||
<string>Icon-Small-40@3x</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>com.lyndir.masterpassword</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>masterpassword</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>[auto]</string>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>firefox</string>
|
||||
<string>googlechrome</string>
|
||||
<string>opera-http</string>
|
||||
<string>spectre</string>
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
@@ -103,6 +126,34 @@
|
||||
</array>
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Master Password JSON export</string>
|
||||
<key>UTTypeIconFiles</key>
|
||||
<array>
|
||||
<string>Icon-Small-40.png</string>
|
||||
<string>Icon-Small-40@2x.png</string>
|
||||
<string>Icon-Small-40@3x.png</string>
|
||||
</array>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.lyndir.masterpassword.json</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>https://gitlab.com/MasterPassword/MasterPassword/-/wikis/File-Format</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>mpjson</string>
|
||||
<string>mpsites.json</string>
|
||||
</array>
|
||||
<key>public.mime-type</key>
|
||||
<string>text/plain</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
@@ -112,9 +163,9 @@
|
||||
<string>Master Password sites</string>
|
||||
<key>UTTypeIconFiles</key>
|
||||
<array>
|
||||
<string>Icon-Small.png</string>
|
||||
<string>Icon-64.png</string>
|
||||
<string>Icon-320.png</string>
|
||||
<string>Icon-Small-40.png</string>
|
||||
<string>Icon-Small-40@2x.png</string>
|
||||
<string>Icon-Small-40@3x.png</string>
|
||||
</array>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.lyndir.masterpassword.sites</string>
|
||||
@@ -123,6 +174,7 @@
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>mpsites</string>
|
||||
<string>mpsites.txt</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="Q1S-vU-GGO">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17154" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="Q1S-vU-GGO">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16086"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17124"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<customFonts key="customFonts">
|
||||
@@ -97,10 +97,10 @@
|
||||
</constraints>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0Sa-Vg-EEI" userLabel="Name Backdrop">
|
||||
<rect key="frame" x="43.5" y="263" width="128.5" height="16"/>
|
||||
<rect key="frame" x="43.5" y="263" width="128" height="16"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalCompressionResistancePriority="1000" text="Maarten Billemont" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cLT-s0-4SQ" userLabel="Name Field">
|
||||
<rect key="frame" x="5" y="0.0" width="118.5" height="16"/>
|
||||
<rect key="frame" x="5" y="0.0" width="118" height="16"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-ExtraBold" family="Exo 2.0" pointSize="13"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -164,7 +164,7 @@
|
||||
<outlet property="delegate" destination="S8q-YF-Kt9" id="det-Eh-phM"/>
|
||||
</connections>
|
||||
</collectionView>
|
||||
<button opaque="NO" alpha="0.69999999999999996" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9u7-pu-Wtv" userLabel="Previous Avatar">
|
||||
<button opaque="NO" alpha="0.69999999999999996" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9u7-pu-Wtv" userLabel="Previous Avatar">
|
||||
<rect key="frame" x="0.0" y="439.5" width="44" height="53"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="44" id="Ay6-Jg-c3T"/>
|
||||
@@ -177,7 +177,7 @@
|
||||
<action selector="changeAvatar:" destination="S8q-YF-Kt9" eventType="touchUpInside" id="lNu-mK-3zD"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" alpha="0.69999999999999996" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fUK-gJ-NRE" userLabel="Next Avatar">
|
||||
<button opaque="NO" alpha="0.69999999999999996" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fUK-gJ-NRE" userLabel="Next Avatar">
|
||||
<rect key="frame" x="370" y="439.5" width="44" height="53"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="44" id="oAm-YX-Fx5"/>
|
||||
@@ -276,7 +276,7 @@
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XEP-O3-ayG" userLabel="Footer">
|
||||
<rect key="frame" x="0.0" y="824" width="414" height="72"/>
|
||||
<subviews>
|
||||
<button opaque="NO" alpha="0.5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4md-Gp-SLG">
|
||||
<button opaque="NO" alpha="0.5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4md-Gp-SLG">
|
||||
<rect key="frame" x="20" y="48" width="374" height="24"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="10"/>
|
||||
<state key="normal" title="Thanks, lhunath ➚">
|
||||
@@ -288,14 +288,14 @@
|
||||
</connections>
|
||||
</button>
|
||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="069-Pu-yXe" userLabel="Thanks Tip">
|
||||
<rect key="frame" x="91" y="0.0" width="232.5" height="60"/>
|
||||
<rect key="frame" x="90.5" y="0.0" width="233" height="60"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" translatesAutoresizingMaskIntoConstraints="NO" id="Z8P-ZK-aS0">
|
||||
<rect key="frame" x="0.0" y="0.0" width="232.5" height="60"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="233" height="60"/>
|
||||
<rect key="contentStretch" x="0.15000000000000002" y="0.0" width="0.69999999999999973" height="1"/>
|
||||
</imageView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Why is Master Password free?" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="BLV-3x-Q0z">
|
||||
<rect key="frame" x="20" y="11.5" width="192.5" height="17"/>
|
||||
<rect key="frame" x="20" y="11.5" width="193" height="17"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="14"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -442,21 +442,12 @@
|
||||
<outlet property="nextAvatarButton" destination="fUK-gJ-NRE" id="5qo-lK-rSa"/>
|
||||
<outlet property="preferencesTipContainer" destination="0Um-Ot-hI6" id="Cv8-Bp-ZZs"/>
|
||||
<outlet property="previousAvatarButton" destination="9u7-pu-Wtv" id="Hgv-lN-S1n"/>
|
||||
<outlet property="searchDisplayController" destination="h98-GT-FoS" id="VvS-JO-rqq"/>
|
||||
<outlet property="storeLoadingActivity" destination="VDd-oM-ZOO" id="MJ7-2f-e8n"/>
|
||||
<outlet property="thanksTipContainer" destination="069-Pu-yXe" id="wWf-2X-Ryw"/>
|
||||
<outlet property="userSelectionContainer" destination="rWM-08-aab" id="Yme-hX-8P0"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="8hZ-Tb-wZw" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
<searchDisplayController id="h98-GT-FoS">
|
||||
<connections>
|
||||
<outlet property="delegate" destination="S8q-YF-Kt9" id="hyY-rf-2x2"/>
|
||||
<outlet property="searchContentsController" destination="S8q-YF-Kt9" id="2RA-rs-GhH"/>
|
||||
<outlet property="searchResultsDataSource" destination="S8q-YF-Kt9" id="Cdu-go-UBQ"/>
|
||||
<outlet property="searchResultsDelegate" destination="S8q-YF-Kt9" id="xxe-xE-sFM"/>
|
||||
</connections>
|
||||
</searchDisplayController>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2041" y="226"/>
|
||||
</scene>
|
||||
@@ -472,17 +463,11 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<webView contentMode="scaleToFill" scalesPageToFit="YES" suppressesIncrementalRendering="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3aB-Hk-Fgd">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Sd5-eW-Cx2" id="ePX-qz-XXR"/>
|
||||
</connections>
|
||||
</webView>
|
||||
<navigationBar contentMode="scaleToFill" barStyle="black" translatesAutoresizingMaskIntoConstraints="NO" id="03x-KT-JQN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="90"/>
|
||||
<items>
|
||||
<navigationItem title="masterpassword.app" prompt="Loading" id="Wpf-6b-UJb">
|
||||
<barButtonItem key="leftBarButtonItem" systemItem="action" id="d9P-Hd-rdw"/>
|
||||
<barButtonItem key="rightBarButtonItem" systemItem="done" id="Tbg-c3-qOh">
|
||||
<connections>
|
||||
<action selector="done:" destination="Sd5-eW-Cx2" id="cuN-bV-cwl"/>
|
||||
@@ -494,19 +479,14 @@
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="3aB-Hk-Fgd" firstAttribute="top" secondItem="zXV-QC-CZm" secondAttribute="bottom" id="3Od-Xa-Ssc"/>
|
||||
<constraint firstItem="03x-KT-JQN" firstAttribute="leading" secondItem="2Jz-8H-3nG" secondAttribute="leading" id="BAn-wU-k2A"/>
|
||||
<constraint firstItem="03x-KT-JQN" firstAttribute="top" secondItem="zXV-QC-CZm" secondAttribute="bottom" id="JU6-uj-GA3"/>
|
||||
<constraint firstAttribute="bottom" secondItem="3aB-Hk-Fgd" secondAttribute="bottom" id="S01-AA-E0a"/>
|
||||
<constraint firstAttribute="trailing" secondItem="03x-KT-JQN" secondAttribute="trailing" id="sQs-u3-M3r"/>
|
||||
<constraint firstItem="3aB-Hk-Fgd" firstAttribute="leading" secondItem="2Jz-8H-3nG" secondAttribute="leading" id="w1l-x3-qCi"/>
|
||||
<constraint firstAttribute="trailing" secondItem="3aB-Hk-Fgd" secondAttribute="trailing" id="xdJ-WF-yw0"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="gmy-ym-z4I"/>
|
||||
<connections>
|
||||
<outlet property="webNavigationItem" destination="Wpf-6b-UJb" id="8gM-LU-pHk"/>
|
||||
<outlet property="webView" destination="3aB-Hk-Fgd" id="Mie-rI-l4h"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="hNt-WS-DuE" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
@@ -542,12 +522,23 @@
|
||||
<view key="view" contentMode="scaleToFill" id="c4P-nn-PjR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qca-aL-Un8">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<connections>
|
||||
<segue destination="Ac5-na-hOV" kind="embed" identifier="root" id="x4h-Hl-KXD"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="qca-aL-Un8" firstAttribute="top" secondItem="c4P-nn-PjR" secondAttribute="top" id="7ix-Oo-ELN"/>
|
||||
<constraint firstAttribute="bottom" secondItem="qca-aL-Un8" secondAttribute="bottom" id="JRU-fk-cPG"/>
|
||||
<constraint firstItem="qca-aL-Un8" firstAttribute="leading" secondItem="c4P-nn-PjR" secondAttribute="leading" id="OAO-XC-DQ1"/>
|
||||
<constraint firstAttribute="trailing" secondItem="qca-aL-Un8" secondAttribute="trailing" id="R9n-bd-GVl"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="V6W-ql-3TD"/>
|
||||
<connections>
|
||||
<segue destination="Ac5-na-hOV" kind="custom" identifier="root" customClass="MPRootSegue" id="UKS-gd-oD2"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="fQY-fV-sIe" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
@@ -568,12 +559,25 @@
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" image="background.png" translatesAutoresizingMaskIntoConstraints="NO" id="Lkg-xn-bce" userLabel="Background">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
</imageView>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="91I-wN-JQb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="ignoreTouches" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<segue destination="S8q-YF-Kt9" kind="embed" identifier="users" id="GzD-Zv-DzW"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="91I-wN-JQb" firstAttribute="leading" secondItem="fkJ-D0-yue" secondAttribute="leading" id="E4w-Dw-Vip"/>
|
||||
<constraint firstItem="Lkg-xn-bce" firstAttribute="top" secondItem="fkJ-D0-yue" secondAttribute="top" id="EIy-Cd-0vW"/>
|
||||
<constraint firstItem="91I-wN-JQb" firstAttribute="top" secondItem="fkJ-D0-yue" secondAttribute="top" id="EeB-9X-PEK"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Lkg-xn-bce" secondAttribute="trailing" id="ROW-fK-z92"/>
|
||||
<constraint firstItem="Lkg-xn-bce" firstAttribute="leading" secondItem="fkJ-D0-yue" secondAttribute="leading" id="UH5-Kk-taJ"/>
|
||||
<constraint firstAttribute="bottom" secondItem="91I-wN-JQb" secondAttribute="bottom" id="mxv-9s-jxT"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Lkg-xn-bce" secondAttribute="bottom" id="txR-pf-v3l"/>
|
||||
<constraint firstAttribute="trailing" secondItem="91I-wN-JQb" secondAttribute="trailing" id="uef-ig-RRl"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="MPa-zX-Kaq"/>
|
||||
@@ -581,7 +585,6 @@
|
||||
<connections>
|
||||
<segue destination="osn-5H-SWW" kind="custom" identifier="emergency" customClass="MPOverlaySegue" id="gtX-Cx-AA2"/>
|
||||
<segue destination="nkY-z6-8jd" kind="custom" identifier="passwords" customClass="MPSitesSegue" id="Ozp-YT-Utx"/>
|
||||
<segue destination="S8q-YF-Kt9" kind="custom" identifier="users" customClass="MPRootSegue" id="StK-nr-nps"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="F33-Fe-Tb6" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
@@ -795,7 +798,7 @@
|
||||
<constraint firstAttribute="height" constant="110" id="zBf-EA-iDN"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" alpha="0.69999998807907104" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DzC-Ts-gew" userLabel="Previous Avatar">
|
||||
<button opaque="NO" alpha="0.69999998807907104" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DzC-Ts-gew" userLabel="Previous Avatar">
|
||||
<rect key="frame" x="20" y="148.5" width="44" height="53"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="44" id="1Wu-gS-flK"/>
|
||||
@@ -809,7 +812,7 @@
|
||||
<action selector="previousAvatar:" destination="JFc-sj-awD" eventType="touchUpInside" id="D92-6I-zFd"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" alpha="0.69999998807907104" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yAf-fc-SKl" userLabel="Next Avatar">
|
||||
<button opaque="NO" alpha="0.69999998807907104" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yAf-fc-SKl" userLabel="Next Avatar">
|
||||
<rect key="frame" x="350" y="148.5" width="44" height="53"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="44" id="pEf-Vp-D7s"/>
|
||||
@@ -1036,7 +1039,7 @@ Note that this feature requires you enable the Save Password option and have pur
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Rl7-cr-FHf">
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Rl7-cr-FHf">
|
||||
<rect key="frame" x="20" y="118" width="374" height="27"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
|
||||
<state key="normal" title="Home Page">
|
||||
@@ -1046,7 +1049,7 @@ Note that this feature requires you enable the Save Password option and have pur
|
||||
<action selector="homePageButton:" destination="JFc-sj-awD" eventType="touchUpInside" id="ptD-cv-NMr"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="epW-Rm-9St">
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="epW-Rm-9St">
|
||||
<rect key="frame" x="20" y="153" width="374" height="27"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
|
||||
<state key="normal" title="Understanding Master Password's Security">
|
||||
@@ -1056,7 +1059,7 @@ Note that this feature requires you enable the Save Password option and have pur
|
||||
<action selector="securityButton:" destination="JFc-sj-awD" eventType="touchUpInside" id="Efv-cp-Xfh"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LTN-ch-h8D">
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LTN-ch-h8D">
|
||||
<rect key="frame" x="20" y="188" width="374" height="27"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
|
||||
<state key="normal" title="Get the Master Password source code">
|
||||
@@ -1066,7 +1069,7 @@ Note that this feature requires you enable the Save Password option and have pur
|
||||
<action selector="sourceButton:" destination="JFc-sj-awD" eventType="touchUpInside" id="Y3O-di-CZo"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Z60-lc-Nka">
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Z60-lc-Nka">
|
||||
<rect key="frame" x="20" y="223" width="374" height="27"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="12"/>
|
||||
<state key="normal" title="Send Thanks">
|
||||
@@ -1146,7 +1149,8 @@ Note that this feature requires you enable the Save Password option and have pur
|
||||
<collectionView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" minimumZoomScale="0.0" maximumZoomScale="0.0" keyboardDismissMode="interactive" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="aXw-tn-8Sj" userLabel="Password Collection">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" sectionInsetReference="safeArea" id="Mv1-29-TWx">
|
||||
<edgeInsets key="layoutMargins" top="100" left="0.0" bottom="0.0" right="0.0"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" sectionInsetReference="layoutMargins" id="Mv1-29-TWx">
|
||||
<size key="itemSize" width="355" height="100"/>
|
||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
||||
@@ -1154,7 +1158,7 @@ Note that this feature requires you enable the Save Password option and have pur
|
||||
</collectionViewFlowLayout>
|
||||
<cells>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPSiteCell" id="W2g-yv-V3V" customClass="MPSiteCell">
|
||||
<rect key="frame" x="29.5" y="10" width="355" height="100"/>
|
||||
<rect key="frame" x="29.5" y="110" width="355" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="355" height="100"/>
|
||||
@@ -1671,16 +1675,16 @@ eg. apple.com, rmitchell@twitter.com</string>
|
||||
<view opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3ve-eR-1IW">
|
||||
<rect key="frame" x="0.0" y="740" width="414" height="156"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="PWC-I5-RSl">
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="PWC-I5-RSl">
|
||||
<rect key="frame" x="8" y="8" width="398" height="106"/>
|
||||
<state key="normal" backgroundImage="tip_alert_black"/>
|
||||
<connections>
|
||||
<action selector="upgradeVolto:" destination="nkY-z6-8jd" eventType="touchUpInside" id="8KJ-vm-3D0"/>
|
||||
<action selector="upgradeSpectre:" destination="nkY-z6-8jd" eventType="touchUpInside" id="8KJ-vm-3D0"/>
|
||||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XgC-Ky-oVC">
|
||||
<rect key="frame" x="80" y="15" width="315" height="84"/>
|
||||
<string key="text">The next generation of password security is now called «Volto»:
|
||||
<string key="text">The next generation of password security is now called «Spectre»:
|
||||
Tap to install the upgrade.
|
||||
|
||||
This app is now out of maintenance.</string>
|
||||
@@ -1703,17 +1707,17 @@ This app is now out of maintenance.</string>
|
||||
<view opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="67c-5R-Foa">
|
||||
<rect key="frame" x="0.0" y="740" width="414" height="156"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EZK-er-8ql">
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EZK-er-8ql">
|
||||
<rect key="frame" x="8" y="8" width="398" height="106"/>
|
||||
<state key="normal" backgroundImage="tip_alert_black"/>
|
||||
<connections>
|
||||
<action selector="upgradeVolto:" destination="nkY-z6-8jd" eventType="touchUpInside" id="P4a-tL-9yX"/>
|
||||
<action selector="upgradeSpectre:" destination="nkY-z6-8jd" eventType="touchUpInside" id="P4a-tL-9yX"/>
|
||||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fLB-gA-32p">
|
||||
<rect key="frame" x="80" y="15" width="315" height="84"/>
|
||||
<string key="text">The next generation of password security is now called «Volto»:
|
||||
Tap to copy this user into Volto.
|
||||
<string key="text">The next generation of password security is now called «Spectre»:
|
||||
Tap to copy this user into Spectre.
|
||||
|
||||
This app is now out of maintenance.</string>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="14"/>
|
||||
@@ -1812,8 +1816,8 @@ This app is now out of maintenance.</string>
|
||||
<outlet property="popdownView" destination="XNM-XQ-rMe" id="FaW-4m-Fff"/>
|
||||
<outlet property="searchBar" destination="aGs-1S-aC3" id="rTp-DP-rIz"/>
|
||||
<outlet property="sitesToBottomConstraint" destination="dNt-uf-8BC" id="Ta6-eL-z7w"/>
|
||||
<outlet property="voltoInstallAlert" destination="3ve-eR-1IW" id="Ah5-OX-XhQ"/>
|
||||
<outlet property="voltoMigrateAlert" destination="67c-5R-Foa" id="aTi-fu-opO"/>
|
||||
<outlet property="spectreInstallAlert" destination="3ve-eR-1IW" id="Ah5-OX-XhQ"/>
|
||||
<outlet property="spectreMigrateAlert" destination="67c-5R-Foa" id="aTi-fu-opO"/>
|
||||
<segue destination="z9O-w0-6oR" kind="modal" identifier="guide" id="Ql4-wf-T8u"/>
|
||||
<segue destination="Foa-Er-RBr" kind="custom" identifier="message" customClass="MPOverlaySegue" id="Xne-Sm-HQt"/>
|
||||
</connections>
|
||||
@@ -1842,10 +1846,10 @@ This app is now out of maintenance.</string>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1lc-e7-Qme" userLabel="Emergency Generator">
|
||||
<rect key="frame" x="20" y="240.5" width="374" height="415.5"/>
|
||||
<rect key="frame" x="20" y="240" width="374" height="416"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Emergency Generator" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="4Lh-s0-Dbt">
|
||||
<rect key="frame" x="20" y="20" width="334" height="21"/>
|
||||
<rect key="frame" x="20" y="20" width="334" height="21.5"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -1853,7 +1857,7 @@ This app is now out of maintenance.</string>
|
||||
<size key="shadowOffset" width="0.0" height="1"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Generate your password without logging in. Great for if you're borrowing a friend's device or are having trouble logging in." lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="vHS-3A-Tae">
|
||||
<rect key="frame" x="20" y="49" width="334" height="51.5"/>
|
||||
<rect key="frame" x="20" y="49.5" width="334" height="51.5"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Thin" family="Exo 2.0" pointSize="14"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -1861,7 +1865,7 @@ This app is now out of maintenance.</string>
|
||||
<size key="shadowOffset" width="0.0" height="1"/>
|
||||
</label>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Your Name" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="XAC-Da-lpf" userLabel="User Name">
|
||||
<rect key="frame" x="20" y="108.5" width="334" height="34"/>
|
||||
<rect key="frame" x="20" y="109" width="334" height="34"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="words" keyboardAppearance="alert" returnKeyType="next" enablesReturnKeyAutomatically="YES"/>
|
||||
<connections>
|
||||
@@ -1870,7 +1874,7 @@ This app is now out of maintenance.</string>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Your Master Password" clearsOnBeginEditing="YES" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="J46-0E-no3" userLabel="Master Password">
|
||||
<rect key="frame" x="20" y="150.5" width="334" height="34"/>
|
||||
<rect key="frame" x="20" y="151" width="334" height="34"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardAppearance="alert" returnKeyType="next" enablesReturnKeyAutomatically="YES" secureTextEntry="YES"/>
|
||||
<connections>
|
||||
@@ -1879,7 +1883,7 @@ This app is now out of maintenance.</string>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Site Name" clearsOnBeginEditing="YES" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="56H-xR-09J" userLabel="Site Name">
|
||||
<rect key="frame" x="20" y="192.5" width="334" height="34"/>
|
||||
<rect key="frame" x="20" y="193" width="334" height="34"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL" keyboardAppearance="alert" returnKeyType="done" enablesReturnKeyAutomatically="YES"/>
|
||||
<connections>
|
||||
@@ -1888,7 +1892,7 @@ This app is now out of maintenance.</string>
|
||||
</connections>
|
||||
</textField>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bar" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="e4b-Iv-Pk9" userLabel="Type">
|
||||
<rect key="frame" x="20" y="234.5" width="334" height="32"/>
|
||||
<rect key="frame" x="20" y="235" width="334" height="32"/>
|
||||
<segments>
|
||||
<segment title="Max"/>
|
||||
<segment title="Long"/>
|
||||
@@ -1903,7 +1907,7 @@ This app is now out of maintenance.</string>
|
||||
</connections>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Counter" lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="cAo-K2-E23">
|
||||
<rect key="frame" x="20" y="277.5" width="64" height="21.5"/>
|
||||
<rect key="frame" x="20" y="278.5" width="64" height="21.5"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -1911,13 +1915,13 @@ This app is now out of maintenance.</string>
|
||||
<size key="shadowOffset" width="0.0" height="1"/>
|
||||
</label>
|
||||
<stepper opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" maximumValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="ZPT-EI-yuv" userLabel="Counter">
|
||||
<rect key="frame" x="260" y="273.5" width="94" height="32"/>
|
||||
<rect key="frame" x="260" y="274" width="94" height="32"/>
|
||||
<connections>
|
||||
<action selector="controlChanged:" destination="osn-5H-SWW" eventType="valueChanged" id="eQA-3X-uc9"/>
|
||||
</connections>
|
||||
</stepper>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="1" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="3Cd-XH-Wau">
|
||||
<rect key="frame" x="245" y="278.5" width="7" height="20"/>
|
||||
<rect key="frame" x="245" y="279" width="7" height="20.5"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -1958,10 +1962,10 @@ This app is now out of maintenance.</string>
|
||||
</state>
|
||||
</button>
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" hidesWhenStopped="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="4sN-hm-xio">
|
||||
<rect key="frame" x="168.5" y="352" width="37" height="37"/>
|
||||
<rect key="frame" x="168.5" y="352.5" width="37" height="37"/>
|
||||
</activityIndicatorView>
|
||||
<button opaque="NO" clipsSubviews="YES" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="clip" translatesAutoresizingMaskIntoConstraints="NO" id="bHR-he-dnZ">
|
||||
<rect key="frame" x="20" y="345.5" width="334" height="50"/>
|
||||
<rect key="frame" x="20" y="346" width="334" height="50"/>
|
||||
<gestureRecognizers/>
|
||||
<fontDescription key="fontDescription" name="SourceCodePro-Black" family="Source Code Pro" pointSize="30"/>
|
||||
<state key="normal" title="XapaNuwjFihn6$">
|
||||
@@ -1973,7 +1977,7 @@ This app is now out of maintenance.</string>
|
||||
</connections>
|
||||
</button>
|
||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="beo-cJ-jIn" userLabel="View - Content Tip">
|
||||
<rect key="frame" x="82" y="310.5" width="210" height="60"/>
|
||||
<rect key="frame" x="82" y="311" width="210" height="60"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" translatesAutoresizingMaskIntoConstraints="NO" id="nyL-cO-aPa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="210" height="60"/>
|
||||
@@ -2052,14 +2056,41 @@ This app is now out of maintenance.</string>
|
||||
<constraint firstItem="1lc-e7-Qme" firstAttribute="leading" secondItem="whU-l0-2bU" secondAttribute="leading" constant="20" id="ztv-2f-RAc"/>
|
||||
</constraints>
|
||||
</scrollView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="cbe-hc-9K5">
|
||||
<rect key="frame" x="20" y="820" width="374" height="42"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Anonymous Device Identifier" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="VyZ-qP-VkG">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="18"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Thin" family="Exo 2.0" pointSize="14"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<color key="shadowColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<size key="shadowOffset" width="0.0" height="1"/>
|
||||
</label>
|
||||
<button opaque="NO" alpha="0.5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DVF-Im-H2I">
|
||||
<rect key="frame" x="0.0" y="18" width="374" height="24"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="10"/>
|
||||
<state key="normal" title="0000000000000000000000000000000000000000">
|
||||
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="copyDevice:" destination="osn-5H-SWW" eventType="touchUpInside" id="0dD-IS-Ktn"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="whU-l0-2bU" firstAttribute="height" secondItem="GiS-3g-cDj" secondAttribute="height" multiplier="1:2" id="4oQ-JI-wQv"/>
|
||||
<constraint firstAttribute="width" secondItem="whU-l0-2bU" secondAttribute="width" id="AiQ-LE-3bh"/>
|
||||
<constraint firstItem="IV3-lc-Fnf" firstAttribute="top" secondItem="gRG-Ys-94p" secondAttribute="bottom" id="IMb-wl-Eeb"/>
|
||||
<constraint firstItem="cbe-hc-9K5" firstAttribute="leading" secondItem="GiS-3g-cDj" secondAttribute="leadingMargin" id="KNZ-jb-npt"/>
|
||||
<constraint firstAttribute="trailing" secondItem="gRG-Ys-94p" secondAttribute="trailing" id="Pb1-eY-0FG"/>
|
||||
<constraint firstItem="IV3-lc-Fnf" firstAttribute="top" secondItem="cbe-hc-9K5" secondAttribute="bottom" id="YWv-H4-Ij3"/>
|
||||
<constraint firstItem="gRG-Ys-94p" firstAttribute="top" secondItem="GiS-3g-cDj" secondAttribute="top" id="oyk-Xr-zTZ"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="cbe-hc-9K5" secondAttribute="trailing" id="wss-B8-PT6"/>
|
||||
<constraint firstItem="gRG-Ys-94p" firstAttribute="leading" secondItem="GiS-3g-cDj" secondAttribute="leading" id="zhC-jf-5dY"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
@@ -2074,6 +2105,7 @@ This app is now out of maintenance.</string>
|
||||
<outlet property="containerView" destination="GiS-3g-cDj" id="01o-PU-SNZ"/>
|
||||
<outlet property="counterLabel" destination="3Cd-XH-Wau" id="wv7-jZ-6tX"/>
|
||||
<outlet property="counterStepper" destination="ZPT-EI-yuv" id="w5c-hO-T51"/>
|
||||
<outlet property="deviceButton" destination="DVF-Im-H2I" id="TMU-Vo-bDo"/>
|
||||
<outlet property="dialogView" destination="1lc-e7-Qme" id="JYt-mv-XV2"/>
|
||||
<outlet property="fullNameField" destination="XAC-Da-lpf" id="XCk-0H-IcI"/>
|
||||
<outlet property="masterPasswordField" destination="J46-0E-no3" id="DfH-4n-cop"/>
|
||||
@@ -2115,10 +2147,10 @@ This app is now out of maintenance.</string>
|
||||
</items>
|
||||
</navigationBar>
|
||||
<pageControl opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" numberOfPages="3" translatesAutoresizingMaskIntoConstraints="NO" id="8A2-ly-WTX">
|
||||
<rect key="frame" x="187.5" y="771" width="39" height="37"/>
|
||||
<rect key="frame" x="141" y="778.5" width="132" height="29.5"/>
|
||||
</pageControl>
|
||||
<collectionView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" minimumZoomScale="0.0" maximumZoomScale="0.0" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="i2y-lo-HXR">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="637"/>
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="644.5"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="m8O-kY-22j">
|
||||
<size key="itemSize" width="320" height="458"/>
|
||||
@@ -2128,7 +2160,7 @@ This app is now out of maintenance.</string>
|
||||
</collectionViewFlowLayout>
|
||||
<cells>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPGuideStepCell" id="oGu-pJ-3bQ" customClass="MPGuideStepCell">
|
||||
<rect key="frame" x="0.0" y="89.5" width="320" height="458"/>
|
||||
<rect key="frame" x="0.0" y="93.5" width="320" height="458"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="458"/>
|
||||
@@ -2157,13 +2189,13 @@ This app is now out of maintenance.</string>
|
||||
</connections>
|
||||
</collectionView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="To begin, tap the "New User" icon and add yourself as a user to the application." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ciw-56-nNy" userLabel="Caption">
|
||||
<rect key="frame" x="8" y="689" width="398" height="82"/>
|
||||
<rect key="frame" x="8" y="696.5" width="398" height="82"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="13"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label hidden="YES" opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Oop-Ff-gbz" userLabel="Caption Height Strut">
|
||||
<rect key="frame" x="8" y="689" width="1" height="82"/>
|
||||
<rect key="frame" x="8" y="696.5" width="1" height="82"/>
|
||||
<string key="text" base64-UTF8="YES">
|
||||
CgoKCgoKCgoKCgoKCg
|
||||
</string>
|
||||
@@ -2324,7 +2356,7 @@ Suspendisse potenti. Etiam ut nisi id augue tempor ultrices et sit amet sapien.
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" translatesAutoresizingMaskIntoConstraints="NO" id="OsH-Mq-gpM">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" image="background.png" translatesAutoresizingMaskIntoConstraints="NO" id="OsH-Mq-gpM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||
</imageView>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ol8-3I-X99">
|
||||
@@ -2412,7 +2444,7 @@ However, it means that anyone who finds your device unlocked can do the same.</s
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" translatesAutoresizingMaskIntoConstraints="NO" id="Hrg-vp-M2J">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" image="background.png" translatesAutoresizingMaskIntoConstraints="NO" id="Hrg-vp-M2J">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||
</imageView>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fJc-xU-1xA">
|
||||
@@ -2752,7 +2784,7 @@ Invested: 3.7 work hours</string>
|
||||
<rect key="frame" x="188.5" y="20" width="37" height="37"/>
|
||||
</activityIndicatorView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="751" text="Loading products..." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="12" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="NPg-it-juF">
|
||||
<rect key="frame" x="134.5" y="97" width="145.5" height="25"/>
|
||||
<rect key="frame" x="134" y="97" width="146" height="25"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -2781,7 +2813,7 @@ Invested: 3.7 work hours</string>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" verticalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lQ1-b9-Xp4">
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" verticalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lQ1-b9-Xp4">
|
||||
<rect key="frame" x="20" y="34" width="374" height="27"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
|
||||
<state key="normal" title="Restore Previous Purchases">
|
||||
@@ -2791,7 +2823,7 @@ Invested: 3.7 work hours</string>
|
||||
<action selector="restorePurchases:" destination="pdl-xv-zjX" eventType="touchUpInside" id="Q8M-ud-OHL"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eus-kQ-emn">
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eus-kQ-emn">
|
||||
<rect key="frame" x="8" y="69" width="398" height="27"/>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="12"/>
|
||||
<state key="normal" title="Send Thanks">
|
||||
@@ -3036,7 +3068,7 @@ Invested: 3.7 work hours</string>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="center" image="background.png" translatesAutoresizingMaskIntoConstraints="NO" id="rvb-7K-MHe">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" image="background.png" translatesAutoresizingMaskIntoConstraints="NO" id="rvb-7K-MHe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||
</imageView>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7A7-Yn-F6L">
|
||||
@@ -3269,7 +3301,7 @@ Ut in geometria, prima si dederis, danda sunt omnia. Nonne igitur tibi videntur,
|
||||
</scenes>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="Ql4-wf-T8u"/>
|
||||
<segue reference="GZk-I4-JyH"/>
|
||||
<segue reference="gtb-zE-u9H"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<resources>
|
||||
|
||||
@@ -28,7 +28,7 @@ mpw_expect() {
|
||||
json) file=~/.mpw.d/"$user.mpjson" ;;
|
||||
esac
|
||||
fi
|
||||
[[ $file ]] && (( ! keep )) && rm "$file"
|
||||
[[ -e $file ]] && (( ! keep )) && rm "$file"
|
||||
|
||||
printf '.'
|
||||
local result=$(./mpw -q "${args[@]}") err=$?
|
||||
@@ -79,397 +79,429 @@ mpw_expect() {
|
||||
esac
|
||||
fi
|
||||
|
||||
[[ $file ]] && (( ! keep )) && rm "$file"
|
||||
[[ -e $file ]] && (( ! keep )) && rm "$file"
|
||||
}
|
||||
|
||||
|
||||
# mpw_tests.xml
|
||||
## V3
|
||||
printf "\nV%d, none: " 3
|
||||
mpw_expect 'CefoTiciJuba7@' -Fnone \
|
||||
-u 'test' -M 'test' 'test'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' 'ẗesẗ'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'KovxFipe5:Zatu' -Fnone \
|
||||
-u '⛄' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'ModoLalhRapo6#' -Fnone \
|
||||
-u 'tesẗ' -M '⛄' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'CudmTecuPune7:' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' '⛄'
|
||||
mpw_expect 'yubfalago' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -p 'identification' 'ẗesẗ'
|
||||
mpw_expect 'yubfalago' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a3 -p 'identification' -C '' 'ẗesẗ'
|
||||
mpw_expect 'jip nodwoqude dizo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -p 'recovery' 'ẗesẗ'
|
||||
mpw_expect 'jip nodwoqude dizo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a3 -p 'recovery' -C '' 'ẗesẗ'
|
||||
mpw_expect 'dok sorkicoyu ruya' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a3 -p 'recovery' -C 'quesẗion' 'ẗesẗ'
|
||||
mpw_expect 'j5TJ%G0WWwSMvYb)hr4)' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmax -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'TinRaz2?' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmed -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'jad0IQA3' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tbasic -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Tin0' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tshort -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect '1710' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tpin -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'tinraziqu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'tinr ziq taghuye zuj' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'HidiLonoFopt9&' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c4294967295 -a3 -p 'authentication' 'ẗesẗ'
|
||||
mpw_expect 'CefoTiciJuba7@' -Fnone \
|
||||
-u 'test' -M 'test' 'test'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' 'ẗesẗ'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Tina0#NotaMahu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'KovxFipe5:Zatu' -Fnone \
|
||||
-u '⛄' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'ModoLalhRapo6#' -Fnone \
|
||||
-u 'tesẗ' -M '⛄' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'CudmTecuPune7:' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' '⛄'
|
||||
mpw_expect 'yubfalago' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -p 'identification' -C '' 'ẗesẗ'
|
||||
mpw_expect 'yubfalago' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a3 -p 'identification' -C '' 'ẗesẗ'
|
||||
mpw_expect 'jip nodwoqude dizo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -p 'recovery' -C '' 'ẗesẗ'
|
||||
mpw_expect 'jip nodwoqude dizo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a3 -p 'recovery' -C '' 'ẗesẗ'
|
||||
mpw_expect 'dok sorkicoyu ruya' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a3 -p 'recovery' -C 'quesẗion' 'ẗesẗ'
|
||||
mpw_expect 'j5TJ%G0WWwSMvYb)hr4)' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmax -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'TinRaz2?' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmed -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'jad0IQA3' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tbasic -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Tin0' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tshort -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect '1710' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tpin -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'tinraziqu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'tinr ziq taghuye zuj' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'HidiLonoFopt9&' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c4294967295 -a3 -p 'authentication' -C '' 'ẗesẗ'
|
||||
|
||||
## V2
|
||||
printf "\nV%d, none: " 2
|
||||
mpw_expect 'CefoTiciJuba7@' -Fnone \
|
||||
-u 'test' -M 'test' -tlong -c1 -a2 -p 'authentication' -C '' 'test'
|
||||
mpw_expect "HuczFina3'Qatf" -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'SicrJuwaWaql0#' -Fnone \
|
||||
-u '⛄' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'LokaJayp1@Faba' -Fnone \
|
||||
-u 'tesẗ' -M '⛄' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'DoqaHulu8:Funh' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' '⛄'
|
||||
mpw_expect 'yiyguxoxe' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a2 -p 'identification' -C '' 'ẗesẗ'
|
||||
mpw_expect 'CefoTiciJuba7@' -Fnone \
|
||||
-u 'test' -M 'test' -tlong -c1 -a2 -p 'authentication' -C '' 'test'
|
||||
mpw_expect "HuczFina3'Qatf" -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'SicrJuwaWaql0#' -Fnone \
|
||||
-u '⛄' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'LokaJayp1@Faba' -Fnone \
|
||||
-u 'tesẗ' -M '⛄' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'DoqaHulu8:Funh' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' '⛄'
|
||||
mpw_expect 'yiyguxoxe' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a2 -p 'identification' -C '' 'ẗesẗ'
|
||||
mpw_expect 'vu yelyo bat kujavmu' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a2 -p 'recovery' -C '' 'ẗesẗ'
|
||||
mpw_expect 'ka deqce xad vomacgi' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a2 -p 'recovery' -C 'quesẗion' 'ẗesẗ'
|
||||
mpw_expect 'wRF$LmB@umWGLWeVlB0-' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmax -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'HucZuk0!' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmed -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'wb59VoB5' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tbasic -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Huc9' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tshort -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect '2959' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tpin -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'huczukamo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'huc finmokozi fota' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Mixa1~BulgNijo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c4294967295 -a2 -p 'authentication' 'ẗesẗ'
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a2 -p 'recovery' -C '' 'ẗesẗ'
|
||||
mpw_expect 'ka deqce xad vomacgi' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a2 -p 'recovery' -C 'quesẗion' 'ẗesẗ'
|
||||
mpw_expect 'wRF$LmB@umWGLWeVlB0-' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmax -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'HucZuk0!' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmed -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'wb59VoB5' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tbasic -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Huc9' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tshort -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect '2959' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tpin -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'huczukamo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'huc finmokozi fota' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Mixa1~BulgNijo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c4294967295 -a2 -p 'authentication' -C '' 'ẗesẗ'
|
||||
|
||||
## V1
|
||||
printf "\nV%d, none: " 1
|
||||
mpw_expect 'CefoTiciJuba7@' -Fnone \
|
||||
-u 'test' -M 'test' -tlong -c1 -a1 -p 'authentication' -C '' 'test'
|
||||
mpw_expect 'SuxiHoteCuwe3/' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'CupaTixu8:Hetu' -Fnone \
|
||||
-u '⛄' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'NaqmBanu9+Decs' -Fnone \
|
||||
-u 'tesẗ' -M '⛄' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'XowaDokoGeyu2)' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' '⛄'
|
||||
mpw_expect 'makmabivo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a1 -p 'identification' -C '' 'ẗesẗ'
|
||||
mpw_expect 'CefoTiciJuba7@' -Fnone \
|
||||
-u 'test' -M 'test' -tlong -c1 -a1 -p 'authentication' -C '' 'test'
|
||||
mpw_expect 'SuxiHoteCuwe3/' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'CupaTixu8:Hetu' -Fnone \
|
||||
-u '⛄' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'NaqmBanu9+Decs' -Fnone \
|
||||
-u 'tesẗ' -M '⛄' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'XowaDokoGeyu2)' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' '⛄'
|
||||
mpw_expect 'makmabivo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a1 -p 'identification' -C '' 'ẗesẗ'
|
||||
mpw_expect 'je mutbo buf puhiywo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a1 -p 'recovery' -C '' 'ẗesẗ'
|
||||
mpw_expect 'ne hapfa dax qamayqo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a1 -p 'recovery' -C 'quesẗion' 'ẗesẗ'
|
||||
mpw_expect 'JlZo&eLhqgoxqtJ!NC5/' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmax -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'SuxHot2*' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmed -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Jly28Veh' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tbasic -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Sux2' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tshort -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect '4922' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tpin -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'suxhotito' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'su hotte pav calewxo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Luxn2#JapiXopa' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c4294967295 -a1 -p 'authentication' 'ẗesẗ'
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a1 -p 'recovery' -C '' 'ẗesẗ'
|
||||
mpw_expect 'ne hapfa dax qamayqo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a1 -p 'recovery' -C 'quesẗion' 'ẗesẗ'
|
||||
mpw_expect 'JlZo&eLhqgoxqtJ!NC5/' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmax -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'SuxHot2*' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmed -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Jly28Veh' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tbasic -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Sux2' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tshort -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect '4922' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tpin -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'suxhotito' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'su hotte pav calewxo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Luxn2#JapiXopa' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c4294967295 -a1 -p 'authentication' -C '' 'ẗesẗ'
|
||||
|
||||
## V0
|
||||
printf "\nV%d, none: " 0
|
||||
mpw_expect 'GeqoBigiFubh2!' -Fnone \
|
||||
-u 'test' -M 'test' -tlong -c1 -a0 -p 'authentication' -C '' 'test'
|
||||
mpw_expect 'WumiZobxGuhe8]' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'KuhaXimj8@Zebu' -Fnone \
|
||||
-u '⛄' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'CajtFayv9_Pego' -Fnone \
|
||||
-u 'tesẗ' -M '⛄' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'QohaPokgYevu2!' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' '⛄'
|
||||
mpw_expect 'takxabico' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a0 -p 'identification' -C '' 'ẗesẗ'
|
||||
mpw_expect 'GeqoBigiFubh2!' -Fnone \
|
||||
-u 'test' -M 'test' -tlong -c1 -a0 -p 'authentication' -C '' 'test'
|
||||
mpw_expect 'WumiZobxGuhe8]' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'KuhaXimj8@Zebu' -Fnone \
|
||||
-u '⛄' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'CajtFayv9_Pego' -Fnone \
|
||||
-u 'tesẗ' -M '⛄' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'QohaPokgYevu2!' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' '⛄'
|
||||
mpw_expect 'takxabico' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a0 -p 'identification' -C '' 'ẗesẗ'
|
||||
mpw_expect 'je tuxfo fut huzivlo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a0 -p 'recovery' -C '' 'ẗesẗ'
|
||||
mpw_expect 'ye zahqa lam jatavmo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a0 -p 'recovery' -C 'quesẗion' 'ẗesẗ'
|
||||
mpw_expect 'g4@)4SlA#)cJ#ib)vvH3' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmax -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Wum7_Xix' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmed -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'gAo78ARD' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tbasic -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Wum7' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tshort -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect '9427' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tpin -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'wumdoxixo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'wu doxbe hac kaselqo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Pumy7.JadjQoda' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c4294967295 -a0 -p 'authentication' 'ẗesẗ'
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a0 -p 'recovery' -C '' 'ẗesẗ'
|
||||
mpw_expect 'ye zahqa lam jatavmo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a0 -p 'recovery' -C 'quesẗion' 'ẗesẗ'
|
||||
mpw_expect 'g4@)4SlA#)cJ#ib)vvH3' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmax -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Wum7_Xix' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tmed -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'gAo78ARD' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tbasic -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Wum7' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tshort -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect '9427' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tpin -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'wumdoxixo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tname -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'wu doxbe hac kaselqo' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tphrase -c1 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
mpw_expect 'Pumy7.JadjQoda' -Fnone \
|
||||
-u 'tesẗ' -M 'ẗest' -tlong -c4294967295 -a0 -p 'authentication' -C '' 'ẗesẗ'
|
||||
|
||||
## V3
|
||||
printf "\nV%d, flat: " 3
|
||||
mpw_expect 'IfHuAUUpqpKZDZlNvz8$' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmax -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.max'
|
||||
mpw_expect 'FamiJirk1)Zehc' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.long'
|
||||
mpw_expect 'NofhMusw8+Cebo' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.⛄'
|
||||
mpw_expect 'Necx1$LagaRizu' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tlong -c4294967295 -a3 -p 'authentication' 'ẗesẗ.c+a3pa'
|
||||
mpw_expect 'Poq2)Tey' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmed -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.med'
|
||||
mpw_expect 'Wr07Okx0' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tbasic -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.basic'
|
||||
mpw_expect 'Bug9' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tshort -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.short'
|
||||
mpw_expect '3560' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tpin -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.pin'
|
||||
mpw_expect 'jupxiqepi' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tname -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.name'
|
||||
mpw_expect 'vuh buxtukewo puhe' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tphrase -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.phrase'
|
||||
mpw_expect 'mophabiwe' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tname -c1 -a3 -p 'identification' -C '' 'ẗesẗ.c1a3pi'
|
||||
mpw_expect 'mup wulbezaxa juca' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tphrase -c1 -a3 -p 'recovery' -C '' 'ẗesẗ.c1a3pr'
|
||||
mpw_expect 'IfHuAUUpqpKZDZlNvz8$' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmax -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.max'
|
||||
mpw_expect 'FamiJirk1)Zehc' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.long'
|
||||
mpw_expect 'NofhMusw8+Cebo' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.⛄'
|
||||
mpw_expect 'Necx1$LagaRizu' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -c4294967295 -a3 -p 'authentication' -C '' 'ẗesẗ.c+a3pa'
|
||||
mpw_expect 'Poq2)Tey' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmed -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.med'
|
||||
mpw_expect 'Wr07Okx0' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tbasic -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.basic'
|
||||
mpw_expect 'Bug9' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tshort -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.short'
|
||||
mpw_expect '3560' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tpin -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.pin'
|
||||
mpw_expect 'jupxiqepi' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tname -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.name'
|
||||
mpw_expect 'vuh buxtukewo puhe' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tphrase -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.phrase'
|
||||
mpw_expect 'Cq5$TfH#OHmPS9yREp7)' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmax -c1 -a3 -p 'identification' -C '' 'ẗesẗ.c1a3pi.max'
|
||||
mpw_expect 'mophabiwe' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -c1 -a3 -p 'identification' -C '' 'ẗesẗ.c1a3pi'
|
||||
mpw_expect 'lA^ul!%9&TD%fj6icT1[' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmax -c1 -a3 -p 'recovery' -C '' 'ẗesẗ.c1a3pr.max'
|
||||
mpw_expect 'mup wulbezaxa juca' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -c1 -a3 -p 'recovery' -C '' 'ẗesẗ.c1a3pr'
|
||||
mpw_expect 'molg rux kaczuvi ror' -Fflat -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tphrase -c1 -a3 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a3pr.quesẗion'
|
||||
-u 'tesẗ.v3' -M 'ẗest' -c1 -a3 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a3pr.quesẗion'
|
||||
|
||||
## V2
|
||||
printf "\nV%d, flat: " 2
|
||||
mpw_expect 'i7@0M*DdP4DgD#jJIzyL' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmax -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.max'
|
||||
mpw_expect 'Lifw5]DablSuga' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.long'
|
||||
mpw_expect 'Leja5%RavoZapa' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.⛄'
|
||||
mpw_expect 'NejnGazo8?Seqo' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tlong -c4294967295 -a2 -p 'authentication' 'ẗesẗ.c+a2pa'
|
||||
mpw_expect 'XicSux2&' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmed -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.med'
|
||||
mpw_expect 'uEY50hcZ' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tbasic -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.basic'
|
||||
mpw_expect 'Jif6' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tshort -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.short'
|
||||
mpw_expect '4001' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tpin -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.pin'
|
||||
mpw_expect 'rexmibace' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tname -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.name'
|
||||
mpw_expect 'cez fexlemozo yula' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tphrase -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.phrase'
|
||||
mpw_expect 'camfibeye' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tname -c1 -a2 -p 'identification' -C '' 'ẗesẗ.c1a2pi'
|
||||
mpw_expect 'ye vemcu keq xepewmi' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tphrase -c1 -a2 -p 'recovery' -C '' 'ẗesẗ.c1a2pr'
|
||||
mpw_expect 'i7@0M*DdP4DgD#jJIzyL' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmax -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.max'
|
||||
mpw_expect 'Lifw5]DablSuga' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.long'
|
||||
mpw_expect 'Leja5%RavoZapa' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.⛄'
|
||||
mpw_expect 'NejnGazo8?Seqo' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -c4294967295 -a2 -p 'authentication' -C '' 'ẗesẗ.c+a2pa'
|
||||
mpw_expect 'XicSux2&' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmed -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.med'
|
||||
mpw_expect 'uEY50hcZ' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tbasic -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.basic'
|
||||
mpw_expect 'Jif6' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tshort -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.short'
|
||||
mpw_expect '4001' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tpin -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.pin'
|
||||
mpw_expect 'rexmibace' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tname -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.name'
|
||||
mpw_expect 'cez fexlemozo yula' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tphrase -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.phrase'
|
||||
mpw_expect 'T8+xi4NMd3HUGdV#GW*%' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmax -c1 -a2 -p 'identification' -C '' 'ẗesẗ.c1a2pi.max'
|
||||
mpw_expect 'camfibeye' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -c1 -a2 -p 'identification' -C '' 'ẗesẗ.c1a2pi'
|
||||
mpw_expect 'YLcoWeBwyiBf2*irFq1.' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmax -c1 -a2 -p 'recovery' -C '' 'ẗesẗ.c1a2pr.max'
|
||||
mpw_expect 'ye vemcu keq xepewmi' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -c1 -a2 -p 'recovery' -C '' 'ẗesẗ.c1a2pr'
|
||||
mpw_expect 'yi qazne tid najuvme' -Fflat -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tphrase -c1 -a2 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a2pr.quesẗion'
|
||||
-u 'tesẗ.v2' -M 'ẗest' -c1 -a2 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a2pr.quesẗion'
|
||||
|
||||
## V1
|
||||
printf "\nV%d, flat: " 1
|
||||
mpw_expect 'a3~AiGkHk)Pgjbb)mk6H' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmax -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.max'
|
||||
mpw_expect 'Lojz6?VotaJall' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.long'
|
||||
mpw_expect 'Yoqu7)NiziFito' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.⛄'
|
||||
mpw_expect 'Foha4[TojmXanc' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tlong -c4294967295 -a1 -p 'authentication' 'ẗesẗ.c+a1pa'
|
||||
mpw_expect 'Hiy3*Zag' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmed -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.med'
|
||||
mpw_expect 'UJR7HpG0' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tbasic -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.basic'
|
||||
mpw_expect 'Cij7' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tshort -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.short'
|
||||
mpw_expect '0020' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tpin -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.pin'
|
||||
mpw_expect 'vadxovezu' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tname -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.name'
|
||||
mpw_expect 'sij jihloyenu kizi' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tphrase -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.phrase'
|
||||
mpw_expect 'qipberize' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tname -c1 -a1 -p 'identification' -C '' 'ẗesẗ.c1a1pi'
|
||||
mpw_expect 'sok torxibute reza' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tphrase -c1 -a1 -p 'recovery' -C '' 'ẗesẗ.c1a1pr'
|
||||
mpw_expect 'a3~AiGkHk)Pgjbb)mk6H' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmax -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.max'
|
||||
mpw_expect 'Lojz6?VotaJall' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.long'
|
||||
mpw_expect 'Yoqu7)NiziFito' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.⛄'
|
||||
mpw_expect 'Foha4[TojmXanc' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -c4294967295 -a1 -p 'authentication' -C '' 'ẗesẗ.c+a1pa'
|
||||
mpw_expect 'Hiy3*Zag' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmed -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.med'
|
||||
mpw_expect 'UJR7HpG0' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tbasic -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.basic'
|
||||
mpw_expect 'Cij7' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tshort -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.short'
|
||||
mpw_expect '0020' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tpin -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.pin'
|
||||
mpw_expect 'vadxovezu' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tname -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.name'
|
||||
mpw_expect 'sij jihloyenu kizi' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tphrase -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.phrase'
|
||||
mpw_expect 'z2U9)(uQ78TXqtaus)8.' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmax -c1 -a1 -p 'identification' -C '' 'ẗesẗ.c1a1pi.max'
|
||||
mpw_expect 'qipberize' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -c1 -a1 -p 'identification' -C '' 'ẗesẗ.c1a1pi'
|
||||
mpw_expect 'QMciaKyi1&I*g%tHz99,' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmax -c1 -a1 -p 'recovery' -C '' 'ẗesẗ.c1a1pr.max'
|
||||
mpw_expect 'sok torxibute reza' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -c1 -a1 -p 'recovery' -C '' 'ẗesẗ.c1a1pr'
|
||||
mpw_expect 'xacp qaw qutbece gan' -Fflat -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tphrase -c1 -a1 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a1pr.quesẗion'
|
||||
-u 'tesẗ.v1' -M 'ẗest' -c1 -a1 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a1pr.quesẗion'
|
||||
|
||||
## V0
|
||||
printf "\nV%d, flat: " 0
|
||||
mpw_expect 'b5@ww@Jmb4cAioRbivb)' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmax -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.max'
|
||||
mpw_expect 'ZuceHazwLojz8!' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.long'
|
||||
mpw_expect 'Boxj2!YabePodp' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.⛄'
|
||||
mpw_expect 'PeblLuqc6]Cala' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tlong -c4294967295 -a0 -p 'authentication' 'ẗesẗ.c+a0pa'
|
||||
mpw_expect 'XelQac0@' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmed -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.med'
|
||||
mpw_expect 'qS07SRc8' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tbasic -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.basic'
|
||||
mpw_expect 'Fih8' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tshort -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.short'
|
||||
mpw_expect '6121' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tpin -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.pin'
|
||||
mpw_expect 'rivfutipe' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tname -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.name'
|
||||
mpw_expect 'xir qebdohogo buno' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tphrase -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.phrase'
|
||||
mpw_expect 'ragcoxudo' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tname -c1 -a0 -p 'identification' -C '' 'ẗesẗ.c1a0pi'
|
||||
mpw_expect 'kokl hov lowmaya xaf' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tphrase -c1 -a0 -p 'recovery' -C '' 'ẗesẗ.c1a0pr'
|
||||
mpw_expect 'wi zanmu nug zuwidwe' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tphrase -c1 -a0 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a0pr.quesẗion'
|
||||
mpw_expect 'b5@ww@Jmb4cAioRbivb)' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmax -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.max'
|
||||
mpw_expect 'ZuceHazwLojz8!' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.long'
|
||||
mpw_expect 'Boxj2!YabePodp' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.⛄'
|
||||
mpw_expect 'PeblLuqc6]Cala' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -c4294967295 -a0 -p 'authentication' -C '' 'ẗesẗ.c+a0pa'
|
||||
mpw_expect 'XelQac0@' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmed -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.med'
|
||||
mpw_expect 'qS07SRc8' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tbasic -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.basic'
|
||||
mpw_expect 'Fih8' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tshort -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.short'
|
||||
mpw_expect '6121' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tpin -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.pin'
|
||||
mpw_expect 'rivfutipe' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tname -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.name'
|
||||
mpw_expect 'xir qebdohogo buno' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tphrase -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.phrase'
|
||||
mpw_expect "RoAm3bJSvo@#loHSRA6\'" -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmax -c1 -a0 -p 'identification' -C '' 'ẗesẗ.c1a0pi.max'
|
||||
mpw_expect 'ragcoxudo' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -c1 -a0 -p 'identification' -C '' 'ẗesẗ.c1a0pi'
|
||||
mpw_expect 'm8]SiJHiAS@H@Rbw))34' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmax -c1 -a0 -p 'recovery' -C '' 'ẗesẗ.c1a0pr.max'
|
||||
mpw_expect 'kokl hov lowmaya xaf' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -c1 -a0 -p 'recovery' -C '' 'ẗesẗ.c1a0pr'
|
||||
mpw_expect 'wi zanmu nug zuwidwe' -Fflat -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -c1 -a0 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a0pr.quesẗion'
|
||||
|
||||
|
||||
## V3
|
||||
printf "\nV%d, json: " 3
|
||||
mpw_expect 'IfHuAUUpqpKZDZlNvz8$' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmax -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.max'
|
||||
mpw_expect 'FamiJirk1)Zehc' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.long'
|
||||
mpw_expect 'NofhMusw8+Cebo' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.⛄'
|
||||
mpw_expect 'Necx1$LagaRizu' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tlong -c4294967295 -a3 -p 'authentication' 'ẗesẗ.c+a3pa'
|
||||
mpw_expect 'Poq2)Tey' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmed -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.med'
|
||||
mpw_expect 'Wr07Okx0' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tbasic -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.basic'
|
||||
mpw_expect 'Bug9' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tshort -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.short'
|
||||
mpw_expect '3560' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tpin -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.pin'
|
||||
mpw_expect 'jupxiqepi' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tname -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.name'
|
||||
mpw_expect 'vuh buxtukewo puhe' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tphrase -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.phrase'
|
||||
mpw_expect 'mophabiwe' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tname -c1 -a3 -p 'identification' -C '' 'ẗesẗ.c1a3pi'
|
||||
mpw_expect 'mup wulbezaxa juca' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tphrase -c1 -a3 -p 'recovery' -C '' 'ẗesẗ.c1a3pr'
|
||||
mpw_expect 'IfHuAUUpqpKZDZlNvz8$' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmax -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.max'
|
||||
mpw_expect 'FamiJirk1)Zehc' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.long'
|
||||
mpw_expect 'NofhMusw8+Cebo' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tlong -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.⛄'
|
||||
mpw_expect 'Necx1$LagaRizu' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -c4294967295 -a3 -p 'authentication' -C '' 'ẗesẗ.c+a3pa'
|
||||
mpw_expect 'Poq2)Tey' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmed -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.med'
|
||||
mpw_expect 'Wr07Okx0' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tbasic -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.basic'
|
||||
mpw_expect 'Bug9' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tshort -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.short'
|
||||
mpw_expect '3560' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tpin -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.pin'
|
||||
mpw_expect 'jupxiqepi' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tname -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.name'
|
||||
mpw_expect 'vuh buxtukewo puhe' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tphrase -c1 -a3 -p 'authentication' -C '' 'ẗesẗ.c1a3pa.phrase'
|
||||
mpw_expect 'Cq5$TfH#OHmPS9yREp7)' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmax -c1 -a3 -p 'identification' -C '' 'ẗesẗ.c1a3pi.max'
|
||||
mpw_expect 'mophabiwe' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -c1 -a3 -p 'identification' -C '' 'ẗesẗ.c1a3pi'
|
||||
mpw_expect 'lA^ul!%9&TD%fj6icT1[' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tmax -c1 -a3 -p 'recovery' -C '' 'ẗesẗ.c1a3pr.max'
|
||||
mpw_expect 'mup wulbezaxa juca' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -c1 -a3 -p 'recovery' -C '' 'ẗesẗ.c1a3pr'
|
||||
mpw_expect 'molg rux kaczuvi ror' -Fjson -R0 \
|
||||
-u 'tesẗ.v3' -M 'ẗest' -tphrase -c1 -a3 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a3pr.quesẗion'
|
||||
-u 'tesẗ.v3' -M 'ẗest' -c1 -a3 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a3pr.quesẗion'
|
||||
|
||||
## V2
|
||||
printf "\nV%d, json: " 2
|
||||
mpw_expect 'i7@0M*DdP4DgD#jJIzyL' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmax -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.max'
|
||||
mpw_expect 'Lifw5]DablSuga' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.long'
|
||||
mpw_expect 'Leja5%RavoZapa' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.⛄'
|
||||
mpw_expect 'NejnGazo8?Seqo' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tlong -c4294967295 -a2 -p 'authentication' 'ẗesẗ.c+a2pa'
|
||||
mpw_expect 'XicSux2&' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmed -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.med'
|
||||
mpw_expect 'uEY50hcZ' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tbasic -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.basic'
|
||||
mpw_expect 'Jif6' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tshort -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.short'
|
||||
mpw_expect '4001' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tpin -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.pin'
|
||||
mpw_expect 'rexmibace' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tname -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.name'
|
||||
mpw_expect 'cez fexlemozo yula' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tphrase -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.phrase'
|
||||
mpw_expect 'camfibeye' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tname -c1 -a2 -p 'identification' -C '' 'ẗesẗ.c1a2pi'
|
||||
mpw_expect 'ye vemcu keq xepewmi' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tphrase -c1 -a2 -p 'recovery' -C '' 'ẗesẗ.c1a2pr'
|
||||
mpw_expect 'i7@0M*DdP4DgD#jJIzyL' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmax -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.max'
|
||||
mpw_expect 'Lifw5]DablSuga' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.long'
|
||||
mpw_expect 'Leja5%RavoZapa' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tlong -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.⛄'
|
||||
mpw_expect 'NejnGazo8?Seqo' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -c4294967295 -a2 -p 'authentication' -C '' 'ẗesẗ.c+a2pa'
|
||||
mpw_expect 'XicSux2&' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmed -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.med'
|
||||
mpw_expect 'uEY50hcZ' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tbasic -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.basic'
|
||||
mpw_expect 'Jif6' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tshort -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.short'
|
||||
mpw_expect '4001' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tpin -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.pin'
|
||||
mpw_expect 'rexmibace' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tname -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.name'
|
||||
mpw_expect 'cez fexlemozo yula' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tphrase -c1 -a2 -p 'authentication' -C '' 'ẗesẗ.c1a2pa.phrase'
|
||||
mpw_expect 'T8+xi4NMd3HUGdV#GW*%' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmax -c1 -a2 -p 'identification' -C '' 'ẗesẗ.c1a2pi.max'
|
||||
mpw_expect 'camfibeye' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -c1 -a2 -p 'identification' -C '' 'ẗesẗ.c1a2pi'
|
||||
mpw_expect 'YLcoWeBwyiBf2*irFq1.' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tmax -c1 -a2 -p 'recovery' -C '' 'ẗesẗ.c1a2pr.max'
|
||||
mpw_expect 'ye vemcu keq xepewmi' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -c1 -a2 -p 'recovery' -C '' 'ẗesẗ.c1a2pr'
|
||||
mpw_expect 'yi qazne tid najuvme' -Fjson -R0 \
|
||||
-u 'tesẗ.v2' -M 'ẗest' -tphrase -c1 -a2 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a2pr.quesẗion'
|
||||
-u 'tesẗ.v2' -M 'ẗest' -c1 -a2 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a2pr.quesẗion'
|
||||
|
||||
## V1
|
||||
printf "\nV%d, json: " 1
|
||||
mpw_expect 'a3~AiGkHk)Pgjbb)mk6H' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmax -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.max'
|
||||
mpw_expect 'Lojz6?VotaJall' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.long'
|
||||
mpw_expect 'Yoqu7)NiziFito' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.⛄'
|
||||
mpw_expect 'Foha4[TojmXanc' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tlong -c4294967295 -a1 -p 'authentication' 'ẗesẗ.c+a1pa'
|
||||
mpw_expect 'Hiy3*Zag' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmed -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.med'
|
||||
mpw_expect 'UJR7HpG0' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tbasic -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.basic'
|
||||
mpw_expect 'Cij7' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tshort -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.short'
|
||||
mpw_expect '0020' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tpin -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.pin'
|
||||
mpw_expect 'vadxovezu' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tname -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.name'
|
||||
mpw_expect 'sij jihloyenu kizi' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tphrase -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.phrase'
|
||||
mpw_expect 'qipberize' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tname -c1 -a1 -p 'identification' -C '' 'ẗesẗ.c1a1pi'
|
||||
mpw_expect 'sok torxibute reza' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tphrase -c1 -a1 -p 'recovery' -C '' 'ẗesẗ.c1a1pr'
|
||||
mpw_expect 'a3~AiGkHk)Pgjbb)mk6H' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmax -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.max'
|
||||
mpw_expect 'Lojz6?VotaJall' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.long'
|
||||
mpw_expect 'Yoqu7)NiziFito' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tlong -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.⛄'
|
||||
mpw_expect 'Foha4[TojmXanc' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -c4294967295 -a1 -p 'authentication' -C '' 'ẗesẗ.c+a1pa'
|
||||
mpw_expect 'Hiy3*Zag' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmed -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.med'
|
||||
mpw_expect 'UJR7HpG0' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tbasic -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.basic'
|
||||
mpw_expect 'Cij7' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tshort -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.short'
|
||||
mpw_expect '0020' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tpin -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.pin'
|
||||
mpw_expect 'vadxovezu' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tname -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.name'
|
||||
mpw_expect 'sij jihloyenu kizi' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tphrase -c1 -a1 -p 'authentication' -C '' 'ẗesẗ.c1a1pa.phrase'
|
||||
mpw_expect 'z2U9)(uQ78TXqtaus)8.' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmax -c1 -a1 -p 'identification' -C '' 'ẗesẗ.c1a1pi.max'
|
||||
mpw_expect 'qipberize' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -c1 -a1 -p 'identification' -C '' 'ẗesẗ.c1a1pi'
|
||||
mpw_expect 'QMciaKyi1&I*g%tHz99,' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tmax -c1 -a1 -p 'recovery' -C '' 'ẗesẗ.c1a1pr.max'
|
||||
mpw_expect 'sok torxibute reza' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -c1 -a1 -p 'recovery' -C '' 'ẗesẗ.c1a1pr'
|
||||
mpw_expect 'xacp qaw qutbece gan' -Fjson -R0 \
|
||||
-u 'tesẗ.v1' -M 'ẗest' -tphrase -c1 -a1 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a1pr.quesẗion'
|
||||
-u 'tesẗ.v1' -M 'ẗest' -c1 -a1 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a1pr.quesẗion'
|
||||
|
||||
## V0
|
||||
printf "\nV%d, json: " 0
|
||||
mpw_expect 'b5@ww@Jmb4cAioRbivb)' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmax -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.max'
|
||||
mpw_expect 'ZuceHazwLojz8!' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.long'
|
||||
mpw_expect 'Boxj2!YabePodp' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.⛄'
|
||||
mpw_expect 'PeblLuqc6]Cala' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tlong -c4294967295 -a0 -p 'authentication' 'ẗesẗ.c+a0pa'
|
||||
mpw_expect 'XelQac0@' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmed -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.med'
|
||||
mpw_expect 'qS07SRc8' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tbasic -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.basic'
|
||||
mpw_expect 'Fih8' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tshort -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.short'
|
||||
mpw_expect '6121' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tpin -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.pin'
|
||||
mpw_expect 'rivfutipe' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tname -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.name'
|
||||
mpw_expect 'xir qebdohogo buno' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tphrase -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.phrase'
|
||||
mpw_expect 'ragcoxudo' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tname -c1 -a0 -p 'identification' -C '' 'ẗesẗ.c1a0pi'
|
||||
mpw_expect 'kokl hov lowmaya xaf' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tphrase -c1 -a0 -p 'recovery' -C '' 'ẗesẗ.c1a0pr'
|
||||
mpw_expect 'wi zanmu nug zuwidwe' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tphrase -c1 -a0 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a0pr.quesẗion'
|
||||
mpw_expect 'b5@ww@Jmb4cAioRbivb)' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmax -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.max'
|
||||
mpw_expect 'ZuceHazwLojz8!' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.long'
|
||||
mpw_expect 'Boxj2!YabePodp' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tlong -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.⛄'
|
||||
mpw_expect 'PeblLuqc6]Cala' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -c4294967295 -a0 -p 'authentication' -C '' 'ẗesẗ.c+a0pa'
|
||||
mpw_expect 'XelQac0@' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmed -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.med'
|
||||
mpw_expect 'qS07SRc8' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tbasic -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.basic'
|
||||
mpw_expect 'Fih8' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tshort -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.short'
|
||||
mpw_expect '6121' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tpin -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.pin'
|
||||
mpw_expect 'rivfutipe' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tname -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.name'
|
||||
mpw_expect 'xir qebdohogo buno' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tphrase -c1 -a0 -p 'authentication' -C '' 'ẗesẗ.c1a0pa.phrase'
|
||||
mpw_expect "RoAm3bJSvo@#loHSRA6\'" -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmax -c1 -a0 -p 'identification' -C '' 'ẗesẗ.c1a0pi.max'
|
||||
mpw_expect 'ragcoxudo' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -c1 -a0 -p 'identification' -C '' 'ẗesẗ.c1a0pi'
|
||||
mpw_expect 'm8]SiJHiAS@H@Rbw))34' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -tmax -c1 -a0 -p 'recovery' -C '' 'ẗesẗ.c1a0pr.max'
|
||||
mpw_expect 'kokl hov lowmaya xaf' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -c1 -a0 -p 'recovery' -C '' 'ẗesẗ.c1a0pr'
|
||||
mpw_expect 'wi zanmu nug zuwidwe' -Fjson -R0 \
|
||||
-u 'tesẗ.v0' -M 'ẗest' -c1 -a0 -p 'recovery' -C 'quesẗion' 'ẗesẗ.c1a0pr.quesẗion'
|
||||
|
||||
|
||||
# Finish
|
||||
|
||||
@@ -166,6 +166,11 @@ const char *mpw_site_crypted_password_v0(
|
||||
err( "Missing encrypted state." );
|
||||
return NULL;
|
||||
}
|
||||
if (strlen( cipherText ) % 4 != 0) {
|
||||
wrn( "Malformed encrypted state, not base64." );
|
||||
// This can happen if state was stored in a non-encrypted form, eg. login in old mpsites.
|
||||
return strdup( cipherText );
|
||||
}
|
||||
|
||||
// Base64-decode
|
||||
uint8_t *cipherBuf = calloc( 1, mpw_base64_decode_max( cipherText ) );
|
||||
@@ -184,8 +189,10 @@ const char *mpw_site_crypted_password_v0(
|
||||
mpw_free( &plainBytes, bufSize );
|
||||
if (!plainText)
|
||||
err( "AES decryption error: %s", strerror( errno ) );
|
||||
else if (!mpw_utf8_strchars( plainText ))
|
||||
wrn( "decrypted -> plainText: %zu bytes = illegal UTF-8 = %s", strlen( plainText ), mpw_hex( plainText, bufSize ) );
|
||||
else
|
||||
trc( "decrypted -> plainText: %zu bytes = %s = %s", strlen( plainText ), plainText, mpw_hex( plainText, strlen( plainText ) ) );
|
||||
trc( "decrypted -> plainText: %zu bytes = %s = %s", strlen( plainText ), plainText, mpw_hex( plainText, bufSize ) );
|
||||
|
||||
return plainText;
|
||||
}
|
||||
|
||||
@@ -176,6 +176,21 @@ MPMarshalledFile *mpw_marshal_file(
|
||||
return file;
|
||||
}
|
||||
|
||||
MPMarshalledFile *mpw_marshal_error(
|
||||
MPMarshalledFile *file, MPMarshalErrorType type, const char *format, ...) {
|
||||
|
||||
file = mpw_marshal_file( file, NULL, NULL );
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
file->error = (MPMarshalError){ type, mpw_strdup( mpw_vstr( format, args ) ) };
|
||||
va_end( args );
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
void mpw_marshal_info_free(
|
||||
MPMarshalledInfo **info) {
|
||||
|
||||
@@ -228,6 +243,7 @@ void mpw_marshal_file_free(
|
||||
|
||||
mpw_marshal_info_free( &(*file)->info );
|
||||
mpw_marshal_data_free( &(*file)->data );
|
||||
mpw_free_string( &(*file)->error.message );
|
||||
mpw_free( file, sizeof( MPMarshalledFile ) );
|
||||
}
|
||||
|
||||
@@ -539,7 +555,7 @@ static const char *mpw_marshal_write_flat(
|
||||
|
||||
const MPMarshalledData *data = file->data;
|
||||
if (!data) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorMissing, "Missing data." };
|
||||
mpw_marshal_error( file, MPMarshalErrorMissing, "Missing data." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -583,9 +599,9 @@ static const char *mpw_marshal_write_flat(
|
||||
}
|
||||
|
||||
if (!out)
|
||||
file->error = (MPMarshalError){ MPMarshalErrorFormat, "Couldn't encode JSON." };
|
||||
mpw_marshal_error( file, MPMarshalErrorFormat, "Couldn't encode JSON." );
|
||||
else
|
||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
||||
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -637,7 +653,7 @@ static const char *mpw_marshal_write_json(
|
||||
// Section: "export"
|
||||
json_object *json_file = mpw_get_json_data( file->data );
|
||||
if (!json_file) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorFormat, "Couldn't serialize export data." };
|
||||
mpw_marshal_error( file, MPMarshalErrorFormat, "Couldn't serialize export data." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -650,9 +666,9 @@ static const char *mpw_marshal_write_json(
|
||||
json_object_put( json_file );
|
||||
|
||||
if (!out)
|
||||
file->error = (MPMarshalError){ MPMarshalErrorFormat, "Couldn't encode JSON." };
|
||||
mpw_marshal_error( file, MPMarshalErrorFormat, "Couldn't encode JSON." );
|
||||
else
|
||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
||||
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -698,17 +714,17 @@ const char *mpw_marshal_write(
|
||||
if (!file_)
|
||||
mpw_marshal_file_free( &file );
|
||||
else
|
||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate data." };
|
||||
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't allocate data." );
|
||||
return NULL;
|
||||
}
|
||||
if (!user->fullName || !strlen( user->fullName )) {
|
||||
if (!file_)
|
||||
mpw_marshal_file_free( &file );
|
||||
else
|
||||
file->error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
|
||||
mpw_marshal_error( file, MPMarshalErrorMissing, "Missing full name." );
|
||||
return NULL;
|
||||
}
|
||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
||||
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||
|
||||
MPMasterKey masterKey = NULL;
|
||||
if (user->masterKeyProvider)
|
||||
@@ -749,7 +765,7 @@ const char *mpw_marshal_write(
|
||||
if (!file_)
|
||||
mpw_marshal_file_free( &file );
|
||||
else
|
||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't derive master key." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -807,7 +823,7 @@ const char *mpw_marshal_write(
|
||||
const char *out = NULL;
|
||||
switch (outFormat) {
|
||||
case MPMarshalFormatNone:
|
||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
||||
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||
break;
|
||||
case MPMarshalFormatFlat:
|
||||
out = mpw_marshal_write_flat( file );
|
||||
@@ -818,7 +834,7 @@ const char *mpw_marshal_write(
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
file->error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorFormat, "Unsupported output format: %u", outFormat );
|
||||
break;
|
||||
}
|
||||
if (out && file->error.type == MPMarshalSuccess)
|
||||
@@ -839,7 +855,7 @@ static void mpw_marshal_read_flat(
|
||||
|
||||
mpw_marshal_file( file, NULL, mpw_marshal_data_new() );
|
||||
if (!file->data) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate data." };
|
||||
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't allocate data." );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -891,10 +907,7 @@ static void mpw_marshal_read_flat(
|
||||
const char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" );
|
||||
const char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
||||
if (!headerName || !headerValue) {
|
||||
file->error = (MPMarshalError){
|
||||
MPMarshalErrorStructure,
|
||||
mpw_str( "Invalid header: %s", mpw_strndup( line, (size_t)(endOfLine - line) ) )
|
||||
};
|
||||
mpw_marshal_error( file, MPMarshalErrorStructure, "Invalid header: %s", mpw_strndup( line, (size_t)(endOfLine - line) ) );
|
||||
mpw_free_strings( &headerName, &headerValue, NULL );
|
||||
continue;
|
||||
}
|
||||
@@ -908,7 +921,7 @@ static void mpw_marshal_read_flat(
|
||||
if (mpw_strcasecmp( headerName, "Algorithm" ) == OK) {
|
||||
unsigned long value = strtoul( headerValue, NULL, 10 );
|
||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast)
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user algorithm version: %s", headerValue ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid user algorithm version: %s", headerValue );
|
||||
else
|
||||
algorithm = (MPAlgorithmVersion)value;
|
||||
}
|
||||
@@ -923,7 +936,7 @@ static void mpw_marshal_read_flat(
|
||||
if (mpw_strcasecmp( headerName, "Default Type" ) == OK) {
|
||||
unsigned long value = strtoul( headerValue, NULL, 10 );
|
||||
if (!mpw_type_short_name( (MPResultType)value ))
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user default type: %s", headerValue ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid user default type: %s", headerValue );
|
||||
else
|
||||
defaultType = (MPResultType)value;
|
||||
}
|
||||
@@ -934,7 +947,7 @@ static void mpw_marshal_read_flat(
|
||||
if (!headerEnded)
|
||||
continue;
|
||||
if (!fullName)
|
||||
file->error = (MPMarshalError){ MPMarshalErrorMissing, "Missing header: Full Name" };
|
||||
mpw_marshal_error( file, MPMarshalErrorMissing, "Missing header: Full Name" );
|
||||
if (positionInLine >= endOfLine)
|
||||
continue;
|
||||
|
||||
@@ -967,13 +980,13 @@ static void mpw_marshal_read_flat(
|
||||
str_counter = mpw_strdup( strtok( NULL, "" ) );
|
||||
mpw_free_string( &typeAndVersionAndCounter );
|
||||
}
|
||||
siteLoginState = mpw_get_token( &positionInLine, endOfLine, "\t\n" ); // TODO: Needs to be encoded if redacted?
|
||||
siteLoginState = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
||||
siteName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
||||
siteResultState = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unexpected import format: %u", format ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorFormat, "Unexpected import format: %u", format );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -981,28 +994,24 @@ static void mpw_marshal_read_flat(
|
||||
if (siteName && str_type && str_counter && str_algorithm && str_uses && str_lastUsed) {
|
||||
MPResultType siteType = (MPResultType)strtoul( str_type, NULL, 10 );
|
||||
if (!mpw_type_short_name( siteType )) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site type: %s: %s", siteName, str_type ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site type: %s: %s", siteName, str_type );
|
||||
continue;
|
||||
}
|
||||
long long int value = strtoll( str_counter, NULL, 10 );
|
||||
if (value < MPCounterValueFirst || value > MPCounterValueLast) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site counter: %s: %s", siteName, str_counter ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site counter: %s: %s", siteName, str_counter );
|
||||
continue;
|
||||
}
|
||||
MPCounterValue siteCounter = (MPCounterValue)value;
|
||||
value = strtoll( str_algorithm, NULL, 0 );
|
||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
||||
file->error = (MPMarshalError){
|
||||
MPMarshalErrorIllegal, mpw_str( "Invalid site algorithm: %s: %s", siteName, str_algorithm )
|
||||
};
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site algorithm: %s: %s", siteName, str_algorithm );
|
||||
continue;
|
||||
}
|
||||
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
|
||||
time_t siteLastUsed = mpw_timegm( str_lastUsed );
|
||||
if (!siteLastUsed) {
|
||||
file->error = (MPMarshalError){
|
||||
MPMarshalErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed )
|
||||
};
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site last used: %s: %s", siteName, str_lastUsed );
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1010,21 +1019,17 @@ static void mpw_marshal_read_flat(
|
||||
mpw_marshal_data_set_num( siteCounter, file->data, "sites", siteName, "counter", NULL );
|
||||
mpw_marshal_data_set_num( siteAlgorithm, file->data, "sites", siteName, "algorithm", NULL );
|
||||
mpw_marshal_data_set_num( siteType, file->data, "sites", siteName, "type", NULL );
|
||||
mpw_marshal_data_set_str( siteResultState && strlen( siteResultState )? siteResultState: NULL, file->data, "sites", siteName,
|
||||
"password", NULL );
|
||||
mpw_marshal_data_set_str( siteResultState, file->data, "sites", siteName, "password", NULL );
|
||||
mpw_marshal_data_set_num( MPResultTypeDefault, file->data, "sites", siteName, "login_type", NULL );
|
||||
mpw_marshal_data_set_str( siteLoginState && strlen( siteLoginState )? siteLoginState: NULL, file->data, "sites", siteName,
|
||||
"login_name", NULL );
|
||||
mpw_marshal_data_set_str( siteLoginState, file->data, "sites", siteName, "login_name", NULL );
|
||||
mpw_marshal_data_set_num( strtol( str_uses, NULL, 10 ), file->data, "sites", siteName, "uses", NULL );
|
||||
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &siteLastUsed ) ))
|
||||
mpw_marshal_data_set_str( dateString, file->data, "sites", siteName, "last_used", NULL );
|
||||
}
|
||||
else {
|
||||
file->error = (MPMarshalError){
|
||||
MPMarshalErrorMissing,
|
||||
mpw_str( "Missing one of: lastUsed=%s, uses=%s, type=%s, version=%s, counter=%s, loginName=%s, siteName=%s",
|
||||
str_lastUsed, str_uses, str_type, str_algorithm, str_counter, siteLoginState, siteName )
|
||||
};
|
||||
mpw_marshal_error( file, MPMarshalErrorMissing,
|
||||
"Missing one of: lastUsed=%s, uses=%s, type=%s, version=%s, counter=%s, loginName=%s, siteName=%s",
|
||||
str_lastUsed, str_uses, str_type, str_algorithm, str_counter, siteLoginState, siteName );
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1044,7 +1049,7 @@ static void mpw_marshal_read_json(
|
||||
|
||||
mpw_marshal_file( file, NULL, mpw_marshal_data_new() );
|
||||
if (!file->data) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate data." };
|
||||
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't allocate data." );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1052,7 +1057,7 @@ static void mpw_marshal_read_json(
|
||||
enum json_tokener_error json_error = json_tokener_success;
|
||||
json_object *json_file = json_tokener_parse_verbose( in, &json_error );
|
||||
if (!json_file || json_error != json_tokener_success) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Couldn't parse JSON: %s", json_tokener_error_desc( json_error ) ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorFormat, "Couldn't parse JSON: %s", json_tokener_error_desc( json_error ) );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1074,9 +1079,9 @@ MPMarshalledFile *mpw_marshal_read(
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
||||
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||
if (!info) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate info." };
|
||||
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't allocate info." );
|
||||
return file;
|
||||
}
|
||||
|
||||
@@ -1090,6 +1095,8 @@ MPMarshalledFile *mpw_marshal_read(
|
||||
info->format = MPMarshalFormatJSON;
|
||||
#if MPW_JSON
|
||||
mpw_marshal_read_json( file, in );
|
||||
#else
|
||||
mpw_marshal_error( file, MPMarshalErrorFormat, "JSON support is not enabled." );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1116,13 +1123,13 @@ MPMarshalledUser *mpw_marshal_auth(
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
||||
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||
if (!file->info) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorMissing, "File wasn't parsed yet." };
|
||||
mpw_marshal_error( file, MPMarshalErrorMissing, "File wasn't parsed yet." );
|
||||
return NULL;
|
||||
}
|
||||
if (!file->data) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorMissing, "No input data." };
|
||||
mpw_marshal_error( file, MPMarshalErrorMissing, "No input data." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1132,43 +1139,43 @@ MPMarshalledUser *mpw_marshal_auth(
|
||||
MPAlgorithmVersion algorithm =
|
||||
mpw_default_n( MPAlgorithmVersionCurrent, mpw_marshal_data_get_num( file->data, "user", "algorithm", NULL ) );
|
||||
if (algorithm < MPAlgorithmVersionFirst || algorithm > MPAlgorithmVersionLast) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user algorithm: %u", algorithm ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid user algorithm: %u", algorithm );
|
||||
return NULL;
|
||||
}
|
||||
unsigned int avatar = mpw_default_n( 0U, mpw_marshal_data_get_num( file->data, "user", "avatar", NULL ) );
|
||||
const char *fullName = mpw_marshal_data_get_str( file->data, "user", "full_name", NULL );
|
||||
if (!fullName || !strlen( fullName )) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorMissing, "Missing value for full name." };
|
||||
mpw_marshal_error( file, MPMarshalErrorMissing, "Missing value for full name." );
|
||||
return NULL;
|
||||
}
|
||||
MPIdenticon identicon = mpw_identicon_encoded( mpw_marshal_data_get_str( file->data, "user", "identicon", NULL ) );
|
||||
const char *keyID = mpw_marshal_data_get_str( file->data, "user", "key_id", NULL );
|
||||
MPResultType defaultType = mpw_default_n( MPResultTypeDefault, mpw_marshal_data_get_num( file->data, "user", "default_type", NULL ) );
|
||||
if (!mpw_type_short_name( defaultType )) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user default type: %u", defaultType ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid user default type: %u", defaultType );
|
||||
return NULL;
|
||||
}
|
||||
const char *str_lastUsed = mpw_marshal_data_get_str( file->data, "user", "last_used", NULL );
|
||||
time_t lastUsed = mpw_timegm( str_lastUsed );
|
||||
if (!lastUsed) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user last used: %s", str_lastUsed ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid user last used: %s", str_lastUsed );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MPMasterKey masterKey = NULL;
|
||||
if (masterKeyProvider && !(masterKey = masterKeyProvider( algorithm, fullName ))) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't derive master key." );
|
||||
return NULL;
|
||||
}
|
||||
if (keyID && masterKey && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Master key doesn't match key ID." };
|
||||
mpw_marshal_error( file, MPMarshalErrorMasterPassword, "Master key doesn't match key ID." );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MPMarshalledUser *user = NULL;
|
||||
if (!(user = mpw_marshal_user( fullName, masterKeyProvider, algorithm ))) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new user." };
|
||||
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't allocate a new user." );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_user_free( &user );
|
||||
return NULL;
|
||||
@@ -1189,21 +1196,21 @@ MPMarshalledUser *mpw_marshal_auth(
|
||||
|
||||
algorithm = mpw_default_n( user->algorithm, mpw_marshal_data_get_num( siteData, "algorithm", NULL ) );
|
||||
if (algorithm < MPAlgorithmVersionFirst || algorithm > MPAlgorithmVersionLast) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site algorithm: %s: %u", siteName, algorithm ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site algorithm: %s: %u", siteName, algorithm );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_user_free( &user );
|
||||
return NULL;
|
||||
}
|
||||
MPCounterValue siteCounter = mpw_default_n( MPCounterValueDefault, mpw_marshal_data_get_num( siteData, "counter", NULL ) );
|
||||
if (siteCounter < MPCounterValueFirst || siteCounter > MPCounterValueLast) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site counter: %s: %d", siteName, siteCounter ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site counter: %s: %d", siteName, siteCounter );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_user_free( &user );
|
||||
return NULL;
|
||||
}
|
||||
MPResultType siteType = mpw_default_n( user->defaultType, mpw_marshal_data_get_num( siteData, "type", NULL ) );
|
||||
if (!mpw_type_short_name( siteType )) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site type: %s: %u", siteName, siteType ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site type: %s: %u", siteName, siteType );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_user_free( &user );
|
||||
return NULL;
|
||||
@@ -1211,7 +1218,7 @@ MPMarshalledUser *mpw_marshal_auth(
|
||||
const char *siteResultState = mpw_marshal_data_get_str( siteData, "password", NULL );
|
||||
MPResultType siteLoginType = mpw_default_n( MPResultTypeTemplateName, mpw_marshal_data_get_num( siteData, "login_type", NULL ) );
|
||||
if (!mpw_type_short_name( siteLoginType )) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site login type: %s: %u", siteName, siteLoginType ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site login type: %s: %u", siteName, siteLoginType );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_user_free( &user );
|
||||
return NULL;
|
||||
@@ -1221,7 +1228,7 @@ MPMarshalledUser *mpw_marshal_auth(
|
||||
str_lastUsed = mpw_marshal_data_get_str( siteData, "last_used", NULL );
|
||||
time_t siteLastUsed = mpw_timegm( str_lastUsed );
|
||||
if (!siteLastUsed) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed ) };
|
||||
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site last used: %s: %s", siteName, str_lastUsed );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_user_free( &user );
|
||||
return NULL;
|
||||
@@ -1231,7 +1238,7 @@ MPMarshalledUser *mpw_marshal_auth(
|
||||
|
||||
MPMarshalledSite *site = mpw_marshal_site( user, siteName, siteType, siteCounter, algorithm );
|
||||
if (!site) {
|
||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new site." };
|
||||
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't allocate a new site." );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_user_free( &user );
|
||||
return NULL;
|
||||
@@ -1245,10 +1252,7 @@ MPMarshalledUser *mpw_marshal_auth(
|
||||
// Clear Text
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
if (!masterKeyProvider || !(masterKey = masterKeyProvider( site->algorithm, user->fullName ))) {
|
||||
file->error = (MPMarshalError){
|
||||
MPMarshalErrorInternal,
|
||||
"Couldn't derive master key."
|
||||
};
|
||||
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't derive master key." );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_user_free( &user );
|
||||
return NULL;
|
||||
|
||||
@@ -223,6 +223,7 @@ const char *mpw_marshal_write(
|
||||
MPMarshalledFile *mpw_marshal_read(
|
||||
MPMarshalledFile *file, const char *in);
|
||||
/** Authenticate as the user identified by the given marshalled file.
|
||||
* @note This object stores a reference to the given key provider.
|
||||
* @return A user object (allocated), or NULL if the file format provides no marshalling or a format error occurred. */
|
||||
MPMarshalledUser *mpw_marshal_auth(
|
||||
MPMarshalledFile *file, const MPMasterKeyProvider masterKeyProvider);
|
||||
@@ -230,22 +231,32 @@ MPMarshalledUser *mpw_marshal_auth(
|
||||
//// Creating.
|
||||
|
||||
/** Create a new user object ready for marshalling.
|
||||
* @note This object stores copies of the strings assigned to it and manages their deallocation internally.
|
||||
* @return A user object (allocated), or NULL if the fullName is missing or the marshalled user couldn't be allocated. */
|
||||
MPMarshalledUser *mpw_marshal_user(
|
||||
const char *fullName, const MPMasterKeyProvider masterKeyProvider, const MPAlgorithmVersion algorithmVersion);
|
||||
/** Create a new site attached to the given user object, ready for marshalling.
|
||||
* @note This object stores copies of the strings assigned to it and manages their deallocation internally.
|
||||
* @return A site object (allocated), or NULL if the siteName is missing or the marshalled site couldn't be allocated. */
|
||||
MPMarshalledSite *mpw_marshal_site(
|
||||
MPMarshalledUser *user,
|
||||
const char *siteName, const MPResultType resultType, const MPCounterValue siteCounter, const MPAlgorithmVersion algorithmVersion);
|
||||
/** Create a new question attached to the given site object, ready for marshalling.
|
||||
* @note This object stores copies of the strings assigned to it and manages their deallocation internally.
|
||||
* @return A question object (allocated), or NULL if the marshalled question couldn't be allocated. */
|
||||
MPMarshalledQuestion *mpw_marshal_question(
|
||||
MPMarshalledSite *site, const char *keyword);
|
||||
/** Create or update a marshal file descriptor.
|
||||
* @param file If NULL, a new file will be allocated. Otherwise, the given file will be updated and the updated file returned.
|
||||
* @param info If NULL, the file's info will be left as-is, otherwise it will be replaced by the given one. The file will manage the info's deallocation.
|
||||
* @param data If NULL, the file's data will be left as-is, otherwise it will be replaced by the given one. The file will manage the data's deallocation.
|
||||
* @return The given file or new (allocated) if file is NULL; or NULL if the user is missing or the file couldn't be allocated. */
|
||||
MPMarshalledFile *mpw_marshal_file(
|
||||
MPMarshalledFile *file, MPMarshalledInfo *info, MPMarshalledData *data);
|
||||
/** Record a marshal error.
|
||||
* @return The given file or new (allocated) if file is NULL; or NULL if the file couldn't be allocated. */
|
||||
MPMarshalledFile *mpw_marshal_error(
|
||||
MPMarshalledFile *file, MPMarshalErrorType type, const char *format, ...);
|
||||
|
||||
//// Disposing.
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#endif
|
||||
|
||||
MP_LIBS_BEGIN
|
||||
#define __STDC_WANT_LIB_EXT1__ 1
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@@ -607,6 +607,9 @@ const uint8_t *mpw_unhex(const char *hex, size_t *length) {
|
||||
|
||||
size_t mpw_utf8_charlen(const char *utf8String) {
|
||||
|
||||
if (!utf8String)
|
||||
return 0;
|
||||
|
||||
// Legal UTF-8 byte sequences: <http://www.unicode.org/unicode/uni2errata/UTF-8_Corrigendum.html>
|
||||
unsigned char utf8Char = (unsigned char)*utf8String;
|
||||
if (utf8Char >= 0x00 && utf8Char <= 0x7F)
|
||||
@@ -624,8 +627,9 @@ size_t mpw_utf8_charlen(const char *utf8String) {
|
||||
size_t mpw_utf8_strchars(const char *utf8String) {
|
||||
|
||||
size_t strchars = 0, charlen;
|
||||
for (char *remaining = (char *)utf8String; (charlen = mpw_utf8_charlen( remaining )); remaining += charlen)
|
||||
++strchars;
|
||||
for (char *remaining = (char *)utf8String; remaining && *remaining; remaining += charlen, ++strchars)
|
||||
if (!(charlen = mpw_utf8_charlen( remaining )))
|
||||
return 0;
|
||||
|
||||
return strchars;
|
||||
}
|
||||
|
||||
@@ -256,9 +256,9 @@ bool mpw_id_buf_equals(MPKeyID id1, MPKeyID id2);
|
||||
|
||||
//// String utilities.
|
||||
|
||||
/** @return The byte length of the UTF-8 character at the start of the given string. */
|
||||
/** @return The byte length of the UTF-8 character at the start of the given string or 0 if it is NULL, empty or not a legal UTF-8 character. */
|
||||
size_t mpw_utf8_charlen(const char *utf8String);
|
||||
/** @return The amount of UTF-8 characters in the given string. */
|
||||
/** @return The amount of UTF-8 characters in the given string or 0 if it is NULL, empty, or contains bytes that are not legal in UTF-8. */
|
||||
size_t mpw_utf8_strchars(const char *utf8String);
|
||||
/** Drop-in for memdup(3).
|
||||
* @return A buffer (allocated, len) with len bytes copied from src or NULL if src is missing or the buffer could not be allocated. */
|
||||
|
||||
@@ -151,7 +151,7 @@ public interface MPAlgorithm {
|
||||
/**
|
||||
* The algorithm iterations.
|
||||
*/
|
||||
enum Version implements MPAlgorithm {
|
||||
enum Version implements MPAlgorithm {
|
||||
|
||||
/**
|
||||
* bugs:
|
||||
@@ -346,7 +346,7 @@ public interface MPAlgorithm {
|
||||
@Nonnull
|
||||
@Override
|
||||
public Version version() {
|
||||
return MPAlgorithm.Version.V0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
||||
@@ -20,7 +20,6 @@ package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumMap;
|
||||
@@ -56,6 +55,7 @@ public class MPMasterKey {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void finalize()
|
||||
throws Throwable {
|
||||
|
||||
|
||||