Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
16f6c3c593 | ||
|
|
63ca2ae83e | ||
|
|
1c3ea3826f | ||
|
|
ff9596aef0 | ||
|
|
b79ed1ca0b | ||
|
|
9a362f13a3 | ||
|
|
11d6660e5a | ||
|
|
62e1563fa6 | ||
|
|
9b8ff7ad0c | ||
|
|
f1fc07cf9e | ||
|
|
00ac788f4f | ||
|
|
514c383310 | ||
|
|
9a3bcd1c6f | ||
|
|
d30d469663 | ||
|
|
b428ee0003 | ||
|
|
f80ffd078b | ||
|
|
7f1a28ffa7 | ||
|
|
8eeba2e005 | ||
|
|
fd6cbaa9a5 | ||
|
|
1651e9ad4a | ||
|
|
02c1e2af46 | ||
|
|
b275286b2d | ||
|
|
7818feaf0b | ||
|
|
3970cd2eac | ||
|
|
21b0053ccb | ||
|
|
6dd8790404 | ||
|
|
508abec94e | ||
|
|
b010432796 | ||
|
|
a91e65f72f |
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
|||||||
# OS-Specific junk.
|
# OS-Specific junk.
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
*~
|
||||||
|
|
||||||
# IntelliJ
|
# IntelliJ
|
||||||
.idea
|
.idea
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ build_project:
|
|||||||
- "( ./lib/bin/build_libsodium-macos clean && ./lib/bin/build_libsodium-macos )"
|
- "( ./lib/bin/build_libsodium-macos clean && ./lib/bin/build_libsodium-macos )"
|
||||||
- "( ./lib/bin/build_libjson-c-macos clean && ./lib/bin/build_libjson-c-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 )"
|
- "( 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 )"
|
- "( ./gradlew --stacktrace --info clean test )"
|
||||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword iOS' -sdk iphonesimulator clean build )"
|
- "( cd platform-darwin && pod install )"
|
||||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword macOS' clean build )"
|
- "( 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:
|
tags:
|
||||||
- brew
|
- brew
|
||||||
- java_9
|
- java
|
||||||
- xcode_9
|
- cocoapods
|
||||||
|
- xcode
|
||||||
|
|||||||
15
.gitmodules
vendored
@@ -1,21 +1,9 @@
|
|||||||
[submodule "External/Pearl"]
|
[submodule "External/Pearl"]
|
||||||
path = platform-darwin/External/Pearl
|
path = platform-darwin/External/Pearl
|
||||||
url = git://github.com/Lyndir/Pearl.git
|
url = git://github.com/Lyndir/Pearl.git
|
||||||
[submodule "External/InAppSettingsKit"]
|
|
||||||
path = platform-darwin/External/InAppSettingsKit
|
|
||||||
url = git://github.com/lhunath/InAppSettingsKit.git
|
|
||||||
[submodule "External/KCOrderedAccessorFix"]
|
|
||||||
path = platform-darwin/External/KCOrderedAccessorFix
|
|
||||||
url = https://github.com/lhunath/KCOrderedAccessorFix.git
|
|
||||||
[submodule "External/AttributedMarkdown"]
|
[submodule "External/AttributedMarkdown"]
|
||||||
path = platform-darwin/External/AttributedMarkdown
|
path = platform-darwin/External/AttributedMarkdown
|
||||||
url = https://github.com/dreamwieber/AttributedMarkdown.git
|
url = https://github.com/dreamwieber/AttributedMarkdown.git
|
||||||
[submodule "External/uicolor-utilities"]
|
|
||||||
path = platform-darwin/External/uicolor-utilities
|
|
||||||
url = git://github.com/lhunath/uicolor-utilities.git
|
|
||||||
[submodule "External/jrswizzle"]
|
|
||||||
path = platform-darwin/External/jrswizzle
|
|
||||||
url = git://github.com/jonmarimba/jrswizzle.git
|
|
||||||
[submodule "MasterPassword/Web/js/mpw-js"]
|
[submodule "MasterPassword/Web/js/mpw-js"]
|
||||||
path = platform-independent/web/js/mpw-js
|
path = platform-independent/web/js/mpw-js
|
||||||
url = https://github.com/tmthrgd/mpw-js.git
|
url = https://github.com/tmthrgd/mpw-js.git
|
||||||
@@ -27,7 +15,6 @@
|
|||||||
url = https://github.com/json-c/json-c.git
|
url = https://github.com/json-c/json-c.git
|
||||||
[submodule "public/site"]
|
[submodule "public/site"]
|
||||||
path = public/site
|
path = public/site
|
||||||
url = https://github.com/Lyndir/MasterPassword.git
|
url = https://gitlab.com/MasterPassword/MasterPassword.git
|
||||||
branch = gh-pages
|
branch = gh-pages
|
||||||
shallow = true
|
shallow = true
|
||||||
update = none
|
|
||||||
|
|||||||
2
platform-darwin/External/AttributedMarkdown
vendored
1
platform-darwin/External/InAppSettingsKit
vendored
2
platform-darwin/External/Pearl
vendored
1
platform-darwin/External/jrswizzle
vendored
1
platform-darwin/External/uicolor-utilities
vendored
@@ -73,6 +73,13 @@
|
|||||||
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
||||||
referenceType = "1">
|
referenceType = "1">
|
||||||
</LocationScenarioReference>
|
</LocationScenarioReference>
|
||||||
|
<EnvironmentVariables>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "TERM"
|
||||||
|
value = "color"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
</EnvironmentVariables>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
|||||||
@@ -10,17 +10,13 @@
|
|||||||
7352E972184B980C428B66A2 /* Pods_MasterPassword_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E9477508F419F29008C7553 /* Pods_MasterPassword_macOS.framework */; };
|
7352E972184B980C428B66A2 /* Pods_MasterPassword_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E9477508F419F29008C7553 /* Pods_MasterPassword_macOS.framework */; };
|
||||||
93D390C676DF52DA7E459F19 /* MPSitesWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D9D0061FF1159998F06 /* MPSitesWindow.m */; };
|
93D390C676DF52DA7E459F19 /* MPSitesWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D9D0061FF1159998F06 /* MPSitesWindow.m */; };
|
||||||
93D391E61DC23E128DA4446C /* NSView+Traversing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393EE88DE554BCCBC1C2D /* NSView+Traversing.h */; };
|
93D391E61DC23E128DA4446C /* NSView+Traversing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393EE88DE554BCCBC1C2D /* NSView+Traversing.h */; };
|
||||||
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */; };
|
|
||||||
93D393A1646430FAAC73E7FE /* MPMacApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F83DD151985F2C7345A /* MPMacApplication.m */; };
|
93D393A1646430FAAC73E7FE /* MPMacApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F83DD151985F2C7345A /* MPMacApplication.m */; };
|
||||||
93D394C4254EEB45FB335AFB /* MPSitesTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39423D7BF4FD31FE6D27C /* MPSitesTableView.m */; };
|
93D394C4254EEB45FB335AFB /* MPSitesTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39423D7BF4FD31FE6D27C /* MPSitesTableView.m */; };
|
||||||
93D395E4830290EBB6E71F34 /* MPNoStateButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39538C4CEFF46DF379254 /* MPNoStateButton.m */; };
|
93D395E4830290EBB6E71F34 /* MPNoStateButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39538C4CEFF46DF379254 /* MPNoStateButton.m */; };
|
||||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
|
|
||||||
93D39784E725A34D1EE3FB3B /* MPInitialWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D3CB30874147D9A9E1B /* MPInitialWindowController.m */; };
|
93D39784E725A34D1EE3FB3B /* MPInitialWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D3CB30874147D9A9E1B /* MPInitialWindowController.m */; };
|
||||||
93D3987F6D9046DBEE4D8364 /* NSView+Traversing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D392870DF659AFC1870521 /* NSView+Traversing.m */; };
|
93D3987F6D9046DBEE4D8364 /* NSView+Traversing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D392870DF659AFC1870521 /* NSView+Traversing.m */; };
|
||||||
93D398D1F5D8CD5A22AF6929 /* MPGradientView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39934FD8D5BFABA46F41C /* MPGradientView.m */; };
|
93D398D1F5D8CD5A22AF6929 /* MPGradientView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39934FD8D5BFABA46F41C /* MPGradientView.m */; };
|
||||||
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
|
|
||||||
93D39C5789EFA607CF788082 /* MPSiteModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E73BF5CBF8E5B005CD3 /* MPSiteModel.m */; };
|
93D39C5789EFA607CF788082 /* MPSiteModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E73BF5CBF8E5B005CD3 /* MPSiteModel.m */; };
|
||||||
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
|
|
||||||
93D39F833DEC1C89B2F795AC /* MPSitesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A57A7823DE98A0FF83C /* MPSitesWindowController.m */; };
|
93D39F833DEC1C89B2F795AC /* MPSitesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A57A7823DE98A0FF83C /* MPSitesWindowController.m */; };
|
||||||
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */; };
|
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */; };
|
||||||
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CF1747B91B00DE1CEF /* appstore.png */; };
|
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CF1747B91B00DE1CEF /* appstore.png */; };
|
||||||
@@ -87,7 +83,6 @@
|
|||||||
DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3B8451190FC86F00246EEA /* NSManagedObject+Pearl.h */; };
|
DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3B8451190FC86F00246EEA /* NSManagedObject+Pearl.h */; };
|
||||||
DA3B8456190FC89700246EEA /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3B8454190FC89700246EEA /* MPFixable.m */; };
|
DA3B8456190FC89700246EEA /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3B8454190FC89700246EEA /* MPFixable.m */; };
|
||||||
DA3BCFCD19BD09E0006B2681 /* SourceCodePro-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA3BCFCC19BD09E0006B2681 /* SourceCodePro-Regular.otf */; };
|
DA3BCFCD19BD09E0006B2681 /* SourceCodePro-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA3BCFCC19BD09E0006B2681 /* SourceCodePro-Regular.otf */; };
|
||||||
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
|
|
||||||
DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE921A7D8117003E5423 /* MPAlgorithmV3.m */; };
|
DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE921A7D8117003E5423 /* MPAlgorithmV3.m */; };
|
||||||
DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE931A7D8117003E5423 /* MPTypes.m */; };
|
DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE931A7D8117003E5423 /* MPTypes.m */; };
|
||||||
DA5180CA19FF2F9200A587E9 /* MPAlgorithmV2.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5180C719FF2F9200A587E9 /* MPAlgorithmV2.m */; };
|
DA5180CA19FF2F9200A587E9 /* MPAlgorithmV2.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5180C719FF2F9200A587E9 /* MPAlgorithmV2.m */; };
|
||||||
@@ -119,6 +114,7 @@
|
|||||||
DA6774431A474A3B004F356A /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; };
|
DA6774431A474A3B004F356A /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; };
|
||||||
DA6774451A474A3B004F356A /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; };
|
DA6774451A474A3B004F356A /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; };
|
||||||
DA6774461A474A3B004F356A /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; };
|
DA6774461A474A3B004F356A /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; };
|
||||||
|
DA72E2272444081200676D4F /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DABB981515100B4000B05417 /* SystemConfiguration.framework */; };
|
||||||
DA7471A31F2B71AE005F3468 /* mpw-marshal-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */; };
|
DA7471A31F2B71AE005F3468 /* mpw-marshal-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */; };
|
||||||
DA7471A61F2B71B9005F3468 /* mpw-marshal-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */; };
|
DA7471A61F2B71B9005F3468 /* mpw-marshal-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */; };
|
||||||
DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = DA89D4EA1A51EABD00AC64D7 /* Pearl-Cocoa.h */; };
|
DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = DA89D4EA1A51EABD00AC64D7 /* Pearl-Cocoa.h */; };
|
||||||
@@ -126,7 +122,6 @@
|
|||||||
DA8ED895192906920099B726 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8ED891192906920099B726 /* PearlTween.m */; };
|
DA8ED895192906920099B726 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8ED891192906920099B726 /* PearlTween.m */; };
|
||||||
DA8ED896192906920099B726 /* PearlTween.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8ED892192906920099B726 /* PearlTween.h */; };
|
DA8ED896192906920099B726 /* PearlTween.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8ED892192906920099B726 /* PearlTween.h */; };
|
||||||
DA8ED897192906920099B726 /* map-macro.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8ED894192906920099B726 /* map-macro.h */; };
|
DA8ED897192906920099B726 /* map-macro.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8ED894192906920099B726 /* map-macro.h */; };
|
||||||
DA9261511BE1A86700369DE5 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA92614F1BE1A86700369DE5 /* SystemConfiguration.framework */; };
|
|
||||||
DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261531BE1A88900369DE5 /* libc++.tbd */; };
|
DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261531BE1A88900369DE5 /* libc++.tbd */; };
|
||||||
DA9261561BE1A89600369DE5 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261551BE1A89600369DE5 /* libz.tbd */; };
|
DA9261561BE1A89600369DE5 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261551BE1A89600369DE5 /* libz.tbd */; };
|
||||||
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */; };
|
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */; };
|
||||||
@@ -136,8 +131,6 @@
|
|||||||
DAADCC4819FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */; };
|
DAADCC4819FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */; };
|
||||||
DAADCC4919FAFFAD00987B1D /* NSPersistentStore+PearlMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = DAADCC4019FAFFAD00987B1D /* NSPersistentStore+PearlMigration.m */; };
|
DAADCC4919FAFFAD00987B1D /* NSPersistentStore+PearlMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = DAADCC4019FAFFAD00987B1D /* NSPersistentStore+PearlMigration.m */; };
|
||||||
DAADCC4B19FB000C00987B1D /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
|
DAADCC4B19FB000C00987B1D /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
|
||||||
DAADCC6919FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m in Sources */ = {isa = PBXBuildFile; fileRef = DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */; };
|
|
||||||
DAADCC6A19FB00B500987B1D /* libKCOrderedAccessorFix.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAADCC5019FB006500987B1D /* libKCOrderedAccessorFix.a */; };
|
|
||||||
DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */; };
|
DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */; };
|
||||||
DAB07CA01F7725D400CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
|
DAB07CA01F7725D400CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
|
||||||
DAB07CA31F77261400CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
|
DAB07CA31F77261400CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
|
||||||
@@ -166,7 +159,6 @@
|
|||||||
DABD5EF9242BBCE200200755 /* icon_512x512.png in Resources */ = {isa = PBXBuildFile; fileRef = DAD0C5FE19FD6034009CB08D /* icon_512x512.png */; };
|
DABD5EF9242BBCE200200755 /* icon_512x512.png in Resources */ = {isa = PBXBuildFile; fileRef = DAD0C5FE19FD6034009CB08D /* icon_512x512.png */; };
|
||||||
DABD5EFA242BBCE200200755 /* icon_512x512@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAD0C5FF19FD6034009CB08D /* icon_512x512@2x.png */; };
|
DABD5EFA242BBCE200200755 /* icon_512x512@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAD0C5FF19FD6034009CB08D /* icon_512x512@2x.png */; };
|
||||||
DABD5F00242BC32D00200755 /* MPSecrets.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD5EFE242BC32D00200755 /* MPSecrets.m */; };
|
DABD5F00242BC32D00200755 /* MPSecrets.m in Sources */ = {isa = PBXBuildFile; fileRef = DABD5EFE242BC32D00200755 /* MPSecrets.m */; };
|
||||||
DAC6326D148680650075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
|
||||||
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||||
DACA26FE1705DF81002C6C22 /* logo-bare.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA241C1705DF7D002C6C22 /* logo-bare.png */; };
|
DACA26FE1705DF81002C6C22 /* logo-bare.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA241C1705DF7D002C6C22 /* logo-bare.png */; };
|
||||||
DACA27121705DF81002C6C22 /* avatar-13@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA24321705DF7D002C6C22 /* avatar-13@2x.png */; };
|
DACA27121705DF81002C6C22 /* avatar-13@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA24321705DF7D002C6C22 /* avatar-13@2x.png */; };
|
||||||
@@ -211,8 +203,6 @@
|
|||||||
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */; };
|
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */; };
|
||||||
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */; };
|
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */; };
|
||||||
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; };
|
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; };
|
||||||
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; };
|
|
||||||
DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA298C1705E2BD002C6C22 /* JRSwizzle.m */; };
|
|
||||||
DAD9B5F01762CAA4001835F9 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */; };
|
DAD9B5F01762CAA4001835F9 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */; };
|
||||||
DAD9B5F11762CAB9001835F9 /* MasterPassword-Mac-LoginHelper.app in Copy LoginHelper */ = {isa = PBXBuildFile; fileRef = DAD9B5E6176299BA001835F9 /* MasterPassword-Mac-LoginHelper.app */; };
|
DAD9B5F11762CAB9001835F9 /* MasterPassword-Mac-LoginHelper.app in Copy LoginHelper */ = {isa = PBXBuildFile; fileRef = DAD9B5E6176299BA001835F9 /* MasterPassword-Mac-LoginHelper.app */; };
|
||||||
DAEB942E18B47FB3000490CC /* MPInitialWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */; };
|
DAEB942E18B47FB3000490CC /* MPInitialWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */; };
|
||||||
@@ -308,13 +298,6 @@
|
|||||||
remoteGlobalIDString = DAD9B5C0176299B9001835F9;
|
remoteGlobalIDString = DAD9B5C0176299B9001835F9;
|
||||||
remoteInfo = "MasterPassword-Mac-LoginHelper";
|
remoteInfo = "MasterPassword-Mac-LoginHelper";
|
||||||
};
|
};
|
||||||
DAC63285148681200075AEA5 /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */;
|
|
||||||
proxyType = 1;
|
|
||||||
remoteGlobalIDString = DAC6326B148680650075AEA5;
|
|
||||||
remoteInfo = jrswizzle;
|
|
||||||
};
|
|
||||||
DAD9B5E5176299BA001835F9 /* PBXContainerItemProxy */ = {
|
DAD9B5E5176299BA001835F9 /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = DAD9B5E1176299B9001835F9 /* MasterPassword-Mac-LoginHelper.xcodeproj */;
|
containerPortal = DAD9B5E1176299B9001835F9 /* MasterPassword-Mac-LoginHelper.xcodeproj */;
|
||||||
@@ -352,15 +335,6 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 1;
|
runOnlyForDeploymentPostprocessing = 1;
|
||||||
};
|
};
|
||||||
DAADCC4E19FB006500987B1D /* CopyFiles */ = {
|
|
||||||
isa = PBXCopyFilesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
dstPath = "include/$(PRODUCT_NAME)";
|
|
||||||
dstSubfolderSpec = 16;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
DAD9B5EE1762CA3A001835F9 /* Copy LoginHelper */ = {
|
DAD9B5EE1762CA3A001835F9 /* Copy LoginHelper */ = {
|
||||||
isa = PBXCopyFilesBuildPhase;
|
isa = PBXCopyFilesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -380,23 +354,19 @@
|
|||||||
1E9ED9547411486CE0898611 /* Pods-MasterPassword-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword-macOS.debug.xcconfig"; path = "Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS.debug.xcconfig"; sourceTree = "<group>"; };
|
1E9ED9547411486CE0898611 /* Pods-MasterPassword-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword-macOS.debug.xcconfig"; path = "Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
28DD0F6129ECC496C8DFE6F8 /* Pods-MasterPassword-macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword-macOS.release.xcconfig"; path = "Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS.release.xcconfig"; sourceTree = "<group>"; };
|
28DD0F6129ECC496C8DFE6F8 /* Pods-MasterPassword-macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword-macOS.release.xcconfig"; path = "Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
7791961245EBC3023523FDCD /* Pods-MasterPassword.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword.release.xcconfig"; path = "Target Support Files/Pods-MasterPassword/Pods-MasterPassword.release.xcconfig"; sourceTree = "<group>"; };
|
7791961245EBC3023523FDCD /* Pods-MasterPassword.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword.release.xcconfig"; path = "Target Support Files/Pods-MasterPassword/Pods-MasterPassword.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; };
|
|
||||||
93D39240B5143E01F0B75E96 /* MPSiteModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteModel.h; sourceTree = "<group>"; };
|
93D39240B5143E01F0B75E96 /* MPSiteModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteModel.h; sourceTree = "<group>"; };
|
||||||
93D392870DF659AFC1870521 /* NSView+Traversing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSView+Traversing.m"; sourceTree = "<group>"; };
|
93D392870DF659AFC1870521 /* NSView+Traversing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSView+Traversing.m"; sourceTree = "<group>"; };
|
||||||
93D392A4F3DE0BD758B9B056 /* MPNoStateButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPNoStateButton.h; sourceTree = "<group>"; };
|
93D392A4F3DE0BD758B9B056 /* MPNoStateButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPNoStateButton.h; sourceTree = "<group>"; };
|
||||||
93D392C3918763B3B72CF366 /* MPSitesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSitesWindowController.h; sourceTree = "<group>"; };
|
93D392C3918763B3B72CF366 /* MPSitesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSitesWindowController.h; sourceTree = "<group>"; };
|
||||||
93D392FD65A1DF0E8B2A45C6 /* MPGradientView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPGradientView.h; sourceTree = "<group>"; };
|
93D392FD65A1DF0E8B2A45C6 /* MPGradientView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPGradientView.h; sourceTree = "<group>"; };
|
||||||
93D39368EF3CBFEF2AFCA15A /* MPInitialWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPInitialWindowController.h; sourceTree = "<group>"; };
|
93D39368EF3CBFEF2AFCA15A /* MPInitialWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPInitialWindowController.h; sourceTree = "<group>"; };
|
||||||
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
|
|
||||||
93D393EE88DE554BCCBC1C2D /* NSView+Traversing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSView+Traversing.h"; sourceTree = "<group>"; };
|
93D393EE88DE554BCCBC1C2D /* NSView+Traversing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSView+Traversing.h"; sourceTree = "<group>"; };
|
||||||
93D3942099C9AD0374B5777D /* MPMacApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMacApplication.h; sourceTree = "<group>"; };
|
93D3942099C9AD0374B5777D /* MPMacApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMacApplication.h; sourceTree = "<group>"; };
|
||||||
93D39423D7BF4FD31FE6D27C /* MPSitesTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesTableView.m; sourceTree = "<group>"; };
|
93D39423D7BF4FD31FE6D27C /* MPSitesTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesTableView.m; sourceTree = "<group>"; };
|
||||||
93D39538C4CEFF46DF379254 /* MPNoStateButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNoStateButton.m; sourceTree = "<group>"; };
|
93D39538C4CEFF46DF379254 /* MPNoStateButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNoStateButton.m; sourceTree = "<group>"; };
|
||||||
93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = "<group>"; };
|
|
||||||
93D3977484534E99F9BA579D /* MPSitesWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSitesWindow.h; sourceTree = "<group>"; };
|
93D3977484534E99F9BA579D /* MPSitesWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSitesWindow.h; sourceTree = "<group>"; };
|
||||||
93D39934FD8D5BFABA46F41C /* MPGradientView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPGradientView.m; sourceTree = "<group>"; };
|
93D39934FD8D5BFABA46F41C /* MPGradientView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPGradientView.m; sourceTree = "<group>"; };
|
||||||
93D39A57A7823DE98A0FF83C /* MPSitesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesWindowController.m; sourceTree = "<group>"; };
|
93D39A57A7823DE98A0FF83C /* MPSitesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesWindowController.m; sourceTree = "<group>"; };
|
||||||
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = "<group>"; };
|
|
||||||
93D39AC6360DDC16AEAA4119 /* MPSitesTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSitesTableView.h; sourceTree = "<group>"; };
|
93D39AC6360DDC16AEAA4119 /* MPSitesTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSitesTableView.h; sourceTree = "<group>"; };
|
||||||
93D39D3CB30874147D9A9E1B /* MPInitialWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPInitialWindowController.m; sourceTree = "<group>"; };
|
93D39D3CB30874147D9A9E1B /* MPInitialWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPInitialWindowController.m; sourceTree = "<group>"; };
|
||||||
93D39D9D0061FF1159998F06 /* MPSitesWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesWindow.m; sourceTree = "<group>"; };
|
93D39D9D0061FF1159998F06 /* MPSitesWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesWindow.m; sourceTree = "<group>"; };
|
||||||
@@ -937,7 +907,6 @@
|
|||||||
DA8ED891192906920099B726 /* PearlTween.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlTween.m; sourceTree = "<group>"; };
|
DA8ED891192906920099B726 /* PearlTween.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlTween.m; sourceTree = "<group>"; };
|
||||||
DA8ED892192906920099B726 /* PearlTween.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlTween.h; sourceTree = "<group>"; };
|
DA8ED892192906920099B726 /* PearlTween.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlTween.h; sourceTree = "<group>"; };
|
||||||
DA8ED894192906920099B726 /* map-macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "map-macro.h"; sourceTree = "<group>"; };
|
DA8ED894192906920099B726 /* map-macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "map-macro.h"; sourceTree = "<group>"; };
|
||||||
DA92614F1BE1A86700369DE5 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
|
||||||
DA9261531BE1A88900369DE5 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
DA9261531BE1A88900369DE5 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||||
DA9261551BE1A89600369DE5 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
DA9261551BE1A89600369DE5 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||||
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal.c"; sourceTree = "<group>"; };
|
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal.c"; sourceTree = "<group>"; };
|
||||||
@@ -1032,9 +1001,6 @@
|
|||||||
DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = "<group>"; };
|
DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = "<group>"; };
|
||||||
DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPersistentStore+PearlMigration.h"; sourceTree = "<group>"; };
|
DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPersistentStore+PearlMigration.h"; sourceTree = "<group>"; };
|
||||||
DAADCC4019FAFFAD00987B1D /* NSPersistentStore+PearlMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSPersistentStore+PearlMigration.m"; sourceTree = "<group>"; };
|
DAADCC4019FAFFAD00987B1D /* NSPersistentStore+PearlMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSPersistentStore+PearlMigration.m"; sourceTree = "<group>"; };
|
||||||
DAADCC5019FB006500987B1D /* libKCOrderedAccessorFix.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libKCOrderedAccessorFix.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
DAADCC6619FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSManagedObjectModel+KCOrderedAccessorFix.h"; sourceTree = "<group>"; };
|
|
||||||
DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObjectModel+KCOrderedAccessorFix.m"; sourceTree = "<group>"; };
|
|
||||||
DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-cli-util.c"; sourceTree = "<group>"; };
|
DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-cli-util.c"; sourceTree = "<group>"; };
|
||||||
DAAF16641F5897EA0013B8AE /* mpw-cli-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-cli-util.h"; sourceTree = "<group>"; };
|
DAAF16641F5897EA0013B8AE /* mpw-cli-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-cli-util.h"; sourceTree = "<group>"; };
|
||||||
DAB07C9E1F7725D400CC6D43 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = "<group>"; };
|
DAB07C9E1F7725D400CC6D43 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = "<group>"; };
|
||||||
@@ -1050,7 +1016,6 @@
|
|||||||
DABB981515100B4000B05417 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
DABB981515100B4000B05417 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
||||||
DABD5EFE242BC32D00200755 /* MPSecrets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSecrets.m; sourceTree = "<group>"; };
|
DABD5EFE242BC32D00200755 /* MPSecrets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSecrets.m; sourceTree = "<group>"; };
|
||||||
DABD5EFF242BC32D00200755 /* MPSecrets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSecrets.h; sourceTree = "<group>"; };
|
DABD5EFF242BC32D00200755 /* MPSecrets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSecrets.h; sourceTree = "<group>"; };
|
||||||
DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
||||||
DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
DACA241C1705DF7D002C6C22 /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-bare.png"; sourceTree = "<group>"; };
|
DACA241C1705DF7D002C6C22 /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-bare.png"; sourceTree = "<group>"; };
|
||||||
@@ -1096,8 +1061,6 @@
|
|||||||
DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-ExtraLight.otf"; sourceTree = "<group>"; };
|
DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-ExtraLight.otf"; sourceTree = "<group>"; };
|
||||||
DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Black.otf"; sourceTree = "<group>"; };
|
DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Black.otf"; sourceTree = "<group>"; };
|
||||||
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
|
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
|
||||||
DACA29771705E2BD002C6C22 /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRSwizzle.h; sourceTree = "<group>"; };
|
|
||||||
DACA298C1705E2BD002C6C22 /* JRSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JRSwizzle.m; sourceTree = "<group>"; };
|
|
||||||
DACBFCDB1C59B22E007EF90F /* NSMutableSet+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableSet+Pearl.h"; sourceTree = "<group>"; };
|
DACBFCDB1C59B22E007EF90F /* NSMutableSet+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableSet+Pearl.h"; sourceTree = "<group>"; };
|
||||||
DACBFCDC1C59B22E007EF90F /* NSMutableSet+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableSet+Pearl.m"; sourceTree = "<group>"; };
|
DACBFCDC1C59B22E007EF90F /* NSMutableSet+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableSet+Pearl.m"; sourceTree = "<group>"; };
|
||||||
DAD0C5F619FD6034009CB08D /* icon_128x128.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_128x128.png; sourceTree = "<group>"; };
|
DAD0C5F619FD6034009CB08D /* icon_128x128.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_128x128.png; sourceTree = "<group>"; };
|
||||||
@@ -1185,14 +1148,13 @@
|
|||||||
DAB7AE5B1F3D750B00C856B1 /* libjson-c.a in Frameworks */,
|
DAB7AE5B1F3D750B00C856B1 /* libjson-c.a in Frameworks */,
|
||||||
DA9261561BE1A89600369DE5 /* libz.tbd in Frameworks */,
|
DA9261561BE1A89600369DE5 /* libz.tbd in Frameworks */,
|
||||||
DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */,
|
DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */,
|
||||||
DAADCC6A19FB00B500987B1D /* libKCOrderedAccessorFix.a in Frameworks */,
|
|
||||||
DA9261511BE1A86700369DE5 /* SystemConfiguration.framework in Frameworks */,
|
|
||||||
DA250925195148E200AC23F1 /* QuartzCore.framework in Frameworks */,
|
DA250925195148E200AC23F1 /* QuartzCore.framework in Frameworks */,
|
||||||
DAD9B5F01762CAA4001835F9 /* ServiceManagement.framework in Frameworks */,
|
DAD9B5F01762CAA4001835F9 /* ServiceManagement.framework in Frameworks */,
|
||||||
DA16B341170661DB000A0EAB /* Carbon.framework in Frameworks */,
|
DA16B341170661DB000A0EAB /* Carbon.framework in Frameworks */,
|
||||||
DA16B342170661E0000A0EAB /* Security.framework in Frameworks */,
|
DA16B342170661E0000A0EAB /* Security.framework in Frameworks */,
|
||||||
DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */,
|
DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */,
|
||||||
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */,
|
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */,
|
||||||
|
DA72E2272444081200676D4F /* SystemConfiguration.framework in Frameworks */,
|
||||||
7352E972184B980C428B66A2 /* Pods_MasterPassword_macOS.framework in Frameworks */,
|
7352E972184B980C428B66A2 /* Pods_MasterPassword_macOS.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -1205,27 +1167,11 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
DAADCC4D19FB006500987B1D /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
DAC63269148680650075AEA5 /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
DAC6326D148680650075AEA5 /* Foundation.framework in Frameworks */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
DAC77CAA148291A600BCF976 /* Frameworks */ = {
|
DAC77CAA148291A600BCF976 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
DAADCC4B19FB000C00987B1D /* QuartzCore.framework in Frameworks */,
|
DAADCC4B19FB000C00987B1D /* QuartzCore.framework in Frameworks */,
|
||||||
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */,
|
|
||||||
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */,
|
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -1272,14 +1218,6 @@
|
|||||||
name = "Other Frameworks";
|
name = "Other Frameworks";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
DA3B8449190FC5A900246EEA /* Mac */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DA92614F1BE1A86700369DE5 /* SystemConfiguration.framework */,
|
|
||||||
);
|
|
||||||
path = Mac;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DA5BFA39147E415C00F98B1E = {
|
DA5BFA39147E415C00F98B1E = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -1298,8 +1236,6 @@
|
|||||||
children = (
|
children = (
|
||||||
DA5BFA44147E415C00F98B1E /* Master Password.app */,
|
DA5BFA44147E415C00F98B1E /* Master Password.app */,
|
||||||
DAC77CAD148291A600BCF976 /* libPearl.a */,
|
DAC77CAD148291A600BCF976 /* libPearl.a */,
|
||||||
DAC6326C148680650075AEA5 /* libjrswizzle.a */,
|
|
||||||
DAADCC5019FB006500987B1D /* libKCOrderedAccessorFix.a */,
|
|
||||||
DA67743B1A474A03004F356A /* mpw-test */,
|
DA67743B1A474A03004F356A /* mpw-test */,
|
||||||
DA1C7AB61F1A8F24009A3551 /* mpw-cli */,
|
DA1C7AB61F1A8F24009A3551 /* mpw-cli */,
|
||||||
DA1C7AD61F1A8FD8009A3551 /* mpw-bench */,
|
DA1C7AD61F1A8FD8009A3551 /* mpw-bench */,
|
||||||
@@ -2025,15 +1961,6 @@
|
|||||||
path = lib;
|
path = lib;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
DAADCC6819FB007F00987B1D /* KCOrderedAccessorFix */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DAADCC6619FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.h */,
|
|
||||||
DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */,
|
|
||||||
);
|
|
||||||
path = KCOrderedAccessorFix;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DAC77CAF148291A600BCF976 /* Pearl */ = {
|
DAC77CAF148291A600BCF976 /* Pearl */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -2050,9 +1977,6 @@
|
|||||||
children = (
|
children = (
|
||||||
DAA7BC0D20C4C1B500101DC7 /* libjson-c-macos */,
|
DAA7BC0D20C4C1B500101DC7 /* libjson-c-macos */,
|
||||||
DAA7BBC920C4C17300101DC7 /* libsodium-macos */,
|
DAA7BBC920C4C17300101DC7 /* libsodium-macos */,
|
||||||
DACA29751705E2BD002C6C22 /* jrswizzle */,
|
|
||||||
DAADCC6819FB007F00987B1D /* KCOrderedAccessorFix */,
|
|
||||||
DA3B8449190FC5A900246EEA /* Mac */,
|
|
||||||
DAC77CAF148291A600BCF976 /* Pearl */,
|
DAC77CAF148291A600BCF976 /* Pearl */,
|
||||||
);
|
);
|
||||||
path = External;
|
path = External;
|
||||||
@@ -2152,15 +2076,6 @@
|
|||||||
path = Data;
|
path = Data;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
DACA29751705E2BD002C6C22 /* jrswizzle */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DACA29771705E2BD002C6C22 /* JRSwizzle.h */,
|
|
||||||
DACA298C1705E2BD002C6C22 /* JRSwizzle.m */,
|
|
||||||
);
|
|
||||||
path = jrswizzle;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DAD0C5F419FD6034009CB08D /* mac */ = {
|
DAD0C5F419FD6034009CB08D /* mac */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -2205,14 +2120,10 @@
|
|||||||
DAB4FBDD202FF93D002768FB /* PearlHangDetector.h */,
|
DAB4FBDD202FF93D002768FB /* PearlHangDetector.h */,
|
||||||
DAB4FBDE202FF93D002768FB /* PearlHangDetector.m */,
|
DAB4FBDE202FF93D002768FB /* PearlHangDetector.m */,
|
||||||
DA8ED893192906920099B726 /* include */,
|
DA8ED893192906920099B726 /* include */,
|
||||||
93D396D04E57792A54D437AC /* NSArray+Indexing.h */,
|
|
||||||
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */,
|
|
||||||
DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */,
|
DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */,
|
||||||
DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */,
|
DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */,
|
||||||
DAFE4A63150399FF003ABA93 /* NSDateFormatter+RFC3339.h */,
|
DAFE4A63150399FF003ABA93 /* NSDateFormatter+RFC3339.h */,
|
||||||
DAFE4A63150399FF003ABA91 /* NSDateFormatter+RFC3339.m */,
|
DAFE4A63150399FF003ABA91 /* NSDateFormatter+RFC3339.m */,
|
||||||
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */,
|
|
||||||
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */,
|
|
||||||
DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */,
|
DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */,
|
||||||
DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */,
|
DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */,
|
||||||
DA3B8451190FC86F00246EEA /* NSManagedObject+Pearl.h */,
|
DA3B8451190FC86F00246EEA /* NSManagedObject+Pearl.h */,
|
||||||
@@ -2292,14 +2203,6 @@
|
|||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXHeadersBuildPhase section */
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
DAC6326A148680650075AEA5 /* Headers */ = {
|
|
||||||
isa = PBXHeadersBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
DAC77CAB148291A600BCF976 /* Headers */ = {
|
DAC77CAB148291A600BCF976 /* Headers */ = {
|
||||||
isa = PBXHeadersBuildPhase;
|
isa = PBXHeadersBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -2335,8 +2238,6 @@
|
|||||||
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */,
|
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */,
|
||||||
DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */,
|
DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */,
|
||||||
DAFE4A63150399FF003ABA94 /* NSDateFormatter+RFC3339.h in Headers */,
|
DAFE4A63150399FF003ABA94 /* NSDateFormatter+RFC3339.h in Headers */,
|
||||||
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */,
|
|
||||||
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */,
|
|
||||||
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */,
|
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */,
|
||||||
DA2C3D681BD9665B001137B3 /* PearlProfiler.h in Headers */,
|
DA2C3D681BD9665B001137B3 /* PearlProfiler.h in Headers */,
|
||||||
DA2CA4EE18D323D3007798F8 /* NSError+PearlFullDescription.h in Headers */,
|
DA2CA4EE18D323D3007798F8 /* NSError+PearlFullDescription.h in Headers */,
|
||||||
@@ -2428,7 +2329,7 @@
|
|||||||
DAD9B5EE1762CA3A001835F9 /* Copy LoginHelper */,
|
DAD9B5EE1762CA3A001835F9 /* Copy LoginHelper */,
|
||||||
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */,
|
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */,
|
||||||
43E5966C8C236E86824DDADE /* [CP] Embed Pods Frameworks */,
|
43E5966C8C236E86824DDADE /* [CP] Embed Pods Frameworks */,
|
||||||
DA3C4EB2243941AE00A6C4A8 /* Upload Sentry dSYM */,
|
DA3C4EB2243941AE00A6C4A8 /* Sentry dSYM Upload */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -2460,40 +2361,6 @@
|
|||||||
productReference = DA67743B1A474A03004F356A /* mpw-test */;
|
productReference = DA67743B1A474A03004F356A /* mpw-test */;
|
||||||
productType = "com.apple.product-type.tool";
|
productType = "com.apple.product-type.tool";
|
||||||
};
|
};
|
||||||
DAADCC4F19FB006500987B1D /* KCOrderedAccessorFix */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = DAADCC5E19FB006500987B1D /* Build configuration list for PBXNativeTarget "KCOrderedAccessorFix" */;
|
|
||||||
buildPhases = (
|
|
||||||
DAADCC4C19FB006500987B1D /* Sources */,
|
|
||||||
DAADCC4D19FB006500987B1D /* Frameworks */,
|
|
||||||
DAADCC4E19FB006500987B1D /* CopyFiles */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = KCOrderedAccessorFix;
|
|
||||||
productName = KCOrderedAccessorFix;
|
|
||||||
productReference = DAADCC5019FB006500987B1D /* libKCOrderedAccessorFix.a */;
|
|
||||||
productType = "com.apple.product-type.library.static";
|
|
||||||
};
|
|
||||||
DAC6326B148680650075AEA5 /* jrswizzle */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = DAC63274148680650075AEA5 /* Build configuration list for PBXNativeTarget "jrswizzle" */;
|
|
||||||
buildPhases = (
|
|
||||||
DAC63268148680650075AEA5 /* Sources */,
|
|
||||||
DAC63269148680650075AEA5 /* Frameworks */,
|
|
||||||
DAC6326A148680650075AEA5 /* Headers */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = jrswizzle;
|
|
||||||
productName = jrswizzle;
|
|
||||||
productReference = DAC6326C148680650075AEA5 /* libjrswizzle.a */;
|
|
||||||
productType = "com.apple.product-type.library.static";
|
|
||||||
};
|
|
||||||
DAC77CAC148291A600BCF976 /* Pearl */ = {
|
DAC77CAC148291A600BCF976 /* Pearl */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = DAC77CB7148291A600BCF976 /* Build configuration list for PBXNativeTarget "Pearl" */;
|
buildConfigurationList = DAC77CB7148291A600BCF976 /* Build configuration list for PBXNativeTarget "Pearl" */;
|
||||||
@@ -2505,7 +2372,6 @@
|
|||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
DAC63286148681200075AEA5 /* PBXTargetDependency */,
|
|
||||||
);
|
);
|
||||||
name = Pearl;
|
name = Pearl;
|
||||||
productName = Pearl;
|
productName = Pearl;
|
||||||
@@ -2549,18 +2415,11 @@
|
|||||||
CreatedOnToolsVersion = 6.1.1;
|
CreatedOnToolsVersion = 6.1.1;
|
||||||
DevelopmentTeam = HL3Q45LX9N;
|
DevelopmentTeam = HL3Q45LX9N;
|
||||||
};
|
};
|
||||||
DAADCC4F19FB006500987B1D = {
|
|
||||||
CreatedOnToolsVersion = 6.0.1;
|
|
||||||
DevelopmentTeam = HL3Q45LX9N;
|
|
||||||
};
|
|
||||||
DAB7AE421F3D466D00C856B1 = {
|
DAB7AE421F3D466D00C856B1 = {
|
||||||
CreatedOnToolsVersion = 8.3.3;
|
CreatedOnToolsVersion = 8.3.3;
|
||||||
DevelopmentTeam = HL3Q45LX9N;
|
DevelopmentTeam = HL3Q45LX9N;
|
||||||
ProvisioningStyle = Automatic;
|
ProvisioningStyle = Automatic;
|
||||||
};
|
};
|
||||||
DAC6326B148680650075AEA5 = {
|
|
||||||
DevelopmentTeam = HL3Q45LX9N;
|
|
||||||
};
|
|
||||||
DAC77CAC148291A600BCF976 = {
|
DAC77CAC148291A600BCF976 = {
|
||||||
DevelopmentTeam = HL3Q45LX9N;
|
DevelopmentTeam = HL3Q45LX9N;
|
||||||
};
|
};
|
||||||
@@ -2587,8 +2446,6 @@
|
|||||||
targets = (
|
targets = (
|
||||||
DA5BFA43147E415C00F98B1E /* MasterPassword-macOS */,
|
DA5BFA43147E415C00F98B1E /* MasterPassword-macOS */,
|
||||||
DAC77CAC148291A600BCF976 /* Pearl */,
|
DAC77CAC148291A600BCF976 /* Pearl */,
|
||||||
DAC6326B148680650075AEA5 /* jrswizzle */,
|
|
||||||
DAADCC4F19FB006500987B1D /* KCOrderedAccessorFix */,
|
|
||||||
DA67743A1A474A03004F356A /* mpw-test */,
|
DA67743A1A474A03004F356A /* mpw-test */,
|
||||||
DA1C7AC61F1A8FD8009A3551 /* mpw-bench */,
|
DA1C7AC61F1A8FD8009A3551 /* mpw-bench */,
|
||||||
DA1C7AA61F1A8F24009A3551 /* mpw-cli */,
|
DA1C7AA61F1A8F24009A3551 /* mpw-cli */,
|
||||||
@@ -2716,22 +2573,19 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS-frameworks.sh",
|
"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
"${BUILT_PRODUCTS_DIR}/Countly-macOS/Countly.framework",
|
|
||||||
"${BUILT_PRODUCTS_DIR}/Sentry-macOS/Sentry.framework",
|
|
||||||
);
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputPaths = (
|
outputFileListPaths = (
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Countly.framework",
|
"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework",
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS-frameworks.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS-frameworks.sh\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
DA3C4EB2243941AE00A6C4A8 /* Upload Sentry dSYM */ = {
|
DA3C4EB2243941AE00A6C4A8 /* Sentry dSYM Upload */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 8;
|
buildActionMask = 8;
|
||||||
files = (
|
files = (
|
||||||
@@ -2739,15 +2593,16 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
);
|
);
|
||||||
inputPaths = (
|
inputPaths = (
|
||||||
|
"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}",
|
||||||
);
|
);
|
||||||
name = "Upload Sentry dSYM";
|
name = "Sentry dSYM Upload";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
);
|
);
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 1;
|
runOnlyForDeploymentPostprocessing = 1;
|
||||||
shellPath = "/bin/sh -e";
|
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;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
DA4EF9CB19FD4B600032ECB5 /* Run Script: genassets */ = {
|
DA4EF9CB19FD4B600032ECB5 /* Run Script: genassets */ = {
|
||||||
@@ -2891,22 +2746,6 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
DAADCC4C19FB006500987B1D /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
DAADCC6919FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
DAC63268148680650075AEA5 /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
DAC77CA9148291A600BCF976 /* Sources */ = {
|
DAC77CA9148291A600BCF976 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -2942,8 +2781,6 @@
|
|||||||
DAB4FBEA202FF951002768FB /* NSMutableSet+Pearl.m in Sources */,
|
DAB4FBEA202FF951002768FB /* NSMutableSet+Pearl.m in Sources */,
|
||||||
DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */,
|
DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */,
|
||||||
DAFE4A63150399FF003ABA92 /* NSDateFormatter+RFC3339.m in Sources */,
|
DAFE4A63150399FF003ABA92 /* NSDateFormatter+RFC3339.m in Sources */,
|
||||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */,
|
|
||||||
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */,
|
|
||||||
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */,
|
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */,
|
||||||
93D3987F6D9046DBEE4D8364 /* NSView+Traversing.m in Sources */,
|
93D3987F6D9046DBEE4D8364 /* NSView+Traversing.m in Sources */,
|
||||||
);
|
);
|
||||||
@@ -2987,11 +2824,6 @@
|
|||||||
name = "MasterPassword-Mac-LoginHelper";
|
name = "MasterPassword-Mac-LoginHelper";
|
||||||
targetProxy = DABFA071176E3FDF00E83589 /* PBXContainerItemProxy */;
|
targetProxy = DABFA071176E3FDF00E83589 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
DAC63286148681200075AEA5 /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
target = DAC6326B148680650075AEA5 /* jrswizzle */;
|
|
||||||
targetProxy = DAC63285148681200075AEA5 /* PBXContainerItemProxy */;
|
|
||||||
};
|
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
@@ -3370,8 +3202,6 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
||||||
@@ -3391,6 +3221,7 @@
|
|||||||
"\"$(PROJECT_DIR)/../lib/libsodium/build-macos~/out/lib\"",
|
"\"$(PROJECT_DIR)/../lib/libsodium/build-macos~/out/lib\"",
|
||||||
"\"$(PROJECT_DIR)/../lib/libjson-c/build-macos~/out/lib\"",
|
"\"$(PROJECT_DIR)/../lib/libjson-c/build-macos~/out/lib\"",
|
||||||
);
|
);
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||||
OTHER_CFLAGS = (
|
OTHER_CFLAGS = (
|
||||||
"-DMPW_SODIUM=1",
|
"-DMPW_SODIUM=1",
|
||||||
"-DMPW_JSON=1",
|
"-DMPW_JSON=1",
|
||||||
@@ -3410,8 +3241,6 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Source/Mac/MasterPassword.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
|
||||||
@@ -3431,6 +3260,7 @@
|
|||||||
"\"$(PROJECT_DIR)/../lib/libsodium/build-macos~/out/lib\"",
|
"\"$(PROJECT_DIR)/../lib/libsodium/build-macos~/out/lib\"",
|
||||||
"\"$(PROJECT_DIR)/../lib/libjson-c/build-macos~/out/lib\"",
|
"\"$(PROJECT_DIR)/../lib/libjson-c/build-macos~/out/lib\"",
|
||||||
);
|
);
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||||
OTHER_CFLAGS = (
|
OTHER_CFLAGS = (
|
||||||
"-DMPW_SODIUM=1",
|
"-DMPW_SODIUM=1",
|
||||||
"-DMPW_JSON=1",
|
"-DMPW_JSON=1",
|
||||||
@@ -3490,22 +3320,6 @@
|
|||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
DAADCC5F19FB006500987B1D /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
DAADCC6019FB006500987B1D /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
DAB7AE441F3D466D00C856B1 /* Debug */ = {
|
DAB7AE441F3D466D00C856B1 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@@ -3547,34 +3361,6 @@
|
|||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
DAC63275148680650075AEA5 /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CLANG_ENABLE_OBJC_ARC = NO;
|
|
||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
|
||||||
DSTROOT = /tmp/jrswizzle.dst;
|
|
||||||
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
|
|
||||||
OTHER_LDFLAGS = "-ObjC";
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SKIP_INSTALL = YES;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
DAC63276148680650075AEA5 /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CLANG_ENABLE_OBJC_ARC = NO;
|
|
||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
|
||||||
DSTROOT = /tmp/jrswizzle.dst;
|
|
||||||
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
|
|
||||||
OTHER_LDFLAGS = "-ObjC";
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SKIP_INSTALL = YES;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
DAC77CB5148291A600BCF976 /* Debug */ = {
|
DAC77CB5148291A600BCF976 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@@ -3658,15 +3444,6 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Debug;
|
defaultConfigurationName = Debug;
|
||||||
};
|
};
|
||||||
DAADCC5E19FB006500987B1D /* Build configuration list for PBXNativeTarget "KCOrderedAccessorFix" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
DAADCC5F19FB006500987B1D /* Debug */,
|
|
||||||
DAADCC6019FB006500987B1D /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Debug;
|
|
||||||
};
|
|
||||||
DAB7AE431F3D466D00C856B1 /* Build configuration list for PBXLegacyTarget "libjson-c-macos" */ = {
|
DAB7AE431F3D466D00C856B1 /* Build configuration list for PBXLegacyTarget "libjson-c-macos" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
@@ -3676,15 +3453,6 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Debug;
|
defaultConfigurationName = Debug;
|
||||||
};
|
};
|
||||||
DAC63274148680650075AEA5 /* Build configuration list for PBXNativeTarget "jrswizzle" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
DAC63275148680650075AEA5 /* Debug */,
|
|
||||||
DAC63276148680650075AEA5 /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Debug;
|
|
||||||
};
|
|
||||||
DAC77CB7148291A600BCF976 /* Build configuration list for PBXNativeTarget "Pearl" */ = {
|
DAC77CB7148291A600BCF976 /* Build configuration list for PBXNativeTarget "Pearl" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|||||||
@@ -59,6 +59,17 @@
|
|||||||
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
|
<EnvironmentVariables>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "TERM"
|
||||||
|
value = "color"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
</EnvironmentVariables>
|
||||||
|
<LocationScenarioReference
|
||||||
|
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
||||||
|
referenceType = "1">
|
||||||
|
</LocationScenarioReference>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
|||||||
@@ -59,6 +59,17 @@
|
|||||||
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
|
<EnvironmentVariables>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "TERM"
|
||||||
|
value = "color"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
</EnvironmentVariables>
|
||||||
|
<LocationScenarioReference
|
||||||
|
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
||||||
|
referenceType = "1">
|
||||||
|
</LocationScenarioReference>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
|
|||||||
@@ -85,6 +85,13 @@
|
|||||||
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
||||||
referenceType = "1">
|
referenceType = "1">
|
||||||
</LocationScenarioReference>
|
</LocationScenarioReference>
|
||||||
|
<EnvironmentVariables>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "TERM"
|
||||||
|
value = "color"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
</EnvironmentVariables>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
|
|||||||
@@ -60,6 +60,17 @@
|
|||||||
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
|
<EnvironmentVariables>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "TERM"
|
||||||
|
value = "color"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
</EnvironmentVariables>
|
||||||
|
<LocationScenarioReference
|
||||||
|
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
|
||||||
|
referenceType = "1">
|
||||||
|
</LocationScenarioReference>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ target 'MasterPassword-iOS' do
|
|||||||
|
|
||||||
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git'
|
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git'
|
||||||
pod 'Countly'
|
pod 'Countly'
|
||||||
|
pod 'UIColor-Utilities'
|
||||||
|
pod 'KCOrderedAccessorFix'
|
||||||
|
pod 'JRSwizzle'
|
||||||
end
|
end
|
||||||
|
|
||||||
target 'MasterPassword-macOS' do
|
target 'MasterPassword-macOS' do
|
||||||
@@ -22,4 +25,17 @@ target 'MasterPassword-macOS' do
|
|||||||
|
|
||||||
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git'
|
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git'
|
||||||
pod 'Countly'
|
pod 'Countly'
|
||||||
|
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
|
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
|
# 57@1@iphone@:Icon.png
|
||||||
# 29@1@iphone@:Icon-Small.png
|
# 29@1@iphone@:Icon-Small.png
|
||||||
# iPad
|
# 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
|
152@2@ipad@7.0:Icon-76@2x.png
|
||||||
167@2@ipad@9.0:Icon-83@2x.png
|
167@2@ipad@9.0:Icon-83@2x.png
|
||||||
20@1@ipad@7.0:Icon-Small-20.png
|
20@1@ipad@7.0:Icon-Small-20.png
|
||||||
|
|||||||
@@ -46,9 +46,10 @@ esac
|
|||||||
description=$(git describe --always --dirty --long --match "*-$platform*")
|
description=$(git describe --always --dirty --long --match "*-$platform*")
|
||||||
version=${description%-g*} build=${version##*-} version=${version%-$build}
|
version=${description%-g*} build=${version##*-} version=${version%-$build}
|
||||||
version=${version//-$platform/} version=${version//-/.} commit=${description##*-g}
|
version=${version//-$platform/} version=${version//-/.} commit=${description##*-g}
|
||||||
|
IFS=. read major minor build <<< "$version"
|
||||||
|
|
||||||
addPlistWithKey GITDescription string "$description"
|
addPlistWithKey GITDescription string "$description"
|
||||||
setPlistWithKey CFBundleVersion "$(hr "${version%%.*}" 14).${version#*.}"
|
setPlistWithKey CFBundleVersion "$(hr "$major" 14)$(printf '%02d' "$minor")$(printf '%02d' "$build")"
|
||||||
setPlistWithKey CFBundleShortVersionString "$version"
|
setPlistWithKey CFBundleShortVersionString "$version"
|
||||||
|
|
||||||
setSettingWithTitle "Build" "$commit"
|
setSettingWithTitle "Build" "$commit"
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ static NSOperationQueue *_mpwQueue = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
NSOperation *operation = [NSBlockOperation blockOperationWithBlock:operationBlock];
|
NSOperation *operation = [NSBlockOperation blockOperationWithBlock:operationBlock];
|
||||||
if ([operation respondsToSelector:@selector( qualityOfService )])
|
|
||||||
operation.qualityOfService = NSQualityOfServiceUserInitiated;
|
operation.qualityOfService = NSQualityOfServiceUserInitiated;
|
||||||
[_mpwQueue addOperations:@[ operation ] waitUntilFinished:YES];
|
[_mpwQueue addOperations:@[ operation ] waitUntilFinished:YES];
|
||||||
}
|
}
|
||||||
@@ -622,7 +621,7 @@ static NSOperationQueue *_mpwQueue = nil;
|
|||||||
|
|
||||||
- (NSString *)exportLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)key {
|
- (NSString *)exportLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)key {
|
||||||
|
|
||||||
if (!(site.type & MPSiteFeatureExportContent) || site.loginGenerated || ![site.loginName length])
|
if (site.loginGenerated || ![site.loginName length])
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
__block NSData *state = nil;
|
__block NSData *state = nil;
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
|
|||||||
[self performPurchaseProductWithIdentifier:productIdentifier quantity:quantity];
|
[self performPurchaseProductWithIdentifier:productIdentifier quantity:quantity];
|
||||||
}]];
|
}]];
|
||||||
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
[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;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -158,35 +158,27 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
|
|||||||
|
|
||||||
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
|
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
|
||||||
|
|
||||||
MPError( error, @"StoreKit request (%@) failed.", request );
|
MPError( error, @"StoreKit request failed." );
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
PearlMainQueue( ^{
|
PearlMainQueue( ^{
|
||||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Purchase Failed" message:
|
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Purchase Failed" message:
|
||||||
strf( @"%@\n\n%@", error.localizedDescription,
|
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];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[controller addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
|
[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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)requestDidFinish:(SKRequest *)request {
|
|
||||||
|
|
||||||
dbg( @"StoreKit request (%@) finished.", request );
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - SKPaymentTransactionObserver
|
#pragma mark - SKPaymentTransactionObserver
|
||||||
|
|
||||||
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
|
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
|
||||||
|
|
||||||
for (SKPaymentTransaction *transaction in transactions) {
|
for (SKPaymentTransaction *transaction in transactions) {
|
||||||
dbg( @"transaction updated: %@ -> %d", transaction.payment.productIdentifier, (int)(transaction.transactionState) );
|
|
||||||
|
|
||||||
switch (transaction.transactionState) {
|
switch (transaction.transactionState) {
|
||||||
case SKPaymentTransactionStatePurchased: {
|
case SKPaymentTransactionStatePurchased: {
|
||||||
inf( @"Purchased: %@", transaction.payment.productIdentifier );
|
|
||||||
NSMutableDictionary *attributes = [NSMutableDictionary new];
|
NSMutableDictionary *attributes = [NSMutableDictionary new];
|
||||||
|
|
||||||
if ([transaction.payment.productIdentifier isEqualToString:MPProductFuel]) {
|
if ([transaction.payment.productIdentifier isEqualToString:MPProductFuel]) {
|
||||||
@@ -205,7 +197,6 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
|
|||||||
forKey:transaction.payment.productIdentifier];
|
forKey:transaction.payment.productIdentifier];
|
||||||
[queue finishTransaction:transaction];
|
[queue finishTransaction:transaction];
|
||||||
|
|
||||||
if ([[MPConfig get].sendInfo boolValue]) {
|
|
||||||
SKProduct *product = self.products[transaction.payment.productIdentifier];
|
SKProduct *product = self.products[transaction.payment.productIdentifier];
|
||||||
[attributes addEntriesFromDictionary:@{
|
[attributes addEntriesFromDictionary:@{
|
||||||
@"id": product.productIdentifier,
|
@"id": product.productIdentifier,
|
||||||
@@ -216,11 +207,9 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
|
|||||||
@"quantity": @(transaction.payment.quantity).description,
|
@"quantity": @(transaction.payment.quantity).description,
|
||||||
}];
|
}];
|
||||||
[Countly.sharedInstance recordEvent:@"purchase" segmentation:attributes];
|
[Countly.sharedInstance recordEvent:@"purchase" segmentation:attributes];
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SKPaymentTransactionStateRestored: {
|
case SKPaymentTransactionStateRestored: {
|
||||||
inf( @"Restored: %@", transaction.payment.productIdentifier );
|
|
||||||
[[NSUserDefaults standardUserDefaults] setObject:transaction.transactionIdentifier
|
[[NSUserDefaults standardUserDefaults] setObject:transaction.transactionIdentifier
|
||||||
forKey:transaction.payment.productIdentifier];
|
forKey:transaction.payment.productIdentifier];
|
||||||
[queue finishTransaction:transaction];
|
[queue finishTransaction:transaction];
|
||||||
@@ -233,7 +222,17 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
|
|||||||
MPError( transaction.error, @"Transaction failed: %@.", transaction.payment.productIdentifier );
|
MPError( transaction.error, @"Transaction failed: %@.", transaction.payment.productIdentifier );
|
||||||
[queue finishTransaction:transaction];
|
[queue finishTransaction:transaction];
|
||||||
|
|
||||||
if ([[MPConfig get].sendInfo boolValue]) {
|
#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];
|
SKProduct *product = self.products[transaction.payment.productIdentifier];
|
||||||
[Countly.sharedInstance recordEvent:@"purchase" segmentation:@{
|
[Countly.sharedInstance recordEvent:@"purchase" segmentation:@{
|
||||||
@"id": product.productIdentifier,
|
@"id": product.productIdentifier,
|
||||||
@@ -244,7 +243,6 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
|
|||||||
@"quantity": @(transaction.payment.quantity).description,
|
@"quantity": @(transaction.payment.quantity).description,
|
||||||
@"reason" : [transaction.error localizedFailureReason]?: [transaction.error localizedDescription],
|
@"reason" : [transaction.error localizedFailureReason]?: [transaction.error localizedDescription],
|
||||||
}];
|
}];
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,13 +173,11 @@
|
|||||||
else
|
else
|
||||||
dbg( @"Automatic login failed for user: %@", user.userID );
|
dbg( @"Automatic login failed for user: %@", user.userID );
|
||||||
|
|
||||||
if ([[MPConfig get].sendInfo boolValue]) {
|
|
||||||
[Countly.sharedInstance recordEvent:@"login" segmentation:@{
|
[Countly.sharedInstance recordEvent:@"login" segmentation:@{
|
||||||
@"method" : password? @"Password": @"Automatic",
|
@"method" : password? @"Password": @"Automatic",
|
||||||
@"state" : @"failed",
|
@"state" : @"failed",
|
||||||
@"algorithm": @(user.algorithm.version).description,
|
@"algorithm": @(user.algorithm.version).description,
|
||||||
}];
|
}];
|
||||||
}
|
|
||||||
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
@@ -203,7 +201,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@try {
|
@try {
|
||||||
if ([[MPConfig get].sendInfo boolValue]) {
|
[SentrySDK setUser:[[SentryUser alloc] initWithUserId:user.userID]];
|
||||||
[Countly.sharedInstance userLoggedIn:user.userID];
|
[Countly.sharedInstance userLoggedIn:user.userID];
|
||||||
|
|
||||||
[Countly.sharedInstance recordEvent:@"login" segmentation:@{
|
[Countly.sharedInstance recordEvent:@"login" segmentation:@{
|
||||||
@@ -212,7 +210,6 @@
|
|||||||
@"algorithm": @(user.algorithm.version).description,
|
@"algorithm": @(user.algorithm.version).description,
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@catch (id exception) {
|
@catch (id exception) {
|
||||||
err( @"While setting username: %@", exception );
|
err( @"While setting username: %@", exception );
|
||||||
}
|
}
|
||||||
@@ -252,18 +249,18 @@
|
|||||||
masterPassword = PearlAwait( ^(void (^setResult)(id)) {
|
masterPassword = PearlAwait( ^(void (^setResult)(id)) {
|
||||||
PearlMainQueue( ^{
|
PearlMainQueue( ^{
|
||||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Enter Old Master Password" message:
|
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];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[controller addTextFieldWithConfigurationHandler:nil];
|
[controller addTextFieldWithConfigurationHandler:nil];
|
||||||
[controller addAction:[UIAlertAction actionWithTitle:@"Migrate" style:UIAlertActionStyleDefault handler:
|
[controller addAction:[UIAlertAction actionWithTitle:@"Migrate" style:UIAlertActionStyleDefault handler:
|
||||||
^(UIAlertAction *_Nonnull action) {
|
^(UIAlertAction *_Nonnull action) {
|
||||||
setResult( controller.textFields.firstObject.text );
|
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) {
|
^(UIAlertAction *_Nonnull action) {
|
||||||
setResult( nil );
|
setResult( nil );
|
||||||
}]];
|
}]];
|
||||||
[self.navigationController presentViewController:controller animated:YES completion:nil];
|
[self.window.rootViewController presentViewController:controller animated:YES completion:nil];
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
|
|
||||||
@interface MPAppDelegate_Shared : PearlAppDelegate
|
@interface MPAppDelegate_Shared : UIResponder<UIApplicationDelegate, PearlConfigDelegate>
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
MPLogSink mpw_log_sink_pearl;
|
MPLogSink mpw_log_sink_pearl;
|
||||||
void mpw_log_sink_pearl(const MPLogEvent *record) {
|
bool mpw_log_sink_pearl(const MPLogEvent *record) {
|
||||||
|
|
||||||
PearlLogLevel level = PearlLogLevelInfo;
|
PearlLogLevel level = PearlLogLevelInfo;
|
||||||
switch (record->level) {
|
switch (record->level) {
|
||||||
@@ -58,6 +58,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
|
|||||||
|
|
||||||
[[PearlLogger get] inFile:[@(record->file) lastPathComponent] atLine:record->line fromFunction:@(record->function)
|
[[PearlLogger get] inFile:[@(record->file) lastPathComponent] atLine:record->line fromFunction:@(record->function)
|
||||||
withLevel:level text:@(record->message)];
|
withLevel:level text:@(record->message)];
|
||||||
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation MPAppDelegate_Shared
|
@implementation MPAppDelegate_Shared
|
||||||
@@ -112,18 +113,16 @@ static MPAppDelegate_Shared *instance;
|
|||||||
- (void)setActiveUser:(MPUserEntity *)activeUser {
|
- (void)setActiveUser:(MPUserEntity *)activeUser {
|
||||||
|
|
||||||
NSManagedObjectID *activeUserOID = activeUser.permanentObjectID;
|
NSManagedObjectID *activeUserOID = activeUser.permanentObjectID;
|
||||||
if ([self.activeUserOID isEqual:activeUserOID])
|
if (self.activeUserOID == activeUserOID || [self.activeUserOID isEqual:activeUserOID])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (self.key)
|
|
||||||
self.key = nil;
|
self.key = nil;
|
||||||
|
[SentrySDK setUser:nil];
|
||||||
if ([[MPConfig get].sendInfo boolValue])
|
|
||||||
[Countly.sharedInstance userLoggedOut];
|
[Countly.sharedInstance userLoggedOut];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPSignedOutNotification object:self];
|
|
||||||
|
|
||||||
self.activeUserOID = activeUserOID;
|
self.activeUserOID = activeUserOID;
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPSignedOutNotification object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)handleCoordinatorError:(NSError *)error {
|
- (void)handleCoordinatorError:(NSError *)error {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
- (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock;
|
- (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock;
|
||||||
|
|
||||||
- (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context;
|
- (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context;
|
||||||
|
- (void)retryCorruptStore;
|
||||||
- (void)deleteAndResetStore;
|
- (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. */
|
/** @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
|
askImportPassword:(NSString *( ^ )(NSString *userName))importPassword
|
||||||
askUserPassword:(NSString *( ^ )(NSString *userName))userPassword
|
askUserPassword:(NSString *( ^ )(NSString *userName))userPassword
|
||||||
result:(void ( ^ )(NSError *error))resultBlock;
|
result:(void ( ^ )(NSError *error))resultBlock;
|
||||||
- (void)exportSitesRevealPasswords:(BOOL)revealPasswords
|
- (NSString *)exportSitesFor:(MPUserEntity *)user
|
||||||
askExportPassword:(NSString *( ^ )(NSString *userName))askImportPassword
|
revealPasswords:(BOOL)revealPasswords
|
||||||
result:(void ( ^ )(NSString *exportedUser, NSError *error))resultBlock;
|
askExportPassword:(NSString *( ^ )(NSString *userName))askExportPassword
|
||||||
|
error:(__autoreleasing NSError **)error;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -232,22 +232,27 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
}];
|
}];
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
||||||
// Create a new store coordinator.
|
// Create a new store coordinator.
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
NSURL *localStoreURL = [self localStoreURL];
|
NSURL *localStoreURL = [self localStoreURL];
|
||||||
if (![[NSFileManager defaultManager] createDirectoryAtURL:[localStoreURL URLByDeletingLastPathComponent]
|
if (![[NSFileManager defaultManager] createDirectoryAtURL:[localStoreURL URLByDeletingLastPathComponent]
|
||||||
withIntermediateDirectories:YES attributes:nil error:&error]) {
|
withIntermediateDirectories:YES attributes:nil error:&error]) {
|
||||||
MPError( error, @"Couldn't create our application support directory." );
|
MPError( error, @"Couldn't create our application support directory." );
|
||||||
|
PearlRemoveNotificationObserversFrom( self.mainManagedObjectContext );
|
||||||
|
self.mainManagedObjectContext = nil;
|
||||||
|
self.privateManagedObjectContext = nil;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (![self.storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self localStoreURL]
|
if (![self.storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:localStoreURL
|
||||||
options:@{
|
options:@{
|
||||||
NSMigratePersistentStoresAutomaticallyOption: @YES,
|
NSMigratePersistentStoresAutomaticallyOption: @YES,
|
||||||
NSInferMappingModelAutomaticallyOption : @YES,
|
NSInferMappingModelAutomaticallyOption : @YES,
|
||||||
STORE_OPTIONS
|
STORE_OPTIONS
|
||||||
} error:&error]) {
|
} error:&error]) {
|
||||||
MPError( error, @"Failed to open store." );
|
MPError( error, @"Failed to open store." );
|
||||||
|
PearlRemoveNotificationObserversFrom( self.mainManagedObjectContext );
|
||||||
|
self.mainManagedObjectContext = nil;
|
||||||
|
self.privateManagedObjectContext = nil;
|
||||||
self.storeCorrupted = @YES;
|
self.storeCorrupted = @YES;
|
||||||
[self handleCoordinatorError:error];
|
[self handleCoordinatorError:error];
|
||||||
return;
|
return;
|
||||||
@@ -274,6 +279,12 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)retryCorruptStore {
|
||||||
|
|
||||||
|
self.storeCorrupted = @NO;
|
||||||
|
[self loadStore];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)deleteAndResetStore {
|
- (void)deleteAndResetStore {
|
||||||
|
|
||||||
@synchronized (self) {
|
@synchronized (self) {
|
||||||
@@ -563,21 +574,20 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
|
|
||||||
// Read metadata for the import file.
|
// Read metadata for the import file.
|
||||||
MPMarshalledFile *file = mpw_marshal_read( NULL, importData.UTF8String );
|
MPMarshalledFile *file = mpw_marshal_read( NULL, importData.UTF8String );
|
||||||
|
MPMarshalledUser *importUser = nil;
|
||||||
|
@try {
|
||||||
if (!file)
|
if (!file)
|
||||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||||
@"type" : @(MPMarshalErrorInternal),
|
@"type" : @(MPMarshalErrorInternal),
|
||||||
NSLocalizedDescriptionKey: @"Could not process Master Password import data.",
|
NSLocalizedDescriptionKey: @"Could not process Master Password import data.",
|
||||||
}]), @"While importing sites." );
|
}]), @"While importing sites." );
|
||||||
if (file->error.type != MPMarshalSuccess) {
|
if (file->error.type != MPMarshalSuccess) {
|
||||||
MPMarshalErrorType type = file->error.type;
|
|
||||||
mpw_marshal_file_free( &file );
|
|
||||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||||
@"type" : @(type),
|
@"type" : @(file->error.type),
|
||||||
NSLocalizedDescriptionKey: @"Could not parse Master Password import data.",
|
NSLocalizedDescriptionKey: strf( @"Could not parse Master Password import data:\n%@", @(file->error.message) ),
|
||||||
}]), @"While importing sites." );
|
}]), @"While importing sites." );
|
||||||
}
|
}
|
||||||
if (file->info->format == MPMarshalFormatNone) {
|
if (file->info->format == MPMarshalFormatNone) {
|
||||||
mpw_marshal_file_free( &file );
|
|
||||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||||
@"type" : @(MPMarshalErrorFormat),
|
@"type" : @(MPMarshalErrorFormat),
|
||||||
NSLocalizedDescriptionKey: @"This is not a Master Password import file.",
|
NSLocalizedDescriptionKey: @"This is not a Master Password import file.",
|
||||||
@@ -591,7 +601,6 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
importMasterPassword = askImportPassword( @(file->info->fullName) );
|
importMasterPassword = askImportPassword( @(file->info->fullName) );
|
||||||
if (!importMasterPassword) {
|
if (!importMasterPassword) {
|
||||||
inf( @"Import cancelled." );
|
inf( @"Import cancelled." );
|
||||||
mpw_marshal_file_free( &file );
|
|
||||||
return MPError( ([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]), @"" );
|
return MPError( ([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]), @"" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,13 +609,11 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
caseInsensitiveCompare:@(file->info->keyID)] != NSOrderedSame);
|
caseInsensitiveCompare:@(file->info->keyID)] != NSOrderedSame);
|
||||||
|
|
||||||
// Parse import data.
|
// Parse import data.
|
||||||
MPMarshalledUser *importUser = mpw_marshal_auth( file, mpw_masterKeyProvider_str( importMasterPassword.UTF8String ) );
|
importUser = mpw_marshal_auth( file, mpw_masterKeyProvider_str( importMasterPassword.UTF8String ) );
|
||||||
|
|
||||||
@try {
|
|
||||||
if (!importUser || file->error.type != MPMarshalSuccess)
|
if (!importUser || file->error.type != MPMarshalSuccess)
|
||||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||||
@"type" : @(file->error.type),
|
@"type" : @(file->error.type),
|
||||||
NSLocalizedDescriptionKey: @(file->error.message),
|
NSLocalizedDescriptionKey: strf( @"Could not authenticate Master Password import:\n%@", @(file->error.message) ),
|
||||||
}]), @"While importing sites." );
|
}]), @"While importing sites." );
|
||||||
|
|
||||||
// Find an existing user to update.
|
// Find an existing user to update.
|
||||||
@@ -643,7 +650,6 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
user.avatar = importUser->avatar;
|
user.avatar = importUser->avatar;
|
||||||
user.defaultType = importUser->defaultType;
|
user.defaultType = importUser->defaultType;
|
||||||
user.lastUsed = [NSDate dateWithTimeIntervalSince1970:MAX( user.lastUsed.timeIntervalSince1970, importUser->lastUsed )];
|
user.lastUsed = [NSDate dateWithTimeIntervalSince1970:MAX( user.lastUsed.timeIntervalSince1970, importUser->lastUsed )];
|
||||||
dbg( @"Importing user: %@", [user debugDescription] );
|
|
||||||
|
|
||||||
// Update or create sites.
|
// Update or create sites.
|
||||||
for (size_t s = 0; s < importUser->sites_count; ++s) {
|
for (size_t s = 0; s < importUser->sites_count; ++s) {
|
||||||
@@ -657,10 +663,8 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
return MPError( error, @"Lookup of existing sites failed for site: %@, user: %@", @(importSite->siteName), user.userID );
|
return MPError( error, @"Lookup of existing sites failed for site: %@, user: %@", @(importSite->siteName), user.userID );
|
||||||
if ([existingSites count])
|
if ([existingSites count])
|
||||||
// Update existing site.
|
// Update existing site.
|
||||||
for (MPSiteEntity *site in existingSites) {
|
for (MPSiteEntity *site in existingSites)
|
||||||
[self importSite:importSite protectedByKey:importKey intoSite:site usingKey:userKey];
|
[self importSite:importSite protectedByKey:importKey intoSite:site usingKey:userKey];
|
||||||
dbg( @"Updated site: %@", [site debugDescription] );
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
// Create new site.
|
// Create new site.
|
||||||
id<MPAlgorithm> algorithm = MPAlgorithmForVersion( importSite->algorithm );
|
id<MPAlgorithm> algorithm = MPAlgorithmForVersion( importSite->algorithm );
|
||||||
@@ -673,7 +677,6 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
site.user = user;
|
site.user = user;
|
||||||
|
|
||||||
[self importSite:importSite protectedByKey:importKey intoSite:site usingKey:userKey];
|
[self importSite:importSite protectedByKey:importKey intoSite:site usingKey:userKey];
|
||||||
dbg( @"Created site: %@", [site debugDescription] );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -712,31 +715,40 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
site.lastUsed = [NSDate dateWithTimeIntervalSince1970:importSite->lastUsed];
|
site.lastUsed = [NSDate dateWithTimeIntervalSince1970:importSite->lastUsed];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)exportSitesRevealPasswords:(BOOL)revealPasswords
|
- (NSString *)exportSitesFor:(MPUserEntity *)user
|
||||||
askExportPassword:(NSString *( ^ )(NSString *userName))askImportPassword
|
revealPasswords:(BOOL)revealPasswords
|
||||||
result:(void ( ^ )(NSString *exportedUser, NSError *error))resultBlock {
|
askExportPassword:(NSString *( ^ )(NSString *userName))askExportPassword
|
||||||
|
error:(__autoreleasing NSError **)error {
|
||||||
[MPAppDelegate_Shared managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
|
||||||
MPUserEntity *user = [self activeUserInContext:context];
|
|
||||||
|
|
||||||
|
MPMarshalledUser *exportUser = NULL;
|
||||||
|
MPMarshalledFile *exportFile = NULL;
|
||||||
|
@try {
|
||||||
inf( @"Exporting sites, %@, for user: %@", revealPasswords? @"revealing passwords": @"omitting passwords", user.userID );
|
inf( @"Exporting sites, %@, for user: %@", revealPasswords? @"revealing passwords": @"omitting passwords", user.userID );
|
||||||
MPMarshalledUser *exportUser = mpw_marshal_user( user.name.UTF8String,
|
NSString *masterPassword = askExportPassword( user.name );
|
||||||
mpw_masterKeyProvider_str( askImportPassword( user.name ).UTF8String ), user.algorithm.version );
|
if (!masterPassword) {
|
||||||
|
inf( @"Export cancelled." );
|
||||||
|
return 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->redacted = !revealPasswords;
|
||||||
exportUser->avatar = (unsigned int)user.avatar;
|
exportUser->avatar = (unsigned int)user.avatar;
|
||||||
exportUser->keyID = mpw_strdup( [user.keyID encodeHex].UTF8String );
|
exportUser->keyID = mpw_strdup( [user.keyID encodeHex].UTF8String );
|
||||||
exportUser->defaultType = user.defaultType;
|
exportUser->defaultType = user.defaultType;
|
||||||
exportUser->lastUsed = (time_t)user.lastUsed.timeIntervalSince1970;
|
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;
|
MPCounterValue counter = MPCounterValueInitial;
|
||||||
if ([site isKindOfClass:[MPGeneratedSiteEntity class]])
|
if ([site isKindOfClass:[MPGeneratedSiteEntity class]])
|
||||||
counter = ((MPGeneratedSiteEntity *)site).counter;
|
counter = ((MPGeneratedSiteEntity *)site).counter;
|
||||||
MPMarshalledSite *exportSite = mpw_marshal_site( exportUser,
|
MPMarshalledSite *exportSite = mpw_marshal_site( exportUser, site.name.UTF8String, site.type, counter, site.algorithm.version );
|
||||||
site.name.UTF8String, site.type, counter, site.algorithm.version );
|
exportSite->resultState = mpw_strdup( [site.algorithm exportPasswordForSite:site usingKey:key].UTF8String );
|
||||||
exportSite->resultState = mpw_strdup( [site.algorithm exportPasswordForSite:site usingKey:self.key].UTF8String );
|
exportSite->loginState = mpw_strdup( [site.algorithm exportLoginForSite:site usingKey:key].UTF8String );
|
||||||
exportSite->loginState = mpw_strdup( [site.algorithm exportLoginForSite:site usingKey:self.key].UTF8String );
|
exportSite->loginType = site.loginGenerated || !exportSite->loginState? MPResultTypeTemplateName: MPResultTypeStatefulPersonal;
|
||||||
exportSite->loginType = site.loginGenerated? MPResultTypeTemplateName: MPResultTypeStatefulPersonal;
|
|
||||||
exportSite->url = mpw_strdup( site.url.UTF8String );
|
exportSite->url = mpw_strdup( site.url.UTF8String );
|
||||||
exportSite->uses = (unsigned int)site.uses;
|
exportSite->uses = (unsigned int)site.uses;
|
||||||
exportSite->lastUsed = (time_t)site.lastUsed.timeIntervalSince1970;
|
exportSite->lastUsed = (time_t)site.lastUsed.timeIntervalSince1970;
|
||||||
@@ -745,22 +757,26 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
mpw_marshal_question( exportSite, siteQuestion.keyword.UTF8String );
|
mpw_marshal_question( exportSite, siteQuestion.keyword.UTF8String );
|
||||||
}
|
}
|
||||||
|
|
||||||
MPMarshalledFile *exportFile = NULL;
|
|
||||||
const char *export = mpw_marshal_write( MPMarshalFormatDefault, &exportFile, exportUser );
|
const char *export = mpw_marshal_write( MPMarshalFormatDefault, &exportFile, exportUser );
|
||||||
NSString *exportedUser = nil;
|
NSString *exportedUser = nil;
|
||||||
if (export && exportFile && exportFile->error.type == MPMarshalSuccess)
|
if (export && exportFile && exportFile->error.type == MPMarshalSuccess)
|
||||||
exportedUser = [NSString stringWithCString:export encoding:NSUTF8StringEncoding];
|
exportedUser = [NSString stringWithCString:export encoding:NSUTF8StringEncoding];
|
||||||
mpw_free_string( &export );
|
mpw_free_string( &export );
|
||||||
|
|
||||||
resultBlock( exportedUser, exportFile && exportFile->error.type == MPMarshalSuccess? nil:
|
if (error)
|
||||||
|
*error = exportFile && exportFile->error.type == MPMarshalSuccess? nil:
|
||||||
[NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
[NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||||
@"type" : @(exportFile? exportFile->error.type: MPMarshalErrorInternal),
|
@"type" : @(exportFile? exportFile->error.type: MPMarshalErrorInternal),
|
||||||
NSLocalizedDescriptionKey: @(exportFile? exportFile->error.message: nil),
|
NSLocalizedDescriptionKey: @(exportFile? exportFile->error.message: nil),
|
||||||
}] );
|
}];
|
||||||
|
|
||||||
|
return exportedUser;
|
||||||
|
}
|
||||||
|
@finally {
|
||||||
mpw_marshal_file_free( &exportFile );
|
mpw_marshal_file_free( &exportFile );
|
||||||
mpw_marshal_user_free( &exportUser );
|
mpw_marshal_user_free( &exportUser );
|
||||||
mpw_masterKeyProvider_free();
|
mpw_masterKeyProvider_free();
|
||||||
}];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -21,11 +21,13 @@
|
|||||||
@interface MPConfig : PearlConfig
|
@interface MPConfig : PearlConfig
|
||||||
|
|
||||||
@property(nonatomic, retain) NSNumber *sendInfo;
|
@property(nonatomic, retain) NSNumber *sendInfo;
|
||||||
|
@property(nonatomic, retain) NSNumber *sendInfoDecided;
|
||||||
|
@property(nonatomic, retain) NSNumber *notificationsDecided;
|
||||||
|
|
||||||
@property(nonatomic, retain) NSNumber *rememberLogin;
|
@property(nonatomic, retain) NSNumber *rememberLogin;
|
||||||
@property(nonatomic, retain) NSNumber *hidePasswords;
|
@property(nonatomic, retain) NSNumber *hidePasswords;
|
||||||
|
@property(nonatomic, strong) NSNumber *siteAttacker;
|
||||||
|
|
||||||
@property(nonatomic, retain) NSNumber *checkInconsistency;
|
@property(nonatomic, retain) NSNumber *checkInconsistency;
|
||||||
|
|
||||||
@property(nonatomic, strong) NSNumber *siteAttacker;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
@implementation MPConfig
|
@implementation MPConfig
|
||||||
|
|
||||||
@dynamic sendInfo, rememberLogin, checkInconsistency, hidePasswords, siteAttacker;
|
@dynamic sendInfo, sendInfoDecided, notificationsDecided, rememberLogin, hidePasswords, siteAttacker, checkInconsistency;
|
||||||
|
|
||||||
- (id)init {
|
- (id)init {
|
||||||
|
|
||||||
@@ -29,13 +29,16 @@
|
|||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
[self.defaults registerDefaults:@{
|
[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( rememberLogin ) ) : @NO,
|
||||||
NSStringFromSelector( @selector( hidePasswords ) ) : @NO,
|
NSStringFromSelector( @selector( hidePasswords ) ) : @NO,
|
||||||
NSStringFromSelector( @selector( checkInconsistency ) ): @NO,
|
|
||||||
NSStringFromSelector( @selector( siteAttacker ) ) : @(MPAttacker1),
|
NSStringFromSelector( @selector( siteAttacker ) ) : @(MPAttacker1),
|
||||||
|
|
||||||
|
NSStringFromSelector( @selector( checkInconsistency ) ) : @NO,
|
||||||
|
NSStringFromSelector( @selector( askForReviews ) ) : @YES,
|
||||||
}];
|
}];
|
||||||
|
|
||||||
self.delegate = [MPAppDelegate_Shared get];
|
self.delegate = [MPAppDelegate_Shared get];
|
||||||
|
|||||||
@@ -20,11 +20,19 @@
|
|||||||
#import "base64.h"
|
#import "base64.h"
|
||||||
|
|
||||||
// printf <secret> | openssl enc -[ed] -aes-128-cbc -a -A -K <appSecret> -iv 0
|
// printf <secret> | openssl enc -[ed] -aes-128-cbc -a -A -K <appSecret> -iv 0
|
||||||
NSString *appSecret = @"";
|
#if TARGET_OS_IOS
|
||||||
NSString *appSalt = @"";
|
NSString *appSecret = @"946a6b12e6e6e004cc35bad1ea11478c";
|
||||||
NSString *sentryDSN = @"";
|
NSString *appSalt = @"uBcsbZeTB8TfSS7dDw4yUq6wMZD/2nREvR0mqzqsNXvv9guh+62hkt99ly6QcJ5n";
|
||||||
NSString *countlyKey = @"";
|
NSString *sentryDSN = @"tmVjdMN9DpZ+0EIrrvHi44hWfaBkwrlrxjBkdeau2rDk+zlvgSdAZkAvNj7m1V+5NUR7i8Y/NumNKOaYlWJvPynEMJ4ZBvPepSbivgVvmr8=";
|
||||||
NSString *countlySalt = @"";
|
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) {
|
NSString *decrypt(NSString *secret) {
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,9 @@ __END_DECLS
|
|||||||
\
|
\
|
||||||
if (__error && [[MPConfig get].sendInfo boolValue]) { \
|
if (__error && [[MPConfig get].sendInfo boolValue]) { \
|
||||||
SentryEvent *event = [[SentryEvent alloc] initWithLevel:kSentryLevelError]; \
|
SentryEvent *event = [[SentryEvent alloc] initWithLevel:kSentryLevelError]; \
|
||||||
event.message = strf(@"%@: %@", message_, [__error localizedDescription]); \
|
event.message = strf( message_ @": %@", ##__VA_ARGS__, [__error localizedDescription]); \
|
||||||
event.logger = @"MPError"; \
|
event.logger = @"MPError"; \
|
||||||
|
event.fingerprint = @[ message_, __error.domain, @(__error.code) ]; \
|
||||||
[SentrySDK captureEvent:event]; \
|
[SentrySDK captureEvent:event]; \
|
||||||
} \
|
} \
|
||||||
__error; \
|
__error; \
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12118" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="16096" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12118"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="16096"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||||
@@ -12,11 +12,11 @@
|
|||||||
</customObject>
|
</customObject>
|
||||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
<menu title="AMainMenu" systemMenu="main" id="29"/>
|
|
||||||
<customObject id="494" customClass="MPMacAppDelegate">
|
<customObject id="494" customClass="MPMacAppDelegate">
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="createUserItem" destination="757" id="763"/>
|
<outlet property="createUserItem" destination="757" id="763"/>
|
||||||
<outlet property="deleteUserItem" destination="ZgZ-p2-463" id="smU-PF-mKA"/>
|
<outlet property="deleteUserItem" destination="ZgZ-p2-463" id="smU-PF-mKA"/>
|
||||||
|
<outlet property="diagnosticsItem" destination="GSN-f0-q7s" id="kns-3O-fu0"/>
|
||||||
<outlet property="hidePasswordsItem" destination="9G7-17-PzY" id="qPX-VT-jVx"/>
|
<outlet property="hidePasswordsItem" destination="9G7-17-PzY" id="qPX-VT-jVx"/>
|
||||||
<outlet property="lockItem" destination="720" id="726"/>
|
<outlet property="lockItem" destination="720" id="726"/>
|
||||||
<outlet property="openAtLoginItem" destination="785" id="788"/>
|
<outlet property="openAtLoginItem" destination="785" id="788"/>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
<items>
|
<items>
|
||||||
<menuItem title="Users" id="755">
|
<menuItem title="Users" id="755">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<menu key="submenu" title="Users" id="756">
|
<menu key="submenu" title="Users" autoenablesItems="NO" id="756">
|
||||||
<items>
|
<items>
|
||||||
<menuItem title="New User" enabled="NO" toolTip="Creating users is not yet supported. Please use the iOS app with iCloud enabled to create users and sites." id="757">
|
<menuItem title="New User" enabled="NO" toolTip="Creating users is not yet supported. Please use the iOS app with iCloud enabled to create users and sites." id="757">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
@@ -47,6 +47,53 @@
|
|||||||
<action selector="deleteUser:" target="494" id="eia-X5-QMc"/>
|
<action selector="deleteUser:" target="494" id="eia-X5-QMc"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
|
<menuItem title="Import User..." id="EFK-zt-EvJ">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="importSites:" target="494" id="CNv-4j-036"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Export User" id="r1P-hr-mh5">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Export User" id="fnk-gK-yCi">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Secure Export (recommended)" id="06i-og-eLt">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="exportSitesSecure:" target="494" id="LVH-es-imA"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Your passwords are not visible." enabled="NO" id="ybY-P3-eao">
|
||||||
|
<attributedString key="attributedTitle">
|
||||||
|
<fragment content="Your passwords are not visible.">
|
||||||
|
<attributes>
|
||||||
|
<font key="NSFont" metaFont="user"/>
|
||||||
|
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
|
||||||
|
</attributes>
|
||||||
|
</fragment>
|
||||||
|
</attributedString>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Reveal Passwords" id="fMG-TT-bTn">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="exportSitesReveal:" target="494" id="1IW-VT-Oeu"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Keep this file secure or delete it when you're done with it!" enabled="NO" id="cQu-oR-SUa">
|
||||||
|
<attributedString key="attributedTitle">
|
||||||
|
<fragment content="Keep this file secure or delete it when you're done with it!">
|
||||||
|
<attributes>
|
||||||
|
<font key="NSFont" metaFont="user"/>
|
||||||
|
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
|
||||||
|
</attributes>
|
||||||
|
</fragment>
|
||||||
|
</attributedString>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
<menuItem isSeparatorItem="YES" id="759"/>
|
<menuItem isSeparatorItem="YES" id="759"/>
|
||||||
</items>
|
</items>
|
||||||
</menu>
|
</menu>
|
||||||
@@ -152,53 +199,23 @@
|
|||||||
</attributedString>
|
</attributedString>
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem title="Export Sites" id="r1P-hr-mh5">
|
<menuItem title="Diagnostics" id="GSN-f0-q7s">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<menu key="submenu" title="Export Sites" id="fnk-gK-yCi">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Secure Export" id="06i-og-eLt">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="exportSitesSecure:" target="494" id="LVH-es-imA"/>
|
<action selector="togglePreference:" target="494" id="ZNq-yf-fxg"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem title="Your passwords are not visible." enabled="NO" id="ybY-P3-eao">
|
<menuItem title="Crash and usage information is anonymized and sent to development." enabled="NO" id="WfD-lX-C93">
|
||||||
<attributedString key="attributedTitle">
|
<attributedString key="attributedTitle">
|
||||||
<fragment content="Your passwords are not visible.">
|
<fragment content="Crash and usage information is anonymized and sent to development.">
|
||||||
<attributes>
|
<attributes>
|
||||||
<font key="NSFont" size="12" name="Helvetica"/>
|
<font key="NSFont" size="11" name="Helvetica"/>
|
||||||
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
|
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural" firstLineHeadIndent="8"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</fragment>
|
</fragment>
|
||||||
</attributedString>
|
</attributedString>
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem title="Reveal Passwords" id="fMG-TT-bTn">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="exportSitesReveal:" target="494" id="1IW-VT-Oeu"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Keep this file secure or delete it when you're done with it!" enabled="NO" id="cQu-oR-SUa">
|
|
||||||
<attributedString key="attributedTitle">
|
|
||||||
<fragment content="Keep this file secure or delete it when you're done with it!">
|
|
||||||
<attributes>
|
|
||||||
<font key="NSFont" size="12" name="Helvetica"/>
|
|
||||||
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
|
|
||||||
</attributes>
|
|
||||||
</fragment>
|
|
||||||
</attributedString>
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Import Sites..." id="EFK-zt-EvJ">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="importSites:" target="494" id="CNv-4j-036"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
</items>
|
||||||
</menu>
|
</menu>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
@@ -221,6 +238,10 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
</items>
|
</items>
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="494" id="Slu-zT-yO4"/>
|
||||||
|
</connections>
|
||||||
|
<point key="canvasLocation" x="140" y="23"/>
|
||||||
</menu>
|
</menu>
|
||||||
</objects>
|
</objects>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@@ -21,9 +21,9 @@
|
|||||||
#import "MPSitesWindowController.h"
|
#import "MPSitesWindowController.h"
|
||||||
#import "MPInitialWindowController.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) MPSitesWindowController *sitesWindowController;
|
||||||
@property(nonatomic, strong) MPInitialWindowController *initialWindowController;
|
@property(nonatomic, strong) MPInitialWindowController *initialWindowController;
|
||||||
@property(nonatomic, weak) IBOutlet NSMenuItem *lockItem;
|
@property(nonatomic, weak) IBOutlet NSMenuItem *lockItem;
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
@property(nonatomic, weak) IBOutlet NSMenuItem *openAtLoginItem;
|
@property(nonatomic, weak) IBOutlet NSMenuItem *openAtLoginItem;
|
||||||
@property(nonatomic, weak) IBOutlet NSMenuItem *showFullScreenItem;
|
@property(nonatomic, weak) IBOutlet NSMenuItem *showFullScreenItem;
|
||||||
@property(nonatomic, weak) IBOutlet NSMenuItem *savePasswordItem;
|
@property(nonatomic, weak) IBOutlet NSMenuItem *savePasswordItem;
|
||||||
|
@property(nonatomic, weak) IBOutlet NSMenuItem *diagnosticsItem;
|
||||||
@property(nonatomic, weak) IBOutlet NSMenuItem *createUserItem;
|
@property(nonatomic, weak) IBOutlet NSMenuItem *createUserItem;
|
||||||
@property(nonatomic, weak) IBOutlet NSMenuItem *deleteUserItem;
|
@property(nonatomic, weak) IBOutlet NSMenuItem *deleteUserItem;
|
||||||
@property(nonatomic, weak) IBOutlet NSMenuItem *usersItem;
|
@property(nonatomic, weak) IBOutlet NSMenuItem *usersItem;
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
|
|
||||||
@try {
|
@try {
|
||||||
// Sentry
|
// Sentry
|
||||||
[SentrySDK initWithOptions:@{
|
[SentrySDK startWithOptions:@{
|
||||||
@"dsn" : decrypt( sentryDSN ),
|
@"dsn" : NilToNSNull( decrypt( sentryDSN ) ),
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@"debug" : @(YES),
|
@"debug" : @(YES),
|
||||||
@"environment" : @"Development",
|
@"environment" : @"Development",
|
||||||
@@ -80,11 +80,12 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
@"debug" : @(NO),
|
@"debug" : @(NO),
|
||||||
@"environment" : @"Private",
|
@"environment" : @"Private",
|
||||||
#endif
|
#endif
|
||||||
@"enabled" : [MPMacConfig get].sendInfo,
|
@"enabled" : @([[MPMacConfig get].sendInfo boolValue] || ![[MPMacConfig get].sendInfoDecided boolValue]),
|
||||||
|
@"enableAutoSessionTracking": @(YES),
|
||||||
}];
|
}];
|
||||||
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
||||||
PearlLogLevel level = PearlLogLevelWarn;
|
PearlLogLevel level = PearlLogLevelWarn;
|
||||||
if ([[MPConfig get].sendInfo boolValue])
|
if ([[MPMacConfig get].sendInfo boolValue])
|
||||||
level = PearlLogLevelDebug;
|
level = PearlLogLevelDebug;
|
||||||
|
|
||||||
if (message.level >= level) {
|
if (message.level >= level) {
|
||||||
@@ -130,11 +131,11 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
countlyConfig.deviceID = [PearlKeyChain deviceIdentifier];
|
countlyConfig.deviceID = [PearlKeyChain deviceIdentifier];
|
||||||
countlyConfig.secretSalt = decrypt( countlySalt );
|
countlyConfig.secretSalt = decrypt( countlySalt );
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
countlyConfig.pushTestMode = CLYPushTestModeDevelopment;
|
|
||||||
countlyConfig.enableDebug = YES;
|
countlyConfig.enableDebug = YES;
|
||||||
|
countlyConfig.pushTestMode = CLYPushTestModeDevelopment;
|
||||||
#elif !PUBLIC
|
#elif !PUBLIC
|
||||||
countlyConfig.pushTestMode = CLYPushTestModeTestFlightOrAdHoc;
|
|
||||||
countlyConfig.enableDebug = NO;
|
countlyConfig.enableDebug = NO;
|
||||||
|
countlyConfig.pushTestMode = CLYPushTestModeTestFlightOrAdHoc;
|
||||||
#endif
|
#endif
|
||||||
[Countly.sharedInstance startWithConfig:countlyConfig];
|
[Countly.sharedInstance startWithConfig:countlyConfig];
|
||||||
}
|
}
|
||||||
@@ -143,7 +144,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup delegates and listeners.
|
// Setup delegates and listeners.
|
||||||
[MPConfig get].delegate = self;
|
[MPMacConfig get].delegate = self;
|
||||||
__weak id weakSelf = self;
|
__weak id weakSelf = self;
|
||||||
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
||||||
dispatch_async( dispatch_get_main_queue(), ^{
|
dispatch_async( dispatch_get_main_queue(), ^{
|
||||||
@@ -157,12 +158,10 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
} forKeyPath:@"activeUser" options:0 context:nil];
|
} forKeyPath:@"activeUser" options:0 context:nil];
|
||||||
|
|
||||||
// Status item.
|
// Status item.
|
||||||
self.statusView = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
|
self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
|
||||||
self.statusView.image = [NSImage imageNamed:@"menu-icon"];
|
self.statusItem.menu = self.statusMenu;
|
||||||
self.statusView.image.template = YES;
|
self.statusItem.button.image = [NSImage imageNamed:@"menu-icon"];
|
||||||
self.statusView.menu = self.statusMenu;
|
self.statusItem.button.image.template = YES;
|
||||||
self.statusView.target = self;
|
|
||||||
self.statusView.action = @selector( showMenu );
|
|
||||||
|
|
||||||
PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, self.storeCoordinator, nil,
|
PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, self.storeCoordinator, nil,
|
||||||
^(id self, NSNotification *note) {
|
^(id self, NSNotification *note) {
|
||||||
@@ -202,11 +201,13 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
.window makeKeyAndOrderFront:self];
|
.window makeKeyAndOrderFront:self];
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[self tryNotifications];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationWillResignActive:(NSNotification *)notification {
|
- (void)applicationWillResignActive:(NSNotification *)notification {
|
||||||
|
|
||||||
if (![[MPConfig get].rememberLogin boolValue])
|
if (![[MPMacConfig get].rememberLogin boolValue])
|
||||||
[self lock:nil];
|
[self lock:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,6 +228,42 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
return NSTerminateNow;
|
return NSTerminateNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)tryNotifications {
|
||||||
|
|
||||||
|
[Countly.sharedInstance giveConsentForFeature:CLYConsentPushNotifications];
|
||||||
|
if (@available( macOS 10.14, * )) {
|
||||||
|
[Countly.sharedInstance askForNotificationPermissionWithOptions:UNAuthorizationOptionProvisional | UNAuthorizationOptionAlert
|
||||||
|
completionHandler:^(BOOL granted, NSError *error) {
|
||||||
|
if (!granted)
|
||||||
|
err( @"No provisional notification permission: %@", error );
|
||||||
|
|
||||||
|
[self askNotifications];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[self askNotifications];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)askNotifications {
|
||||||
|
|
||||||
|
if ([[MPMacConfig get].notificationsDecided boolValue])
|
||||||
|
return;
|
||||||
|
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - State
|
#pragma mark - State
|
||||||
|
|
||||||
- (void)setActiveUser:(MPUserEntity *)activeUser {
|
- (void)setActiveUser:(MPUserEntity *)activeUser {
|
||||||
@@ -369,10 +406,12 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
|
|
||||||
- (IBAction)togglePreference:(id)sender {
|
- (IBAction)togglePreference:(id)sender {
|
||||||
|
|
||||||
|
if (sender == self.diagnosticsItem)
|
||||||
|
[MPMacConfig get].sendInfo = @(self.diagnosticsItem.state != NSOnState);
|
||||||
if (sender == self.hidePasswordsItem)
|
if (sender == self.hidePasswordsItem)
|
||||||
[MPConfig get].hidePasswords = @(self.hidePasswordsItem.state != NSOnState);
|
[MPMacConfig get].hidePasswords = @(self.hidePasswordsItem.state != NSOnState);
|
||||||
if (sender == self.rememberPasswordItem)
|
if (sender == self.rememberPasswordItem)
|
||||||
[MPConfig get].rememberLogin = @(self.rememberPasswordItem.state != NSOnState);
|
[MPMacConfig get].rememberLogin = @(self.rememberPasswordItem.state != NSOnState);
|
||||||
if (sender == self.openAtLoginItem)
|
if (sender == self.openAtLoginItem)
|
||||||
[self setLoginItemEnabled:self.openAtLoginItem.state != NSOnState];
|
[self setLoginItemEnabled:self.openAtLoginItem.state != NSOnState];
|
||||||
if (sender == self.showFullScreenItem) {
|
if (sender == self.showFullScreenItem) {
|
||||||
@@ -461,7 +500,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
|
|
||||||
- (IBAction)showPopup:(id)sender {
|
- (IBAction)showPopup:(id)sender {
|
||||||
|
|
||||||
[self.statusView popUpStatusItemMenu:self.statusView.menu];
|
[[self.statusItem button] performClick:sender];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)showPasswordWindow:(id)sender {
|
- (IBAction)showPasswordWindow:(id)sender {
|
||||||
@@ -505,15 +544,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
return;
|
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];
|
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
||||||
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
||||||
|
|
||||||
@@ -538,11 +568,13 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
if ([savePanel runModal] == NSFileHandlingPanelCancelButton)
|
if ([savePanel runModal] == NSFileHandlingPanelCancelButton)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[self exportSitesRevealPasswords:revealPasswords
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
askExportPassword:^NSString *(NSString *userName) {
|
NSError *error = nil;
|
||||||
|
NSString *exportedUser = [self exportSitesFor:[self activeUserInContext:context] revealPasswords:revealPasswords askExportPassword:
|
||||||
|
^NSString *(NSString *userName) {
|
||||||
return PearlMainQueueAwait( ^id {
|
return PearlMainQueueAwait( ^id {
|
||||||
NSAlert *alert = [NSAlert new];
|
NSAlert *alert = [NSAlert new];
|
||||||
[alert addButtonWithTitle:@"Import"];
|
[alert addButtonWithTitle:@"Export"];
|
||||||
[alert addButtonWithTitle:@"Cancel"];
|
[alert addButtonWithTitle:@"Cancel"];
|
||||||
alert.messageText = strf( @"Master Password For\n%@", userName );
|
alert.messageText = strf( @"Master Password For\n%@", userName );
|
||||||
alert.informativeText = @"Enter the current master password for this user.";
|
alert.informativeText = @"Enter the current master password for this user.";
|
||||||
@@ -553,19 +585,20 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
else
|
else
|
||||||
return nil;
|
return nil;
|
||||||
} );
|
} );
|
||||||
} result:^(NSString *mpsites, NSError *error) {
|
} error:&error];
|
||||||
if (!mpsites || error) {
|
|
||||||
|
if (error)
|
||||||
PearlMainQueue( ^{
|
PearlMainQueue( ^{
|
||||||
[[NSAlert alertWithError:MPError( error, @"Failed to export mpsites." )] runModal];
|
[[NSAlert alertWithError:MPError( error, @"Failed to export mpsites." )] runModal];
|
||||||
} );
|
} );
|
||||||
|
if (!exportedUser)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
NSError *coordinateError = nil;
|
NSError *coordinateError = nil;
|
||||||
[[[NSFileCoordinator alloc] initWithFilePresenter:nil]
|
[[[NSFileCoordinator alloc] initWithFilePresenter:nil]
|
||||||
coordinateWritingItemAtURL:savePanel.URL options:0 error:&coordinateError byAccessor:^(NSURL *newURL) {
|
coordinateWritingItemAtURL:savePanel.URL options:0 error:&coordinateError byAccessor:^(NSURL *newURL) {
|
||||||
NSError *writeError = nil;
|
NSError *writeError = nil;
|
||||||
if (![mpsites writeToURL:newURL atomically:NO encoding:NSUTF8StringEncoding error:&writeError])
|
if (![exportedUser writeToURL:newURL atomically:NO encoding:NSUTF8StringEncoding error:&writeError])
|
||||||
PearlMainQueue( ^{
|
PearlMainQueue( ^{
|
||||||
[[NSAlert alertWithError:MPError( writeError, @"Could not write to the export file." )] runModal];
|
[[NSAlert alertWithError:MPError( writeError, @"Could not write to the export file." )] runModal];
|
||||||
} );
|
} );
|
||||||
@@ -579,10 +612,13 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
|
|
||||||
- (void)updateUsers {
|
- (void)updateUsers {
|
||||||
|
|
||||||
[[[self.usersItem submenu] itemArray] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
|
BOOL foundSeparator = NO;
|
||||||
if (idx > 2)
|
for (NSMenuItem *item in [[self.usersItem submenu] itemArray]) {
|
||||||
[[self.usersItem submenu] removeItem:obj];
|
if (foundSeparator)
|
||||||
}];
|
[[self.usersItem submenu] removeItem:item];
|
||||||
|
else if (item.isSeparatorItem)
|
||||||
|
foundSeparator = YES;
|
||||||
|
}
|
||||||
|
|
||||||
NSManagedObjectContext *mainContext = [MPMacAppDelegate managedObjectContextForMainThreadIfReady];
|
NSManagedObjectContext *mainContext = [MPMacAppDelegate managedObjectContextForMainThreadIfReady];
|
||||||
if (!mainContext) {
|
if (!mainContext) {
|
||||||
@@ -644,13 +680,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
[self updateMenuItems];
|
[self updateMenuItems];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showMenu {
|
|
||||||
|
|
||||||
[self updateMenuItems];
|
|
||||||
|
|
||||||
[self.statusView popUpStatusItemMenu:self.statusView.menu];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)updateMenuItems {
|
- (void)updateMenuItems {
|
||||||
|
|
||||||
MPUserEntity *activeUser = [self activeUserForMainThread];
|
MPUserEntity *activeUser = [self activeUserForMainThread];
|
||||||
@@ -679,10 +708,13 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL loginItemEnabled = [self loginItemEnabled];
|
BOOL loginItemEnabled = [self loginItemEnabled];
|
||||||
|
self.initialWindowController.openAtLoginButton.state = loginItemEnabled? NSOnState: NSOffState;
|
||||||
self.openAtLoginItem.state = loginItemEnabled? NSOnState: NSOffState;
|
self.openAtLoginItem.state = loginItemEnabled? NSOnState: NSOffState;
|
||||||
self.showFullScreenItem.state = [[MPMacConfig get].fullScreen boolValue]? NSOnState: NSOffState;
|
self.showFullScreenItem.state = [[MPMacConfig get].fullScreen boolValue]? NSOnState: NSOffState;
|
||||||
self.initialWindowController.openAtLoginButton.state = loginItemEnabled? NSOnState: NSOffState;
|
self.rememberPasswordItem.state = [[MPMacConfig get].rememberLogin boolValue]? NSOnState: NSOffState;
|
||||||
self.rememberPasswordItem.state = [[MPConfig get].rememberLogin boolValue]? NSOnState: NSOffState;
|
self.diagnosticsItem.state = [[MPMacConfig get].sendInfo boolValue]? NSOnState: NSOffState;
|
||||||
|
self.hidePasswordsItem.state = [[MPMacConfig get].hidePasswords boolValue]? NSOnState: NSOffState;
|
||||||
|
self.rememberPasswordItem.state = [[MPMacConfig get].rememberLogin boolValue]? NSOnState: NSOffState;
|
||||||
|
|
||||||
self.savePasswordItem.state = activeUser.saveKey? NSOnState: NSOffState;
|
self.savePasswordItem.state = activeUser.saveKey? NSOnState: NSOffState;
|
||||||
if (!activeUser) {
|
if (!activeUser) {
|
||||||
@@ -702,6 +734,13 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSMenuDelegate
|
||||||
|
|
||||||
|
- (void)menuNeedsUpdate:(NSMenu *)menu {
|
||||||
|
|
||||||
|
[self updateMenuItems];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - PearlConfigDelegate
|
#pragma mark - PearlConfigDelegate
|
||||||
|
|
||||||
- (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)oldValue {
|
- (void)didUpdateConfigForKey:(SEL)configKey fromValue:(id)oldValue {
|
||||||
@@ -712,39 +751,42 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
- (void)updateConfigKey:(NSString *)key {
|
- (void)updateConfigKey:(NSString *)key {
|
||||||
|
|
||||||
PearlMainQueue( ^{
|
PearlMainQueue( ^{
|
||||||
|
if (!key || [key isEqualToString:NSStringFromSelector( @selector( sendInfo ) )])
|
||||||
|
self.diagnosticsItem.state = [[MPMacConfig get].sendInfo boolValue]? NSOnState: NSOffState;
|
||||||
if (!key || [key isEqualToString:NSStringFromSelector( @selector( hidePasswords ) )])
|
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 ) )])
|
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
|
// Send info
|
||||||
if ([[MPConfig get].sendInfo boolValue]) {
|
NSArray *countlyFeatures = @[
|
||||||
[Countly.sharedInstance giveConsentForAllFeatures];
|
CLYConsentSessions, CLYConsentEvents, CLYConsentUserDetails, CLYConsentCrashReporting, CLYConsentViewTracking, CLYConsentStarRating
|
||||||
|
];
|
||||||
|
if ([[MPMacConfig get].sendInfo boolValue] || ![[MPMacConfig get].sendInfoDecided boolValue]) {
|
||||||
if ([PearlLogger get].printLevel > PearlLogLevelInfo)
|
if ([PearlLogger get].printLevel > PearlLogLevelInfo)
|
||||||
[PearlLogger get].printLevel = PearlLogLevelInfo;
|
[PearlLogger get].printLevel = PearlLogLevelInfo;
|
||||||
|
|
||||||
NSMutableDictionary *prefs = [NSMutableDictionary new];
|
[SentrySDK.currentHub getClient].options.enabled = @YES;
|
||||||
prefs[@"rememberLogin"] = [MPConfig get].rememberLogin;
|
|
||||||
prefs[@"sendInfo"] = [MPConfig get].sendInfo;
|
|
||||||
prefs[@"fullScreen"] = [MPMacConfig get].fullScreen;
|
|
||||||
prefs[@"firstRun"] = [PearlConfig get].firstRun;
|
|
||||||
prefs[@"launchCount"] = [PearlConfig get].launchCount;
|
|
||||||
prefs[@"askForReviews"] = [PearlConfig get].askForReviews;
|
|
||||||
prefs[@"reviewAfterLaunches"] = [PearlConfig get].reviewAfterLaunches;
|
|
||||||
prefs[@"reviewedVersion"] = [PearlConfig get].reviewedVersion;
|
|
||||||
prefs[@"simulator"] = @([PearlDeviceUtils isSimulator]);
|
|
||||||
prefs[@"encrypted"] = @([PearlDeviceUtils isAppEncrypted]);
|
|
||||||
prefs[@"platform"] = [PearlDeviceUtils platform];
|
|
||||||
|
|
||||||
[SentrySDK configureScope:^(SentryScope *scope) {
|
[SentrySDK configureScope:^(SentryScope *scope) {
|
||||||
for (NSString *pref in prefs.allKeys)
|
[scope setExtraValue:[MPMacConfig get].rememberLogin forKey:@"rememberLogin"];
|
||||||
[scope setExtraValue:prefs[pref] forKey:pref];
|
[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"];
|
||||||
|
[scope setExtraValue:[PearlConfig get].askForReviews forKey:@"askForReviews"];
|
||||||
|
[scope setExtraValue:[PearlConfig get].reviewAfterLaunches forKey:@"reviewAfterLaunches"];
|
||||||
|
[scope setExtraValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"];
|
||||||
|
[scope setExtraValue:@([PearlDeviceUtils isSimulator]) forKey:@"simulator"];
|
||||||
|
[scope setExtraValue:@([PearlDeviceUtils isAppEncrypted]) forKey:@"encrypted"];
|
||||||
|
[scope setExtraValue:[PearlDeviceUtils platform] forKey:@"platform"];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
[Countly.sharedInstance giveConsentForFeatures:countlyFeatures];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
[Countly.sharedInstance cancelConsentForAllFeatures];
|
[Countly.sharedInstance cancelConsentForFeatures:countlyFeatures];
|
||||||
|
[SentrySDK.currentHub getClient].options.enabled = @NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
@property(nonatomic, readonly) BOOL stored;
|
@property(nonatomic, readonly) BOOL stored;
|
||||||
@property(nonatomic, readonly) BOOL transient;
|
@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;
|
- (instancetype)initWithName:(NSString *)siteName forUser:(MPUserEntity *)user;
|
||||||
- (MPSiteEntity *)entityInContext:(NSManagedObjectContext *)moc;
|
- (MPSiteEntity *)entityInContext:(NSManagedObjectContext *)moc;
|
||||||
|
|
||||||
|
|||||||
@@ -31,12 +31,12 @@
|
|||||||
|
|
||||||
@implementation MPSiteModel
|
@implementation MPSiteModel
|
||||||
|
|
||||||
- (instancetype)initWithEntity:(MPSiteEntity *)entity fuzzyGroups:(NSArray *)fuzzyGroups {
|
- (instancetype)initWithEntity:(MPSiteEntity *)entity queryGroups:(NSArray *)queryGroups {
|
||||||
|
|
||||||
if (!(self = [super init]))
|
if (!(self = [super init]))
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
[self setEntity:entity fuzzyGroups:fuzzyGroups];
|
[self setEntity:entity queryGroups:queryGroups];
|
||||||
self.initialized = YES;
|
self.initialized = YES;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -53,23 +53,25 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setEntity:(MPSiteEntity *)entity fuzzyGroups:(NSArray *)fuzzyGroups {
|
- (void)setEntity:(MPSiteEntity *)entity queryGroups:(NSArray *)queryGroups {
|
||||||
|
|
||||||
if ([self.entityOID isEqual:entity.permanentObjectID])
|
if ([self.entityOID isEqual:entity.permanentObjectID])
|
||||||
return;
|
return;
|
||||||
self.entityOID = entity.permanentObjectID;
|
self.entityOID = entity.permanentObjectID;
|
||||||
|
|
||||||
NSString *siteName = entity.name;
|
NSString *siteName = entity.name;
|
||||||
NSMutableAttributedString *attributedSiteName = [[NSMutableAttributedString alloc] initWithString:siteName];
|
NSMutableAttributedString *attributedSiteName = [[NSMutableAttributedString alloc] initWithString:siteName?: @""];
|
||||||
for (NSUInteger f = 0, s = (NSUInteger)-1; f < [fuzzyGroups count]; ++f) {
|
if ([attributedSiteName length])
|
||||||
s = [siteName rangeOfString:fuzzyGroups[f] options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch
|
for (NSUInteger f = 0, s = 0; f < [queryGroups count]; ++f, ++s) {
|
||||||
range:NSMakeRange( s + 1, [siteName length] - (s + 1) )].location;
|
s = [siteName rangeOfString:queryGroups[f] options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch
|
||||||
|
range:NSMakeRange( s, [siteName length] - s )].location;
|
||||||
if (s == NSNotFound)
|
if (s == NSNotFound)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
[attributedSiteName addAttribute:NSBackgroundColorAttributeName value:[NSColor alternateSelectedControlColor]
|
[attributedSiteName addAttribute:NSBackgroundColorAttributeName value:[NSColor alternateSelectedControlColor]
|
||||||
range:NSMakeRange( s, [fuzzyGroups[f] length] )];
|
range:NSMakeRange( s, [queryGroups[f] length] )];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
|
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
|
||||||
paragraphStyle.alignment = NSCenterTextAlignment;
|
paragraphStyle.alignment = NSCenterTextAlignment;
|
||||||
[attributedSiteName addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange( 0, [siteName length] )];
|
[attributedSiteName addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange( 0, [siteName length] )];
|
||||||
@@ -179,7 +181,8 @@
|
|||||||
if (algorithmVersion == self.algorithm.version)
|
if (algorithmVersion == self.algorithm.version)
|
||||||
return;
|
return;
|
||||||
[self willChangeValueForKey:@"outdated"];
|
[self willChangeValueForKey:@"outdated"];
|
||||||
self.algorithm = MPAlgorithmForVersion( algorithmVersion )?: self.algorithm;
|
self.algorithm =
|
||||||
|
MPAlgorithmForVersion( MIN( MPAlgorithmVersionLast, MAX( MPAlgorithmVersionFirst, algorithmVersion ) ) )?: self.algorithm;
|
||||||
[self didChangeValueForKey:@"outdated"];
|
[self didChangeValueForKey:@"outdated"];
|
||||||
|
|
||||||
if (self.entityOID)
|
if (self.entityOID)
|
||||||
@@ -270,6 +273,8 @@
|
|||||||
|
|
||||||
PearlMainQueue( ^{
|
PearlMainQueue( ^{
|
||||||
self.content = result;
|
self.content = result;
|
||||||
|
|
||||||
|
if (!([NSEvent modifierFlags] & NSShiftKeyMask))
|
||||||
self.displayedContent = displayResult;
|
self.displayedContent = displayResult;
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
@@ -278,6 +283,9 @@
|
|||||||
|
|
||||||
PearlMainQueue( ^{
|
PearlMainQueue( ^{
|
||||||
self.loginName = loginName;
|
self.loginName = loginName;
|
||||||
|
|
||||||
|
if ([NSEvent modifierFlags] & NSShiftKeyMask)
|
||||||
|
self.displayedContent = loginName;
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#import <QuartzCore/QuartzCore.h>
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
#import <Countly/Countly.h>
|
||||||
|
#import <UserNotifications/UserNotifications.h>
|
||||||
#import "MPSitesWindowController.h"
|
#import "MPSitesWindowController.h"
|
||||||
#import "MPMacAppDelegate.h"
|
#import "MPMacAppDelegate.h"
|
||||||
#import "MPAppDelegate_Store.h"
|
#import "MPAppDelegate_Store.h"
|
||||||
@@ -42,13 +44,27 @@
|
|||||||
prof_rewind( @"replaceFonts" );
|
prof_rewind( @"replaceFonts" );
|
||||||
|
|
||||||
PearlAddNotificationObserver( NSWindowDidBecomeKeyNotification, self.window, [NSOperationQueue mainQueue],
|
PearlAddNotificationObserver( NSWindowDidBecomeKeyNotification, self.window, [NSOperationQueue mainQueue],
|
||||||
^(id host, NSNotification *note) {
|
(^(id host, NSNotification *note) {
|
||||||
prof_new( @"didBecomeKey" );
|
prof_new( @"didBecomeKey" );
|
||||||
[self.window makeKeyAndOrderFront:nil];
|
[self.window makeKeyAndOrderFront:nil];
|
||||||
prof_rewind( @"fadeIn" );
|
prof_rewind( @"fadeIn" );
|
||||||
[self updateUser];
|
[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],
|
PearlAddNotificationObserver( NSWindowWillCloseNotification, self.window, [NSOperationQueue mainQueue],
|
||||||
^(id host, NSNotification *note) {
|
^(id host, NSNotification *note) {
|
||||||
NSWindow *sheet = [self.window attachedSheet];
|
NSWindow *sheet = [self.window attachedSheet];
|
||||||
@@ -66,7 +82,7 @@
|
|||||||
[self updateUser];
|
[self updateUser];
|
||||||
} );
|
} );
|
||||||
[self observeKeyPath:@"sitesController.selection" withBlock:^(id from, id to, NSKeyValueChange cause, id self) {
|
[self observeKeyPath:@"sitesController.selection" withBlock:^(id from, id to, NSKeyValueChange cause, id self) {
|
||||||
[self updateSelection];
|
[self updateTable];
|
||||||
}];
|
}];
|
||||||
prof_rewind( @"observers" );
|
prof_rewind( @"observers" );
|
||||||
|
|
||||||
@@ -81,7 +97,16 @@
|
|||||||
self.siteTable.superview.superview.layer.mask = self.siteGradient;
|
self.siteTable.superview.superview.layer.mask = self.siteGradient;
|
||||||
|
|
||||||
self.siteTable.controller = self;
|
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 {
|
- (void)dealloc {
|
||||||
@@ -105,14 +130,18 @@
|
|||||||
- (void)flagsChanged:(NSEvent *)theEvent {
|
- (void)flagsChanged:(NSEvent *)theEvent {
|
||||||
|
|
||||||
BOOL shiftPressed = (theEvent.modifierFlags & NSShiftKeyMask) != 0;
|
BOOL shiftPressed = (theEvent.modifierFlags & NSShiftKeyMask) != 0;
|
||||||
if (shiftPressed != self.shiftPressed)
|
if (shiftPressed != self.shiftPressed) {
|
||||||
self.shiftPressed = shiftPressed;
|
self.shiftPressed = shiftPressed;
|
||||||
|
[self.selectedSite updateContent];
|
||||||
|
[self updateSelection];
|
||||||
|
}
|
||||||
|
|
||||||
BOOL alternatePressed = (theEvent.modifierFlags & NSAlternateKeyMask) != 0;
|
BOOL alternatePressed = (theEvent.modifierFlags & NSAlternateKeyMask) != 0;
|
||||||
if (alternatePressed != self.alternatePressed) {
|
if (alternatePressed != self.alternatePressed) {
|
||||||
self.alternatePressed = alternatePressed;
|
self.alternatePressed = alternatePressed;
|
||||||
self.showVersionContainer = self.alternatePressed || self.selectedSite.outdated;
|
self.showVersionContainer = self.alternatePressed || self.selectedSite.outdated;
|
||||||
[self.selectedSite updateContent];
|
[self.selectedSite updateContent];
|
||||||
|
[self updateSelection];
|
||||||
|
|
||||||
if (self.locked) {
|
if (self.locked) {
|
||||||
NSTextField *passwordField = self.securePasswordField;
|
NSTextField *passwordField = self.securePasswordField;
|
||||||
@@ -261,6 +290,9 @@
|
|||||||
[alert setInformativeText:strf( @"Your login name for: %@", self.selectedSite.name )];
|
[alert setInformativeText:strf( @"Your login name for: %@", self.selectedSite.name )];
|
||||||
NSTextField *loginField = [NSTextField new];
|
NSTextField *loginField = [NSTextField new];
|
||||||
[loginField bind:@"value" toObject:self.selectedSite withKeyPath:@"loginName" options:nil];
|
[loginField bind:@"value" toObject:self.selectedSite withKeyPath:@"loginName" options:nil];
|
||||||
|
[loginField bind:@"enabled" toObject:self.selectedSite withKeyPath:@"loginGenerated" options:@{
|
||||||
|
NSValueTransformerNameBindingOption: NSNegateBooleanTransformerName
|
||||||
|
}];
|
||||||
NSButton *generatedField = [NSButton new];
|
NSButton *generatedField = [NSButton new];
|
||||||
[generatedField setButtonType:NSSwitchButton];
|
[generatedField setButtonType:NSSwitchButton];
|
||||||
[generatedField bind:@"value" toObject:self.selectedSite withKeyPath:@"loginGenerated" options:nil];
|
[generatedField bind:@"value" toObject:self.selectedSite withKeyPath:@"loginGenerated" options:nil];
|
||||||
@@ -369,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;
|
MPSiteModel *site = self.selectedSite;
|
||||||
NSArray *types = [site.algorithm allTypes];
|
NSArray *types = [site.algorithm allTypes];
|
||||||
@@ -477,16 +554,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Performing action while content is available. Copy it.
|
// Performing action while content is available. Copy it.
|
||||||
[self copyContent:self.shiftPressed? selectedSite.answer: selectedSite.content];
|
[self copyContent:self.shiftPressed? selectedSite.loginName: selectedSite.content];
|
||||||
[NSApp hide:nil];
|
[NSApp hide:nil];
|
||||||
|
|
||||||
NSUserNotification *notification = [NSUserNotification new];
|
if (@available( macOS 10.14, * )) {
|
||||||
notification.title = @"Password Copied";
|
UNMutableNotificationContent *notification = [UNMutableNotificationContent new];
|
||||||
|
notification.title = self.shiftPressed? @"Login Copied": @"Password Copied";
|
||||||
if (selectedSite.loginName.length)
|
if (selectedSite.loginName.length)
|
||||||
notification.subtitle = strf( @"%@ at %@", selectedSite.loginName, selectedSite.name );
|
notification.subtitle = strf( @"%@ at %@", selectedSite.loginName, selectedSite.name );
|
||||||
else
|
else
|
||||||
notification.subtitle = selectedSite.name;
|
notification.subtitle = selectedSite.name;
|
||||||
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
|
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:
|
||||||
|
[UNNotificationRequest requestWithIdentifier:selectedSite.name content:notification trigger:nil]
|
||||||
|
withCompletionHandler:^(NSError *error) {
|
||||||
|
dbg( @"notification: %@, completed w/errror: %@", notification, error );
|
||||||
|
}];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateUser {
|
- (void)updateUser {
|
||||||
@@ -528,22 +611,20 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NSRegularExpression *fuzzyRE;
|
|
||||||
static dispatch_once_t once = 0;
|
|
||||||
dispatch_once( &once, ^{
|
|
||||||
fuzzyRE = [NSRegularExpression regularExpressionWithPattern:@"(.)" options:0 error:nil];
|
|
||||||
} );
|
|
||||||
|
|
||||||
prof_new( @"updateSites" );
|
prof_new( @"updateSites" );
|
||||||
NSString *queryString = self.siteField.stringValue;
|
NSString *queryString = self.siteField.stringValue;
|
||||||
NSString *queryPattern = [[queryString stringByReplacingMatchesOfExpression:fuzzyRE withTemplate:@"*$1"] stringByAppendingString:@"*"];
|
NSMutableArray *queryGroups = [NSMutableArray new];
|
||||||
prof_rewind( @"queryPattern" );
|
NSMutableString *queryPattern = [NSMutableString new];
|
||||||
NSMutableArray *fuzzyGroups = [NSMutableArray new];
|
[queryString enumerateSubstringsInRange: NSMakeRange(0, [queryString length]) options: NSStringEnumerationByComposedCharacterSequences
|
||||||
[fuzzyRE enumerateMatchesInString:queryString options:0 range:NSMakeRange( 0, queryString.length )
|
usingBlock: ^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
|
||||||
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
if (substringRange.location < 10) {
|
||||||
[fuzzyGroups addObject:[queryString substringWithRange:result.range]];
|
[queryGroups addObject:substring];
|
||||||
|
[queryPattern appendString:@"*"];
|
||||||
|
}
|
||||||
|
[queryPattern appendString:substring];
|
||||||
}];
|
}];
|
||||||
prof_rewind( @"fuzzyRE" );
|
[queryPattern appendString:@"*"];
|
||||||
|
prof_rewind( @"queryPattern" );
|
||||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
prof_rewind( @"moc" );
|
prof_rewind( @"moc" );
|
||||||
|
|
||||||
@@ -565,7 +646,7 @@
|
|||||||
BOOL exact = NO;
|
BOOL exact = NO;
|
||||||
NSMutableArray *newSites = [NSMutableArray arrayWithCapacity:[siteResults count]];
|
NSMutableArray *newSites = [NSMutableArray arrayWithCapacity:[siteResults count]];
|
||||||
for (MPSiteEntity *site in siteResults) {
|
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];
|
exact |= [site.name isEqualToString:queryString];
|
||||||
}
|
}
|
||||||
prof_rewind( @"newSites: %u, exact: %d", (uint)[siteResults count], exact );
|
prof_rewind( @"newSites: %u, exact: %d", (uint)[siteResults count], exact );
|
||||||
@@ -582,7 +663,7 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateSelection {
|
- (void)updateTable {
|
||||||
|
|
||||||
[self.siteTable scrollRowToVisible:(NSInteger)self.sitesController.selectionIndex];
|
[self.siteTable scrollRowToVisible:(NSInteger)self.sitesController.selectionIndex];
|
||||||
|
|
||||||
@@ -596,8 +677,13 @@
|
|||||||
(__bridge id)[NSColor colorWithDeviceWhite:1 alpha:gradientOpacity].CGColor
|
(__bridge id)[NSColor colorWithDeviceWhite:1 alpha:gradientOpacity].CGColor
|
||||||
];
|
];
|
||||||
|
|
||||||
|
[self updateSelection];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateSelection {
|
||||||
self.showVersionContainer = self.alternatePressed || self.selectedSite.outdated;
|
self.showVersionContainer = self.alternatePressed || self.selectedSite.outdated;
|
||||||
[self.sitePasswordTipField setAttributedStringValue:straf( @"Your password for %@:", self.selectedSite.displayedName )];
|
[self.sitePasswordTipField setAttributedStringValue:
|
||||||
|
straf( @"Your %@ for %@:", self.shiftPressed? @"login": @"password", self.selectedSite.displayedName, nil )];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)createNewSite:(NSString *)siteName {
|
- (void)createNewSite:(NSString *)siteName {
|
||||||
|
|||||||
@@ -31,20 +31,20 @@
|
|||||||
<rect key="contentRect" x="0.0" y="0.0" width="640" height="577"/>
|
<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"/>
|
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||||
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ" userLabel="Root">
|
<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"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<visualEffectView blendingMode="behindWindow" material="popover" state="followsWindowActiveState" translatesAutoresizingMaskIntoConstraints="NO" id="eRe-Ef-AZx">
|
<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>
|
</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">
|
<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>
|
</progressIndicator>
|
||||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="NGk-Io-Buc" userLabel="Top Box">
|
<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>
|
<subviews>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ond-dT-x5d" userLabel="Site Password Label">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ia6-7b-dFr">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -108,13 +108,13 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OaQ-of-zmb" userLabel="Initial Help">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</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">
|
<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="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@@ -136,18 +136,18 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="sYt-eL-uwt" userLabel="Initial Tip">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" id="9c4-NI-NM0">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" id="9c4-NI-NM0">
|
||||||
<font key="font" size="12" name="HelveticaNeue"/>
|
<font key="font" metaFont="message" size="11"/>
|
||||||
<string key="title">– When you create an account with a site, use Master Password to create a password for it.
|
<string key="title">⑴ When you create an account on a site, open Master Password to create your account password.
|
||||||
– For accounts you already have, change the password to that created by Master Password for it.
|
⑵ Consider changing all your existing account passwords to the password Master Password creates for those sites.
|
||||||
– To get a password, enter the site's bare domain name in the "site name" field (eg. apple.com).
|
⑶ To get the password for a site, just enter its 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*.
|
⑷ When chosing a master password, make it easy but long (eg. a short sentence).
|
||||||
– It's OK to share your site passwords. They can be changed if necessary.</string>
|
⑸ 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="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="XUV-zU-Y9c" userLabel="Site Password">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
<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 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="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 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="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="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"/>
|
<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 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="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="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="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 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"/>
|
<constraint firstAttribute="centerY" secondItem="sYt-eL-uwt" secondAttribute="centerY" id="zLS-QG-MKS"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</customView>
|
</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">
|
<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">
|
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="e11-59-xSS">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="512" height="177"/>
|
<rect key="frame" x="0.0" y="0.0" width="512" height="177"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
@@ -251,7 +251,7 @@
|
|||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" alignment="center" title="apple.com" id="o0g-Zv-pH4">
|
<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="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@@ -310,7 +310,7 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</scrollView>
|
</scrollView>
|
||||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="nM8-O3-spM" customClass="MPGradientView">
|
<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>
|
<userDefinedRuntimeAttributes>
|
||||||
<userDefinedRuntimeAttribute type="color" keyPath="startingColor">
|
<userDefinedRuntimeAttribute type="color" keyPath="startingColor">
|
||||||
<color key="value" red="0.11764705882352941" green="0.11764705882352941" blue="0.11764705882352941" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="value" red="0.11764705882352941" green="0.11764705882352941" blue="0.11764705882352941" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
@@ -324,7 +324,7 @@
|
|||||||
</userDefinedRuntimeAttributes>
|
</userDefinedRuntimeAttributes>
|
||||||
</customView>
|
</customView>
|
||||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="Aue-Zx-6Mf" userLabel="Settings Gear">
|
<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">
|
<shadow key="shadow">
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
@@ -339,7 +339,7 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gAU-xs-aae">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -358,7 +358,7 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OnR-s6-d4P" userLabel="Site Name Label">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -370,7 +370,7 @@
|
|||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<secureTextField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="iGR-wo-ual" userLabel="Secure Master Password">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -405,7 +405,7 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</secureTextField>
|
</secureTextField>
|
||||||
<textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="v80-wd-hUR" userLabel="Revealed Master Password">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -444,13 +444,13 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="lW3-2z-cEa" userLabel="Master Password Tip">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Hold alt ⌥ to reveal tips and unmask ●●●●●●●●." id="4Ep-xX-Ky8">
|
<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="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@@ -471,13 +471,13 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Oy5-B7-hdN" userLabel="Revealed Master Password Tip">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</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">
|
<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="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@@ -499,7 +499,7 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<searchField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="CnS-iI-dhr" userLabel="Site Name">
|
<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>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="512" id="rW7-Vq-4Xy"/>
|
<constraint firstAttribute="width" constant="512" id="rW7-Vq-4Xy"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
@@ -508,7 +508,7 @@
|
|||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<searchFieldCell key="cell" selectable="YES" editable="YES" focusRingType="none" alignment="center" placeholderString="Site Name" sendsSearchStringImmediately="YES" id="ppl-2c-1E9">
|
<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="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</searchFieldCell>
|
</searchFieldCell>
|
||||||
@@ -519,13 +519,13 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</searchField>
|
</searchField>
|
||||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="npC-Kk-gUM" userLabel="Site Name Tip">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</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">
|
<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="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@@ -542,13 +542,13 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="rhm-sC-xFS" userLabel="Site Name Tip">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" id="n3W-XU-dya">
|
<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.
|
<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>
|
Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
<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>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<stackView distribution="fill" orientation="horizontal" alignment="bottom" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pHt-gg-ZNX">
|
<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>
|
<subviews>
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1Qo-iG-CQt">
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1Qo-iG-CQt">
|
||||||
<rect key="frame" x="0.0" y="-1" width="85" height="19"/>
|
<rect key="frame" x="0.0" y="-1" width="85" height="19"/>
|
||||||
@@ -591,10 +591,10 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<stackView distribution="fill" orientation="vertical" alignment="centerX" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DT0-RU-3LT">
|
<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>
|
<subviews>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="uol-dE-I8H">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -631,7 +631,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="brI-fg-Kav">
|
<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">
|
<shadow key="shadow">
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
@@ -659,6 +659,35 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</binding>
|
</binding>
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</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">
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="R46-fx-n14">
|
||||||
<rect key="frame" x="0.0" y="85" width="177" height="19"/>
|
<rect key="frame" x="0.0" y="85" width="177" height="19"/>
|
||||||
<shadow key="shadow">
|
<shadow key="shadow">
|
||||||
@@ -686,26 +715,26 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</connections>
|
</connections>
|
||||||
</button>
|
</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">
|
<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>
|
<subviews>
|
||||||
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mcq-qD-yte">
|
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mcq-qD-yte">
|
||||||
<rect key="frame" x="-3" y="-3" width="19" height="28"/>
|
<rect key="frame" x="-3" y="-3" width="19" height="28"/>
|
||||||
<shadow key="shadow">
|
<shadow key="shadow">
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</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>
|
<connections>
|
||||||
<binding destination="mcS-ik-b0n" name="value" keyPath="selection.algorithmVersion" id="GyA-hK-6cD"/>
|
<binding destination="mcS-ik-b0n" name="value" keyPath="selection.algorithmVersion" id="GyA-hK-6cD"/>
|
||||||
</connections>
|
</connections>
|
||||||
</stepper>
|
</stepper>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gyg-Fh-yn7">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="V1" id="Pjy-Fm-zwB">
|
<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="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="calibratedRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="calibratedRGB"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@@ -740,26 +769,26 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</connections>
|
</connections>
|
||||||
</stackView>
|
</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">
|
<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>
|
<subviews>
|
||||||
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="XgA-Vl-CKh" userLabel="Counter Stepper">
|
<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"/>
|
<rect key="frame" x="-3" y="-3" width="19" height="28"/>
|
||||||
<shadow key="shadow">
|
<shadow key="shadow">
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</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>
|
<connections>
|
||||||
<binding destination="mcS-ik-b0n" name="value" keyPath="selection.counter" id="qmm-6z-boy"/>
|
<binding destination="mcS-ik-b0n" name="value" keyPath="selection.counter" id="qmm-6z-boy"/>
|
||||||
</connections>
|
</connections>
|
||||||
</stepper>
|
</stepper>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="NvO-kt-eZ2" userLabel="Counter Field">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="1" id="dhQ-bJ-rn3">
|
<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="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="calibratedRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="calibratedRGB"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@@ -805,7 +834,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<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">
|
<binding destination="mcS-ik-b0n" name="hidden" keyPath="canRemove" id="Hat-GU-hcQ">
|
||||||
<dictionary key="options">
|
<dictionary key="options">
|
||||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
<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"/>
|
||||||
<integer value="1000"/>
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
</visibilityPriorities>
|
</visibilityPriorities>
|
||||||
<customSpacing>
|
<customSpacing>
|
||||||
<real value="3.4028234663852886e+38"/>
|
<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"/>
|
||||||
<real value="3.4028234663852886e+38"/>
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
</customSpacing>
|
</customSpacing>
|
||||||
</stackView>
|
</stackView>
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="whJ-Bw-pr4">
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="whJ-Bw-pr4">
|
||||||
@@ -886,7 +917,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</customSpacing>
|
</customSpacing>
|
||||||
</stackView>
|
</stackView>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="luC-0j-BeV">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -923,7 +954,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gjx-bt-fKM">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -960,7 +991,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="dbM-ja-dKO" userLabel="Version Tip">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -988,13 +1019,13 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ido-NQ-3MY">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘L" id="fUB-rF-7x8">
|
<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="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@@ -1016,7 +1047,7 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="9b3-wy-KBb">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -1044,13 +1075,13 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="qal-PP-YtO">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘D" id="PPC-be-w4E">
|
<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="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@@ -1072,13 +1103,13 @@ Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
|||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="qLF-A6-ThX">
|
<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">
|
<shadow key="shadow" blurRadius="0.5">
|
||||||
<size key="offset" width="0.0" height="1"/>
|
<size key="offset" width="0.0" height="1"/>
|
||||||
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
<color key="color" name="controlLightHighlightColor" catalog="System" colorSpace="catalog"/>
|
||||||
</shadow>
|
</shadow>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘S" id="qh6-k2-MUr">
|
<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="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
|
<key>LSApplicationCategoryType</key>
|
||||||
|
<string>public.app-category.productivity</string>
|
||||||
<key>LSBackgroundOnly</key>
|
<key>LSBackgroundOnly</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>com.apple.developer.aps-environment</key>
|
||||||
|
<string>development</string>
|
||||||
<key>com.apple.security.app-sandbox</key>
|
<key>com.apple.security.app-sandbox</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
|
|||||||
@@ -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>
|
|
||||||
#import "IASKAppSettingsViewController.h"
|
|
||||||
|
|
||||||
@interface MPAppSettingsViewController : IASKAppSettingsViewController
|
|
||||||
@end
|
|
||||||
@@ -1,45 +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 "MPAppSettingsViewController.h"
|
|
||||||
#import "UIColor+Expanded.h"
|
|
||||||
|
|
||||||
@implementation MPAppSettingsViewController
|
|
||||||
|
|
||||||
- (void)viewWillAppear:(BOOL)animated {
|
|
||||||
|
|
||||||
[super viewWillAppear:animated];
|
|
||||||
|
|
||||||
self.tableView.contentInset = UIEdgeInsetsMake( 64, 0, 49, 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
||||||
|
|
||||||
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
|
|
||||||
cell.backgroundColor = [UIColor clearColor];
|
|
||||||
cell.textLabel.textColor = [UIColor whiteColor];
|
|
||||||
|
|
||||||
if (cell.selectionStyle != UITableViewCellSelectionStyleNone) {
|
|
||||||
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.bounds];
|
|
||||||
cell.selectedBackgroundView.backgroundColor = [UIColor colorWithRGBAHex:0x78DDFB33];
|
|
||||||
}
|
|
||||||
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
self.mode = MPCombinedModeUserSelection;
|
self.mode = MPCombinedModeUserSelection;
|
||||||
[self performSegueWithIdentifier:@"users" sender:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillAppear:(BOOL)animated {
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
@@ -102,8 +101,6 @@
|
|||||||
#pragma mark - Actions
|
#pragma mark - Actions
|
||||||
|
|
||||||
- (IBAction)unwindToCombined:(UIStoryboardSegue *)sender {
|
- (IBAction)unwindToCombined:(UIStoryboardSegue *)sender {
|
||||||
|
|
||||||
dbg( @"unwindToCombined:%@", sender );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - State
|
#pragma mark - State
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
#import "MPLogsViewController.h"
|
#import "MPLogsViewController.h"
|
||||||
#import "MPiOSAppDelegate.h"
|
#import "MPiOSAppDelegate.h"
|
||||||
#import "MPAppDelegate_Store.h"
|
|
||||||
|
|
||||||
@implementation MPLogsViewController
|
@implementation MPLogsViewController
|
||||||
|
|
||||||
@@ -52,6 +51,17 @@
|
|||||||
PearlRemoveNotificationObservers();
|
PearlRemoveNotificationObservers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma ide diagnostic ignored "UnavailableInDeploymentTarget"
|
||||||
|
- (void)viewSafeAreaInsetsDidChange {
|
||||||
|
|
||||||
|
[super viewSafeAreaInsetsDidChange];
|
||||||
|
|
||||||
|
self.logView.contentInset = UIEdgeInsetsMake( 44, 0, 0, 0 );
|
||||||
|
self.logView.scrollIndicatorInsets = UIEdgeInsetsMake( 44, 0, 0, 0 );
|
||||||
|
}
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
- (IBAction)toggleLevelControl:(UISegmentedControl *)sender {
|
- (IBAction)toggleLevelControl:(UISegmentedControl *)sender {
|
||||||
|
|
||||||
BOOL traceEnabled = (BOOL)self.levelControl.selectedSegmentIndex;
|
BOOL traceEnabled = (BOOL)self.levelControl.selectedSegmentIndex;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#import "MPNavigationController.h"
|
#import "MPNavigationController.h"
|
||||||
#import "MPWebViewController.h"
|
#import "MPWebViewController.h"
|
||||||
|
#import "MPiOSAppDelegate.h"
|
||||||
|
|
||||||
@implementation MPNavigationController
|
@implementation MPNavigationController
|
||||||
|
|
||||||
@@ -29,6 +30,16 @@
|
|||||||
[self performSegueWithIdentifier:@"setup" sender:self];
|
[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 {
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
|
||||||
if ([segue.identifier isEqualToString:@"web"])
|
if ([segue.identifier isEqualToString:@"web"])
|
||||||
|
|||||||
@@ -33,13 +33,6 @@
|
|||||||
self.dismissSegueByButton = [NSMutableDictionary dictionary];
|
self.dismissSegueByButton = [NSMutableDictionary dictionary];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidLoad {
|
|
||||||
|
|
||||||
[super viewDidLoad];
|
|
||||||
|
|
||||||
[self performSegueWithIdentifier:@"root" sender:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UIViewController *)childViewControllerForStatusBarStyle {
|
- (UIViewController *)childViewControllerForStatusBarStyle {
|
||||||
|
|
||||||
return [self.childViewControllers lastObject];
|
return [self.childViewControllers lastObject];
|
||||||
|
|||||||
@@ -52,6 +52,17 @@
|
|||||||
[self reload];
|
[self reload];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma ide diagnostic ignored "UnavailableInDeploymentTarget"
|
||||||
|
- (void)viewSafeAreaInsetsDidChange {
|
||||||
|
|
||||||
|
[super viewSafeAreaInsetsDidChange];
|
||||||
|
|
||||||
|
self.tableView.contentInset = UIEdgeInsetsMake( 44, 0, 0, 0 );
|
||||||
|
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake( 44, 0, 0, 0 );
|
||||||
|
}
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
- (void)reload {
|
- (void)reload {
|
||||||
|
|
||||||
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForMainThread];
|
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForMainThread];
|
||||||
|
|||||||
@@ -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>
|
@interface MPSiteCell : MPCell<UIScrollViewDelegate, UITextFieldDelegate>
|
||||||
|
|
||||||
@property(nonatomic) NSArray *fuzzyGroups;
|
@property(nonatomic) NSArray *queryGroups;
|
||||||
|
|
||||||
- (void)setSite:(MPSiteEntity *)site animated:(BOOL)animated;
|
- (void)setSite:(MPSiteEntity *)site animated:(BOOL)animated;
|
||||||
- (void)setTransientSite:(NSString *)siteName animated:(BOOL)animated;
|
- (void)setTransientSite:(NSString *)siteName animated:(BOOL)animated;
|
||||||
|
|||||||
@@ -135,7 +135,7 @@
|
|||||||
[super prepareForReuse];
|
[super prepareForReuse];
|
||||||
|
|
||||||
self.siteOID = nil;
|
self.siteOID = nil;
|
||||||
self.fuzzyGroups = nil;
|
self.queryGroups = nil;
|
||||||
self.transientSite = nil;
|
self.transientSite = nil;
|
||||||
self.mode = MPPasswordCellModePassword;
|
self.mode = MPPasswordCellModePassword;
|
||||||
[self updateAnimated:NO];
|
[self updateAnimated:NO];
|
||||||
@@ -150,11 +150,11 @@
|
|||||||
|
|
||||||
#pragma mark - State
|
#pragma mark - State
|
||||||
|
|
||||||
- (void)setFuzzyGroups:(NSArray *)fuzzyGroups {
|
- (void)setQueryGroups:(NSArray *)queryGroups {
|
||||||
|
|
||||||
if (self.fuzzyGroups == fuzzyGroups)
|
if (self.queryGroups == queryGroups)
|
||||||
return;
|
return;
|
||||||
_fuzzyGroups = fuzzyGroups;
|
_queryGroups = queryGroups;
|
||||||
|
|
||||||
[self updateSiteName:[self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]];
|
[self updateSiteName:[self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]];
|
||||||
}
|
}
|
||||||
@@ -263,6 +263,7 @@
|
|||||||
|
|
||||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Delete %@?", site.name ) message:nil
|
UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Delete %@?", site.name ) message:nil
|
||||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||||
|
[controller.popoverPresentationController setSourceView:sender];
|
||||||
[controller addAction:[UIAlertAction actionWithTitle:@"Delete Site" style:UIAlertActionStyleDestructive
|
[controller addAction:[UIAlertAction actionWithTitle:@"Delete Site" style:UIAlertActionStyleDestructive
|
||||||
handler:^(UIAlertAction *_Nonnull action) {
|
handler:^(UIAlertAction *_Nonnull action) {
|
||||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
@@ -284,6 +285,7 @@
|
|||||||
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Change Password Type" message:nil
|
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Change Password Type" message:nil
|
||||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||||
|
[controller.popoverPresentationController setSourceView:sender];
|
||||||
for (NSNumber *typeNumber in [mainSite.algorithm allTypes]) {
|
for (NSNumber *typeNumber in [mainSite.algorithm allTypes]) {
|
||||||
MPResultType type = (MPResultType)[typeNumber unsignedIntegerValue];
|
MPResultType type = (MPResultType)[typeNumber unsignedIntegerValue];
|
||||||
NSString *typeName = [mainSite.algorithm nameOfType:type];
|
NSString *typeName = [mainSite.algorithm nameOfType:type];
|
||||||
@@ -425,7 +427,7 @@
|
|||||||
if (!site || ![site isKindOfClass:[MPGeneratedSiteEntity class]])
|
if (!site || ![site isKindOfClass:[MPGeneratedSiteEntity class]])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
((MPGeneratedSiteEntity *)site).counter = 1;
|
((MPGeneratedSiteEntity *)site).counter = MPCounterValueInitial;
|
||||||
[context saveToStore];
|
[context saveToStore];
|
||||||
|
|
||||||
[PearlOverlay showTemporaryOverlayWithTitle:@"Counter Reset" dismissAfter:2];
|
[PearlOverlay showTemporaryOverlayWithTitle:@"Counter Reset" dismissAfter:2];
|
||||||
@@ -444,6 +446,7 @@
|
|||||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Create Site" message:
|
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Create Site" message:
|
||||||
strf( @"Remember site named:\n%@", self.transientSite )
|
strf( @"Remember site named:\n%@", self.transientSite )
|
||||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||||
|
[controller.popoverPresentationController setSourceView:sender];
|
||||||
[controller addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:
|
[controller addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:
|
||||||
^(UIAlertAction *_Nonnull action) {
|
^(UIAlertAction *_Nonnull action) {
|
||||||
[[MPiOSAppDelegate get]
|
[[MPiOSAppDelegate get]
|
||||||
@@ -512,16 +515,24 @@
|
|||||||
|
|
||||||
- (void)updateAnimated:(BOOL)animated {
|
- (void)updateAnimated:(BOOL)animated {
|
||||||
|
|
||||||
Weakify( self );
|
|
||||||
if (![NSThread isMainThread]) {
|
if (![NSThread isMainThread]) {
|
||||||
PearlMainQueueOperation( ^{
|
PearlMainQueueOperation( ^{
|
||||||
Strongify( self );
|
|
||||||
[self updateAnimated:animated];
|
[self updateAnimated:animated];
|
||||||
} );
|
} );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[UIView animateWithDuration:animated? .3f: 0 animations:^{
|
if (animated)
|
||||||
|
[UIView animateWithDuration:.3f animations:^{
|
||||||
|
[self updateWasAnimated:animated];
|
||||||
|
}];
|
||||||
|
else
|
||||||
|
[self updateWasAnimated:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateWasAnimated:(BOOL)animated {
|
||||||
|
|
||||||
|
Weakify( self );
|
||||||
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
@@ -572,7 +583,7 @@
|
|||||||
wrn( @"Could not load cell content: key unavailable." );
|
wrn( @"Could not load cell content: key unavailable." );
|
||||||
PearlMainQueueOperation( ^{
|
PearlMainQueueOperation( ^{
|
||||||
Strongify( self );
|
Strongify( self );
|
||||||
[self updateAnimated:YES];
|
[self updateAnimated:animated];
|
||||||
} );
|
} );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -632,12 +643,12 @@
|
|||||||
wrn( @"Could not load cell content: store unavailable." );
|
wrn( @"Could not load cell content: store unavailable." );
|
||||||
PearlMainQueueOperation( ^{
|
PearlMainQueueOperation( ^{
|
||||||
Strongify( self );
|
Strongify( self );
|
||||||
[self updateAnimated:YES];
|
[self updateAnimated:animated];
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (animated)
|
||||||
[self.contentView layoutIfNeeded];
|
[self.contentView layoutIfNeeded];
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateSiteName:(MPSiteEntity *)site {
|
- (void)updateSiteName:(MPSiteEntity *)site {
|
||||||
@@ -645,14 +656,14 @@
|
|||||||
NSString *siteName = self.transientSite?: site.name;
|
NSString *siteName = self.transientSite?: site.name;
|
||||||
NSMutableAttributedString *attributedSiteName = [[NSMutableAttributedString alloc] initWithString:siteName?: @""];
|
NSMutableAttributedString *attributedSiteName = [[NSMutableAttributedString alloc] initWithString:siteName?: @""];
|
||||||
if ([attributedSiteName length])
|
if ([attributedSiteName length])
|
||||||
for (NSUInteger f = 0, s = (NSUInteger)-1; f < [self.fuzzyGroups count]; ++f) {
|
for (NSUInteger f = 0, s = 0; f < [self.queryGroups count]; ++f, ++s) {
|
||||||
s = [siteName rangeOfString:self.fuzzyGroups[f] options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch
|
s = [siteName rangeOfString:self.queryGroups[f] options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch
|
||||||
range:NSMakeRange( s + 1, [siteName length] - (s + 1) )].location;
|
range:NSMakeRange( s, [siteName length] - s )].location;
|
||||||
if (s == NSNotFound)
|
if (s == NSNotFound)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
[attributedSiteName addAttribute:NSBackgroundColorAttributeName value:[UIColor redColor]
|
[attributedSiteName addAttribute:NSBackgroundColorAttributeName value:[UIColor redColor]
|
||||||
range:NSMakeRange( s, [self.fuzzyGroups[f] length] )];
|
range:NSMakeRange( s, [self.queryGroups[f] length] )];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.transientSite)
|
if (self.transientSite)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
UIView *sitesView = sitesVC.view;
|
UIView *sitesView = sitesVC.view;
|
||||||
sitesView.frame = combinedVC.view.bounds;
|
sitesView.frame = combinedVC.view.bounds;
|
||||||
sitesView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
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) {
|
[sitesVC setActive:YES animated:self.animated completion:^(BOOL finished) {
|
||||||
if (!finished)
|
if (!finished)
|
||||||
|
|||||||
@@ -33,11 +33,10 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
|||||||
MPPasswordsBadNameTip = 1 << 0,
|
MPPasswordsBadNameTip = 1 << 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@interface MPSitesViewController()<NSFetchedResultsControllerDelegate, SKStoreProductViewControllerDelegate>
|
@interface MPSitesViewController()<NSFetchedResultsControllerDelegate>
|
||||||
|
|
||||||
@property(nonatomic, strong) SKStoreProductViewController *voltoViewController;
|
|
||||||
@property(nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
|
@property(nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
|
||||||
@property(nonatomic, strong) NSArray *fuzzyGroups;
|
@property(nonatomic, strong) NSArray *queryGroups;
|
||||||
@property(nonatomic, strong) NSCharacterSet *siteNameAcceptableCharactersSet;
|
@property(nonatomic, strong) NSCharacterSet *siteNameAcceptableCharactersSet;
|
||||||
@property(nonatomic, strong) NSMutableArray<NSMutableArray *> *dataSource;
|
@property(nonatomic, strong) NSMutableArray<NSMutableArray *> *dataSource;
|
||||||
@property(nonatomic, weak) UIViewController *popdownVC;
|
@property(nonatomic, weak) UIViewController *popdownVC;
|
||||||
@@ -64,13 +63,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
|||||||
self.collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
self.collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||||
[self.collectionView automaticallyAdjustInsetsForKeyboard];
|
[self.collectionView automaticallyAdjustInsetsForKeyboard];
|
||||||
self.searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
self.searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||||
if ([self.searchBar respondsToSelector:@selector( keyboardAppearance )])
|
|
||||||
self.searchBar.keyboardAppearance = UIKeyboardAppearanceDark;
|
self.searchBar.keyboardAppearance = UIKeyboardAppearanceDark;
|
||||||
else
|
|
||||||
[self.searchBar enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
|
||||||
if ([subview isKindOfClass:[UITextField class]])
|
|
||||||
((UITextField *)subview).keyboardAppearance = UIKeyboardAppearanceDark;
|
|
||||||
} recurse:YES];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillAppear:(BOOL)animated {
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
@@ -127,6 +120,16 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
|||||||
PearlRemoveNotificationObservers();
|
PearlRemoveNotificationObservers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)viewDidLayoutSubviews {
|
||||||
|
|
||||||
|
[super viewDidLayoutSubviews];
|
||||||
|
|
||||||
|
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 {
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
|
||||||
if ([segue.identifier isEqualToString:@"popdown"])
|
if ([segue.identifier isEqualToString:@"popdown"])
|
||||||
@@ -144,33 +147,6 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
|||||||
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - UICollectionViewDelegateFlowLayout
|
|
||||||
|
|
||||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout
|
|
||||||
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
|
||||||
|
|
||||||
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)collectionViewLayout;
|
|
||||||
CGFloat itemWidth = UIEdgeInsetsInsetRect( collectionView.bounds, layout.sectionInset ).size.width;
|
|
||||||
return CGSizeMake( itemWidth, 100 );
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout
|
|
||||||
insetForSectionAtIndex:(NSInteger)section {
|
|
||||||
|
|
||||||
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)collectionViewLayout;
|
|
||||||
UIEdgeInsets occludedInsets = [self.collectionView occludedInsets];
|
|
||||||
UIEdgeInsets insets = layout.sectionInset;
|
|
||||||
insets.top = insets.bottom; // Undo storyboard hack for manual top-occluded insets.
|
|
||||||
|
|
||||||
if (section == 0)
|
|
||||||
insets.top += occludedInsets.top;
|
|
||||||
|
|
||||||
if (section == collectionView.numberOfSections - 1)
|
|
||||||
insets.bottom += occludedInsets.bottom;
|
|
||||||
|
|
||||||
return insets;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - UICollectionViewDataSource
|
#pragma mark - UICollectionViewDataSource
|
||||||
|
|
||||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||||
@@ -186,7 +162,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
|||||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
MPSiteCell *cell = [MPSiteCell dequeueFromCollectionView:collectionView indexPath: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];
|
id item = self.dataSource[(NSUInteger)indexPath.section][(NSUInteger)indexPath.item];
|
||||||
if ([item isKindOfClass:[MPSiteEntity class]])
|
if ([item isKindOfClass:[MPSiteEntity class]])
|
||||||
[cell setSite:item animated:NO];
|
[cell setSite:item animated:NO];
|
||||||
@@ -196,6 +172,19 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
|||||||
return cell;
|
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
|
#pragma mark - UIScrollDelegate
|
||||||
|
|
||||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
|
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
|
||||||
@@ -379,21 +368,19 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
|||||||
- (void)reloadSites {
|
- (void)reloadSites {
|
||||||
|
|
||||||
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
[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 *queryString = self.query;
|
||||||
NSString *queryPattern = [[queryString stringByReplacingMatchesOfExpression:fuzzyRE withTemplate:@"*$1"]
|
NSMutableArray *queryGroups = [NSMutableArray new];
|
||||||
stringByAppendingString:@"*"];
|
NSMutableString *queryPattern = [NSMutableString new];
|
||||||
NSMutableArray *fuzzyGroups = [NSMutableArray new];
|
[queryString enumerateSubstringsInRange: NSMakeRange(0, [queryString length]) options: NSStringEnumerationByComposedCharacterSequences
|
||||||
[fuzzyRE enumerateMatchesInString:queryString options:0 range:NSMakeRange( 0, queryString.length )
|
usingBlock: ^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
|
||||||
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
if (substringRange.location < 10) {
|
||||||
[fuzzyGroups addObject:[queryString substringWithRange:result.range]];
|
[queryGroups addObject:substring];
|
||||||
|
[queryPattern appendString:@"*"];
|
||||||
|
}
|
||||||
|
[queryPattern appendString:substring];
|
||||||
}];
|
}];
|
||||||
self.fuzzyGroups = fuzzyGroups;
|
[queryPattern appendString:@"*"];
|
||||||
|
self.queryGroups = queryGroups;
|
||||||
|
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
self.fetchedResultsController.fetchRequest.predicate =
|
self.fetchedResultsController.fetchRequest.predicate =
|
||||||
@@ -406,7 +393,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
|||||||
toSections:[self createDataSource]
|
toSections:[self createDataSource]
|
||||||
reloadItems:@[ MPTransientPasswordItem ] completion:^(BOOL finished) {
|
reloadItems:@[ MPTransientPasswordItem ] completion:^(BOOL finished) {
|
||||||
for (MPSiteCell *cell in self.collectionView.visibleCells)
|
for (MPSiteCell *cell in self.collectionView.visibleCells)
|
||||||
[cell setFuzzyGroups:self.fuzzyGroups];
|
[cell setQueryGroups:self.queryGroups];
|
||||||
}];
|
}];
|
||||||
} );
|
} );
|
||||||
}];
|
}];
|
||||||
@@ -460,13 +447,6 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
|||||||
} completion:completion];
|
} completion:completion];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - SKStoreProductViewControllerDelegate
|
|
||||||
|
|
||||||
- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController {
|
|
||||||
|
|
||||||
[viewController dismissViewControllerAnimated:YES completion:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Actions
|
#pragma mark - Actions
|
||||||
|
|
||||||
- (IBAction)dismissPopdown:(id)sender {
|
- (IBAction)dismissPopdown:(id)sender {
|
||||||
@@ -479,45 +459,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
|||||||
|
|
||||||
- (IBAction)upgradeVolto:(UIButton *)sender {
|
- (IBAction)upgradeVolto:(UIButton *)sender {
|
||||||
|
|
||||||
if ([UIApp canOpenURL:[[NSURL alloc] initWithString:@"volto:"]]) {
|
[[MPiOSAppDelegate get] migrateFor:[MPiOSAppDelegate get].activeUserForMainThread];
|
||||||
[[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];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Private
|
#pragma mark - Private
|
||||||
@@ -530,23 +472,8 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
|||||||
self.voltoMigrateAlert.visible = YES;
|
self.voltoMigrateAlert.visible = YES;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.voltoInstallAlert.visible = NO;
|
self.voltoInstallAlert.visible = [MPiOSAppDelegate get].voltoViewController != nil;
|
||||||
self.voltoMigrateAlert.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;
|
|
||||||
}];
|
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,17 @@ PearlEnum( MPDevelopmentFuelConsumption,
|
|||||||
[[MPiOSAppDelegate get] removeProductsObserver:self];
|
[[MPiOSAppDelegate get] removeProductsObserver:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma ide diagnostic ignored "UnavailableInDeploymentTarget"
|
||||||
|
- (void)viewSafeAreaInsetsDidChange {
|
||||||
|
|
||||||
|
[super viewSafeAreaInsetsDidChange];
|
||||||
|
|
||||||
|
self.tableView.contentInset = UIEdgeInsetsMake( 44, 0, 0, 0 );
|
||||||
|
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake( 44, 0, 0, 0 );
|
||||||
|
}
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
#pragma mark - UITableViewDataSource
|
#pragma mark - UITableViewDataSource
|
||||||
|
|
||||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||||
|
|||||||
@@ -231,13 +231,11 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
|
|||||||
user.avatar = newUserAvatar;
|
user.avatar = newUserAvatar;
|
||||||
user.name = newUserName;
|
user.name = newUserName;
|
||||||
|
|
||||||
if ([[MPConfig get].sendInfo boolValue]) {
|
|
||||||
[Countly.sharedInstance recordEvent:@"new-user" segmentation:@{
|
[Countly.sharedInstance recordEvent:@"new-user" segmentation:@{
|
||||||
@"algorithm": @(user.algorithm.version).description,
|
@"algorithm": @(user.algorithm.version).description,
|
||||||
@"avatar" : @(user.avatar).description,
|
@"avatar" : @(user.avatar).description,
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
BOOL signedIn = [[MPiOSAppDelegate get] signInAsUser:user saveInContext:context
|
BOOL signedIn = [[MPiOSAppDelegate get] signInAsUser:user saveInContext:context
|
||||||
usingMasterPassword:masterPassword];
|
usingMasterPassword:masterPassword];
|
||||||
@@ -434,6 +432,7 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
|||||||
|
|
||||||
NSManagedObjectID *userID = user.permanentObjectID;
|
NSManagedObjectID *userID = user.permanentObjectID;
|
||||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:user.name message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
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) {
|
[controller addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
|
||||||
UIAlertController *controller_ = [UIAlertController alertControllerWithTitle:@"Deleting User" message:
|
UIAlertController *controller_ = [UIAlertController alertControllerWithTitle:@"Deleting User" message:
|
||||||
@"The user and its sites will be deleted." preferredStyle:UIAlertControllerStyleAlert];
|
@"The user and its sites will be deleted." preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
|||||||
@@ -17,10 +17,12 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#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) IBOutlet UINavigationItem *webNavigationItem;
|
||||||
|
|
||||||
@property(nonatomic) NSURL *initialURL;
|
@property(nonatomic) NSURL *initialURL;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#import "MPWebViewController.h"
|
#import "MPWebViewController.h"
|
||||||
|
#import "MPiOSAppDelegate.h"
|
||||||
|
|
||||||
@implementation MPWebViewController
|
@implementation MPWebViewController
|
||||||
|
|
||||||
@@ -24,20 +25,30 @@
|
|||||||
|
|
||||||
[super viewDidLoad];
|
[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 {
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
|
|
||||||
[super viewWillAppear:animated];
|
[super viewWillAppear:animated];
|
||||||
|
}
|
||||||
|
|
||||||
if (!self.initialURL)
|
- (void)viewDidLayoutSubviews {
|
||||||
self.initialURL = [NSURL URLWithString:@"https://masterpassword.app"];
|
[self.webView.scrollView insetOcclusion];
|
||||||
|
[super viewDidLayoutSubviews];
|
||||||
self.webNavigationItem.title = self.initialURL.host;
|
|
||||||
|
|
||||||
self.webView.visible = NO;
|
|
||||||
[self.webView loadRequest:[[NSURLRequest alloc] initWithURL:self.initialURL]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIStatusBarStyle)preferredStatusBarStyle {
|
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||||
@@ -45,26 +56,24 @@
|
|||||||
return UIStatusBarStyleLightContent;
|
return UIStatusBarStyleLightContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - UIWebViewDelegate
|
#pragma mark - WKNavigationDelegate
|
||||||
|
|
||||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
|
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
|
||||||
navigationType:(UIWebViewNavigationType)navigationType {
|
decisionHandler:(void ( ^ )(WKNavigationActionPolicy))decisionHandler {
|
||||||
|
|
||||||
if ([[request.URL absoluteString] rangeOfString:@"thanks.lhunath.com"].location != NSNotFound) {
|
if ([navigationAction.request.mainDocumentURL.scheme isEqualToString:@"masterpassword"]) {
|
||||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"tipped.thanks"];
|
[[MPiOSAppDelegate get] openURL:navigationAction.request.mainDocumentURL];
|
||||||
if (![[NSUserDefaults standardUserDefaults] synchronize])
|
decisionHandler( WKNavigationActionPolicyCancel );
|
||||||
wrn( @"Couldn't synchronize thanks tip." );
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([request.URL isEqual:request.mainDocumentURL]) {
|
decisionHandler( WKNavigationActionPolicyAllow );
|
||||||
self.webNavigationItem.title = request.URL.host;
|
}
|
||||||
|
|
||||||
|
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
|
||||||
|
|
||||||
|
self.webNavigationItem.title = webView.URL.host;
|
||||||
self.webNavigationItem.prompt = strl( @"Loading" );
|
self.webNavigationItem.prompt = strl( @"Loading" );
|
||||||
}
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)webViewDidStartLoad:(UIWebView *)webView {
|
|
||||||
|
|
||||||
UIActivityIndicatorView *activityView =
|
UIActivityIndicatorView *activityView =
|
||||||
[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
|
[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
|
||||||
@@ -72,19 +81,57 @@
|
|||||||
[activityView startAnimating];
|
[activityView startAnimating];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)webViewDidFinishLoad:(UIWebView *)webView {
|
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
|
||||||
|
|
||||||
[UIView animateWithDuration:0.3 animations:^{
|
if ([[webView.URL absoluteString] rangeOfString:@"thanks.lhunath.com"].location != NSNotFound) {
|
||||||
self.webView.visible = YES;
|
[[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
|
#pragma mark - Actions
|
||||||
|
|
||||||
|
- (IBAction)action:(id)sender {
|
||||||
|
|
||||||
|
UIAlertController *controller = [UIAlertController alertControllerWithTitle:self.webView.URL.host
|
||||||
|
message:self.webView.URL.absoluteString
|
||||||
|
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||||
|
[controller.popoverPresentationController setSourceView: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 {
|
- (IBAction)done:(id)sender {
|
||||||
|
|
||||||
[self dismissViewControllerAnimated:YES completion:nil];
|
[self dismissViewControllerAnimated:YES completion:nil];
|
||||||
|
|||||||
@@ -17,15 +17,23 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <StoreKit/StoreKit.h>
|
||||||
|
|
||||||
#import "MPAppDelegate_Shared.h"
|
#import "MPAppDelegate_Shared.h"
|
||||||
|
|
||||||
@interface MPiOSAppDelegate : MPAppDelegate_Shared
|
@interface MPiOSAppDelegate : MPAppDelegate_Shared <SKStoreProductViewControllerDelegate>
|
||||||
|
|
||||||
|
@property(nonatomic, strong) UIWindow *window;
|
||||||
|
@property(nonatomic, strong) SKStoreProductViewController *voltoViewController;
|
||||||
|
|
||||||
|
- (void)openURL:(NSURL *)url;
|
||||||
|
|
||||||
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController;
|
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController;
|
||||||
- (void)openFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController;
|
- (void)openFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController;
|
||||||
|
|
||||||
- (void)showExportForVC:(UIViewController *)viewController;
|
- (void)showExportForVC:(UIViewController *)viewController;
|
||||||
|
- (void)migrateFor:(MPUserEntity *)user;
|
||||||
|
|
||||||
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset;
|
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -26,15 +26,30 @@
|
|||||||
#import <Sentry/Sentry.h>
|
#import <Sentry/Sentry.h>
|
||||||
#import <Countly/Countly.h>
|
#import <Countly/Countly.h>
|
||||||
|
|
||||||
|
@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>
|
@interface MPiOSAppDelegate()<UIDocumentInteractionControllerDelegate>
|
||||||
|
|
||||||
@property(nonatomic, strong) UIDocumentInteractionController *interactionController;
|
@property(nonatomic, strong) UIDocumentInteractionController *interactionController;
|
||||||
@property(nonatomic, strong) PearlHangDetector *hangDetector;
|
@property(nonatomic, strong) PearlHangDetector *hangDetector;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MPiOSAppDelegate
|
@implementation MPiOSAppDelegate
|
||||||
|
|
||||||
|
@synthesize window;
|
||||||
|
|
||||||
+ (void)initialize {
|
+ (void)initialize {
|
||||||
|
|
||||||
[MPiOSConfig get];
|
[MPiOSConfig get];
|
||||||
@@ -44,8 +59,8 @@
|
|||||||
|
|
||||||
@try {
|
@try {
|
||||||
// Sentry
|
// Sentry
|
||||||
[SentrySDK initWithOptions:@{
|
[SentrySDK startWithOptions:@{
|
||||||
@"dsn" : decrypt( sentryDSN ),
|
@"dsn" : NilToNSNull( decrypt( sentryDSN ) ),
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@"debug" : @(YES),
|
@"debug" : @(YES),
|
||||||
@"environment" : @"Development",
|
@"environment" : @"Development",
|
||||||
@@ -56,7 +71,8 @@
|
|||||||
@"debug" : @(NO),
|
@"debug" : @(NO),
|
||||||
@"environment" : @"Private",
|
@"environment" : @"Private",
|
||||||
#endif
|
#endif
|
||||||
@"enabled" : [MPiOSConfig get].sendInfo,
|
@"enabled" : @([[MPiOSConfig get].sendInfo boolValue] || ![[MPiOSConfig get].sendInfoDecided boolValue]),
|
||||||
|
@"enableAutoSessionTracking": @(YES),
|
||||||
}];
|
}];
|
||||||
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
||||||
PearlLogLevel level = PearlLogLevelWarn;
|
PearlLogLevel level = PearlLogLevelWarn;
|
||||||
@@ -102,15 +118,16 @@
|
|||||||
countlyConfig.appKey = decrypt( countlyKey );
|
countlyConfig.appKey = decrypt( countlyKey );
|
||||||
countlyConfig.features = @[ CLYPushNotifications, CLYAutoViewTracking ];
|
countlyConfig.features = @[ CLYPushNotifications, CLYAutoViewTracking ];
|
||||||
countlyConfig.requiresConsent = YES;
|
countlyConfig.requiresConsent = YES;
|
||||||
#if DEBUG
|
|
||||||
countlyConfig.pushTestMode = CLYPushTestModeDevelopment;
|
|
||||||
#elif ! PUBLIC
|
|
||||||
countlyConfig.pushTestMode = CLYPushTestModeTestFlightOrAdHoc;
|
|
||||||
#endif
|
|
||||||
countlyConfig.alwaysUsePOST = YES;
|
countlyConfig.alwaysUsePOST = YES;
|
||||||
countlyConfig.deviceID = [PearlKeyChain deviceIdentifier];
|
countlyConfig.deviceID = [PearlKeyChain deviceIdentifier];
|
||||||
countlyConfig.secretSalt = decrypt( countlySalt );
|
countlyConfig.secretSalt = decrypt( countlySalt );
|
||||||
|
#if DEBUG
|
||||||
countlyConfig.enableDebug = YES;
|
countlyConfig.enableDebug = YES;
|
||||||
|
countlyConfig.pushTestMode = CLYPushTestModeDevelopment;
|
||||||
|
#elif ! PUBLIC
|
||||||
|
countlyConfig.enableDebug = NO;
|
||||||
|
countlyConfig.pushTestMode = CLYPushTestModeTestFlightOrAdHoc;
|
||||||
|
#endif
|
||||||
[Countly.sharedInstance startWithConfig:countlyConfig];
|
[Countly.sharedInstance startWithConfig:countlyConfig];
|
||||||
|
|
||||||
#if ! DEBUG
|
#if ! DEBUG
|
||||||
@@ -135,12 +152,6 @@
|
|||||||
@catch (id exception) {
|
@catch (id exception) {
|
||||||
err( @"During Config Test: %@", exception );
|
err( @"During Config Test: %@", exception );
|
||||||
}
|
}
|
||||||
@try {
|
|
||||||
[super application:application didFinishLaunchingWithOptions:launchOptions];
|
|
||||||
}
|
|
||||||
@catch (id exception) {
|
|
||||||
err( @"During Pearl Application Launch: %@", exception );
|
|
||||||
}
|
|
||||||
@try {
|
@try {
|
||||||
inf( @"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier] );
|
inf( @"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier] );
|
||||||
|
|
||||||
@@ -171,30 +182,29 @@
|
|||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
if (@available( iOS 12, * )) {
|
SKStoreProductViewController *migrateVC = [SKStoreProductViewController new];
|
||||||
[Countly.sharedInstance askForNotificationPermissionWithOptions:UNAuthorizationOptionProvisional completionHandler:
|
[migrateVC loadProductWithParameters:@{
|
||||||
^(BOOL granted, NSError *error) {
|
SKStoreProductParameterCampaignToken : @"app-masterpassword.ios", /* Campaign: From MasterPassword iOS */
|
||||||
inf( @"provisional: %d: %@", granted, error );
|
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 );
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
self.voltoViewController = migrateVC;
|
||||||
|
self.voltoViewController.delegate = self;
|
||||||
|
} else {
|
||||||
|
self.voltoViewController = nil;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
PearlMainQueueOperation( ^{
|
PearlMainQueueOperation( ^{
|
||||||
if ([[MPiOSConfig get].showSetup boolValue])
|
if ([[MPiOSConfig get].showSetup boolValue])
|
||||||
[self.navigationController performSegueWithIdentifier:@"setup" sender:self];
|
[self.window.rootViewController performSegueWithIdentifier:@"setup" sender:self];
|
||||||
|
|
||||||
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"notificationsDecided"]) {
|
[self consentFeatures];
|
||||||
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) {
|
|
||||||
[Countly.sharedInstance askForNotificationPermission];
|
|
||||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"notificationsDecided"];
|
|
||||||
}]];
|
|
||||||
[(self.navigationController.presentedViewController?: (UIViewController *)self.navigationController)
|
|
||||||
presentViewController:alert animated:YES completion:nil];
|
|
||||||
}
|
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
@catch (id exception) {
|
@catch (id exception) {
|
||||||
@@ -211,6 +221,12 @@
|
|||||||
if (!url)
|
if (!url)
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
|
// masterpassword: URLs.
|
||||||
|
if ([url.scheme isEqualToString:@"masterpassword"]) {
|
||||||
|
[self openURL:url];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
// Arbitrary URL to mpsites data.
|
// Arbitrary URL to mpsites data.
|
||||||
[[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:
|
[[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:
|
||||||
^(NSData *importedSitesData, NSURLResponse *response, NSError *error) {
|
^(NSData *importedSitesData, NSURLResponse *response, NSError *error) {
|
||||||
@@ -224,7 +240,7 @@
|
|||||||
(id)[error localizedDescription]?: error )
|
(id)[error localizedDescription]?: error )
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
[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;
|
return;
|
||||||
}
|
}
|
||||||
@@ -236,7 +252,7 @@
|
|||||||
@"Master Password couldn't understand the import file."
|
@"Master Password couldn't understand the import file."
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
[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;
|
return;
|
||||||
}
|
}
|
||||||
@@ -247,6 +263,84 @@
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (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, * )) {
|
||||||
|
[Countly.sharedInstance askForNotificationPermissionWithOptions:UNAuthorizationOptionProvisional | UNAuthorizationOptionAlert
|
||||||
|
completionHandler:^(BOOL granted, NSError *error) {
|
||||||
|
if (!granted)
|
||||||
|
err( @"No provisional notification permission: %@", error );
|
||||||
|
|
||||||
|
[self askNotifications];
|
||||||
|
}];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self askNotifications];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)askNotifications {
|
||||||
|
|
||||||
|
if ([[MPiOSConfig get].notificationsDecided boolValue])
|
||||||
|
return;
|
||||||
|
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
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];
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
- (void)importSites:(NSString *)importData {
|
- (void)importSites:(NSString *)importData {
|
||||||
|
|
||||||
if ([NSThread isMainThread]) {
|
if ([NSThread isMainThread]) {
|
||||||
@@ -272,7 +366,7 @@
|
|||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
||||||
setResult( nil );
|
setResult( nil );
|
||||||
}]];
|
}]];
|
||||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
} askUserPassword:^NSString *(NSString *userName) {
|
} askUserPassword:^NSString *(NSString *userName) {
|
||||||
@@ -290,7 +384,7 @@
|
|||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
||||||
setResult( nil );
|
setResult( nil );
|
||||||
}]];
|
}]];
|
||||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
} result:^(NSError *error) {
|
} result:^(NSError *error) {
|
||||||
@@ -301,7 +395,7 @@
|
|||||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:[error localizedDescription]
|
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:[error localizedDescription]
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
[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];
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}];
|
}];
|
||||||
@@ -311,8 +405,6 @@
|
|||||||
|
|
||||||
inf( @"Will foreground" );
|
inf( @"Will foreground" );
|
||||||
|
|
||||||
[super applicationWillEnterForeground:application];
|
|
||||||
|
|
||||||
[self.hangDetector start];
|
[self.hangDetector start];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,20 +427,16 @@
|
|||||||
[UIPasteboard generalPasteboard].string = @"";
|
[UIPasteboard generalPasteboard].string = @"";
|
||||||
}]];
|
}]];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]];
|
[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 );
|
mpw_marshal_file_free( &importFile );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
[super applicationDidBecomeActive:application];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
|
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
|
||||||
|
|
||||||
inf( @"Received memory warning." );
|
inf( @"Received memory warning." );
|
||||||
|
|
||||||
[super applicationDidReceiveMemoryWarning:application];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
||||||
@@ -361,50 +449,46 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[self.hangDetector stop];
|
[self.hangDetector stop];
|
||||||
|
|
||||||
// self.task = [application beginBackgroundTaskWithExpirationHandler:^{
|
|
||||||
// [application endBackgroundTask:self.task];
|
|
||||||
// dbg( @"background expiring" );
|
|
||||||
// }];
|
|
||||||
// PearlNotMainQueueOperation( ^{
|
|
||||||
// NSString *pbstring = [UIPasteboard generalPasteboard].string;
|
|
||||||
// while (YES) {
|
|
||||||
// NSString *newString = [UIPasteboard generalPasteboard].string;
|
|
||||||
// if (![newString isEqualToString:pbstring]) {
|
|
||||||
// dbg( @"pasteboard changed to: %@", newString );
|
|
||||||
// pbstring = newString;
|
|
||||||
// NSURL *url = [NSURL URLWithString:pbstring];
|
|
||||||
// if (url) {
|
|
||||||
// NSString *siteName = [url host];
|
|
||||||
// }
|
|
||||||
// MPKey *key = [MPiOSAppDelegate get].key;
|
|
||||||
// if (key)
|
|
||||||
// [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
|
||||||
// NSFetchRequest<MPSiteEntity *>
|
|
||||||
// *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
|
|
||||||
// fetchRequest.sortDescriptors = @[
|
|
||||||
// [[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO]
|
|
||||||
// ];
|
|
||||||
// fetchRequest.fetchBatchSize = 2;
|
|
||||||
// fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(name LIKE[cd] %@) AND user == %@", siteName,
|
|
||||||
// [[MPiOSAppDelegate get] activeUserOID]];
|
|
||||||
// NSError *error = nil;
|
|
||||||
// NSArray<MPSiteEntity *> *results = [fetchRequest execute:&error];
|
|
||||||
// dbg( @"site search, error: %@, results:\n%@", error, results );
|
|
||||||
// if ([results count]) {
|
|
||||||
// [UIPasteboard generalPasteboard].string = [[results firstObject] resolvePasswordUsingKey:key];
|
|
||||||
// }
|
|
||||||
// }];
|
|
||||||
// }
|
|
||||||
// [NSThread sleepForTimeInterval:5];
|
|
||||||
// }
|
|
||||||
// } );
|
|
||||||
|
|
||||||
[super applicationDidEnterBackground:application];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Behavior
|
#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 {
|
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController {
|
||||||
|
|
||||||
if (![PearlEMail canSendMail]) {
|
if (![PearlEMail canSendMail]) {
|
||||||
@@ -414,7 +498,7 @@
|
|||||||
@"help@masterpassword.app"
|
@"help@masterpassword.app"
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
[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) {
|
else if (logs) {
|
||||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Feedback" message:
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Feedback" message:
|
||||||
@@ -428,7 +512,7 @@
|
|||||||
[alert addAction:[UIAlertAction actionWithTitle:@"No Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
[alert addAction:[UIAlertAction actionWithTitle:@"No Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||||
[self openFeedbackWithLogs:NO forVC:viewController];
|
[self openFeedbackWithLogs:NO forVC:viewController];
|
||||||
}]];
|
}]];
|
||||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
[self openFeedbackWithLogs:NO forVC:viewController];
|
[self openFeedbackWithLogs:NO forVC:viewController];
|
||||||
@@ -474,15 +558,16 @@
|
|||||||
@"This may be due to corruption. You can either reset Master Password and "
|
@"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."
|
@"recreate your user, or E-Mail us your logs and leave your corrupt store as-is for now."
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"E-Mail Logs" style:UIAlertActionStyleDefault
|
[alert addAction:[UIAlertAction actionWithTitle:@"Try Again" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||||
handler:^(UIAlertAction *action) {
|
[self retryCorruptStore];
|
||||||
|
}]];
|
||||||
|
[alert addAction:[UIAlertAction actionWithTitle:@"Send Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||||
[self openFeedbackWithLogs:YES forVC:nil];
|
[self openFeedbackWithLogs:YES forVC:nil];
|
||||||
}]];
|
}]];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
[alert addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||||
[self deleteAndResetStore];
|
[self deleteAndResetStore];
|
||||||
}]];
|
}]];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Ignore" style:UIAlertActionStyleCancel handler:nil]];
|
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
@@ -499,7 +584,7 @@
|
|||||||
@"Would you like to make all your passwords visible in the export file?\n\n"
|
@"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"
|
@"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."
|
@"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) {
|
[sheet addAction:[UIAlertAction actionWithTitle:@"Safe Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||||
[self showExportRevealPasswords:NO forVC:viewController];
|
[self showExportRevealPasswords:NO forVC:viewController];
|
||||||
}]];
|
}]];
|
||||||
@@ -507,10 +592,10 @@
|
|||||||
[self showExportRevealPasswords:YES forVC:viewController];
|
[self showExportRevealPasswords:YES forVC:viewController];
|
||||||
}]];
|
}]];
|
||||||
[sheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
[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]];
|
[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 {
|
- (void)showExportRevealPasswords:(BOOL)revealPasswords forVC:(UIViewController *)viewController {
|
||||||
@@ -521,39 +606,46 @@
|
|||||||
@"Close Master Password, go into Settings and add a Mail account."
|
@"Close Master Password, go into Settings and add a Mail account."
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
[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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self exportSitesRevealPasswords:revealPasswords askExportPassword:^NSString *(NSString *userName) {
|
[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)) {
|
return PearlAwait( ^(void (^setResult)(id)) {
|
||||||
PearlMainQueue( ^{
|
PearlMainQueue( ^{
|
||||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Master Password For:\n%@", userName )
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf(
|
||||||
|
@"Master Password For:\n%@", userName )
|
||||||
message:@"Enter your master password to export the user."
|
message:@"Enter your master password to export the user."
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
||||||
textField.secureTextEntry = YES;
|
textField.secureTextEntry = YES;
|
||||||
}];
|
}];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
[alert addAction:[UIAlertAction actionWithTitle:@"Export" style:UIAlertActionStyleDefault
|
||||||
|
handler:^(UIAlertAction *action) {
|
||||||
setResult( alert.textFields.firstObject.text );
|
setResult( alert.textFields.firstObject.text );
|
||||||
}]];
|
}]];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel
|
||||||
|
handler:^(UIAlertAction *action) {
|
||||||
setResult( nil );
|
setResult( nil );
|
||||||
}]];
|
}]];
|
||||||
[self.navigationController presentViewController:alert animated:YES completion:nil];
|
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
} result:^(NSString *exportedUser, NSError *error) {
|
} error:&error];
|
||||||
if (!exportedUser || error) {
|
|
||||||
MPError( error, @"Failed to export mpsites." );
|
|
||||||
PearlMainQueue( ^{
|
PearlMainQueue( ^{
|
||||||
|
if (error) {
|
||||||
|
MPError( error, @"Failed to export mpsites." );
|
||||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Error" message:[error localizedDescription]
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Error" message:[error localizedDescription]
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
|
[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;
|
|
||||||
}
|
}
|
||||||
|
if (!exportedUser)
|
||||||
|
return;
|
||||||
|
|
||||||
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
|
||||||
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
|
||||||
@@ -561,7 +653,7 @@
|
|||||||
[self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
|
[self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
|
||||||
|
|
||||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Destination" message:nil
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Destination" message:nil
|
||||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Send As E-Mail" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
[alert addAction:[UIAlertAction actionWithTitle:@"Send As E-Mail" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||||
NSString *message;
|
NSString *message;
|
||||||
if (revealPasswords)
|
if (revealPasswords)
|
||||||
@@ -606,10 +698,82 @@
|
|||||||
}
|
}
|
||||||
}]];
|
}]];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
|
[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];
|
||||||
|
} );
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)migrateFor:(MPUserEntity *)user {
|
||||||
|
|
||||||
|
if ([UIApp canOpenURL:[[NSURL alloc] initWithString:@"volto:"]]) {
|
||||||
|
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 Volto."
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
[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];
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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.window.rootViewController presentViewController:self.voltoViewController animated:YES completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset {
|
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset {
|
||||||
|
|
||||||
PearlMainQueue( ^{
|
PearlMainQueue( ^{
|
||||||
@@ -618,7 +782,7 @@
|
|||||||
@"Changing your master password will cause all your generated passwords to change!\n"
|
@"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."
|
@"Changing the master password back to the old one will cause your passwords to revert as well."
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||||
[moc performBlockAndWait:^{
|
[moc performBlockAndWait:^{
|
||||||
inf( @"Clearing keyID for user: %@.", user.userID );
|
inf( @"Clearing keyID for user: %@.", user.userID );
|
||||||
user.keyID = nil;
|
user.keyID = nil;
|
||||||
@@ -631,10 +795,17 @@
|
|||||||
didReset();
|
didReset();
|
||||||
}]];
|
}]];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleCancel handler:nil]];
|
[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
|
#pragma mark - UIDocumentInteractionControllerDelegate
|
||||||
|
|
||||||
- (void)documentInteractionController:(UIDocumentInteractionController *)controller didEndSendingToApplication:(NSString *)application {
|
- (void)documentInteractionController:(UIDocumentInteractionController *)controller didEndSendingToApplication:(NSString *)application {
|
||||||
@@ -655,39 +826,39 @@
|
|||||||
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
|
[PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
|
||||||
|
|
||||||
// Send info
|
// Send info
|
||||||
if ([[MPConfig get].sendInfo boolValue]) {
|
NSArray *countlyFeatures = @[
|
||||||
[Countly.sharedInstance giveConsentForAllFeatures];
|
CLYConsentSessions, CLYConsentEvents, CLYConsentUserDetails, CLYConsentCrashReporting, CLYConsentViewTracking, CLYConsentStarRating
|
||||||
|
];
|
||||||
|
if ([[MPiOSConfig get].sendInfo boolValue] || ![[MPiOSConfig get].sendInfoDecided boolValue]) {
|
||||||
if ([PearlLogger get].printLevel > PearlLogLevelInfo)
|
if ([PearlLogger get].printLevel > PearlLogLevelInfo)
|
||||||
[PearlLogger get].printLevel = PearlLogLevelInfo;
|
[PearlLogger get].printLevel = PearlLogLevelInfo;
|
||||||
|
|
||||||
NSMutableDictionary *prefs = [NSMutableDictionary new];
|
[SentrySDK.currentHub getClient].options.enabled = @YES;
|
||||||
prefs[@"rememberLogin"] = [MPConfig get].rememberLogin;
|
|
||||||
prefs[@"sendInfo"] = [MPConfig get].sendInfo;
|
|
||||||
prefs[@"helpHidden"] = [MPiOSConfig get].helpHidden;
|
|
||||||
prefs[@"showQuickStart"] = [MPiOSConfig get].showSetup;
|
|
||||||
prefs[@"firstRun"] = [PearlConfig get].firstRun;
|
|
||||||
prefs[@"launchCount"] = [PearlConfig get].launchCount;
|
|
||||||
prefs[@"askForReviews"] = [PearlConfig get].askForReviews;
|
|
||||||
prefs[@"reviewAfterLaunches"] = [PearlConfig get].reviewAfterLaunches;
|
|
||||||
prefs[@"reviewedVersion"] = [PearlConfig get].reviewedVersion;
|
|
||||||
prefs[@"simulator"] = @([PearlDeviceUtils isSimulator]);
|
|
||||||
prefs[@"encrypted"] = @([PearlDeviceUtils isAppEncrypted]);
|
|
||||||
prefs[@"jailbroken"] = @([PearlDeviceUtils isJailbroken]);
|
|
||||||
prefs[@"platform"] = [PearlDeviceUtils platform];
|
|
||||||
#ifdef APPSTORE
|
|
||||||
prefs[@"reviewedVersion"] = @([PearlDeviceUtils isAppEncrypted]);
|
|
||||||
#else
|
|
||||||
prefs[@"reviewedVersion"] = @(YES);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[SentrySDK configureScope:^(SentryScope *scope) {
|
[SentrySDK configureScope:^(SentryScope *scope) {
|
||||||
for (NSString *pref in prefs.allKeys)
|
[scope setExtraValue:[MPiOSConfig get].rememberLogin forKey:@"rememberLogin"];
|
||||||
[scope setExtraValue:prefs[pref] forKey:pref];
|
[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"];
|
||||||
|
[scope setExtraValue:[PearlConfig get].launchCount forKey:@"launchCount"];
|
||||||
|
[scope setExtraValue:[PearlConfig get].askForReviews forKey:@"askForReviews"];
|
||||||
|
[scope setExtraValue:[PearlConfig get].reviewAfterLaunches forKey:@"reviewAfterLaunches"];
|
||||||
|
[scope setExtraValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"];
|
||||||
|
[scope setExtraValue:@([PearlDeviceUtils isSimulator]) forKey:@"simulator"];
|
||||||
|
[scope setExtraValue:@([PearlDeviceUtils isAppEncrypted]) forKey:@"encrypted"];
|
||||||
|
[scope setExtraValue:@([PearlDeviceUtils isJailbroken]) forKey:@"jailbroken"];
|
||||||
|
[scope setExtraValue:[PearlDeviceUtils platform] forKey:@"platform"];
|
||||||
|
#ifdef APPSTORE
|
||||||
|
[scope setExtraValue:@([PearlDeviceUtils isAppEncrypted]) forKey:@"reviewedVersion"];
|
||||||
|
#else
|
||||||
|
[scope setExtraValue:@(NO) forKey:@"reviewedVersion"];
|
||||||
|
#endif
|
||||||
}];
|
}];
|
||||||
|
[Countly.sharedInstance giveConsentForFeatures:countlyFeatures];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
[Countly.sharedInstance cancelConsentForAllFeatures];
|
[Countly.sharedInstance cancelConsentForFeatures:countlyFeatures];
|
||||||
|
[SentrySDK.currentHub getClient].options.enabled = @NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,8 @@
|
|||||||
NSStringFromSelector( @selector( siteInfoHidden ) ) : @YES,
|
NSStringFromSelector( @selector( siteInfoHidden ) ) : @YES,
|
||||||
NSStringFromSelector( @selector( showSetup ) ) : @YES,
|
NSStringFromSelector( @selector( showSetup ) ) : @YES,
|
||||||
NSStringFromSelector( @selector( appleID ) ) : @"510296984",
|
NSStringFromSelector( @selector( appleID ) ) : @"510296984",
|
||||||
NSStringFromSelector( @selector( actionsTipShown ) ) : @(!self.firstRun),
|
NSStringFromSelector( @selector( actionsTipShown ) ) : @(![self.firstRun boolValue]),
|
||||||
NSStringFromSelector( @selector( typeTipShown ) ) : @(!self.firstRun),
|
NSStringFromSelector( @selector( typeTipShown ) ) : @(![self.firstRun boolValue]),
|
||||||
NSStringFromSelector( @selector( loginNameTipShown ) ): @NO,
|
NSStringFromSelector( @selector( loginNameTipShown ) ): @NO,
|
||||||
NSStringFromSelector( @selector( traceMode ) ) : @NO,
|
NSStringFromSelector( @selector( traceMode ) ) : @NO,
|
||||||
NSStringFromSelector( @selector( dictationSearch ) ) : @NO,
|
NSStringFromSelector( @selector( dictationSearch ) ) : @NO,
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleTypeIconFiles</key>
|
<key>CFBundleTypeIconFiles</key>
|
||||||
<array>
|
<array>
|
||||||
<string>Icon-Small</string>
|
<string>Icon-Small-40.png</string>
|
||||||
<string>Icon-64.png</string>
|
<string>Icon-Small-40@2x.png</string>
|
||||||
<string>Icon-320.png</string>
|
<string>Icon-Small-40@3x.png</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleTypeName</key>
|
<key>CFBundleTypeName</key>
|
||||||
<string>Master Password sites</string>
|
<string>Master Password sites</string>
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
<string>Alternate</string>
|
<string>Alternate</string>
|
||||||
<key>LSItemContentTypes</key>
|
<key>LSItemContentTypes</key>
|
||||||
<array>
|
<array>
|
||||||
|
<string>com.lyndir.masterpassword.json</string>
|
||||||
<string>com.lyndir.masterpassword.sites</string>
|
<string>com.lyndir.masterpassword.sites</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
@@ -37,12 +38,36 @@
|
|||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>[auto]</string>
|
<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>
|
<key>CFBundleVersion</key>
|
||||||
<string>[auto]</string>
|
<string>[auto]</string>
|
||||||
|
<key>LSApplicationQueriesSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>firefox</string>
|
||||||
|
<string>googlechrome</string>
|
||||||
|
<string>opera-http</string>
|
||||||
|
<string>volto</string>
|
||||||
|
</array>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>NSFaceIDUsageDescription</key>
|
||||||
|
<string>Biometrics are used to load your master password from the device's keychain.</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>© 2011-2020</string>
|
<string>© 2011-2020</string>
|
||||||
<key>UIAppFonts</key>
|
<key>UIAppFonts</key>
|
||||||
@@ -101,6 +126,34 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>UTExportedTypeDeclarations</key>
|
<key>UTExportedTypeDeclarations</key>
|
||||||
<array>
|
<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>
|
<dict>
|
||||||
<key>UTTypeConformsTo</key>
|
<key>UTTypeConformsTo</key>
|
||||||
<array>
|
<array>
|
||||||
@@ -110,9 +163,9 @@
|
|||||||
<string>Master Password sites</string>
|
<string>Master Password sites</string>
|
||||||
<key>UTTypeIconFiles</key>
|
<key>UTTypeIconFiles</key>
|
||||||
<array>
|
<array>
|
||||||
<string>Icon-Small.png</string>
|
<string>Icon-Small-40.png</string>
|
||||||
<string>Icon-64.png</string>
|
<string>Icon-Small-40@2x.png</string>
|
||||||
<string>Icon-320.png</string>
|
<string>Icon-Small-40@3x.png</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UTTypeIdentifier</key>
|
<key>UTTypeIdentifier</key>
|
||||||
<string>com.lyndir.masterpassword.sites</string>
|
<string>com.lyndir.masterpassword.sites</string>
|
||||||
@@ -121,6 +174,7 @@
|
|||||||
<key>public.filename-extension</key>
|
<key>public.filename-extension</key>
|
||||||
<array>
|
<array>
|
||||||
<string>mpsites</string>
|
<string>mpsites</string>
|
||||||
|
<string>mpsites.txt</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<key>Title</key>
|
<key>Title</key>
|
||||||
<string>Version</string>
|
<string>Version</string>
|
||||||
<key>Key</key>
|
<key>Key</key>
|
||||||
<string>unset</string>
|
<string>version</string>
|
||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
<string>PSTitleValueSpecifier</string>
|
<string>PSTitleValueSpecifier</string>
|
||||||
</dict>
|
</dict>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<key>Title</key>
|
<key>Title</key>
|
||||||
<string>Build</string>
|
<string>Build</string>
|
||||||
<key>Key</key>
|
<key>Key</key>
|
||||||
<string>unset</string>
|
<string>build</string>
|
||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
<string>PSTitleValueSpecifier</string>
|
<string>PSTitleValueSpecifier</string>
|
||||||
</dict>
|
</dict>
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
<string>PSTitleValueSpecifier</string>
|
<string>PSTitleValueSpecifier</string>
|
||||||
<key>Key</key>
|
<key>Key</key>
|
||||||
<string>unset</string>
|
<string>copyright</string>
|
||||||
</dict>
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="Q1S-vU-GGO">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16086"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<customFonts key="customFonts">
|
<customFonts key="customFonts">
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
</collectionViewFlowLayout>
|
</collectionViewFlowLayout>
|
||||||
<cells>
|
<cells>
|
||||||
<collectionViewCell opaque="NO" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPAvatarCell" id="Zab-uQ-uk9" customClass="MPAvatarCell">
|
<collectionViewCell opaque="NO" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPAvatarCell" id="Zab-uQ-uk9" customClass="MPAvatarCell">
|
||||||
<rect key="frame" x="80" y="114.5" width="215" height="667"/>
|
<rect key="frame" x="80" y="115" width="215" height="667"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="215" height="667"/>
|
<rect key="frame" x="0.0" y="0.0" width="215" height="667"/>
|
||||||
@@ -97,10 +97,10 @@
|
|||||||
</constraints>
|
</constraints>
|
||||||
</imageView>
|
</imageView>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0Sa-Vg-EEI" userLabel="Name Backdrop">
|
<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>
|
<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">
|
<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"/>
|
<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"/>
|
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
@@ -288,14 +288,14 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="069-Pu-yXe" userLabel="Thanks Tip">
|
<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>
|
<subviews>
|
||||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" translatesAutoresizingMaskIntoConstraints="NO" id="Z8P-ZK-aS0">
|
<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"/>
|
<rect key="contentStretch" x="0.15000000000000002" y="0.0" width="0.69999999999999973" height="1"/>
|
||||||
</imageView>
|
</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">
|
<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"/>
|
<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"/>
|
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
@@ -442,21 +442,12 @@
|
|||||||
<outlet property="nextAvatarButton" destination="fUK-gJ-NRE" id="5qo-lK-rSa"/>
|
<outlet property="nextAvatarButton" destination="fUK-gJ-NRE" id="5qo-lK-rSa"/>
|
||||||
<outlet property="preferencesTipContainer" destination="0Um-Ot-hI6" id="Cv8-Bp-ZZs"/>
|
<outlet property="preferencesTipContainer" destination="0Um-Ot-hI6" id="Cv8-Bp-ZZs"/>
|
||||||
<outlet property="previousAvatarButton" destination="9u7-pu-Wtv" id="Hgv-lN-S1n"/>
|
<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="storeLoadingActivity" destination="VDd-oM-ZOO" id="MJ7-2f-e8n"/>
|
||||||
<outlet property="thanksTipContainer" destination="069-Pu-yXe" id="wWf-2X-Ryw"/>
|
<outlet property="thanksTipContainer" destination="069-Pu-yXe" id="wWf-2X-Ryw"/>
|
||||||
<outlet property="userSelectionContainer" destination="rWM-08-aab" id="Yme-hX-8P0"/>
|
<outlet property="userSelectionContainer" destination="rWM-08-aab" id="Yme-hX-8P0"/>
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="8hZ-Tb-wZw" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<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>
|
</objects>
|
||||||
<point key="canvasLocation" x="2041" y="226"/>
|
<point key="canvasLocation" x="2041" y="226"/>
|
||||||
</scene>
|
</scene>
|
||||||
@@ -472,17 +463,11 @@
|
|||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<subviews>
|
<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">
|
<navigationBar contentMode="scaleToFill" barStyle="black" translatesAutoresizingMaskIntoConstraints="NO" id="03x-KT-JQN">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="90"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="90"/>
|
||||||
<items>
|
<items>
|
||||||
<navigationItem title="masterpassword.app" prompt="Loading" id="Wpf-6b-UJb">
|
<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">
|
<barButtonItem key="rightBarButtonItem" systemItem="done" id="Tbg-c3-qOh">
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="done:" destination="Sd5-eW-Cx2" id="cuN-bV-cwl"/>
|
<action selector="done:" destination="Sd5-eW-Cx2" id="cuN-bV-cwl"/>
|
||||||
@@ -494,19 +479,14 @@
|
|||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<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="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 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 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>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<navigationItem key="navigationItem" id="gmy-ym-z4I"/>
|
<navigationItem key="navigationItem" id="gmy-ym-z4I"/>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="webNavigationItem" destination="Wpf-6b-UJb" id="8gM-LU-pHk"/>
|
<outlet property="webNavigationItem" destination="Wpf-6b-UJb" id="8gM-LU-pHk"/>
|
||||||
<outlet property="webView" destination="3aB-Hk-Fgd" id="Mie-rI-l4h"/>
|
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="hNt-WS-DuE" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<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">
|
<view key="view" contentMode="scaleToFill" id="c4P-nn-PjR">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<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"/>
|
<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>
|
</view>
|
||||||
<navigationItem key="navigationItem" id="V6W-ql-3TD"/>
|
<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>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="fQY-fV-sIe" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="fQY-fV-sIe" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
@@ -568,12 +559,25 @@
|
|||||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" image="background.png" translatesAutoresizingMaskIntoConstraints="NO" id="Lkg-xn-bce" userLabel="Background">
|
<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"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||||
</imageView>
|
</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>
|
</subviews>
|
||||||
<constraints>
|
<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="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 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 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="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>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<navigationItem key="navigationItem" id="MPa-zX-Kaq"/>
|
<navigationItem key="navigationItem" id="MPa-zX-Kaq"/>
|
||||||
@@ -581,7 +585,6 @@
|
|||||||
<connections>
|
<connections>
|
||||||
<segue destination="osn-5H-SWW" kind="custom" identifier="emergency" customClass="MPOverlaySegue" id="gtX-Cx-AA2"/>
|
<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="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>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="F33-Fe-Tb6" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="F33-Fe-Tb6" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
@@ -600,7 +603,6 @@
|
|||||||
<connections>
|
<connections>
|
||||||
<segue destination="JFc-sj-awD" kind="relationship" relationship="viewControllers" id="bwn-ao-Y5g"/>
|
<segue destination="JFc-sj-awD" kind="relationship" relationship="viewControllers" id="bwn-ao-Y5g"/>
|
||||||
<segue destination="C0Q-RC-szS" kind="relationship" relationship="viewControllers" id="wap-5K-BMD"/>
|
<segue destination="C0Q-RC-szS" kind="relationship" relationship="viewControllers" id="wap-5K-BMD"/>
|
||||||
<segue destination="LBn-EA-NAH" kind="relationship" relationship="viewControllers" id="sGh-gf-eKK"/>
|
|
||||||
<segue destination="pdl-xv-zjX" kind="relationship" relationship="viewControllers" id="QTc-cR-VHJ"/>
|
<segue destination="pdl-xv-zjX" kind="relationship" relationship="viewControllers" id="QTc-cR-VHJ"/>
|
||||||
</connections>
|
</connections>
|
||||||
</tabBarController>
|
</tabBarController>
|
||||||
@@ -899,14 +901,15 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</switch>
|
</switch>
|
||||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Biometrics" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6xf-vt-aXd">
|
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Biometrics" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6xf-vt-aXd">
|
||||||
<rect key="frame" x="20" y="20" width="374" height="21"/>
|
<rect key="frame" x="20" y="20" width="374" height="20"/>
|
||||||
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
|
<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"/>
|
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="URR-yZ-QuC">
|
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="URR-yZ-QuC">
|
||||||
<rect key="frame" x="20" y="49" width="374" height="142"/>
|
<rect key="frame" x="20" y="48" width="374" height="143"/>
|
||||||
<string key="text">When enabled on a biometrics-enabled device, your fingerprint or face scan will be required to load your saved password. Note that this feature requires that the Save Password option is enabled and Biometrics support has been purchased from the in-app store.</string>
|
<string key="text">When enabled on a biometrics-enabled device, your fingerprint or face scan will be required to load your stored master password.
|
||||||
|
Note that this feature requires you enable the Save Password option and have purchased Biometrics support from the in-app store.</string>
|
||||||
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="12"/>
|
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="12"/>
|
||||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
@@ -1143,20 +1146,21 @@
|
|||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="K2e-Gh-7hH" userLabel="Passwords Container">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="K2e-Gh-7hH" userLabel="Passwords Container">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<collectionView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" minimumZoomScale="0.0" maximumZoomScale="0.0" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="aXw-tn-8Sj" userLabel="Password Collection">
|
<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"/>
|
<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"/>
|
<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" 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="itemSize" width="355" height="100"/>
|
||||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
||||||
<inset key="sectionInset" minX="10" minY="200" maxX="10" maxY="10"/>
|
<inset key="sectionInset" minX="10" minY="10" maxX="10" maxY="10"/>
|
||||||
</collectionViewFlowLayout>
|
</collectionViewFlowLayout>
|
||||||
<cells>
|
<cells>
|
||||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPSiteCell" id="W2g-yv-V3V" customClass="MPSiteCell">
|
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPSiteCell" id="W2g-yv-V3V" customClass="MPSiteCell">
|
||||||
<rect key="frame" x="29.5" y="200" width="355" height="100"/>
|
<rect key="frame" x="29.5" y="110" width="355" height="100"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
<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"/>
|
<rect key="frame" x="0.0" y="0.0" width="355" height="100"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
@@ -1547,11 +1551,12 @@
|
|||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<gestureRecognizers/>
|
<gestureRecognizers/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="trailing" secondItem="xph-TW-9QO" secondAttribute="trailing" id="Fmt-yZ-Vjo"/>
|
<constraint firstAttribute="trailing" secondItem="xph-TW-9QO" secondAttribute="trailing" priority="900" id="Fmt-yZ-Vjo"/>
|
||||||
<constraint firstItem="xph-TW-9QO" firstAttribute="leading" secondItem="W2g-yv-V3V" secondAttribute="leading" id="IsM-Br-kMe"/>
|
<constraint firstItem="xph-TW-9QO" firstAttribute="leading" secondItem="W2g-yv-V3V" secondAttribute="leading" priority="900" id="IsM-Br-kMe"/>
|
||||||
<constraint firstItem="xph-TW-9QO" firstAttribute="top" secondItem="W2g-yv-V3V" secondAttribute="top" id="KDo-0Z-mc1"/>
|
<constraint firstItem="xph-TW-9QO" firstAttribute="top" secondItem="W2g-yv-V3V" secondAttribute="top" priority="900" id="KDo-0Z-mc1"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="xph-TW-9QO" secondAttribute="bottom" id="W1r-47-bqe"/>
|
<constraint firstAttribute="bottom" secondItem="xph-TW-9QO" secondAttribute="bottom" priority="900" id="W1r-47-bqe"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
<size key="customSize" width="355" height="100"/>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="answersButton" destination="vGk-t6-hZn" id="0oi-2F-M1S"/>
|
<outlet property="answersButton" destination="vGk-t6-hZn" id="0oi-2F-M1S"/>
|
||||||
<outlet property="contentButton" destination="aDw-qY-VjU" id="R3R-kq-XMd"/>
|
<outlet property="contentButton" destination="aDw-qY-VjU" id="R3R-kq-XMd"/>
|
||||||
@@ -2058,9 +2063,7 @@ This app is now out of maintenance.</string>
|
|||||||
<constraint firstAttribute="width" secondItem="whU-l0-2bU" secondAttribute="width" id="AiQ-LE-3bh"/>
|
<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="IV3-lc-Fnf" firstAttribute="top" secondItem="gRG-Ys-94p" secondAttribute="bottom" id="IMb-wl-Eeb"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="gRG-Ys-94p" secondAttribute="trailing" id="Pb1-eY-0FG"/>
|
<constraint firstAttribute="trailing" secondItem="gRG-Ys-94p" secondAttribute="trailing" id="Pb1-eY-0FG"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="GiS-3g-cDj" secondAttribute="trailing" id="TjK-B6-KoI"/>
|
|
||||||
<constraint firstItem="gRG-Ys-94p" firstAttribute="top" secondItem="GiS-3g-cDj" secondAttribute="top" id="oyk-Xr-zTZ"/>
|
<constraint firstItem="gRG-Ys-94p" firstAttribute="top" secondItem="GiS-3g-cDj" secondAttribute="top" id="oyk-Xr-zTZ"/>
|
||||||
<constraint firstItem="IV3-lc-Fnf" firstAttribute="top" secondItem="GiS-3g-cDj" secondAttribute="bottom" id="t22-RN-Hm0"/>
|
|
||||||
<constraint firstItem="gRG-Ys-94p" firstAttribute="leading" secondItem="GiS-3g-cDj" secondAttribute="leading" id="zhC-jf-5dY"/>
|
<constraint firstItem="gRG-Ys-94p" firstAttribute="leading" secondItem="GiS-3g-cDj" secondAttribute="leading" id="zhC-jf-5dY"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<userDefinedRuntimeAttributes>
|
<userDefinedRuntimeAttributes>
|
||||||
@@ -2091,58 +2094,6 @@ This app is now out of maintenance.</string>
|
|||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="2038" y="-518"/>
|
<point key="canvasLocation" x="2038" y="-518"/>
|
||||||
</scene>
|
</scene>
|
||||||
<!--Settings-->
|
|
||||||
<scene sceneID="jGj-Je-kyC">
|
|
||||||
<objects>
|
|
||||||
<navigationController definesPresentationContext="YES" id="LBn-EA-NAH" sceneMemberID="viewController">
|
|
||||||
<tabBarItem key="tabBarItem" title="Settings" image="icon_gears.png" id="6n3-Ay-Knn"/>
|
|
||||||
<navigationBar key="navigationBar" contentMode="scaleToFill" misplaced="YES" id="h6j-1o-LHf">
|
|
||||||
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
</navigationBar>
|
|
||||||
<connections>
|
|
||||||
<segue destination="IJT-xV-jHt" kind="relationship" relationship="rootViewController" id="ymU-OE-v4t"/>
|
|
||||||
</connections>
|
|
||||||
</navigationController>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="PQz-c8-3Ww" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
|
||||||
</objects>
|
|
||||||
<point key="canvasLocation" x="3803" y="919"/>
|
|
||||||
</scene>
|
|
||||||
<!--Settings-->
|
|
||||||
<scene sceneID="fmc-CS-nuo">
|
|
||||||
<objects>
|
|
||||||
<tableViewController automaticallyAdjustsScrollViewInsets="NO" id="IJT-xV-jHt" customClass="MPAppSettingsViewController" sceneMemberID="viewController">
|
|
||||||
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="jPx-Oa-WxU">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
<inset key="scrollIndicatorInsets" minX="0.0" minY="64" maxX="0.0" maxY="49"/>
|
|
||||||
<color key="separatorColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
<color key="sectionIndexColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
<prototypes>
|
|
||||||
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="-" id="3ZC-Sm-lB8">
|
|
||||||
<rect key="frame" x="0.0" y="55.5" width="414" height="44"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3ZC-Sm-lB8" id="UzB-cq-EM3">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
</tableViewCellContentView>
|
|
||||||
</tableViewCell>
|
|
||||||
</prototypes>
|
|
||||||
<connections>
|
|
||||||
<outlet property="dataSource" destination="IJT-xV-jHt" id="bMa-HU-UPY"/>
|
|
||||||
<outlet property="delegate" destination="IJT-xV-jHt" id="MJE-yH-6xk"/>
|
|
||||||
</connections>
|
|
||||||
</tableView>
|
|
||||||
<tabBarItem key="tabBarItem" title="Settings" image="icon_gears.png" id="K62-lO-hO3"/>
|
|
||||||
<navigationItem key="navigationItem" title="Settings" id="FPc-yy-RoS">
|
|
||||||
<barButtonItem key="rightBarButtonItem" title="Logs" id="rO8-gt-aLH"/>
|
|
||||||
</navigationItem>
|
|
||||||
</tableViewController>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="sDE-fE-FNc" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
|
||||||
</objects>
|
|
||||||
<point key="canvasLocation" x="4730" y="919"/>
|
|
||||||
</scene>
|
|
||||||
<!--Usage-->
|
<!--Usage-->
|
||||||
<scene sceneID="9SY-7D-CE9">
|
<scene sceneID="9SY-7D-CE9">
|
||||||
<objects>
|
<objects>
|
||||||
@@ -2278,7 +2229,7 @@ CgoKCgoKCgoKCgoKCg
|
|||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZLZ-Ds-7pp">
|
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZLZ-Ds-7pp">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<inset key="scrollIndicatorInsets" minX="0.0" minY="64" maxX="0.0" maxY="93"/>
|
<inset key="scrollIndicatorInsets" minX="0.0" minY="64" maxX="0.0" maxY="93"/>
|
||||||
<string key="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis tortor leo, iaculis mollis elit dictum et. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In congue justo porta enim imperdiet, id luctus justo fringilla. Nunc nec sem id augue bibendum hendrerit eu ut eros. Ut fermentum augue quis nunc feugiat vehicula. Quisque in ultrices magna. Praesent quis mollis lectus. Sed fringilla massa vitae eros luctus, eget convallis justo pretium. Duis non tristique ante. Sed suscipit tortor ligula, sed fermentum eros sodales ut. Maecenas sed ante et orci posuere lobortis et sodales diam. Nunc non ullamcorper orci.
|
<string key="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis tortor leo, iaculis mollis elit dictum et. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In congue justo porta enim imperdiet, id luctus justo fringilla. Nunc nec sem id augue bibendum hendrerit eu ut eros. Ut fermentum augue quis nunc feugiat vehicula. Quisque in ultrices magna. Praesent quis mollis lectus. Sed fringilla massa vitae eros luctus, eget convallis justo pretium. Duis non tristique ante. Sed suscipit tortor ligula, sed fermentum eros sodales ut. Maecenas sed ante et orci posuere lobortis et sodales diam. Nunc non ullamcorper orci.
|
||||||
@@ -2290,7 +2241,7 @@ Suspendisse potenti. Etiam ut nisi id augue tempor ultrices et sit amet sapien.
|
|||||||
<dataDetectorType key="dataDetectorTypes" link="YES"/>
|
<dataDetectorType key="dataDetectorTypes" link="YES"/>
|
||||||
</textView>
|
</textView>
|
||||||
<toolbar contentMode="scaleToFill" barStyle="black" translatesAutoresizingMaskIntoConstraints="NO" id="WmH-JB-jp2">
|
<toolbar contentMode="scaleToFill" barStyle="black" translatesAutoresizingMaskIntoConstraints="NO" id="WmH-JB-jp2">
|
||||||
<rect key="frame" x="0.0" y="798" width="414" height="49"/>
|
<rect key="frame" x="0.0" y="769" width="414" height="44"/>
|
||||||
<items>
|
<items>
|
||||||
<barButtonItem systemItem="compose" id="BSV-3i-01h">
|
<barButtonItem systemItem="compose" id="BSV-3i-01h">
|
||||||
<connections>
|
<connections>
|
||||||
@@ -2305,7 +2256,7 @@ Suspendisse potenti. Etiam ut nisi id augue tempor ultrices et sit amet sapien.
|
|||||||
<barButtonItem systemItem="flexibleSpace" id="Lp4-ss-KxI"/>
|
<barButtonItem systemItem="flexibleSpace" id="Lp4-ss-KxI"/>
|
||||||
<barButtonItem style="plain" id="aMS-HH-mnE">
|
<barButtonItem style="plain" id="aMS-HH-mnE">
|
||||||
<segmentedControl key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bar" selectedSegmentIndex="0" id="lxp-wx-uCy">
|
<segmentedControl key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bar" selectedSegmentIndex="0" id="lxp-wx-uCy">
|
||||||
<rect key="frame" x="267" y="11" width="127" height="32"/>
|
<rect key="frame" x="267" y="6" width="127" height="32"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<segments>
|
<segments>
|
||||||
<segment title="Normal"/>
|
<segment title="Normal"/>
|
||||||
@@ -2323,8 +2274,8 @@ Suspendisse potenti. Etiam ut nisi id augue tempor ultrices et sit amet sapien.
|
|||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="0.1215686275" green="0.12941176469999999" blue="0.14117647059999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.1215686275" green="0.12941176469999999" blue="0.14117647059999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="bottom" secondItem="WmH-JB-jp2" secondAttribute="bottom" constant="49" id="3MJ-7p-Ko1"/>
|
<constraint firstAttribute="bottomMargin" secondItem="WmH-JB-jp2" secondAttribute="bottom" id="3MJ-7p-Ko1"/>
|
||||||
<constraint firstItem="ZLZ-Ds-7pp" firstAttribute="top" secondItem="VRk-ZF-UQ6" secondAttribute="top" id="SDj-uX-oNC"/>
|
<constraint firstItem="ZLZ-Ds-7pp" firstAttribute="top" secondItem="VRk-ZF-UQ6" secondAttribute="topMargin" id="SDj-uX-oNC"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="ZLZ-Ds-7pp" secondAttribute="bottom" id="bpm-15-Rgy"/>
|
<constraint firstAttribute="bottom" secondItem="ZLZ-Ds-7pp" secondAttribute="bottom" id="bpm-15-Rgy"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="WmH-JB-jp2" secondAttribute="trailing" id="f4Q-oI-Dxc"/>
|
<constraint firstAttribute="trailing" secondItem="WmH-JB-jp2" secondAttribute="trailing" id="f4Q-oI-Dxc"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="ZLZ-Ds-7pp" secondAttribute="trailing" id="iID-PM-DSF"/>
|
<constraint firstAttribute="trailing" secondItem="ZLZ-Ds-7pp" secondAttribute="trailing" id="iID-PM-DSF"/>
|
||||||
@@ -2377,17 +2328,17 @@ 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"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<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"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ol8-3I-X99">
|
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ol8-3I-X99">
|
||||||
<rect key="frame" x="0.0" y="56" width="414" height="752"/>
|
<rect key="frame" x="0.0" y="56" width="414" height="752"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView userInteractionEnabled="NO" contentMode="top" image="unlocked.png" translatesAutoresizingMaskIntoConstraints="NO" id="Cih-B6-Sfd">
|
<imageView userInteractionEnabled="NO" contentMode="top" image="unlocked.png" translatesAutoresizingMaskIntoConstraints="NO" id="Cih-B6-Sfd">
|
||||||
<rect key="frame" x="20" y="20" width="374" height="79.5"/>
|
<rect key="frame" x="20" y="20" width="374" height="80"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Stay Logged In?" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5X1-J4-TbH">
|
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Stay Logged In?" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5X1-J4-TbH">
|
||||||
<rect key="frame" x="20" y="107.5" width="374" height="20"/>
|
<rect key="frame" x="20" y="108" width="374" height="20"/>
|
||||||
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
|
<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"/>
|
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
@@ -2397,7 +2348,7 @@ Suspendisse potenti. Etiam ut nisi id augue tempor ultrices et sit amet sapien.
|
|||||||
<color key="onTintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="onTintColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</switch>
|
</switch>
|
||||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e80-98-V6D">
|
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e80-98-V6D">
|
||||||
<rect key="frame" x="20" y="135.5" width="374" height="151.5"/>
|
<rect key="frame" x="20" y="136" width="374" height="151.5"/>
|
||||||
<string key="text">The right balance between security and convenience is often very personal.
|
<string key="text">The right balance between security and convenience is often very personal.
|
||||||
|
|
||||||
To make getting to your passwords faster, you can remain logged in after you close Master Password. This allows you to skip having to log in the next time.
|
To make getting to your passwords faster, you can remain logged in after you close Master Password. This allows you to skip having to log in the next time.
|
||||||
@@ -2465,7 +2416,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"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<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"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fJc-xU-1xA">
|
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fJc-xU-1xA">
|
||||||
@@ -2805,7 +2756,7 @@ Invested: 3.7 work hours</string>
|
|||||||
<rect key="frame" x="188.5" y="20" width="37" height="37"/>
|
<rect key="frame" x="188.5" y="20" width="37" height="37"/>
|
||||||
</activityIndicatorView>
|
</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">
|
<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"/>
|
<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="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
@@ -3089,7 +3040,7 @@ Invested: 3.7 work hours</string>
|
|||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<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"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7A7-Yn-F6L">
|
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7A7-Yn-F6L">
|
||||||
@@ -3322,7 +3273,7 @@ Ut in geometria, prima si dederis, danda sunt omnia. Nonne igitur tibi videntur,
|
|||||||
</scenes>
|
</scenes>
|
||||||
<inferredMetricsTieBreakers>
|
<inferredMetricsTieBreakers>
|
||||||
<segue reference="Ql4-wf-T8u"/>
|
<segue reference="Ql4-wf-T8u"/>
|
||||||
<segue reference="GZk-I4-JyH"/>
|
<segue reference="gtb-zE-u9H"/>
|
||||||
</inferredMetricsTieBreakers>
|
</inferredMetricsTieBreakers>
|
||||||
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
<resources>
|
<resources>
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ library {
|
|||||||
def arch = targetMachine.getArchitecture().getName().replace('-', '_')
|
def arch = targetMachine.getArchitecture().getName().replace('-', '_')
|
||||||
|
|
||||||
compile.macros.put("MPW_SODIUM", "1")
|
compile.macros.put("MPW_SODIUM", "1")
|
||||||
compile.macros.put("MPW_LOG", "mpw_log_app")
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// libsodium
|
// libsodium
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ static const uint8_t b64ToBits[256] =
|
|||||||
size_t mpw_base64_decode_max(const char *b64Text) {
|
size_t mpw_base64_decode_max(const char *b64Text) {
|
||||||
|
|
||||||
register const char *b64Cursor = b64Text;
|
register const char *b64Cursor = b64Text;
|
||||||
for (; b64ToBits[*b64Cursor] <= 63; ++b64Cursor);
|
for (; b64ToBits[(uint8_t)*b64Cursor] <= 63; ++b64Cursor);
|
||||||
size_t b64Size = b64Cursor - b64Text;
|
size_t b64Size = b64Cursor - b64Text;
|
||||||
|
|
||||||
// Every 4 b64 chars yield 3 plain bytes => len = 3 * ceil(b64Size / 4)
|
// Every 4 b64 chars yield 3 plain bytes => len = 3 * ceil(b64Size / 4)
|
||||||
@@ -91,7 +91,7 @@ size_t mpw_base64_decode_max(const char *b64Text) {
|
|||||||
size_t mpw_base64_decode(uint8_t *plainBuf, const char *b64Text) {
|
size_t mpw_base64_decode(uint8_t *plainBuf, const char *b64Text) {
|
||||||
|
|
||||||
register const uint8_t *b64Cursor = (uint8_t *)b64Text;
|
register const uint8_t *b64Cursor = (uint8_t *)b64Text;
|
||||||
for (; b64ToBits[*b64Cursor] <= 63; ++b64Cursor);
|
for (; b64ToBits[(uint8_t)*b64Cursor] <= 63; ++b64Cursor);
|
||||||
size_t b64Remaining = b64Cursor - (uint8_t *)b64Text;
|
size_t b64Remaining = b64Cursor - (uint8_t *)b64Text;
|
||||||
|
|
||||||
b64Cursor = (uint8_t *)b64Text;
|
b64Cursor = (uint8_t *)b64Text;
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
#undef com_lyndir_masterpassword_MPAlgorithm_Version_AES_BLOCKSIZE
|
|
||||||
#define com_lyndir_masterpassword_MPAlgorithm_Version_AES_BLOCKSIZE 128L
|
|
||||||
/*
|
/*
|
||||||
* Class: com_lyndir_masterpassword_MPAlgorithm_Version
|
* Class: com_lyndir_masterpassword_MPAlgorithm_Version
|
||||||
* Method: _masterKey
|
* Method: _masterKey
|
||||||
@@ -41,6 +39,22 @@ JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Versio
|
|||||||
JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1siteState
|
JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1siteState
|
||||||
(JNIEnv *, jobject, jbyteArray, jbyteArray, jstring, jlong, jint, jstring, jint, jstring, jint);
|
(JNIEnv *, jobject, jbyteArray, jbyteArray, jstring, jlong, jint, jstring, jint, jstring, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_lyndir_masterpassword_MPAlgorithm_Version
|
||||||
|
* Method: _identicon
|
||||||
|
* Signature: (Ljava/lang/String;[B)Lcom/lyndir/masterpassword/MPIdenticon;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobject JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1identicon
|
||||||
|
(JNIEnv *, jobject, jstring, jbyteArray);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_lyndir_masterpassword_MPAlgorithm_Version
|
||||||
|
* Method: _toID
|
||||||
|
* Signature: ([B)Ljava/lang/String;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1toID
|
||||||
|
(JNIEnv *, jobject, jbyteArray);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ const char *mpw_site_result(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *sitePassword = NULL;
|
|
||||||
if (resultType & MPResultTypeClassTemplate) {
|
if (resultType & MPResultTypeClassTemplate) {
|
||||||
switch (algorithmVersion) {
|
switch (algorithmVersion) {
|
||||||
case MPAlgorithmVersionV0:
|
case MPAlgorithmVersionV0:
|
||||||
@@ -172,7 +171,7 @@ const char *mpw_site_result(
|
|||||||
err( "Unsupported password type: %d", resultType );
|
err( "Unsupported password type: %d", resultType );
|
||||||
}
|
}
|
||||||
|
|
||||||
return sitePassword;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *mpw_site_state(
|
const char *mpw_site_state(
|
||||||
|
|||||||
@@ -10,50 +10,46 @@
|
|||||||
static JavaVM* _vm;
|
static JavaVM* _vm;
|
||||||
static jobject logger;
|
static jobject logger;
|
||||||
|
|
||||||
void mpw_log_app(LogLevel level, const char *format, ...) {
|
MPLogSink mpw_log_sink_jni;
|
||||||
|
bool mpw_log_sink_jni(const MPLogEvent *record) {
|
||||||
|
bool sunk = false;
|
||||||
|
|
||||||
JNIEnv *env;
|
JNIEnv *env;
|
||||||
if ((*_vm)->GetEnv( _vm, (void **)&env, JNI_VERSION_1_6 ) != JNI_OK)
|
if ((*_vm)->GetEnv( _vm, (void **)&env, JNI_VERSION_1_6 ) != JNI_OK)
|
||||||
return;
|
return sunk;
|
||||||
|
|
||||||
va_list args;
|
|
||||||
va_start( args, format );
|
|
||||||
|
|
||||||
if (logger && (*env)->PushLocalFrame( env, 16 ) == OK) {
|
if (logger && (*env)->PushLocalFrame( env, 16 ) == OK) {
|
||||||
jmethodID method = NULL;
|
jmethodID method = NULL;
|
||||||
jclass Logger = (*env)->GetObjectClass( env, logger );
|
jclass cLogger = (*env)->GetObjectClass( env, logger );
|
||||||
if (level >= LogLevelTrace)
|
switch (record->level) {
|
||||||
method = (*env)->GetMethodID( env, Logger, "trace", "(Ljava/lang/String;)V" );
|
case LogLevelTrace:
|
||||||
else if (level == LogLevelDebug)
|
method = (*env)->GetMethodID( env, cLogger, "trace", "(Ljava/lang/String;)V" );
|
||||||
method = (*env)->GetMethodID( env, Logger, "debug", "(Ljava/lang/String;)V" );
|
break;
|
||||||
else if (level == LogLevelInfo)
|
case LogLevelDebug:
|
||||||
method = (*env)->GetMethodID( env, Logger, "info", "(Ljava/lang/String;)V" );
|
method = (*env)->GetMethodID( env, cLogger, "debug", "(Ljava/lang/String;)V" );
|
||||||
else if (level == LogLevelWarning)
|
break;
|
||||||
method = (*env)->GetMethodID( env, Logger, "warn", "(Ljava/lang/String;)V" );
|
case LogLevelInfo:
|
||||||
else if (level <= LogLevelError)
|
method = (*env)->GetMethodID( env, cLogger, "info", "(Ljava/lang/String;)V" );
|
||||||
method = (*env)->GetMethodID( env, Logger, "error", "(Ljava/lang/String;)V" );
|
break;
|
||||||
|
case LogLevelWarning:
|
||||||
|
method = (*env)->GetMethodID( env, cLogger, "warn", "(Ljava/lang/String;)V" );
|
||||||
|
break;
|
||||||
|
case LogLevelError:
|
||||||
|
case LogLevelFatal:
|
||||||
|
method = (*env)->GetMethodID( env, cLogger, "error", "(Ljava/lang/String;)V" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
va_list _args;
|
if (method && record->message) {
|
||||||
va_copy( _args, args );
|
// TODO: log file, line & function as markers?
|
||||||
int length = vsnprintf( NULL, 0, format, _args );
|
(*env)->CallVoidMethod( env, logger, method, (*env)->NewStringUTF( env, record->message ) );
|
||||||
va_end( _args );
|
sunk = true;
|
||||||
|
|
||||||
if (length > 0) {
|
|
||||||
size_t size = (size_t) (length + 1);
|
|
||||||
char *message = malloc( size );
|
|
||||||
va_copy( _args, args );
|
|
||||||
if (message && (length = vsnprintf( message, size, format, _args )) > 0)
|
|
||||||
(*env)->CallVoidMethod( env, logger, method, (*env)->NewStringUTF( env, message ) );
|
|
||||||
va_end( _args );
|
|
||||||
mpw_free( &message, (size_t)max( 0, length ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(*env)->PopLocalFrame( env, NULL );
|
(*env)->PopLocalFrame( env, NULL );
|
||||||
}
|
}
|
||||||
else
|
|
||||||
// Can't log via slf4j, fall back to cli logger.
|
|
||||||
mpw_vlog_cli( level, format, args );
|
|
||||||
|
|
||||||
va_end( args );
|
return sunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||||
@@ -61,33 +57,45 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|||||||
if ((*vm)->GetEnv( _vm = vm, (void **)&env, JNI_VERSION_1_6 ) != JNI_OK)
|
if ((*vm)->GetEnv( _vm = vm, (void **)&env, JNI_VERSION_1_6 ) != JNI_OK)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
jclass LoggerFactory = (*env)->FindClass( env, "org/slf4j/LoggerFactory" );
|
do {
|
||||||
jmethodID method = (*env)->GetStaticMethodID( env, LoggerFactory, "getLogger", "(Ljava/lang/String;)Lorg/slf4j/Logger;" );
|
jclass cLoggerFactory = (*env)->FindClass( env, "org/slf4j/LoggerFactory" );
|
||||||
|
if (!cLoggerFactory)
|
||||||
|
break;
|
||||||
|
jmethodID method = (*env)->GetStaticMethodID( env, cLoggerFactory, "getLogger", "(Ljava/lang/String;)Lorg/slf4j/Logger;" );
|
||||||
|
if (!method)
|
||||||
|
break;
|
||||||
jstring name = (*env)->NewStringUTF( env, "com.lyndir.masterpassword.algorithm" );
|
jstring name = (*env)->NewStringUTF( env, "com.lyndir.masterpassword.algorithm" );
|
||||||
if (LoggerFactory && method && name)
|
if (!name)
|
||||||
logger = (*env)->NewGlobalRef( env, (*env)->CallStaticObjectMethod( env, LoggerFactory, method, name ) );
|
break;
|
||||||
else
|
logger = (*env)->NewGlobalRef( env, (*env)->CallStaticObjectMethod( env, cLoggerFactory, method, name ) );
|
||||||
wrn( "Couldn't initialize JNI logger." );
|
if (!logger)
|
||||||
|
break;
|
||||||
|
|
||||||
jclass Logger = (*env)->GetObjectClass( env, logger );
|
jclass cLogger = (*env)->GetObjectClass( env, logger );
|
||||||
if ((*env)->CallBooleanMethod( env, logger, (*env)->GetMethodID( env, Logger, "isTraceEnabled", "()Z" ) ))
|
if ((*env)->CallBooleanMethod( env, logger, (*env)->GetMethodID( env, cLogger, "isTraceEnabled", "()Z" ) ))
|
||||||
mpw_verbosity = LogLevelTrace;
|
mpw_verbosity = LogLevelTrace;
|
||||||
else if ((*env)->CallBooleanMethod( env, logger, (*env)->GetMethodID( env, Logger, "isDebugEnabled", "()Z" ) ))
|
else if ((*env)->CallBooleanMethod( env, logger, (*env)->GetMethodID( env, cLogger, "isDebugEnabled", "()Z" ) ))
|
||||||
mpw_verbosity = LogLevelDebug;
|
mpw_verbosity = LogLevelDebug;
|
||||||
else if ((*env)->CallBooleanMethod( env, logger, (*env)->GetMethodID( env, Logger, "isInfoEnabled", "()Z" ) ))
|
else if ((*env)->CallBooleanMethod( env, logger, (*env)->GetMethodID( env, cLogger, "isInfoEnabled", "()Z" ) ))
|
||||||
mpw_verbosity = LogLevelInfo;
|
mpw_verbosity = LogLevelInfo;
|
||||||
else if ((*env)->CallBooleanMethod( env, logger, (*env)->GetMethodID( env, Logger, "isWarnEnabled", "()Z" ) ))
|
else if ((*env)->CallBooleanMethod( env, logger, (*env)->GetMethodID( env, cLogger, "isWarnEnabled", "()Z" ) ))
|
||||||
mpw_verbosity = LogLevelWarning;
|
mpw_verbosity = LogLevelWarning;
|
||||||
else if ((*env)->CallBooleanMethod( env, logger, (*env)->GetMethodID( env, Logger, "isErrorEnabled", "()Z" ) ))
|
else if ((*env)->CallBooleanMethod( env, logger, (*env)->GetMethodID( env, cLogger, "isErrorEnabled", "()Z" ) ))
|
||||||
mpw_verbosity = LogLevelError;
|
mpw_verbosity = LogLevelError;
|
||||||
else
|
else
|
||||||
mpw_verbosity = LogLevelFatal;
|
mpw_verbosity = LogLevelFatal;
|
||||||
|
|
||||||
|
mpw_log_sink_register( &mpw_log_sink_jni );
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
if (!logger)
|
||||||
|
wrn( "Couldn't initialize JNI logger." );
|
||||||
|
|
||||||
return JNI_VERSION_1_6;
|
return JNI_VERSION_1_6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* native int _masterKey(final String fullName, final byte[] masterPassword, final Version version) */
|
/* native byte[] _masterKey(final String fullName, final byte[] masterPassword, final int algorithmVersion) */
|
||||||
JNIEXPORT jbyteArray JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1masterKey(JNIEnv *env, jobject obj,
|
JNIEXPORT jbyteArray JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1masterKey(JNIEnv *env, jobject obj,
|
||||||
jstring fullName, jbyteArray masterPassword, jint algorithmVersion) {
|
jstring fullName, jbyteArray masterPassword, jint algorithmVersion) {
|
||||||
|
|
||||||
if (!fullName || !masterPassword)
|
if (!fullName || !masterPassword)
|
||||||
@@ -110,9 +118,9 @@ JNIEXPORT jbyteArray JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__
|
|||||||
return masterKey;
|
return masterKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* native int _siteKey(final byte[] masterKey, final String siteName, final long siteCounter,
|
/* native byte[] _siteKey(final byte[] masterKey, final String siteName, final long siteCounter,
|
||||||
final MPKeyPurpose keyPurpose, @Nullable final String keyContext, final Version version) */
|
final int keyPurpose, @Nullable final String keyContext, final int version) */
|
||||||
JNIEXPORT jbyteArray JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1siteKey(JNIEnv *env, jobject obj,
|
JNIEXPORT jbyteArray JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1siteKey(JNIEnv *env, jobject obj,
|
||||||
jbyteArray masterKey, jstring siteName, jlong siteCounter, jint keyPurpose, jstring keyContext, jint algorithmVersion) {
|
jbyteArray masterKey, jstring siteName, jlong siteCounter, jint keyPurpose, jstring keyContext, jint algorithmVersion) {
|
||||||
|
|
||||||
if (!masterKey || !siteName)
|
if (!masterKey || !siteName)
|
||||||
@@ -140,9 +148,9 @@ JNIEXPORT jbyteArray JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* native String _siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final long siteCounter,
|
/* native String _siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final long siteCounter,
|
||||||
final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
|
final int keyPurpose, @Nullable final String keyContext,
|
||||||
final MPResultType resultType, @Nullable final String resultParam, final Version version) */
|
final int resultType, @Nullable final String resultParam, final int algorithmVersion) */
|
||||||
JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1siteResult(JNIEnv *env, jobject obj,
|
JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1siteResult(JNIEnv *env, jobject obj,
|
||||||
jbyteArray masterKey, jbyteArray siteKey, jstring siteName, jlong siteCounter, jint keyPurpose, jstring keyContext,
|
jbyteArray masterKey, jbyteArray siteKey, jstring siteName, jlong siteCounter, jint keyPurpose, jstring keyContext,
|
||||||
jint resultType, jstring resultParam, jint algorithmVersion) {
|
jint resultType, jstring resultParam, jint algorithmVersion) {
|
||||||
|
|
||||||
@@ -175,9 +183,9 @@ JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1si
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* native String _siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final long siteCounter,
|
/* native String _siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final long siteCounter,
|
||||||
final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
|
final int keyPurpose, @Nullable final String keyContext,
|
||||||
final MPResultType resultType, final String resultParam, final Version version) */
|
final int resultType, final String resultParam, final int algorithmVersion) */
|
||||||
JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1siteState(JNIEnv *env, jobject obj,
|
JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1siteState(JNIEnv *env, jobject obj,
|
||||||
jbyteArray masterKey, jbyteArray siteKey, jstring siteName, jlong siteCounter, jint keyPurpose, jstring keyContext,
|
jbyteArray masterKey, jbyteArray siteKey, jstring siteName, jlong siteCounter, jint keyPurpose, jstring keyContext,
|
||||||
jint resultType, jstring resultParam, jint algorithmVersion) {
|
jint resultType, jstring resultParam, jint algorithmVersion) {
|
||||||
|
|
||||||
@@ -208,3 +216,51 @@ JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1si
|
|||||||
|
|
||||||
return siteState;
|
return siteState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* native MPIdenticon _identicon(final String fullName, final byte[] masterPassword) */
|
||||||
|
JNIEXPORT jobject JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1identicon(JNIEnv *env, jobject obj,
|
||||||
|
jstring fullName, jbyteArray masterPassword) {
|
||||||
|
|
||||||
|
if (!fullName || !masterPassword)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const char *fullNameString = (*env)->GetStringUTFChars( env, fullName, NULL );
|
||||||
|
jbyte *masterPasswordString = (*env)->GetByteArrayElements( env, masterPassword, NULL );
|
||||||
|
|
||||||
|
MPIdenticon identicon = mpw_identicon( fullNameString, (char *)masterPasswordString );
|
||||||
|
(*env)->ReleaseStringUTFChars( env, fullName, fullNameString );
|
||||||
|
(*env)->ReleaseByteArrayElements( env, masterPassword, masterPasswordString, JNI_ABORT );
|
||||||
|
if (identicon.color == MPIdenticonColorUnset)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
jclass cMPIdenticonColor = (*env)->FindClass( env, "com/lyndir/masterpassword/MPIdenticon$Color" );
|
||||||
|
if (!cMPIdenticonColor)
|
||||||
|
return NULL;
|
||||||
|
jmethodID method = (*env)->GetStaticMethodID( env, cMPIdenticonColor, "values", "()[Lcom/lyndir/masterpassword/MPIdenticon$Color;" );
|
||||||
|
if (!method)
|
||||||
|
return NULL;
|
||||||
|
jobject values = (*env)->CallStaticObjectMethod( env, cMPIdenticonColor, method );
|
||||||
|
if (!values)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
jclass cMPIdenticon = (*env)->FindClass( env, "com/lyndir/masterpassword/MPIdenticon" );
|
||||||
|
if (!cMPIdenticon)
|
||||||
|
return NULL;
|
||||||
|
jmethodID init = (*env)->GetMethodID( env, cMPIdenticon, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/lyndir/masterpassword/MPIdenticon$Color;)V" );
|
||||||
|
if (!init)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return (*env)->NewObject( env, cMPIdenticon, init, fullName,
|
||||||
|
(*env)->NewStringUTF( env, identicon.leftArm ),
|
||||||
|
(*env)->NewStringUTF( env, identicon.body ),
|
||||||
|
(*env)->NewStringUTF( env, identicon.rightArm ),
|
||||||
|
(*env)->NewStringUTF( env, identicon.accessory ),
|
||||||
|
(*env)->GetObjectArrayElement( env, values, identicon.color ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* native String _toID(final byte[] buffer) */
|
||||||
|
JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1toID(JNIEnv *env, jobject obj,
|
||||||
|
jbyteArray buffer) {
|
||||||
|
|
||||||
|
return (*env)->NewStringUTF( env, mpw_id_buf( (*env)->GetByteArrayElements( env, buffer, NULL ), (*env)->GetArrayLength( env, buffer ) ) );
|
||||||
|
}
|
||||||
|
|||||||
@@ -176,6 +176,21 @@ MPMarshalledFile *mpw_marshal_file(
|
|||||||
return 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(
|
void mpw_marshal_info_free(
|
||||||
MPMarshalledInfo **info) {
|
MPMarshalledInfo **info) {
|
||||||
|
|
||||||
@@ -228,6 +243,7 @@ void mpw_marshal_file_free(
|
|||||||
|
|
||||||
mpw_marshal_info_free( &(*file)->info );
|
mpw_marshal_info_free( &(*file)->info );
|
||||||
mpw_marshal_data_free( &(*file)->data );
|
mpw_marshal_data_free( &(*file)->data );
|
||||||
|
mpw_free_string( &(*file)->error.message );
|
||||||
mpw_free( file, sizeof( MPMarshalledFile ) );
|
mpw_free( file, sizeof( MPMarshalledFile ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,7 +555,7 @@ static const char *mpw_marshal_write_flat(
|
|||||||
|
|
||||||
const MPMarshalledData *data = file->data;
|
const MPMarshalledData *data = file->data;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorMissing, "Missing data." };
|
mpw_marshal_error( file, MPMarshalErrorMissing, "Missing data." );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,9 +599,9 @@ static const char *mpw_marshal_write_flat(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!out)
|
if (!out)
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorFormat, "Couldn't encode JSON." };
|
mpw_marshal_error( file, MPMarshalErrorFormat, "Couldn't encode JSON." );
|
||||||
else
|
else
|
||||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -637,7 +653,7 @@ static const char *mpw_marshal_write_json(
|
|||||||
// Section: "export"
|
// Section: "export"
|
||||||
json_object *json_file = mpw_get_json_data( file->data );
|
json_object *json_file = mpw_get_json_data( file->data );
|
||||||
if (!json_file) {
|
if (!json_file) {
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorFormat, "Couldn't serialize export data." };
|
mpw_marshal_error( file, MPMarshalErrorFormat, "Couldn't serialize export data." );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,9 +666,9 @@ static const char *mpw_marshal_write_json(
|
|||||||
json_object_put( json_file );
|
json_object_put( json_file );
|
||||||
|
|
||||||
if (!out)
|
if (!out)
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorFormat, "Couldn't encode JSON." };
|
mpw_marshal_error( file, MPMarshalErrorFormat, "Couldn't encode JSON." );
|
||||||
else
|
else
|
||||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -698,17 +714,17 @@ const char *mpw_marshal_write(
|
|||||||
if (!file_)
|
if (!file_)
|
||||||
mpw_marshal_file_free( &file );
|
mpw_marshal_file_free( &file );
|
||||||
else
|
else
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate data." };
|
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't allocate data." );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!user->fullName || !strlen( user->fullName )) {
|
if (!user->fullName || !strlen( user->fullName )) {
|
||||||
if (!file_)
|
if (!file_)
|
||||||
mpw_marshal_file_free( &file );
|
mpw_marshal_file_free( &file );
|
||||||
else
|
else
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
|
mpw_marshal_error( file, MPMarshalErrorMissing, "Missing full name." );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||||
|
|
||||||
MPMasterKey masterKey = NULL;
|
MPMasterKey masterKey = NULL;
|
||||||
if (user->masterKeyProvider)
|
if (user->masterKeyProvider)
|
||||||
@@ -749,7 +765,7 @@ const char *mpw_marshal_write(
|
|||||||
if (!file_)
|
if (!file_)
|
||||||
mpw_marshal_file_free( &file );
|
mpw_marshal_file_free( &file );
|
||||||
else
|
else
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't derive master key." );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -807,7 +823,7 @@ const char *mpw_marshal_write(
|
|||||||
const char *out = NULL;
|
const char *out = NULL;
|
||||||
switch (outFormat) {
|
switch (outFormat) {
|
||||||
case MPMarshalFormatNone:
|
case MPMarshalFormatNone:
|
||||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||||
break;
|
break;
|
||||||
case MPMarshalFormatFlat:
|
case MPMarshalFormatFlat:
|
||||||
out = mpw_marshal_write_flat( file );
|
out = mpw_marshal_write_flat( file );
|
||||||
@@ -818,7 +834,7 @@ const char *mpw_marshal_write(
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) };
|
mpw_marshal_error( file, MPMarshalErrorFormat, "Unsupported output format: %u", outFormat );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (out && file->error.type == MPMarshalSuccess)
|
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() );
|
mpw_marshal_file( file, NULL, mpw_marshal_data_new() );
|
||||||
if (!file->data) {
|
if (!file->data) {
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate data." };
|
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't allocate data." );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -891,10 +907,7 @@ static void mpw_marshal_read_flat(
|
|||||||
const char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" );
|
const char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" );
|
||||||
const char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
const char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
||||||
if (!headerName || !headerValue) {
|
if (!headerName || !headerValue) {
|
||||||
file->error = (MPMarshalError){
|
mpw_marshal_error( file, MPMarshalErrorStructure, "Invalid header: %s", mpw_strndup( line, (size_t)(endOfLine - line) ) );
|
||||||
MPMarshalErrorStructure,
|
|
||||||
mpw_str( "Invalid header: %s", mpw_strndup( line, (size_t)(endOfLine - line) ) )
|
|
||||||
};
|
|
||||||
mpw_free_strings( &headerName, &headerValue, NULL );
|
mpw_free_strings( &headerName, &headerValue, NULL );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -908,7 +921,7 @@ static void mpw_marshal_read_flat(
|
|||||||
if (mpw_strcasecmp( headerName, "Algorithm" ) == OK) {
|
if (mpw_strcasecmp( headerName, "Algorithm" ) == OK) {
|
||||||
unsigned long value = strtoul( headerValue, NULL, 10 );
|
unsigned long value = strtoul( headerValue, NULL, 10 );
|
||||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast)
|
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
|
else
|
||||||
algorithm = (MPAlgorithmVersion)value;
|
algorithm = (MPAlgorithmVersion)value;
|
||||||
}
|
}
|
||||||
@@ -923,7 +936,7 @@ static void mpw_marshal_read_flat(
|
|||||||
if (mpw_strcasecmp( headerName, "Default Type" ) == OK) {
|
if (mpw_strcasecmp( headerName, "Default Type" ) == OK) {
|
||||||
unsigned long value = strtoul( headerValue, NULL, 10 );
|
unsigned long value = strtoul( headerValue, NULL, 10 );
|
||||||
if (!mpw_type_short_name( (MPResultType)value ))
|
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
|
else
|
||||||
defaultType = (MPResultType)value;
|
defaultType = (MPResultType)value;
|
||||||
}
|
}
|
||||||
@@ -934,7 +947,7 @@ static void mpw_marshal_read_flat(
|
|||||||
if (!headerEnded)
|
if (!headerEnded)
|
||||||
continue;
|
continue;
|
||||||
if (!fullName)
|
if (!fullName)
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorMissing, "Missing header: Full Name" };
|
mpw_marshal_error( file, MPMarshalErrorMissing, "Missing header: Full Name" );
|
||||||
if (positionInLine >= endOfLine)
|
if (positionInLine >= endOfLine)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -973,7 +986,7 @@ static void mpw_marshal_read_flat(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unexpected import format: %u", format ) };
|
mpw_marshal_error( file, MPMarshalErrorFormat, "Unexpected import format: %u", format );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -981,28 +994,24 @@ static void mpw_marshal_read_flat(
|
|||||||
if (siteName && str_type && str_counter && str_algorithm && str_uses && str_lastUsed) {
|
if (siteName && str_type && str_counter && str_algorithm && str_uses && str_lastUsed) {
|
||||||
MPResultType siteType = (MPResultType)strtoul( str_type, NULL, 10 );
|
MPResultType siteType = (MPResultType)strtoul( str_type, NULL, 10 );
|
||||||
if (!mpw_type_short_name( siteType )) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
long long int value = strtoll( str_counter, NULL, 10 );
|
long long int value = strtoll( str_counter, NULL, 10 );
|
||||||
if (value < MPCounterValueFirst || value > MPCounterValueLast) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
MPCounterValue siteCounter = (MPCounterValue)value;
|
MPCounterValue siteCounter = (MPCounterValue)value;
|
||||||
value = strtoll( str_algorithm, NULL, 0 );
|
value = strtoll( str_algorithm, NULL, 0 );
|
||||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
||||||
file->error = (MPMarshalError){
|
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site algorithm: %s: %s", siteName, str_algorithm );
|
||||||
MPMarshalErrorIllegal, mpw_str( "Invalid site algorithm: %s: %s", siteName, str_algorithm )
|
|
||||||
};
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
|
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
|
||||||
time_t siteLastUsed = mpw_timegm( str_lastUsed );
|
time_t siteLastUsed = mpw_timegm( str_lastUsed );
|
||||||
if (!siteLastUsed) {
|
if (!siteLastUsed) {
|
||||||
file->error = (MPMarshalError){
|
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site last used: %s: %s", siteName, str_lastUsed );
|
||||||
MPMarshalErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed )
|
|
||||||
};
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1020,11 +1029,9 @@ static void mpw_marshal_read_flat(
|
|||||||
mpw_marshal_data_set_str( dateString, file->data, "sites", siteName, "last_used", NULL );
|
mpw_marshal_data_set_str( dateString, file->data, "sites", siteName, "last_used", NULL );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
file->error = (MPMarshalError){
|
mpw_marshal_error( file, MPMarshalErrorMissing,
|
||||||
MPMarshalErrorMissing,
|
"Missing one of: lastUsed=%s, uses=%s, type=%s, version=%s, counter=%s, loginName=%s, siteName=%s",
|
||||||
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 );
|
||||||
str_lastUsed, str_uses, str_type, str_algorithm, str_counter, siteLoginState, siteName )
|
|
||||||
};
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1044,7 +1051,7 @@ static void mpw_marshal_read_json(
|
|||||||
|
|
||||||
mpw_marshal_file( file, NULL, mpw_marshal_data_new() );
|
mpw_marshal_file( file, NULL, mpw_marshal_data_new() );
|
||||||
if (!file->data) {
|
if (!file->data) {
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate data." };
|
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't allocate data." );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1052,7 +1059,7 @@ static void mpw_marshal_read_json(
|
|||||||
enum json_tokener_error json_error = json_tokener_success;
|
enum json_tokener_error json_error = json_tokener_success;
|
||||||
json_object *json_file = json_tokener_parse_verbose( in, &json_error );
|
json_object *json_file = json_tokener_parse_verbose( in, &json_error );
|
||||||
if (!json_file || json_error != json_tokener_success) {
|
if (!json_file || json_error != json_tokener_success) {
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1074,9 +1081,9 @@ MPMarshalledFile *mpw_marshal_read(
|
|||||||
if (!file)
|
if (!file)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||||
if (!info) {
|
if (!info) {
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate info." };
|
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't allocate info." );
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1090,6 +1097,8 @@ MPMarshalledFile *mpw_marshal_read(
|
|||||||
info->format = MPMarshalFormatJSON;
|
info->format = MPMarshalFormatJSON;
|
||||||
#if MPW_JSON
|
#if MPW_JSON
|
||||||
mpw_marshal_read_json( file, in );
|
mpw_marshal_read_json( file, in );
|
||||||
|
#else
|
||||||
|
mpw_marshal_error( file, MPMarshalErrorFormat, "JSON support is not enabled." );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1116,13 +1125,13 @@ MPMarshalledUser *mpw_marshal_auth(
|
|||||||
if (!file)
|
if (!file)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
|
mpw_marshal_error( file, MPMarshalSuccess, NULL );
|
||||||
if (!file->info) {
|
if (!file->info) {
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorMissing, "File wasn't parsed yet." };
|
mpw_marshal_error( file, MPMarshalErrorMissing, "File wasn't parsed yet." );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!file->data) {
|
if (!file->data) {
|
||||||
file->error = (MPMarshalError){ MPMarshalErrorMissing, "No input data." };
|
mpw_marshal_error( file, MPMarshalErrorMissing, "No input data." );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1132,43 +1141,43 @@ MPMarshalledUser *mpw_marshal_auth(
|
|||||||
MPAlgorithmVersion algorithm =
|
MPAlgorithmVersion algorithm =
|
||||||
mpw_default_n( MPAlgorithmVersionCurrent, mpw_marshal_data_get_num( file->data, "user", "algorithm", NULL ) );
|
mpw_default_n( MPAlgorithmVersionCurrent, mpw_marshal_data_get_num( file->data, "user", "algorithm", NULL ) );
|
||||||
if (algorithm < MPAlgorithmVersionFirst || algorithm > MPAlgorithmVersionLast) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
unsigned int avatar = mpw_default_n( 0U, mpw_marshal_data_get_num( file->data, "user", "avatar", 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 );
|
const char *fullName = mpw_marshal_data_get_str( file->data, "user", "full_name", NULL );
|
||||||
if (!fullName || !strlen( fullName )) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
MPIdenticon identicon = mpw_identicon_encoded( mpw_marshal_data_get_str( file->data, "user", "identicon", 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 );
|
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 ) );
|
MPResultType defaultType = mpw_default_n( MPResultTypeDefault, mpw_marshal_data_get_num( file->data, "user", "default_type", NULL ) );
|
||||||
if (!mpw_type_short_name( defaultType )) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
const char *str_lastUsed = mpw_marshal_data_get_str( file->data, "user", "last_used", NULL );
|
const char *str_lastUsed = mpw_marshal_data_get_str( file->data, "user", "last_used", NULL );
|
||||||
time_t lastUsed = mpw_timegm( str_lastUsed );
|
time_t lastUsed = mpw_timegm( str_lastUsed );
|
||||||
if (!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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MPMasterKey masterKey = NULL;
|
MPMasterKey masterKey = NULL;
|
||||||
if (masterKeyProvider && !(masterKey = masterKeyProvider( algorithm, fullName ))) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (keyID && masterKey && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
|
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 );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MPMarshalledUser *user = NULL;
|
MPMarshalledUser *user = NULL;
|
||||||
if (!(user = mpw_marshal_user( fullName, masterKeyProvider, algorithm ))) {
|
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_free( &masterKey, MPMasterKeySize );
|
||||||
mpw_marshal_user_free( &user );
|
mpw_marshal_user_free( &user );
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1189,21 +1198,21 @@ MPMarshalledUser *mpw_marshal_auth(
|
|||||||
|
|
||||||
algorithm = mpw_default_n( user->algorithm, mpw_marshal_data_get_num( siteData, "algorithm", NULL ) );
|
algorithm = mpw_default_n( user->algorithm, mpw_marshal_data_get_num( siteData, "algorithm", NULL ) );
|
||||||
if (algorithm < MPAlgorithmVersionFirst || algorithm > MPAlgorithmVersionLast) {
|
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_free( &masterKey, MPMasterKeySize );
|
||||||
mpw_marshal_user_free( &user );
|
mpw_marshal_user_free( &user );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
MPCounterValue siteCounter = mpw_default_n( MPCounterValueDefault, mpw_marshal_data_get_num( siteData, "counter", NULL ) );
|
MPCounterValue siteCounter = mpw_default_n( MPCounterValueDefault, mpw_marshal_data_get_num( siteData, "counter", NULL ) );
|
||||||
if (siteCounter < MPCounterValueFirst || siteCounter > MPCounterValueLast) {
|
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_free( &masterKey, MPMasterKeySize );
|
||||||
mpw_marshal_user_free( &user );
|
mpw_marshal_user_free( &user );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
MPResultType siteType = mpw_default_n( user->defaultType, mpw_marshal_data_get_num( siteData, "type", NULL ) );
|
MPResultType siteType = mpw_default_n( user->defaultType, mpw_marshal_data_get_num( siteData, "type", NULL ) );
|
||||||
if (!mpw_type_short_name( siteType )) {
|
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_free( &masterKey, MPMasterKeySize );
|
||||||
mpw_marshal_user_free( &user );
|
mpw_marshal_user_free( &user );
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1211,7 +1220,7 @@ MPMarshalledUser *mpw_marshal_auth(
|
|||||||
const char *siteResultState = mpw_marshal_data_get_str( siteData, "password", NULL );
|
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 ) );
|
MPResultType siteLoginType = mpw_default_n( MPResultTypeTemplateName, mpw_marshal_data_get_num( siteData, "login_type", NULL ) );
|
||||||
if (!mpw_type_short_name( siteLoginType )) {
|
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_free( &masterKey, MPMasterKeySize );
|
||||||
mpw_marshal_user_free( &user );
|
mpw_marshal_user_free( &user );
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1221,7 +1230,7 @@ MPMarshalledUser *mpw_marshal_auth(
|
|||||||
str_lastUsed = mpw_marshal_data_get_str( siteData, "last_used", NULL );
|
str_lastUsed = mpw_marshal_data_get_str( siteData, "last_used", NULL );
|
||||||
time_t siteLastUsed = mpw_timegm( str_lastUsed );
|
time_t siteLastUsed = mpw_timegm( str_lastUsed );
|
||||||
if (!siteLastUsed) {
|
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_free( &masterKey, MPMasterKeySize );
|
||||||
mpw_marshal_user_free( &user );
|
mpw_marshal_user_free( &user );
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1231,7 +1240,7 @@ MPMarshalledUser *mpw_marshal_auth(
|
|||||||
|
|
||||||
MPMarshalledSite *site = mpw_marshal_site( user, siteName, siteType, siteCounter, algorithm );
|
MPMarshalledSite *site = mpw_marshal_site( user, siteName, siteType, siteCounter, algorithm );
|
||||||
if (!site) {
|
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_free( &masterKey, MPMasterKeySize );
|
||||||
mpw_marshal_user_free( &user );
|
mpw_marshal_user_free( &user );
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1245,10 +1254,7 @@ MPMarshalledUser *mpw_marshal_auth(
|
|||||||
// Clear Text
|
// Clear Text
|
||||||
mpw_free( &masterKey, MPMasterKeySize );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
if (!masterKeyProvider || !(masterKey = masterKeyProvider( site->algorithm, user->fullName ))) {
|
if (!masterKeyProvider || !(masterKey = masterKeyProvider( site->algorithm, user->fullName ))) {
|
||||||
file->error = (MPMarshalError){
|
mpw_marshal_error( file, MPMarshalErrorInternal, "Couldn't derive master key." );
|
||||||
MPMarshalErrorInternal,
|
|
||||||
"Couldn't derive master key."
|
|
||||||
};
|
|
||||||
mpw_free( &masterKey, MPMasterKeySize );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
mpw_marshal_user_free( &user );
|
mpw_marshal_user_free( &user );
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -246,6 +246,10 @@ MPMarshalledQuestion *mpw_marshal_question(
|
|||||||
* @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. */
|
* @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 *mpw_marshal_file(
|
||||||
MPMarshalledFile *file, MPMarshalledInfo *info, MPMarshalledData *data);
|
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.
|
//// Disposing.
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
MP_LIBS_BEGIN
|
MP_LIBS_BEGIN
|
||||||
|
#define __STDC_WANT_LIB_EXT1__ 1
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -120,18 +121,17 @@ typedef mpw_enum ( uint32_t, MPCounterValue ) {
|
|||||||
|
|
||||||
/** These colours are compatible with the original ANSI SGR. */
|
/** These colours are compatible with the original ANSI SGR. */
|
||||||
typedef mpw_enum( uint8_t, MPIdenticonColor ) {
|
typedef mpw_enum( uint8_t, MPIdenticonColor ) {
|
||||||
MPIdenticonColorBlack,
|
MPIdenticonColorUnset,
|
||||||
MPIdenticonColorRed,
|
MPIdenticonColorRed,
|
||||||
MPIdenticonColorGreen,
|
MPIdenticonColorGreen,
|
||||||
MPIdenticonColorYellow,
|
MPIdenticonColorYellow,
|
||||||
MPIdenticonColorBlue,
|
MPIdenticonColorBlue,
|
||||||
MPIdenticonColorMagenta,
|
MPIdenticonColorMagenta,
|
||||||
MPIdenticonColorCyan,
|
MPIdenticonColorCyan,
|
||||||
MPIdenticonColorWhite,
|
MPIdenticonColorMono,
|
||||||
|
|
||||||
MPIdenticonColorUnset = MPIdenticonColorBlack,
|
|
||||||
MPIdenticonColorFirst = MPIdenticonColorRed,
|
MPIdenticonColorFirst = MPIdenticonColorRed,
|
||||||
MPIdenticonColorLast = MPIdenticonColorWhite,
|
MPIdenticonColorLast = MPIdenticonColorMono,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -97,14 +97,15 @@ void mpw_log_ssink(LogLevel level, const char *file, int line, const char *funct
|
|||||||
.message = message,
|
.message = message,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool sunk = false;
|
||||||
for (unsigned int s = 0; s < sinks_count; ++s) {
|
for (unsigned int s = 0; s < sinks_count; ++s) {
|
||||||
MPLogSink *sink = sinks[s];
|
MPLogSink *sink = sinks[s];
|
||||||
|
|
||||||
if (sink)
|
if (sink)
|
||||||
sink( &record );
|
sunk |= sink( &record );
|
||||||
}
|
}
|
||||||
if (!sinks_count)
|
if (!sunk)
|
||||||
mpw_log_sink_file( &record );
|
sunk = mpw_log_sink_file( &record );
|
||||||
|
|
||||||
if (record.level <= LogLevelError) {
|
if (record.level <= LogLevelError) {
|
||||||
/* error breakpoint */;
|
/* error breakpoint */;
|
||||||
@@ -113,7 +114,7 @@ void mpw_log_ssink(LogLevel level, const char *file, int line, const char *funct
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mpw_log_sink_file(const MPLogEvent *record) {
|
bool mpw_log_sink_file(const MPLogEvent *record) {
|
||||||
|
|
||||||
if (!mpw_log_sink_file_target)
|
if (!mpw_log_sink_file_target)
|
||||||
mpw_log_sink_file_target = stderr;
|
mpw_log_sink_file_target = stderr;
|
||||||
@@ -145,6 +146,7 @@ void mpw_log_sink_file(const MPLogEvent *record) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fprintf( mpw_log_sink_file_target, "%s\n", record->message );
|
fprintf( mpw_log_sink_file_target, "%s\n", record->message );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mpw_uint16(const uint16_t number, uint8_t buf[2]) {
|
void mpw_uint16(const uint16_t number, uint8_t buf[2]) {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ typedef struct {
|
|||||||
} MPLogEvent;
|
} MPLogEvent;
|
||||||
|
|
||||||
/** A log sink describes a function that can receive log events. */
|
/** A log sink describes a function that can receive log events. */
|
||||||
typedef void (MPLogSink)(const MPLogEvent *event);
|
typedef bool (MPLogSink)(const MPLogEvent *event);
|
||||||
|
|
||||||
/** To receive events, sinks need to be registered. If no sinks are registered, log events are sent to the mpw_log_sink_file sink. */
|
/** To receive events, sinks need to be registered. If no sinks are registered, log events are sent to the mpw_log_sink_file sink. */
|
||||||
bool mpw_log_sink_register(MPLogSink *sink);
|
bool mpw_log_sink_register(MPLogSink *sink);
|
||||||
|
|||||||
@@ -87,6 +87,29 @@ public interface MPAlgorithm {
|
|||||||
MPKeyPurpose keyPurpose, @Nullable String keyContext,
|
MPKeyPurpose keyPurpose, @Nullable String keyContext,
|
||||||
MPResultType resultType, String resultParam);
|
MPResultType resultType, String resultParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive an identicon that represents the user's identity in a visually recognizable way.
|
||||||
|
*
|
||||||
|
* @param fullName The name of the user whose identity is described by the key.
|
||||||
|
* @param masterPassword The user's secret that authenticates his access to the identity.
|
||||||
|
*/
|
||||||
|
MPIdenticon identicon(final String fullName, final char[] masterPassword);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode a fingerprint for a message.
|
||||||
|
*/
|
||||||
|
String toID(final String string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode a fingerprint for a char buffer.
|
||||||
|
*/
|
||||||
|
String toID(final char[] message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode a fingerprint for a byte buffer.
|
||||||
|
*/
|
||||||
|
String toID(final byte[] buffer);
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,69 +148,6 @@ public interface MPAlgorithm {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
Charset mpw_charset();
|
Charset mpw_charset();
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Platform-agnostic byte order.
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
ByteOrder mpw_byteOrder();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Key ID hash.
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
MessageDigests mpw_hash();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Site digest.
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
MessageAuthenticationDigests mpw_digest();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Master key size (byte).
|
|
||||||
*/
|
|
||||||
int mpw_dkLen();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Minimum size for derived keys (bit).
|
|
||||||
*/
|
|
||||||
int mpw_keySize_min();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Maximum size for derived keys (bit).
|
|
||||||
*/
|
|
||||||
int mpw_keySize_max();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: validity for the time-based rolling counter (s).
|
|
||||||
*/
|
|
||||||
long mpw_otp_window();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* scrypt: CPU cost parameter.
|
|
||||||
*/
|
|
||||||
int scrypt_N();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* scrypt: Memory cost parameter.
|
|
||||||
*/
|
|
||||||
int scrypt_r();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* scrypt: Parallelization parameter.
|
|
||||||
*/
|
|
||||||
int scrypt_p();
|
|
||||||
|
|
||||||
// Utilities
|
|
||||||
|
|
||||||
byte[] toBytes(final int number);
|
|
||||||
|
|
||||||
byte[] toBytes(final UnsignedInteger number);
|
|
||||||
|
|
||||||
byte[] toBytes(final char[] characters);
|
|
||||||
|
|
||||||
byte[] toID(final byte[] bytes);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The algorithm iterations.
|
* The algorithm iterations.
|
||||||
*/
|
*/
|
||||||
@@ -222,12 +182,9 @@ public interface MPAlgorithm {
|
|||||||
|
|
||||||
public static final Version CURRENT = V3;
|
public static final Version CURRENT = V3;
|
||||||
|
|
||||||
@SuppressWarnings("HardcodedFileSeparator")
|
|
||||||
private static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";
|
|
||||||
private static final int AES_BLOCKSIZE = 128 /* bit */;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Native.load( MPAlgorithm.class, "mpw" );
|
if (!Native.load( MPAlgorithm.class, "mpw" ))
|
||||||
|
Logger.get( MPAlgorithm.class ).err( "Native mpw library unavailable." );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final Logger logger = Logger.get( getClass() );
|
protected final Logger logger = Logger.get( getClass() );
|
||||||
@@ -320,12 +277,76 @@ public interface MPAlgorithm {
|
|||||||
final int keyPurpose, @Nullable final String keyContext,
|
final int keyPurpose, @Nullable final String keyContext,
|
||||||
final int resultType, final String resultParam, final int algorithmVersion);
|
final int resultType, final String resultParam, final int algorithmVersion);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public MPIdenticon identicon(final String fullName, final char[] masterPassword) {
|
||||||
|
|
||||||
|
// Create a memory-safe NUL-terminated UTF-8 C-string byte array variant of masterPassword.
|
||||||
|
CharsetEncoder encoder = mpw_charset().newEncoder();
|
||||||
|
byte[] masterPasswordBytes = new byte[(int) (masterPassword.length * (double) encoder.maxBytesPerChar()) + 1];
|
||||||
|
try {
|
||||||
|
Arrays.fill( masterPasswordBytes, (byte) 0 );
|
||||||
|
ByteBuffer masterPasswordBuffer = ByteBuffer.wrap( masterPasswordBytes );
|
||||||
|
|
||||||
|
CoderResult result = encoder.encode( CharBuffer.wrap( masterPassword ), masterPasswordBuffer, true );
|
||||||
|
if (result.isError())
|
||||||
|
throw new IllegalStateException( result.toString() );
|
||||||
|
result = encoder.flush( masterPasswordBuffer );
|
||||||
|
if (result.isError())
|
||||||
|
throw new IllegalStateException( result.toString() );
|
||||||
|
|
||||||
|
return _identicon( fullName, masterPasswordBytes );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Arrays.fill( masterPasswordBytes, (byte) 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected native MPIdenticon _identicon(final String fullName, final byte[] masterPassword);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toID(final String message) {
|
||||||
|
return toID( message.toCharArray() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toID(final char[] message) {
|
||||||
|
// Create a memory-safe NUL-terminated UTF-8 C-string byte array variant of masterPassword.
|
||||||
|
CharsetEncoder encoder = mpw_charset().newEncoder();
|
||||||
|
byte[] messageBytes = new byte[(int) (message.length * (double) encoder.maxBytesPerChar()) + 1];
|
||||||
|
try {
|
||||||
|
Arrays.fill( messageBytes, (byte) 0 );
|
||||||
|
ByteBuffer messageBuffer = ByteBuffer.wrap( messageBytes );
|
||||||
|
|
||||||
|
CoderResult result = encoder.encode( CharBuffer.wrap( message ), messageBuffer, true );
|
||||||
|
if (result.isError())
|
||||||
|
throw new IllegalStateException( result.toString() );
|
||||||
|
result = encoder.flush( messageBuffer );
|
||||||
|
if (result.isError())
|
||||||
|
throw new IllegalStateException( result.toString() );
|
||||||
|
|
||||||
|
return toID( messageBytes );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Arrays.fill( messageBytes, (byte) 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toID(final byte[] buffer) {
|
||||||
|
return _toID( buffer );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected native String _toID(final byte[] buffer);
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Version version() {
|
public Version version() {
|
||||||
return MPAlgorithm.Version.V0;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@@ -357,93 +378,5 @@ public interface MPAlgorithm {
|
|||||||
public Charset mpw_charset() {
|
public Charset mpw_charset() {
|
||||||
return Charsets.UTF_8;
|
return Charsets.UTF_8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public ByteOrder mpw_byteOrder() {
|
|
||||||
return ByteOrder.BIG_ENDIAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public MessageDigests mpw_hash() {
|
|
||||||
return MessageDigests.SHA256;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public MessageAuthenticationDigests mpw_digest() {
|
|
||||||
return MessageAuthenticationDigests.HmacSHA256;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("MagicNumber")
|
|
||||||
public int mpw_dkLen() {
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("MagicNumber")
|
|
||||||
public int mpw_keySize_min() {
|
|
||||||
return 128;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("MagicNumber")
|
|
||||||
public int mpw_keySize_max() {
|
|
||||||
return 512;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("MagicNumber")
|
|
||||||
public long mpw_otp_window() {
|
|
||||||
return 5 * 60 /* s */;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("MagicNumber")
|
|
||||||
public int scrypt_N() {
|
|
||||||
return 32768;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("MagicNumber")
|
|
||||||
public int scrypt_r() {
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("MagicNumber")
|
|
||||||
public int scrypt_p() {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utilities
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
public byte[] toBytes(final int number) {
|
|
||||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder() ).putInt( number ).array();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
public byte[] toBytes(final UnsignedInteger number) {
|
|
||||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder() ).putInt( number.intValue() ).array();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
public byte[] toBytes(final char[] characters) {
|
|
||||||
ByteBuffer byteBuffer = mpw_charset().encode( CharBuffer.wrap( characters ) );
|
|
||||||
|
|
||||||
byte[] bytes = new byte[byteBuffer.remaining()];
|
|
||||||
byteBuffer.get( bytes );
|
|
||||||
|
|
||||||
Arrays.fill( byteBuffer.array(), (byte) 0 );
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
public byte[] toID(final byte[] bytes) {
|
|
||||||
return mpw_hash().of( bytes );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,14 +20,8 @@ package com.lyndir.masterpassword;
|
|||||||
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
|
||||||
import com.google.common.primitives.UnsignedBytes;
|
|
||||||
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
|
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
import java.nio.*;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
|
||||||
@@ -39,43 +33,23 @@ public class MPIdenticon {
|
|||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
private static final Logger logger = Logger.get( MPIdenticon.class );
|
private static final Logger logger = Logger.get( MPIdenticon.class );
|
||||||
|
|
||||||
private static final Charset charset = Charsets.UTF_8;
|
|
||||||
private static final Color[] colors = {
|
|
||||||
Color.RED, Color.GREEN, Color.YELLOW, Color.BLUE, Color.MAGENTA, Color.CYAN, Color.MONO };
|
|
||||||
private static final char[] leftArm = { '╔', '╚', '╰', '═' };
|
|
||||||
private static final char[] rightArm = { '╗', '╝', '╯', '═' };
|
|
||||||
private static final char[] body = { '█', '░', '▒', '▓', '☺', '☻' };
|
|
||||||
private static final char[] accessory = {
|
|
||||||
'◈', '◎', '◐', '◑', '◒', '◓', '☀', '☁', '☂', '☃', '☄', '★', '☆', '☎', '☏', '⎈', '⌂', '☘', '☢', '☣', '☕', '⌚', '⌛', '⏰', '⚡',
|
|
||||||
'⛄', '⛅', '☔', '♔', '♕', '♖', '♗', '♘', '♙', '♚', '♛', '♜', '♝', '♞', '♟', '♨', '♩', '♪', '♫', '⚐', '⚑', '⚔', '⚖', '⚙', '⚠',
|
|
||||||
'⌘', '⏎', '✄', '✆', '✈', '✉', '✌' };
|
|
||||||
|
|
||||||
private final String fullName;
|
private final String fullName;
|
||||||
|
private final String leftArm;
|
||||||
|
private final String body;
|
||||||
|
private final String rightArm;
|
||||||
|
private final String accessory;
|
||||||
private final Color color;
|
private final Color color;
|
||||||
private final String text;
|
|
||||||
|
|
||||||
public MPIdenticon(final String fullName, final String masterPassword) {
|
|
||||||
this( fullName, masterPassword.toCharArray() );
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressFBWarnings("CLI_CONSTANT_LIST_INDEX")
|
@SuppressFBWarnings("CLI_CONSTANT_LIST_INDEX")
|
||||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
||||||
public MPIdenticon(final String fullName, final char[] masterPassword) {
|
public MPIdenticon(final String fullName, final String leftArm, final String body, final String rightArm, final String accessory,
|
||||||
|
final Color color) {
|
||||||
this.fullName = fullName;
|
this.fullName = fullName;
|
||||||
|
this.leftArm = leftArm;
|
||||||
byte[] masterPasswordBytes = charset.encode( CharBuffer.wrap( masterPassword ) ).array();
|
this.body = body;
|
||||||
ByteBuffer identiconSeedBytes = ByteBuffer.wrap(
|
this.rightArm = rightArm;
|
||||||
MessageAuthenticationDigests.HmacSHA256.of( masterPasswordBytes, fullName.getBytes( charset ) ) );
|
this.accessory = accessory;
|
||||||
Arrays.fill( masterPasswordBytes, (byte) 0 );
|
this.color = color;
|
||||||
|
|
||||||
IntBuffer identiconSeedBuffer = IntBuffer.allocate( identiconSeedBytes.capacity() );
|
|
||||||
while (identiconSeedBytes.hasRemaining())
|
|
||||||
identiconSeedBuffer.put( UnsignedBytes.toInt( identiconSeedBytes.get() ) );
|
|
||||||
int[] identiconSeed = identiconSeedBuffer.array();
|
|
||||||
|
|
||||||
color = colors[identiconSeed[4] % colors.length];
|
|
||||||
text = strf( "%c%c%c%c", leftArm[identiconSeed[0] % leftArm.length], body[identiconSeed[1] % body.length],
|
|
||||||
rightArm[identiconSeed[2] % rightArm.length], accessory[identiconSeed[3] % accessory.length] );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFullName() {
|
public String getFullName() {
|
||||||
@@ -83,11 +57,11 @@ public class MPIdenticon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return text;
|
return strf( "%s%s%s%s", this.leftArm, this.body, this.rightArm, this.accessory );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHTML() {
|
public String getHTML() {
|
||||||
return strf( "<span style='color: %s'>%s</span>", color.getCSS(), text );
|
return strf( "<span style='color: %s'>%s</span>", color.getCSS(), getText() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color getColor() {
|
public Color getColor() {
|
||||||
@@ -95,6 +69,12 @@ public class MPIdenticon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum Color {
|
public enum Color {
|
||||||
|
UNSET {
|
||||||
|
@Override
|
||||||
|
public String getCSS() {
|
||||||
|
return "inherit";
|
||||||
|
}
|
||||||
|
},
|
||||||
RED,
|
RED,
|
||||||
GREEN,
|
GREEN,
|
||||||
YELLOW,
|
YELLOW,
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ package com.lyndir.masterpassword;
|
|||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
@@ -55,6 +54,19 @@ public class MPMasterKey {
|
|||||||
Arrays.fill( masterPassword, (char) 0 );
|
Arrays.fill( masterPassword, (char) 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
protected void finalize()
|
||||||
|
throws Throwable {
|
||||||
|
|
||||||
|
if (isValid()) {
|
||||||
|
logger.wrn( "A master key for %s was abandoned without being invalidated.", getFullName() );
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public String getFullName() {
|
public String getFullName() {
|
||||||
|
|
||||||
@@ -67,7 +79,7 @@ public class MPMasterKey {
|
|||||||
* @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
|
* @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public byte[] getKeyID(final MPAlgorithm algorithm)
|
public String getKeyID(final MPAlgorithm algorithm)
|
||||||
throws MPKeyUnavailableException, MPAlgorithmException {
|
throws MPKeyUnavailableException, MPAlgorithmException {
|
||||||
|
|
||||||
return algorithm.toID( masterKey( algorithm ) );
|
return algorithm.toID( masterKey( algorithm ) );
|
||||||
@@ -98,11 +110,6 @@ public class MPMasterKey {
|
|||||||
|
|
||||||
byte[] masterKey = keyByVersion.get( algorithm.version() );
|
byte[] masterKey = keyByVersion.get( algorithm.version() );
|
||||||
if (masterKey == null) {
|
if (masterKey == null) {
|
||||||
logger.trc( "-- mpw_masterKey (algorithm: %s)", algorithm );
|
|
||||||
logger.trc( "fullName: %s", fullName );
|
|
||||||
logger.trc( "masterPassword.id: %s", CodeUtils.encodeHex(
|
|
||||||
algorithm.toID( algorithm.toBytes( masterPassword ) ) ) );
|
|
||||||
|
|
||||||
keyByVersion.put( algorithm.version(), masterKey = algorithm.masterKey( fullName, masterPassword ) );
|
keyByVersion.put( algorithm.version(), masterKey = algorithm.masterKey( fullName, masterPassword ) );
|
||||||
}
|
}
|
||||||
if (masterKey == null)
|
if (masterKey == null)
|
||||||
@@ -118,13 +125,6 @@ public class MPMasterKey {
|
|||||||
Preconditions.checkArgument( !siteName.isEmpty() );
|
Preconditions.checkArgument( !siteName.isEmpty() );
|
||||||
|
|
||||||
byte[] masterKey = masterKey( algorithm );
|
byte[] masterKey = masterKey( algorithm );
|
||||||
|
|
||||||
logger.trc( "-- mpw_siteKey (algorithm: %s)", algorithm );
|
|
||||||
logger.trc( "siteName: %s", siteName );
|
|
||||||
logger.trc( "siteCounter: %s", siteCounter );
|
|
||||||
logger.trc( "keyPurpose: %d (%s)", keyPurpose.toInt(), keyPurpose.getShortName() );
|
|
||||||
logger.trc( "keyContext: %s", keyContext );
|
|
||||||
|
|
||||||
byte[] siteKey = algorithm.siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
byte[] siteKey = algorithm.siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
||||||
if (siteKey == null)
|
if (siteKey == null)
|
||||||
throw new MPAlgorithmException( "Could not derive site key." );
|
throw new MPAlgorithmException( "Could not derive site key." );
|
||||||
@@ -161,10 +161,6 @@ public class MPMasterKey {
|
|||||||
byte[] masterKey = masterKey( algorithm );
|
byte[] masterKey = masterKey( algorithm );
|
||||||
byte[] siteKey = siteKey( siteName, algorithm, siteCounter, keyPurpose, keyContext );
|
byte[] siteKey = siteKey( siteName, algorithm, siteCounter, keyPurpose, keyContext );
|
||||||
|
|
||||||
logger.trc( "-- mpw_siteResult (algorithm: %s)", algorithm );
|
|
||||||
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
|
||||||
logger.trc( "resultParam: %s", resultParam );
|
|
||||||
|
|
||||||
String siteResult = algorithm.siteResult(
|
String siteResult = algorithm.siteResult(
|
||||||
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
||||||
if (siteResult == null)
|
if (siteResult == null)
|
||||||
@@ -199,10 +195,6 @@ public class MPMasterKey {
|
|||||||
byte[] masterKey = masterKey( algorithm );
|
byte[] masterKey = masterKey( algorithm );
|
||||||
byte[] siteKey = siteKey( siteName, algorithm, siteCounter, keyPurpose, keyContext );
|
byte[] siteKey = siteKey( siteName, algorithm, siteCounter, keyPurpose, keyContext );
|
||||||
|
|
||||||
logger.trc( "-- mpw_siteState (algorithm: %s)", algorithm );
|
|
||||||
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
|
||||||
logger.trc( "resultParam: %d bytes = %s", resultParam.getBytes( algorithm.mpw_charset() ).length, resultParam );
|
|
||||||
|
|
||||||
String siteState = algorithm.siteState(
|
String siteState = algorithm.siteState(
|
||||||
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
||||||
if (siteState == null)
|
if (siteState == null)
|
||||||
|
|||||||
@@ -74,9 +74,9 @@ public final class Native {
|
|||||||
|
|
||||||
// Write the library resource to a temporary file.
|
// Write the library resource to a temporary file.
|
||||||
libraryFile = File.createTempFile( libraryName, libraryExtension );
|
libraryFile = File.createTempFile( libraryName, libraryExtension );
|
||||||
|
libraryFile.deleteOnExit();
|
||||||
FileOutputStream libraryFileStream = new FileOutputStream( libraryFile );
|
FileOutputStream libraryFileStream = new FileOutputStream( libraryFile );
|
||||||
try {
|
try {
|
||||||
libraryFile.deleteOnExit();
|
|
||||||
ByteStreams.copy( libraryStream, libraryFileStream );
|
ByteStreams.copy( libraryStream, libraryFileStream );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@@ -91,8 +91,7 @@ public final class Native {
|
|||||||
catch (@SuppressWarnings("ErrorNotRethrown") final IOException | UnsatisfiedLinkError e) {
|
catch (@SuppressWarnings("ErrorNotRethrown") final IOException | UnsatisfiedLinkError e) {
|
||||||
logger.wrn( e, "Couldn't load library: %s", libraryResource );
|
logger.wrn( e, "Couldn't load library: %s", libraryResource );
|
||||||
|
|
||||||
if (libraryFile != null)
|
if (libraryFile != null && libraryFile.exists() && !libraryFile.delete())
|
||||||
if (libraryFile.exists() && !libraryFile.delete())
|
|
||||||
logger.wrn( "Couldn't clean up library file: %s", libraryFile );
|
logger.wrn( "Couldn't clean up library file: %s", libraryFile );
|
||||||
libraryFile = null;
|
libraryFile = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class MPIncognitoUser extends MPBasicUser<MPIncognitoSite> {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public byte[] getKeyID() {
|
public String getKeyID() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import javax.swing.border.Border;
|
|||||||
import javax.swing.border.CompoundBorder;
|
import javax.swing.border.CompoundBorder;
|
||||||
import javax.swing.event.HyperlinkEvent;
|
import javax.swing.event.HyperlinkEvent;
|
||||||
import javax.swing.text.*;
|
import javax.swing.text.*;
|
||||||
|
import javax.swing.undo.UndoableEdit;
|
||||||
import org.jetbrains.annotations.NonNls;
|
import org.jetbrains.annotations.NonNls;
|
||||||
|
|
||||||
|
|
||||||
@@ -207,7 +208,13 @@ public abstract class Components {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static JPasswordField passwordField() {
|
public static JPasswordField passwordField() {
|
||||||
return new JPasswordField() {
|
return new JPasswordField( new PlainDocument( new GapContent() {
|
||||||
|
@Override
|
||||||
|
public String getString(final int where, final int len)
|
||||||
|
throws BadLocationException {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} ), null, 0 ) {
|
||||||
{
|
{
|
||||||
setBorder( BorderFactory.createCompoundBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ),
|
setBorder( BorderFactory.createCompoundBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ),
|
||||||
BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) );
|
BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) );
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ public abstract class Res {
|
|||||||
|
|
||||||
public static final class Fonts {
|
public static final class Fonts {
|
||||||
|
|
||||||
public Font emoticonsFont(final int size) {
|
public Font identiconFont(final int size) {
|
||||||
return MPFont.emoticonsRegular.get( size );
|
return MPFont.emoticonsRegular.get( size );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ public class UserContentPanel extends JPanel implements State.Listener, MPUser.L
|
|||||||
add( Components.strut() );
|
add( Components.strut() );
|
||||||
|
|
||||||
add( identiconLabel = Components.label( SwingConstants.CENTER ) );
|
add( identiconLabel = Components.label( SwingConstants.CENTER ) );
|
||||||
identiconLabel.setFont( Res.fonts().emoticonsFont( Components.TEXT_SIZE_CONTROL ) );
|
identiconLabel.setFont( Res.fonts().identiconFont( Components.TEXT_SIZE_CONTROL ) );
|
||||||
add( Box.createGlue() );
|
add( Box.createGlue() );
|
||||||
|
|
||||||
add( Components.label( "Master Password:" ) );
|
add( Components.label( "Master Password:" ) );
|
||||||
@@ -330,6 +330,15 @@ public class UserContentPanel extends JPanel implements State.Listener, MPUser.L
|
|||||||
add( Box.createGlue() );
|
add( Box.createGlue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeNotify() {
|
||||||
|
char[] password = masterPasswordField.getPassword();
|
||||||
|
Arrays.fill( password, (char) 0 );
|
||||||
|
masterPasswordField.setText( new String( password ) );
|
||||||
|
|
||||||
|
super.removeNotify();
|
||||||
|
}
|
||||||
|
|
||||||
private void exportUser() {
|
private void exportUser() {
|
||||||
MPFileUser fileUser = (user instanceof MPFileUser)? (MPFileUser) user: null;
|
MPFileUser fileUser = (user instanceof MPFileUser)? (MPFileUser) user: null;
|
||||||
if (fileUser == null)
|
if (fileUser == null)
|
||||||
@@ -449,7 +458,8 @@ public class UserContentPanel extends JPanel implements State.Listener, MPUser.L
|
|||||||
private void updateIdenticon() {
|
private void updateIdenticon() {
|
||||||
char[] masterPassword = masterPasswordField.getPassword();
|
char[] masterPassword = masterPasswordField.getPassword();
|
||||||
MPIdenticon identicon = ((masterPassword != null) && (masterPassword.length > 0))?
|
MPIdenticon identicon = ((masterPassword != null) && (masterPassword.length > 0))?
|
||||||
new MPIdenticon( user.getFullName(), masterPassword ): null;
|
user.getAlgorithm().identicon( user.getFullName(), masterPassword ): null;
|
||||||
|
Arrays.fill( masterPassword, (char) 0 );
|
||||||
|
|
||||||
Res.ui( () -> {
|
Res.ui( () -> {
|
||||||
if (identicon != null) {
|
if (identicon != null) {
|
||||||
@@ -779,7 +789,7 @@ public class UserContentPanel extends JPanel implements State.Listener, MPUser.L
|
|||||||
typeModel.selection( MPResultType.DeriveKey, t -> {
|
typeModel.selection( MPResultType.DeriveKey, t -> {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case DeriveKey:
|
case DeriveKey:
|
||||||
stateModel.setText( Integer.toString( site.getAlgorithm().mpw_keySize_min() ) );
|
stateModel.setText( "128" );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||