2
0

Compare commits

...

25 Commits

Author SHA1 Message Date
Maarten Billemont
0b6e43a18f The root of the users VC interferes with touches from the sites VC when it appears. 2021-11-03 21:13:04 -04:00
Maarten Billemont
c94c52f4b6 Fix migration tips no longer interactable when logged in. 2021-11-03 16:51:37 -04:00
Maarten Billemont
5de9b05299 Move Spectre migration dialogs fully global & make closeable. 2021-11-01 21:16:00 -04:00
Maarten Billemont
f27607e63c fixup! Support for unset login type. 2021-11-01 20:52:04 -04:00
Maarten Billemont
0b45dc584f Fix deadlock when loadStore posts notifications to the main thread. 2021-11-01 20:07:13 -04:00
Maarten Billemont
88a4d7ba4d Support for unset login type. 2021-11-01 20:06:37 -04:00
Maarten Billemont
94a6c925bc Update Sentry SDK. 2021-10-31 14:32:31 -04:00
Maarten Billemont
eda9749cf2 Time to crack script updates.
[ADDED]     Calculate cost for cracking a password.
[UPDATED]   Hardware cost data based on various GPUs with updated hashcat metrics.
[ADDED]     Ability to calculate the strength of an arbitrary password.
2021-10-31 14:17:21 -04:00
Maarten Billemont
4c096555d0 Spectre migration updates.
[ADDED]     Migration prompt to sign-in screen.
[FIXED]     Spectre Apple ID.
2021-10-31 14:15:46 -04:00
Maarten Billemont
403c45519a 2.7-java-12 2021-03-02 19:33:53 -05:00
Maarten Billemont
8d33ff8ec5 Fix password field manipulation bugs.
[FIXED]     By stubbing the password field's document, we broke some editing capabilities. Stub the document in a way that respects its length.
2021-03-02 19:31:47 -05:00
Maarten Billemont
c38f713f05 Update site after release. 2021-02-18 11:27:18 -05:00
Maarten Billemont
d59595824b Fix path for C release VERSION and TAG. 2021-02-18 10:15:40 -05:00
Maarten Billemont
2b78449a48 Update site after release. 2021-02-18 09:58:10 -05:00
Maarten Billemont
2eda9b1152 2.7-java-11 2021-02-18 09:44:11 -05:00
Maarten Billemont
8a032ba891 Master Password is moving to Spectre!
https://gitlab.com/spectre.app
https://spectre.app/

Master Password is no longer actively maintained from here on out.
2021-02-17 23:40:51 -05:00
Maarten Billemont
eda34f6b0b Update binaries for latest core API. 2021-02-11 15:19:51 -05:00
Maarten Billemont
6e1855b00c fixup! Fix ANSI C11 support. 2021-02-11 15:07:59 -05:00
Maarten Billemont
90aaf23bb5 Build script update.
- Fixed build on Windows
- Improved documentation
- Fixed arch logic, separate standard arch from host name
2021-02-11 14:12:06 -05:00
Maarten Billemont
2e9c79f6b3 Fix ANSI C11 support. 2021-02-11 14:11:09 -05:00
Maarten Billemont
83fa6c39bc Site toolbar buttons should toggle on site, not result. 2021-02-08 14:21:52 -05:00
Maarten Billemont
913208255e Temporarily disable findsecbugs due to bug.
https://stackoverflow.com/a/62894507/58803
2021-02-08 14:20:42 -05:00
Maarten Billemont
963a1222be Update SpotBugs. 2021-02-08 14:20:29 -05:00
Maarten Billemont
a1264e0f91 Move main thread assert to the right spot. 2020-10-14 09:24:15 -04:00
Maarten Billemont
4f0065fba8 Update to tighten warnings configuration. 2020-10-14 09:23:46 -04:00
39 changed files with 693 additions and 660 deletions

View File

@ -7,6 +7,6 @@ FROM debian:stable-slim
RUN mkdir -p /usr/share/man/man1
RUN apt-get update && apt-get install -y default-jdk-headless git-core bash libtool automake autoconf make g++-multilib
RUN git clone --depth=3 $(: --shallow-submodules) --recurse-submodules --branch rewrite https://gitlab.com/MasterPassword/MasterPassword.git /mpw
RUN git clone --depth=3 $(: --shallow-submodules) --recurse-submodules https://gitlab.com/MasterPassword/MasterPassword.git /mpw
RUN cd /mpw && ./gradlew -i clean
RUN cd /mpw && git pull && git log -1 && ./gradlew -i check

191
README.md
View File

@ -4,197 +4,38 @@ Master Password is a completely new way of thinking about passwords.
It consists of an algorithm that implements the core idea and applications for various platforms making the alogirthm available to users on a variety of devices and platforms.
To skip the intro and go straight to the information on how to use the code, [click here](#source-code).
Master Password is available for [📲 iOS](https://itunes.apple.com/app/id510296984), [🖥 macOS](https://masterpassword.app/masterpassword-mac.zip), [📲 Android](https://masterpassword.app/masterpassword-android.apk), [🖥 Desktop](https://masterpassword.app/masterpassword-gui.jar), and [⌨ Console](https://masterpassword.app/masterpassword-cli.tar.gz).
## PROJECT MOVED
Master Password is also available from: [macOS: Homebrew](https://brew.sh/) (`brew install mpw`) and [Docker](https://www.docker.com/) (`docker run -ti registry.gitlab.com/masterpassword/masterpassword`).
Get in touch if you are interested in adding Master Password to any other package managers.
Master Password is announcing a massive rewrite, modernizing the solution and clearing the way for exciting new capabilities.
There are many reasons for using Master Password instead of an ordinary password manager, read below for the details, but if you want my personal favourites, they would be:
The project is re-launching as [Spectre](https://gitlab.com/spectre.app), still fully open-source Free Software here on GitLab.
- I don't need to worry about keeping backups of my countless authentication credentials.
- I don't need to worry that when I travel, I might not have access to my passwords vault.
- I don't need to trust an external party, proprietary code or a service to be online and stay online.
- If I feel at risk of my device being stolen or confiscated, I can set a fake master password, delete my user or wipe it worry-free.
Any interested parties are invited to participate in [the alpha or beta programs](https://spectre.app/#beta), to participate in the new Spectre identity platform.
We also have a [Frequently Asked Questions](#faq).
## What is a password?
Ah, the "password". Somehow, passwords have become the default solution to authentication across the web. We've long since accepted this as the way things are, but let's stop to think for a moment about what passwords actually are:
A password is a secret that is known only to the party providing a service and the party that should be allowed access to this service.
Simple enough - a secret that you know and your website knows but nobody else, thereby guaranteeing that you and only you have access to your account on this website. Unfortunately, in practice, the ubiquitous use of passwords has us completely overwhelmed. And the only way we can cope with that is by finding ways of making the problem manageable.
## What's the problem?
Coming up with a secret password is pretty easy. Say you're organizing a secret meeting and will only let people in if they know the password at the door. You tell those you trust, the password for tonight's meeting is "purple oranges with a smile".
The problem we have in our daily lives, however, is the fact that we need secret passwords for almost everything now. A password for our email, twitter, 9gag, facebook, imgur, amazon, ebay, paypal, bank, reddit, etc. And every time we want to use a new site, we need another one. The problem now becomes clear: passwords are meant to be remembered and recalled with ease when needed, but this becomes impossible when we have secrets for every distinct activity in our lives.
We cannot recall passwords the way we are expected to when there are too many.
## Coping
Life gives us no advice on how to deal with this problem. So we find our own ways:
- We use a single personal secret for all our websites, thereby violating the secrecy of these passwords (eg. you've given your email secret to twitter).
- We use simple variations of a personal secret or pattern, thereby trivializing the complexity of these passwords (eg. google98, twitter98; reversals, eg. 8991elgoog)
- We use external means of remembering passwords, thereby increasing the risk of loss (both loss of access when we lose the tool and theft when a thief finds our tool)
These coping mechanisms come in various forms, and they all have down-sides, because at the root of each of these lies an undeniable truth:
Our passwords are no longer true to the original definition.
## Master Password's approach
The theory behind Master Password starts with accepting that it is impossible to keep track of passwords for all your accounts. Instead, we return to the core premise of the password: a secret phrase that you can remember easily, all by yourself.
Master Password solves this problem by letting you remember one and only one password. You use this password with Master Password only. Master Password then gives you access to any website or service you want by creating a website-specific key for it.
1. You sign into Master Password using your one password.
2. You ask Master Password for the key to enter your website, eg. twitter.
3. You log into twitter using your username and the key from Master Password.
Master Password is *not* a password manager. It does not store your website passwords. Therefore, there is zero risk of you losing your website passwords (or them falling in the wrong hands). Master Password simply uses your one password and the name of the site to generate a site-specific secret.
## Benefits
- You don't need to think up a new strong password every time you make a new account - Master Password gives you the key for it.
- You don't need to try remembering a password you created two years ago for that one account - Master Password just gives you the key for it.
- You don't need to worry about getting into that account you made at work after you come home because you don't have your office passwords with you - Master Password is availale everywhere, even offline.
- You don't need to try to keep password lists in sync or stored somewhere easily accessible - Master Password keys can be created anywhere.
- You don't need to worry what you'll do if your computer dies or you need to log into your bank while you're in the airport transit zone - your Master Password keys are always available, even when starting empty.
- You don't need to worry about your password manager website getting hacked, your phone getting duplicated, somebody taking a picture of your passwords book - Master Password stores no secrets.
## How does it work?
The details of how Master Password works [are available here](https://masterpassword.app/masterpassword-algorithm.pdf).
In short:
master-key = SCRYPT( user-name, master-password )
site-key = HMAC-SHA-256( site-name . site-counter, master-key )
site-password = PW-TEMPLATE( site-key, site-template )
Master Password can derive the `site-password` in an entirely stateless manner. It is therefore better defined as a calculator than a manager. It is the user's responsibility to remember the inputs: `user-name`, `master-password`, `site-name`, `site-counter` and `site-template`.
We standardize `user-name` as your full name, `site-name` as the domain name of the site, `site-counter` to `1` (unless you explicitly increment it) and `site-template` to `Long Password`; as a result the only token the user really needs to remember actively is `master-password`.
The Beta program is now open for users with iOS devices. The Spectre Beta introduces a new app, rewritten under Swift, and new capabilities such as AutoFill.
All development effort has moved to the Spectre project. Master Password is no longer actively maintained.
## FAQ
1. If I lose my master password and need to set a new one, will I need to change all of my site passwords?
1. Has there been a change in ownership?
Yes. If your master password is compromised, it is only sensible for you to change all of your site passwords. Just like if you lose the keys in your pocket, you'll have to change all the locks they open. Master Password effectively enforces this security practice.
No. This project is still owned and maintained exclusively by [Maarten Billemont](https://gitlab.com/lhunath).
2. But what if I just forget my master password or I just want to change it to something else?
2. How can I trust Spectre?
Sorry, still yes. Your master password is the secret component to your Master Password identity. If it changes, your identity changes. I wholly encourage you to think very carefully about what makes for a really memorable and good master password before just diving in with something lazy. A short phrase works great, eg. `banana coloured duckling`.
Spectre's code-base is based on the Master Password code-base. The algorithm is exactly the same. The license is the same. The author is the same.
3. Doesn't this mean an attacker can reverse my master password from any of my site passwords?
The applications are being rewritten for modern platforms. Spectre has the exact same trust parameters as Master Password.
Technically, yes. Practically, no.
3. Why is the project changing?
You could argue that site passwords are "breadcrumbs" of your master password, but the same argument would suggest encrypted messages are breadcrumbs to the encryption key. Encryption works because it is computationally unfeasible to "guess" the encryption key that made the encrypted message, just like Master Password works because it is computationally unfeasible to "guess" your master password that made the site password.
Several reasons, in fact. Master Password as a name is too ubiquitous in popular culture, which is a cause for confusion. We are also looking to evolve the capabilities of the platform beyond simply passwords, into a fully decentralized identity platform. We're also looking to be socially inclusive and conscious of the implicit biases present in terminology we've inherited from past societies.
4. The second step is just a HMAC-SHA-256, doesn't that make the SCRYPT completely pointless?
All that said - Spectre is the mark of a complete refresh of the Master Password solution. Hope you'll love it!
No. They are used for different reasons and one is not weaker than the other.
4. How do I migrate?
HMAC-SHA-256 is much faster to compute than SCRYPT, which leads some people to think "all an attacker needs to do is brute-force the SHA and ignore the SCRYPT". The reality is that the HMAC-SHA-256 guards a 64-byte authentication key (the `master-key`) which makes the search space for brute-forcing the HMAC wildly too large to compute.
The `master-password` on the other hand, is only a simple phrase, which means its search space is much smaller. This is why it is guarded by a much tougher SCRYPT operation.
5. I have another question.
Please don't hesitate to [get in touch](#support), we're more than happy to answer all your Master Password questions. Any problems or suggestions can be reported [as GitLab issues](https://gitlab.com/MasterPassword/MasterPassword/issues/).
# Source Code
Master Password's algorithm is [documented](https://masterpassword.app/masterpassword-algorithm.pdf) and its implementation is [Free Software (GPLv3)](LICENSE).
## Components
There are several components available here. As an end-user, you can currently use the iOS app, the Android app, the OS X app, the Java desktop app, the C CLI app or the Java CLI app. There are also several components that are useful for developers:
- `core/c`: This is the reference implementation of the Master Password algorithm, written in C.
- `core/java/algorithm`: This is a Java implementation of the Master Password algorithm.
- `core/java/model`: This is an object model to simplify use of Master Password by Java applications.
- `core/java/tests`: These are Java integration tests designed to ensure Master Password performs as expected.
- `platform-android`: This is the official Android implementation of Master Password in Java.
- `platform-darwin`: This is the official iOS and OS X implementation of Master Password in Objective-C.
- `platform-independent/cli-c`: This is the platform-independent console implementation of Master Password, written in C.
- `platform-independent/cli-java`: This is the platform-independent console implementation of Master Password, written in Java.
- `platform-independent/gui-java`: This is the platform-independent desktop implementation of Master Password, written in Java.
- `platform-independent/web-js`: This is the platform-independent browser application for Master Password, written in JavaScript.
## Building and running
### macOS or iOS
Make sure you have all relevant submodules checked out.
Go into `platform-darwin` and open `MasterPassword.xcworkspace` in Xcode. Select the desired target from the Scheme Selector and build, run or archive.
### Web
Make sure you have all relevant submodules checked out.
Go into `platform-independent/web-js` and open `index.html` in your browser. You should be able to run this locally, there is no need for hosting or an application server.
### Java
Go into the `gradle` directory and run `./gradlew build`. All Java components will then be built:
- `platform-independent/gui-java/build/distributions`:
contains an archive with the Master Password Java GUI. Unpack it and run the `gui` script.
- `platform-independent/cli-java/build/distributions`:
contains an archive with the Master Password Java command-line interface. Unpack it and run the `cli` script.
- `platform-android/build/outputs/apk`:
contains the Android application package. Install it on your Android device.
Note that in order to build the Android application, you will need to have the Android SDK installed and either have the environment variable `ANDROID_HOME` set to its location or a `gradle/local.properties` file with its location, eg. (for Homebrew users who installed the SDK using `brew install android-sdk`):
sdk.dir=/usr/local/opt/android-sdk
### Native CLI
Go into the `platform-independent/cli-c` directory and run `./build`. The native command-line client will then be built.
For detailed instructions, see [the native CLI instructions](platform-independent/c/README.md).
## Support
Feel free to contribute by forking the project, reporting issues or joining the discussion on:
- [Gitter](https://gitter.im/lyndir/MasterPassword)
- #masterpassword (on chat.freenode.net)
- #masterpassword:lyndir.com (on Matrix)
- masterpassword@lyndir.com
Master Password export files are fully supported by Spectre. Migration mechanism exist in Master Password which will trigger as soon as you install Spectre; for instance, as soon as you install Spectre on your iOS device, Master Password will show a pop-up which will copy your user over at a tap.

View File

@ -16,7 +16,7 @@ buildscript {
allprojects {
group = 'com.lyndir.masterpassword'
version = '2.7.10'
version = '2.7.12'
}
subprojects {
@ -29,7 +29,7 @@ subprojects {
maven { url 'https://maven.lyndir.com' }
}
dependencies {
spotbugsPlugins group: 'com.h3xstream.findsecbugs', name: 'findsecbugs-plugin', version: '1.9.0'
//spotbugsPlugins group: 'com.h3xstream.findsecbugs', name: 'findsecbugs-plugin', version: '1.11.0'
//spotbugsPlugins group: 'com.mebigfatguy.sb-contrib', name: 'sb-contrib', version: '7.4.6'
}
spotbugs {

View File

@ -8,8 +8,9 @@
# - initialize
# - needs
# - clean & exit (only if script was ran with "clean" argument)
# - check & exit (only if target has already been successfully built)
# - prepare
# - clean
# - create
# - config
# - target
# - prepare
@ -23,12 +24,14 @@
# For example:
# target_prepare() { make -s distclean; }
# target_configure() { _target_configure "$@" --enable-minimal; }
#
set -e
PATH+=:/usr/local/bin
# needs <binary> ...
#
# Utility for ensuring all tools needed by the script are installed prior to starting.
#
needs() { _needs "$@"; }
_needs() {
local failed=0
@ -48,7 +51,8 @@ _needs() {
# initialize <prefix> <platform>
#
# The build script invokes this once prior to all other actions if the user wants a clean slate.
# The build script invokes this once prior to all other actions.
#
initialize() { _initialize "$@"; }
_initialize() {
initialize_needs "$@"
@ -56,15 +60,23 @@ _initialize() {
# initialize_needs <prefix> <platform>
#
# Check if all tools needed for the default implementations are available.
# Check if all tools required to configure and build for the platform are available.
#
# By default, this will check for:
# - Windows: MSBuild
# - Other: `libtool` (for libtoolize), `automake` (for aclocal), `autoconf` (for autoreconf) and make
#
# By default, this will check for `libtool` (for libtoolize), `automake` (for aclocal), `autoconf` (for autoreconf) and make.
initialize_needs() { _initialize_needs "$@"; }
_initialize_needs() {
if [[ $platform = windows ]]; then
needs cmd
export VSINSTALLDIR="${VSINSTALLDIR:-$(cd "$(cygpath -F 0x002a)/Microsoft Visual Studio"/*/*/Common7/.. && pwd)}"
[[ -e "$VSINSTALLDIR/Common7/Tools/VsMSBuildCmd.bat" ]] || { echo >&2 "Missing: msbuild. Please install 'Build Tools for Visual Studio'. See https://visualstudio.microsoft.com/downloads/?q=build+tools"; return 1; }
for dir in "$VSINSTALLDIR" "$(cygpath -F 0x002a)/Microsoft Visual Studio"/*/*/Common7/..; do
dir=$( [[ $dir ]] && cd "$dir" && [[ -e "Common7/Tools/VsMSBuildCmd.bat" ]] && cygpath -w "$PWD" ) && \
export VSINSTALLDIR=$dir && echo "Using MSBuild: $VSINSTALLDIR" && return
done
echo >&2 "Missing: msbuild. Please install 'Build Tools for Visual Studio'. See https://visualstudio.microsoft.com/downloads/?q=build+tools"
return 1
else
needs libtool:libtoolize,glibtoolize automake autoconf make
fi
@ -74,13 +86,18 @@ _initialize_needs() {
#
# Fully clean up the library code, restoring it to a pristine state.
#
# By default, this will wipe the prefix, run `make distclean` and `git clean -fdx`.
# By default, this will:
# - Windows: `msbuild /t:Clean`, or
# - Makefile: run `make distclean`, or
# - GIT: `git clean -fdx`
#
# Finally, it will wipe the prefix.
#
clean() { _clean "$@"; }
_clean() {
if [[ $platform = windows ]]; then
printf '"%%VSINSTALLDIR%%\Common7\Tools\VsMSBuildCmd.bat" && msbuild /t:Clean' > .clean.bat
cmd //c .clean.bat
rm -f .clean.bat
PATH="$(cygpath "$VSINSTALLDIR")/Common7/Tools:$PATH" \
cmd /v /c 'VsMSBuildCmd && for %s in (*.sln) do msbuild /t:Clean %s'
elif [[ -e Makefile ]] && make -s distclean; then :
elif [[ -e .git ]] && git clean -fdx; then :
fi
@ -88,26 +105,26 @@ _clean() {
rm -rf "$prefix"
}
# prepare <prefix> <platform> [ <arch> ... ]
# prepare <prefix> <platform> [ <arch:host> ... ]
#
# Configure the library for building the <arch>s on this machine.
# Initialize the prefix in anticipation for building the <arch>s on this machine.
# The build script invokes this once prior to building each of its targets.
# The <prefix> has been newly created.
#
# By default, this will run `autoreconf`.
prepare() { _prepare "$@"; }
_prepare() {
prepare_clean "$@"
prepare_create "$@"
prepare_config "$@"
}
# prepare_clean <prefix> <platform> [ <arch> ... ]
# prepare_create <prefix> <platform> [ <arch:host> ... ]
#
# Perform any necessary clean-up of the library code prior to building.
#
# By default, this will wipe the build configuration and re-create the prefix.
prepare_clean() { _prepare_clean "$@"; }
_prepare_clean() {
# TODO: Should this differ from clean()?
#
prepare_create() { _prepare_create "$@"; }
_prepare_create() {
local prefix=$1 platform=$2; shift 2
if [[ $platform = windows ]]; then :
@ -119,11 +136,16 @@ _prepare_clean() {
install -d "$prefix/out"
}
# prepare_config <prefix> <platform> [ <arch> ... ]
# prepare_config <prefix> <platform> [ <arch:host> ... ]
#
# Configure the library for building the <arch>s on this machine.
# Generate build solution for configuring a build on this machine.
# The <prefix> has been newly created.
#
# TODO: cmake support?
# By default, this will:
# - Windows: do nothing
# - Other: run `autoreconf`.
#
# By default, this will run `autoreconf`.
prepare_config() { _prepare_config "$@"; }
_prepare_config() {
local prefix=$1 platform=$2; shift 2
@ -141,11 +163,11 @@ _prepare_config() {
touch "$prefix/out/.prepared"
}
# target <prefix> <platform> <arch>
# target <prefix> <platform> <arch> <host>
#
# Build the library for the given <arch> and <platform> into the given <prefix>.
# Build the library to the <arch> binary for the <host> architecture on <platform> into the given <prefix>.
# The build script invokes this function when it's ready to build the library's code.
# Generic platform-specific environment setup has been done.
#
target() { _target "$@"; }
_target() {
target_prepare "$@"
@ -153,14 +175,71 @@ _target() {
target_build "$@"
}
# target_prepare <prefix> <platform> <arch>
# target_prepare <prefix> <platform> <arch> <host>
#
# Prepare the library configuration for building the target.
# Any build-related work to be done in the prefix prior to building.
#
# By default, this will:
# - Windows: do nothing
# - macOS/iOS: Discover SDKROOT & build flags
# - Android: Prepare an NDK toolchain & build flags
# - Makefile: run `make clean`
#
# By default, this will run `make clean` if a Makefile is found.
target_prepare() { _target_prepare "$@"; }
_target_prepare() {
local prefix=$1 platform=$2 arch=$3; shift 3
local prefix=$1 platform=$2 arch=$3 host=$4; shift 3
case "$platform" in
'windows')
;;
'macos')
SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
export CPPFLAGS="-arch $host -flto -O2 -g -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $CPPFLAGS"
export LDFLAGS="-arch $host -flto -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $LDFLAGS"
;;
'ios')
case "$arch" in
*'arm'*)
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
export CPPFLAGS="-arch $host -mthumb -fembed-bitcode -flto -O2 -g -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $CPPFLAGS"
export LDFLAGS="-arch $host -mthumb -fembed-bitcode -flto -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
;;
*)
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
export CPPFLAGS="-arch $host -flto -O2 -g -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $CPPFLAGS"
export LDFLAGS="-arch $host -flto -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
;;
esac
;;
'android')
[[ -x $ANDROID_NDK_HOME/build/ndk-build ]] || { echo >&2 "Android NDK not found. Please set ANDROID_NDK_HOME."; return 1; }
SDKROOT="$prefix/$arch/ndk"
# Platform 21 is lowest that supports x86_64
"$ANDROID_NDK_HOME/build/tools/make-standalone-toolchain.sh" --force --install-dir="$SDKROOT" --platform='android-21' --arch="$arch"
export PATH="$SDKROOT/bin:$PATH"
export CPPFLAGS="-O2 -g $CPPFLAGS"
export LDFLAGS="-avoid-version $LDFLAGS"
export CC='clang'
;;
*)
case "$arch" in
x86)
export CPPFLAGS="-m32 $CPPFLAGS" LDFLAGS="-m32 $LDFLAGS"
;;
x86_64)
export CPPFLAGS="-m64 $CPPFLAGS" LDFLAGS="-m64 $LDFLAGS"
;;
esac
;;
esac
if [[ $platform = windows ]]; then :
else
@ -168,66 +247,74 @@ _target_prepare() {
fi
}
# target_configure <prefix> <platform> <arch> [ <args> ... ]
# target_configure <prefix> <platform> <arch> <host> [ <args> ... ]
#
# Configure the library for building the target.
# Configure the library for building the target. This generates the compiler configuration.
#
# By default, this will run `./configure --host=<host> --prefix=<prefix>/<arch> <args>`.
# By default, some platform-specific arguments will be passed in as well as
# By default, this will:
# - Windows: do nothing
# - Other: run `./configure --host=<host> --prefix=<prefix>/<arch> <args>`.
#
# Some platform-specific configure arguments will be passed in as well.
# --enable-pic --disable-pie to ensure the resulting library can be linked again.
#
target_configure() { _target_configure "$@"; }
_target_configure() {
local prefix=$1 platform=$2 arch=$3; shift 3
local prefix=$1 platform=$2 arch=$3 host=$4; shift 4
local host=$arch build=
[[ $arch = *arm* ]] && host=arm
local build=
[[ -x config.guess ]] && build=$(./config.guess)
[[ -x build-aux/config.guess ]] && build=$(build-aux/config.guess)
case "$platform" in
'windows')
# doesn't use ./configure
return
return 0
;;
'ios'|'macos')
host+=-apple
set -- --enable-static --disable-shared
set -- --enable-static --disable-shared "$@"
;;
'android')
case "$arch" in
'arm') host='arm' ;;
'arm64') host='aarch64' ;;
'x86') host='i686' ;;
'x86_64') host='x86_64' ;;
esac
host=( "$SDKROOT/$host"*-android* ) host=${host##*/}
set -- --disable-static --enable-shared --with-sysroot="$SDKROOT/sysroot" "$@"
;;
*)
set -- --enable-static --disable-shared
set -- --enable-static --disable-shared "$@"
;;
esac
./configure ${build:+--build="$build"} ${host:+--host="$host"} --prefix="$prefix/$arch" --enable-pic --disable-pie "$@"
}
# target_build <prefix> <platform> <arch>
# target_build <prefix> <platform> <arch> <host>
#
# Build the library code for the target.
# Build the library code for the target. This runs the compiler per the previous configuration.
#
# By default, this will:
# - Windows: run `msbuild /t:Rebuild /p:Configuration:Release;Platform=<host>`
# - Other: run `make check install`.
#
# By default, this will run `make check install`.
target_build() { _target_build "$@"; }
_target_build() {
local prefix=$1 platform=$2 arch=$3; shift 3
local prefix=$1 platform=$2 arch=$3 host=$4; shift 4
if [[ $platform = windows ]]; then
# I cannot for the life of me figure out how to pass this command directly into cmd.
printf '"%%VSINSTALLDIR%%\Common7\Tools\VsMSBuildCmd.bat" && msbuild /t:Rebuild /p:Configuration=Release;Platform=%s;OutDir=%s' "$arch" "$(cygpath -w "${prefix##$PWD/}/$arch/")" > .build.bat
cmd //c .build.bat
rm -f .build.bat
if [[ -e CMakeLists.txt ]]; then
( projdir=$PWD; mkdir -p "$prefix/$arch/"; cd "$prefix/$arch/"
PATH="$(cygpath "$VSINSTALLDIR")/Common7/Tools:$(cygpath "$VSINSTALLDIR")/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin:$PATH" \
cmd /v /c "$(printf 'VsMSBuildCmd && cmake -A %s %s && for %%s in (*.sln) do msbuild /m /t:Rebuild /p:Configuration=Release;Platform=%s;OutDir=. %%s' \
"$host" "$(cygpath -w "$projdir")" "$host")" )
else
PATH="$(cygpath "$VSINSTALLDIR")/Common7/Tools:$PATH" \
cmd /v /c "$(printf 'VsMSBuildCmd && for %%s in (*.sln) do msbuild /m /t:Rebuild /p:Configuration=Release;Platform=%s;OutDir=%s %%s' \
"$host" "$(cygpath -w "${prefix##$PWD/}/$arch/")")"
fi
else
local cores=$(getconf NPROCESSORS_ONLN 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null ||:)
make -j"${cores:-3}" install
#make -j"${cores:-3}" check install # TODO: libjson-c breaks on parallel build for check and install
#make check install # TODO: libjson-c has a failing test atm
make install
fi
}
@ -235,6 +322,7 @@ _target_build() {
#
# Prepare the final build product.
# The build script invokes this once after a successful build of all targets.
#
finalize() { _finalize "$@"; }
_finalize() {
finalize_merge "$@"
@ -246,6 +334,7 @@ _finalize() {
# Merge all targets into a product the application can use, available at `<prefix>/out`.
#
# By default, this will copy the headers to `<prefix>/out/include`, install libraries into `<prefix>/out/lib` and mark the output product as successful.
#
finalize_merge() { _finalize_merge "$@"; }
_finalize_merge() {
local prefix=$1 platform=$2; shift 2
@ -296,6 +385,7 @@ _finalize_merge() {
# Clean up the library after a successful build (eg. housekeeping of temporary files).
#
# By default, this will run `make clean`.
#
finalize_clean() { _finalize_clean "$@"; }
_finalize_clean() {
if [[ $platform = windows ]]; then :
@ -307,6 +397,7 @@ _finalize_clean() {
# build <name> [<platform>]
#
# Build the library <name> (found at ../<name>) for platform <platform> (or "host" if unspecified).
#
build() { _build "$@"; }
_build() {
local name=$1 platform=${2:-host}
@ -322,10 +413,10 @@ _build() {
if (( ! ${#archs[@]} )); then
case "$platform" in
'macos') archs=( 'x86_64' ) ;;
'ios') archs=( 'i386' 'x86_64' 'armv7' 'armv7s' 'arm64' ) ;;
'android') archs=( 'arm' 'arm64' 'x86' 'x86_64' ) ;;
'windows') archs=( 'Win32' 'x64' ) ;;
*) archs=( 'i686' 'x86_64' ) ;;
'ios') archs=( 'x86:i386' 'x86_64' 'armv7' 'armv7s' 'arm64' ) ;;
'android') archs=( 'arm' 'arm64:aarch64' 'x86:i686' 'x86_64' ) ;;
'windows') archs=( 'x86:Win32' 'x86_64:x64' ) ;;
*) archs=( 'x86:i686' 'x86_64' ) ;;
esac
fi
@ -348,60 +439,13 @@ _build() {
# Repeat the build for each individual architecture.
for arch in "${archs[@]}"; do (
local host=${arch#*:} arch=${arch%%:*}
echo
echo " # $name ($platform: $arch) ..."
echo " # $name [$platform: $arch ($host)] ..."
# Set up a base environment for the platform.
case "$platform" in
'windows')
;;
'macos')
SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
export CPPFLAGS="-arch $arch -flto -O2 -g -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $CPPFLAGS"
export LDFLAGS="-arch $arch -flto -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $LDFLAGS"
;;
'ios')
case "$arch" in
*'arm'*)
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
export CPPFLAGS="-arch $arch -mthumb -fembed-bitcode -flto -O2 -g -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $CPPFLAGS"
export LDFLAGS="-arch $arch -mthumb -fembed-bitcode -flto -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
;;
*)
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
export CPPFLAGS="-arch $arch -flto -O2 -g -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $CPPFLAGS"
export LDFLAGS="-arch $arch -flto -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
;;
esac
;;
'android')
[[ -x $ANDROID_NDK_HOME/build/ndk-build ]] || { echo >&2 "Android NDK not found. Please set ANDROID_NDK_HOME."; return 1; }
SDKROOT="$prefix/$arch/ndk"
# Platform 21 is lowest that supports x86_64
"$ANDROID_NDK_HOME/build/tools/make-standalone-toolchain.sh" --force --install-dir="$SDKROOT" --platform='android-21' --arch="$arch"
export PATH="$SDKROOT/bin:$PATH"
export CPPFLAGS="-O2 -g $CPPFLAGS"
export LDFLAGS="-avoid-version $LDFLAGS"
export CC='clang'
;;
*)
case "$arch" in
i686)
export CPPFLAGS="-m32 $CPPFLAGS" LDFLAGS="-m32 $LDFLAGS"
;;
x86_64)
export CPPFLAGS="-m64 $CPPFLAGS" LDFLAGS="-m64 $LDFLAGS"
;;
esac
;;
esac
target "$prefix" "$platform" "$arch"
target "$prefix" "$platform" "$arch" "$host"
); done
finalize "$prefix" "$platform" "${archs[@]}"
finalize "$prefix" "$platform" "${archs[@]%%:*}"
}

View File

@ -30,10 +30,18 @@
/* End PBXFileReference section */
/* Begin PBXGroup section */
536DEA2BDA9F2F9583C53D8F /* Products */ = {
isa = PBXGroup;
children = (
);
name = Products;
sourceTree = "<group>";
};
DA1554D220B3924000EA92C5 = {
isa = PBXGroup;
children = (
DA1554DD20B3928E00EA92C5 /* core */,
536DEA2BDA9F2F9583C53D8F /* Products */,
);
sourceTree = "<group>";
};
@ -105,6 +113,7 @@
Base,
);
mainGroup = DA1554D220B3924000EA92C5;
productRefGroup = 536DEA2BDA9F2F9583C53D8F /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (

View File

@ -7,7 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
13D62249DA5980D1FFC89971 /* Pods_MasterPassword_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B4E180CA32C86ACDC960D8B1 /* Pods_MasterPassword_iOS.framework */; };
148C3B3327EF82FED5464ADA /* Pods_MasterPassword_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A4F020BDEF2099375EBF1E7 /* Pods_MasterPassword_iOS.framework */; };
93D390C1B93F9D3AE37DD0A5 /* MPAnswersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39C426E03358384018E85 /* MPAnswersViewController.m */; };
93D391ECBD9BD2C64115B5DD /* PearlSizedTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39156E806BB78E04F78B9 /* PearlSizedTextView.m */; };
93D3922A53E41A54832E90D9 /* PearlOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390FADEB325D8D54A957D /* PearlOverlay.m */; };
@ -460,7 +460,9 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
5C616FA365D7A5C31689B2FF /* Pods-MasterPassword.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword.test.xcconfig"; path = "Target Support Files/Pods-MasterPassword/Pods-MasterPassword.test.xcconfig"; sourceTree = "<group>"; };
2D3D92F229CDF888708ECB65 /* Pods-MasterPassword-iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword-iOS.debug.xcconfig"; path = "Target Support Files/Pods-MasterPassword-iOS/Pods-MasterPassword-iOS.debug.xcconfig"; sourceTree = "<group>"; };
7902D27548A859ED1D8F5B82 /* Pods-MasterPassword-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword-iOS.release.xcconfig"; path = "Target Support Files/Pods-MasterPassword-iOS/Pods-MasterPassword-iOS.release.xcconfig"; sourceTree = "<group>"; };
7A4F020BDEF2099375EBF1E7 /* Pods_MasterPassword_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MasterPassword_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
93D390519405B76CC6A57C4F /* MPCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCell.h; sourceTree = "<group>"; };
93D3908DF8EABBD952065DC0 /* UICollectionView+PearlReloadItems.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UICollectionView+PearlReloadItems.m"; sourceTree = "<group>"; };
93D390A3B351FEF1B9EDAB56 /* mpw-algorithm_v2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v2.c"; sourceTree = "<group>"; };
@ -546,7 +548,6 @@
93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; };
93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSOrderedSetOrArray.h; sourceTree = "<group>"; };
93D39FD9623E8D5571C0AEB3 /* MPAlgorithmV3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV3.m; sourceTree = "<group>"; };
B4E180CA32C86ACDC960D8B1 /* Pods_MasterPassword_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MasterPassword_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
DA071BF1190187FE00179766 /* empty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "empty@2x.png"; sourceTree = "<group>"; };
DA071BF2190187FE00179766 /* empty.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = empty.png; sourceTree = "<group>"; };
@ -1583,10 +1584,6 @@
DAFE4A63150399FF003ABA8F /* UIScrollView+PearlFlashingIndicators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+PearlFlashingIndicators.h"; sourceTree = "<group>"; };
DAFE4A63150399FF003ABA91 /* NSDateFormatter+RFC3339.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDateFormatter+RFC3339.m"; sourceTree = "<group>"; };
DAFE4A63150399FF003ABA93 /* NSDateFormatter+RFC3339.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDateFormatter+RFC3339.h"; sourceTree = "<group>"; };
DC2D4B0016EB0A535147BA13 /* 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>"; };
E4F11DB2CE85A9CF2A0C79B2 /* Pods-MasterPassword-iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword-iOS.debug.xcconfig"; path = "Target Support Files/Pods-MasterPassword-iOS/Pods-MasterPassword-iOS.debug.xcconfig"; sourceTree = "<group>"; };
FE662C1B92299C911450537C /* Pods-MasterPassword.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword.debug.xcconfig"; path = "Target Support Files/Pods-MasterPassword/Pods-MasterPassword.debug.xcconfig"; sourceTree = "<group>"; };
FFFCFF8FBD5549B1EFF8806D /* Pods-MasterPassword-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword-iOS.release.xcconfig"; path = "Target Support Files/Pods-MasterPassword-iOS/Pods-MasterPassword-iOS.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -1615,7 +1612,7 @@
DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */,
DA5BFA4D147E415C00F98B1E /* CoreGraphics.framework in Frameworks */,
DA5BFA4F147E415C00F98B1E /* CoreData.framework in Frameworks */,
13D62249DA5980D1FFC89971 /* Pods_MasterPassword_iOS.framework in Frameworks */,
148C3B3327EF82FED5464ADA /* Pods_MasterPassword_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1640,11 +1637,8 @@
6B6983E746CC7BE4292982AE /* Pods */ = {
isa = PBXGroup;
children = (
FE662C1B92299C911450537C /* Pods-MasterPassword.debug.xcconfig */,
DC2D4B0016EB0A535147BA13 /* Pods-MasterPassword.release.xcconfig */,
5C616FA365D7A5C31689B2FF /* Pods-MasterPassword.test.xcconfig */,
E4F11DB2CE85A9CF2A0C79B2 /* Pods-MasterPassword-iOS.debug.xcconfig */,
FFFCFF8FBD5549B1EFF8806D /* Pods-MasterPassword-iOS.release.xcconfig */,
2D3D92F229CDF888708ECB65 /* Pods-MasterPassword-iOS.debug.xcconfig */,
7902D27548A859ED1D8F5B82 /* Pods-MasterPassword-iOS.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -1804,7 +1798,7 @@
DABB981515100B4000B05417 /* SystemConfiguration.framework */,
93D394077F8FAB8167647187 /* Twitter.framework */,
DA5BFA48147E415C00F98B1E /* UIKit.framework */,
B4E180CA32C86ACDC960D8B1 /* Pods_MasterPassword_iOS.framework */,
7A4F020BDEF2099375EBF1E7 /* Pods_MasterPassword_iOS.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -3152,14 +3146,14 @@
isa = PBXNativeTarget;
buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword-iOS" */;
buildPhases = (
B8D66904C16DDB94975E6ABD /* [CP] Check Pods Manifest.lock */,
50DCE14ACFF8F47D6AD8D108 /* [CP] Check Pods Manifest.lock */,
DA8D88E019DA412A00B189D0 /* Run Script: genassets */,
DA5BFA40147E415C00F98B1E /* Sources */,
DA5BFA41147E415C00F98B1E /* Frameworks */,
DA5BFA42147E415C00F98B1E /* Resources */,
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */,
4A87858EE3659604089E2F9F /* [CP] Embed Pods Frameworks */,
DA3C4EB32439438B00A6C4A8 /* Sentry dSYM Upload */,
944AD8F1A1196535AF939789 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -3476,24 +3470,7 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
4A87858EE3659604089E2F9F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-iOS/Pods-MasterPassword-iOS-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-iOS/Pods-MasterPassword-iOS-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-iOS/Pods-MasterPassword-iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
B8D66904C16DDB94975E6ABD /* [CP] Check Pods Manifest.lock */ = {
50DCE14ACFF8F47D6AD8D108 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -3515,6 +3492,30 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
944AD8F1A1196535AF939789 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-iOS/Pods-MasterPassword-iOS-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/JRSwizzle-iOS/JRSwizzle.framework",
"${BUILT_PRODUCTS_DIR}/KCOrderedAccessorFix-iOS/KCOrderedAccessorFix.framework",
"${BUILT_PRODUCTS_DIR}/Sentry-iOS/Sentry.framework",
"${BUILT_PRODUCTS_DIR}/UIColor-Utilities/UIColor_Utilities.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/JRSwizzle.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KCOrderedAccessorFix.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/UIColor_Utilities.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-iOS/Pods-MasterPassword-iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
DA3C4EB32439438B00A6C4A8 /* Sentry dSYM Upload */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
@ -3794,33 +3795,45 @@
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_ATOMIC_IMPLICIT_SEQ_CST = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES_ERROR;
CLANG_WARN_BOOL_CONVERSION = YES_ERROR;
CLANG_WARN_COMMA = YES_ERROR;
CLANG_WARN_CONSTANT_CONVERSION = YES_ERROR;
CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_DELETE_NON_VIRTUAL_DTOR = YES_ERROR;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_ENUM_CONVERSION = YES_ERROR;
CLANG_WARN_FLOAT_CONVERSION = YES_ERROR;
CLANG_WARN_FRAMEWORK_INCLUDE_PRIVATE_FROM_PUBLIC = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES_ERROR;
CLANG_WARN_MISSING_NOESCAPE = YES_ERROR;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR;
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_INTERFACE_IVARS = YES_ERROR;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES_ERROR;
CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO;
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_PRAGMA_PACK = YES_ERROR;
CLANG_WARN_PRIVATE_MODULE = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES_ERROR;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
CLANG_WARN_VEXING_PARSE = YES_ERROR;
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
@ -3846,7 +3859,7 @@
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES_ERROR;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
@ -3861,6 +3874,7 @@
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_MISSING_PARENTHESES = YES;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_SHADOW = NO;
GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@ -3868,6 +3882,7 @@
GCC_WARN_UNKNOWN_PRAGMAS = NO;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = NO;
GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
@ -3900,33 +3915,45 @@
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_ATOMIC_IMPLICIT_SEQ_CST = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES_ERROR;
CLANG_WARN_BOOL_CONVERSION = YES_ERROR;
CLANG_WARN_COMMA = YES_ERROR;
CLANG_WARN_CONSTANT_CONVERSION = YES_ERROR;
CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_DELETE_NON_VIRTUAL_DTOR = YES_ERROR;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_ENUM_CONVERSION = YES_ERROR;
CLANG_WARN_FLOAT_CONVERSION = YES_ERROR;
CLANG_WARN_FRAMEWORK_INCLUDE_PRIVATE_FROM_PUBLIC = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES_ERROR;
CLANG_WARN_MISSING_NOESCAPE = YES_ERROR;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR;
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_INTERFACE_IVARS = YES_ERROR;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES_ERROR;
CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO;
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_PRAGMA_PACK = YES_ERROR;
CLANG_WARN_PRIVATE_MODULE = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES_ERROR;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
CLANG_WARN_VEXING_PARSE = YES_ERROR;
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
@ -3950,7 +3977,7 @@
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES_ERROR;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
@ -3965,6 +3992,7 @@
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_MISSING_PARENTHESES = YES;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_SHADOW = NO;
GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@ -3972,6 +4000,7 @@
GCC_WARN_UNKNOWN_PRAGMAS = NO;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = NO;
GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
@ -3992,7 +4021,7 @@
};
DA5BFA6E147E415C00F98B1E /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = E4F11DB2CE85A9CF2A0C79B2 /* Pods-MasterPassword-iOS.debug.xcconfig */;
baseConfigurationReference = 2D3D92F229CDF888708ECB65 /* Pods-MasterPassword-iOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_OBJC_ARC = YES;
@ -4028,7 +4057,7 @@
};
DA5BFA6F147E415C00F98B1E /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = FFFCFF8FBD5549B1EFF8806D /* Pods-MasterPassword-iOS.release.xcconfig */;
baseConfigurationReference = 7902D27548A859ED1D8F5B82 /* Pods-MasterPassword-iOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_OBJC_ARC = YES;

View File

@ -7,7 +7,6 @@
objects = {
/* Begin PBXBuildFile section */
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 */; };
93D391E61DC23E128DA4446C /* NSView+Traversing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393EE88DE554BCCBC1C2D /* NSView+Traversing.h */; };
93D393A1646430FAAC73E7FE /* MPMacApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F83DD151985F2C7345A /* MPMacApplication.m */; };
@ -18,6 +17,7 @@
93D398D1F5D8CD5A22AF6929 /* MPGradientView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39934FD8D5BFABA46F41C /* MPGradientView.m */; };
93D39C5789EFA607CF788082 /* MPSiteModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E73BF5CBF8E5B005CD3 /* MPSiteModel.m */; };
93D39F833DEC1C89B2F795AC /* MPSitesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A57A7823DE98A0FF83C /* MPSitesWindowController.m */; };
C6D1011AA5C6C5391BFC9DC0 /* Pods_MasterPassword_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C2AEAB82916C4A50EE4A4DE /* Pods_MasterPassword_macOS.framework */; };
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 */; };
DA09745E1E99586600F0BFE8 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA09745D1E99586600F0BFE8 /* libxml2.tbd */; };
@ -348,11 +348,8 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
04D86D0B84D29123756339FD /* Pods-MasterPassword.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword.debug.xcconfig"; path = "Target Support Files/Pods-MasterPassword/Pods-MasterPassword.debug.xcconfig"; sourceTree = "<group>"; };
1E9477508F419F29008C7553 /* Pods_MasterPassword_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MasterPassword_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
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>"; };
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>"; };
2C2AEAB82916C4A50EE4A4DE /* Pods_MasterPassword_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MasterPassword_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6F97B456DA90E7D2E95B64A5 /* 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>"; };
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>"; };
93D392A4F3DE0BD758B9B056 /* MPNoStateButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPNoStateButton.h; sourceTree = "<group>"; };
@ -1119,6 +1116,7 @@
DAFE4A63150399FF003ABA87 /* NSObject+PearlKVO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+PearlKVO.h"; sourceTree = "<group>"; };
DAFE4A63150399FF003ABA91 /* NSDateFormatter+RFC3339.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDateFormatter+RFC3339.m"; sourceTree = "<group>"; };
DAFE4A63150399FF003ABA93 /* NSDateFormatter+RFC3339.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDateFormatter+RFC3339.h"; sourceTree = "<group>"; };
DF299A3DC20096A2D2942352 /* 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>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -1154,7 +1152,7 @@
DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */,
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */,
DA72E2272444081200676D4F /* SystemConfiguration.framework in Frameworks */,
7352E972184B980C428B66A2 /* Pods_MasterPassword_macOS.framework in Frameworks */,
C6D1011AA5C6C5391BFC9DC0 /* Pods_MasterPassword_macOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1181,10 +1179,8 @@
0C357E29DE20E18311095EBF /* Pods */ = {
isa = PBXGroup;
children = (
04D86D0B84D29123756339FD /* Pods-MasterPassword.debug.xcconfig */,
7791961245EBC3023523FDCD /* Pods-MasterPassword.release.xcconfig */,
1E9ED9547411486CE0898611 /* Pods-MasterPassword-macOS.debug.xcconfig */,
28DD0F6129ECC496C8DFE6F8 /* Pods-MasterPassword-macOS.release.xcconfig */,
6F97B456DA90E7D2E95B64A5 /* Pods-MasterPassword-macOS.debug.xcconfig */,
DF299A3DC20096A2D2942352 /* Pods-MasterPassword-macOS.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -1261,7 +1257,7 @@
DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */,
DA6701DD16406B7300B61001 /* Social.framework */,
DABB981515100B4000B05417 /* SystemConfiguration.framework */,
1E9477508F419F29008C7553 /* Pods_MasterPassword_macOS.framework */,
2C2AEAB82916C4A50EE4A4DE /* Pods_MasterPassword_macOS.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -2320,15 +2316,15 @@
isa = PBXNativeTarget;
buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword-macOS" */;
buildPhases = (
0DC4F66C2499C40A68A07D58 /* [CP] Check Pods Manifest.lock */,
A4743CFBA7F5C60D2E440512 /* [CP] Check Pods Manifest.lock */,
DA4EF9CB19FD4B600032ECB5 /* Run Script: genassets */,
DA5BFA40147E415C00F98B1E /* Sources */,
DA5BFA41147E415C00F98B1E /* Frameworks */,
DA5BFA42147E415C00F98B1E /* Resources */,
DAD9B5EE1762CA3A001835F9 /* Copy LoginHelper */,
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */,
43E5966C8C236E86824DDADE /* [CP] Embed Pods Frameworks */,
DA3C4EB2243941AE00A6C4A8 /* Sentry dSYM Upload */,
85C937E180CD7620A471A930 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -2544,7 +2540,29 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
0DC4F66C2499C40A68A07D58 /* [CP] Check Pods Manifest.lock */ = {
85C937E180CD7620A471A930 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/JRSwizzle-macOS/JRSwizzle.framework",
"${BUILT_PRODUCTS_DIR}/KCOrderedAccessorFix-macOS/KCOrderedAccessorFix.framework",
"${BUILT_PRODUCTS_DIR}/Sentry-macOS/Sentry.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/JRSwizzle.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KCOrderedAccessorFix.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
A4743CFBA7F5C60D2E440512 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -2566,23 +2584,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
43E5966C8C236E86824DDADE /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MasterPassword-macOS/Pods-MasterPassword-macOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
DA3C4EB2243941AE00A6C4A8 /* Sentry dSYM Upload */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
@ -3194,7 +3195,7 @@
};
DA5BFA6E147E415C00F98B1E /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1E9ED9547411486CE0898611 /* Pods-MasterPassword-macOS.debug.xcconfig */;
baseConfigurationReference = 6F97B456DA90E7D2E95B64A5 /* Pods-MasterPassword-macOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
@ -3234,7 +3235,7 @@
};
DA5BFA6F147E415C00F98B1E /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 28DD0F6129ECC496C8DFE6F8 /* Pods-MasterPassword-macOS.release.xcconfig */;
baseConfigurationReference = DF299A3DC20096A2D2942352 /* Pods-MasterPassword-macOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;

View File

@ -146,10 +146,10 @@ static NSOperationQueue *_mpwQueue = nil;
- (NSString *)nameOfType:(MPResultType)type {
if (!type)
return nil;
switch (type) {
case MPResultTypeNone:
return @"None";
case MPResultTypeTemplateMaximum:
return @"Maximum Security Password";
@ -189,10 +189,10 @@ static NSOperationQueue *_mpwQueue = nil;
- (NSString *)shortNameOfType:(MPResultType)type {
if (!type)
return nil;
switch (type) {
case MPResultTypeNone:
return @"None";
case MPResultTypeTemplateMaximum:
return @"Maximum";
@ -237,9 +237,6 @@ static NSOperationQueue *_mpwQueue = nil;
- (Class)classOfType:(MPResultType)type {
if (!type)
Throw( @"No type given." );
switch (type) {
case MPResultTypeTemplateMaximum:
return [MPGeneratedSiteEntity class];
@ -271,6 +268,7 @@ static NSOperationQueue *_mpwQueue = nil;
case MPResultTypeStatefulDevice:
return [MPStoredSiteEntity class];
case MPResultTypeNone:
case MPResultTypeDeriveKey:
break;
}
@ -322,6 +320,7 @@ static NSOperationQueue *_mpwQueue = nil;
return MPResultTypeStatefulDevice;
case MPResultTypeStatefulDevice:
return MPResultTypeTemplatePhrase;
case MPResultTypeNone:
case MPResultTypeDeriveKey:
break;
}
@ -531,8 +530,13 @@ static NSOperationQueue *_mpwQueue = nil;
return;
}
case MPResultTypeDeriveKey:
case MPResultTypeNone:
case MPResultTypeDeriveKey: {
PearlNotMainQueue( ^{
resultBlock( nil );
} );
return;
}
}
Throw( @"Type not supported: %lu", (long)type );

View File

@ -51,6 +51,8 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
+ (NSManagedObjectContext *)managedObjectContextForMainThreadIfReady {
NSAssert( [[NSThread currentThread] isMainThread], @"Direct access to main MOC only allowed from the main thread." );
NSManagedObjectContext *mainManagedObjectContext = [[self get] mainManagedObjectContextIfReady];
if (!mainManagedObjectContext || ![[NSThread currentThread] isMainThread])
return nil;
@ -154,8 +156,6 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
- (NSManagedObjectContext *)mainManagedObjectContextIfReady {
NSAssert( [[NSThread currentThread] isMainThread], @"Can only access main MOC from the main thread." );
[self loadStore];
if (!self.mainManagedObjectContext && self.privateManagedObjectContext.persistentStoreCoordinator) {

View File

@ -43,7 +43,7 @@ __END_DECLS
\
if (__error && [[MPConfig get].sendInfo boolValue]) { \
SentryEvent *event = [[SentryEvent alloc] initWithLevel:kSentryLevelError]; \
event.message = strf( message_ @": %@", ##__VA_ARGS__, [__error localizedDescription]); \
event.message = [[SentryMessage alloc] initWithFormatted:strf( message_ @": %@", ##__VA_ARGS__, [__error localizedDescription])]; \
event.logger = @"MPError"; \
event.fingerprint = @[ message_, __error.domain, @(__error.code) ]; \
[SentrySDK captureEvent:event]; \

View File

@ -124,7 +124,7 @@
switch (self.mode) {
case MPCombinedModeUserSelection: {
self.usersVC.view.userInteractionEnabled = YES;
self.usersVC.userSelectionContainer.userInteractionEnabled = YES;
[self.usersVC setActive:YES animated:animated];
if (self.sitesVC) {
MPSitesSegue *segue = [[MPSitesSegue alloc] initWithIdentifier:@"passwords" source:self.sitesVC destination:self];
@ -134,7 +134,7 @@
break;
}
case MPCombinedModePasswordSelection: {
self.usersVC.view.userInteractionEnabled = NO;
self.usersVC.userSelectionContainer.userInteractionEnabled = NO;
[self.usersVC setActive:NO animated:animated];
[self performSegueWithIdentifier:@"passwords" sender:@{ @"animated": @(animated) }];
break;

View File

@ -30,8 +30,6 @@
@property(nonatomic, strong) IBOutlet UIView *badNameTipContainer;
@property(nonatomic, strong) IBOutlet UIView *popdownView;
@property(nonatomic, strong) IBOutlet UIView *popdownContainer;
@property(nonatomic, strong) IBOutlet UIView *spectreInstallAlert;
@property(nonatomic, strong) IBOutlet UIView *spectreMigrateAlert;
@property(assign, nonatomic) BOOL active;
@ -39,6 +37,5 @@
- (void)reloadSites;
- (IBAction)dismissPopdown:(id)sender;
- (IBAction)upgradeSpectre:(UIButton *)sender;
@end

View File

@ -74,7 +74,6 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
[self registerObservers];
[self updateConfigKey:nil];
[self updateSpectreAlerts];
static NSRegularExpression *bareHostRE = nil;
static dispatch_once_t once = 0;
@ -318,7 +317,6 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
PearlAddNotificationObserver( UIApplicationWillEnterForegroundNotification, nil, [NSOperationQueue mainQueue],
^(MPSitesViewController *self, NSNotification *note) {
[self viewWillAppear:YES];
[self updateSpectreAlerts];
} );
PearlAddNotificationObserver( MPSignedOutNotification, nil, nil,
^(MPSitesViewController *self, NSNotification *note) {
@ -466,24 +464,4 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
self.popdownToTopConstraint.priority = UILayoutPriorityDefaultHigh;
}
- (IBAction)upgradeSpectre:(UIButton *)sender {
[[MPiOSAppDelegate get] migrateFor:[MPiOSAppDelegate get].activeUserForMainThread];
}
#pragma mark - Private
- (void)updateSpectreAlerts {
BOOL spectreInstalled = [UIApp canOpenURL:[[NSURL alloc] initWithString:@"spectre:"]];
if (spectreInstalled) {
self.spectreInstallAlert.visible = NO;
self.spectreMigrateAlert.visible = YES;
}
else {
self.spectreInstallAlert.visible = [MPiOSAppDelegate get].spectreViewController != nil;
self.spectreMigrateAlert.visible = NO;
}
}
@end

View File

@ -35,10 +35,14 @@
@property(weak, nonatomic) IBOutlet UIButton *nextAvatarButton;
@property(weak, nonatomic) IBOutlet UIButton *previousAvatarButton;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *keyboardHeightConstraint;
@property(weak, nonatomic) IBOutlet UIView *spectreInstallAlert;
@property(weak, nonatomic) IBOutlet UIView *spectreMigrateAlert;
@property(assign, nonatomic, readonly) BOOL active;
- (void)setActive:(BOOL)active animated:(BOOL)animated;
- (IBAction)changeAvatar:(UIButton *)sender;
- (IBAction)upgradeSpectre:(UIButton *)sender;
- (IBAction)dismissSpectre:(UIButton *)sender;
@end

View File

@ -100,6 +100,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
[self registerObservers];
[self reloadUsers];
[self updateSpectreAlerts];
[self.marqueeTipTimer invalidate];
self.marqueeTipTimer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector( firedMarqueeTimer: )
@ -660,6 +661,7 @@ referenceSizeForFooterInSection:(NSInteger)section {
PearlAddNotificationObserver( UIApplicationWillEnterForegroundNotification, nil, [NSOperationQueue mainQueue],
^(MPUsersViewController *self, NSNotification *note) {
[self reloadUsers];
[self updateSpectreAlerts];
} );
PearlAddNotificationObserver( UIApplicationDidBecomeActiveNotification, nil, [NSOperationQueue mainQueue],
^(MPUsersViewController *self, NSNotification *note) {
@ -726,6 +728,19 @@ referenceSizeForFooterInSection:(NSInteger)section {
}];
}
- (void)updateSpectreAlerts {
BOOL spectreInstalled = [UIApp canOpenURL:[[NSURL alloc] initWithString:@"spectre:"]];
if (spectreInstalled) {
self.spectreInstallAlert.visible = NO;
self.spectreMigrateAlert.visible = YES;
}
else {
self.spectreInstallAlert.visible = [MPiOSAppDelegate get].spectreViewController != nil;
self.spectreMigrateAlert.visible = NO;
}
}
#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
@ -907,4 +922,15 @@ referenceSizeForFooterInSection:(NSInteger)section {
++[self selectedAvatar].avatar;
}
- (IBAction)upgradeSpectre:(UIButton *)sender {
[[MPiOSAppDelegate get] migrateFor:[MPiOSAppDelegate get].activeUserForMainThread];
}
- (IBAction)dismissSpectre:(UIButton *)sender {
self.spectreInstallAlert.visible = NO;
self.spectreMigrateAlert.visible = NO;
}
@end

View File

@ -60,22 +60,6 @@ MP_LIBS_END
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
@try {
// Sentry
[SentrySDK startWithOptions:@{
@"dsn" : NilToNSNull( decrypt( sentryDSN ) ),
#ifdef DEBUG
@"debug" : @(NO), //@(YES),
@"environment" : @"Development",
#elif PUBLIC
@"debug" : @(NO),
@"environment" : @"Public",
#else
@"debug" : @(NO),
@"environment" : @"Private",
#endif
@"enabled" : @([[MPiOSConfig get].sendInfo boolValue] || ![[MPiOSConfig get].sendInfoDecided boolValue]),
@"enableAutoSessionTracking": @(YES),
}];
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
PearlLogLevel level = PearlLogLevelWarn;
if ([[MPConfig get].sendInfo boolValue])
@ -148,7 +132,9 @@ MP_LIBS_END
[self updateConfigKey:note.object];
} );
PearlAddNotificationObserver( NSUserDefaultsDidChangeNotification, nil, nil, ^(id self, NSNotification *note) {
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
PearlMainQueueOperation( ^{
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
} );
} );
}
@catch (id exception) {
@ -189,7 +175,7 @@ MP_LIBS_END
SKStoreProductParameterCampaignToken : @"app-masterpassword.ios", /* Campaign: From MasterPassword iOS */
SKStoreProductParameterProviderToken : @153897, /* Provider: Maarten Billemont */
// SKStoreProductParameterITunesItemIdentifier: @510296984, /* Application: MasterPassword iOS */
SKStoreProductParameterITunesItemIdentifier: @1500430196, /* Application: Spectre iOS */
SKStoreProductParameterITunesItemIdentifier: @1526402806, /* Application: Spectre iOS */
} completionBlock:^(BOOL result, NSError *error) {
if (error)
err( @"Failed loading Spectre product information: %@", error );
@ -834,7 +820,23 @@ MP_LIBS_END
if ([PearlLogger get].printLevel > PearlLogLevelInfo)
[PearlLogger get].printLevel = PearlLogLevelInfo;
[SentrySDK.currentHub getClient].options.enabled = @YES;
// Sentry
if (!SentrySDK.isEnabled)
[SentrySDK startWithOptions:@{
@"dsn" : NilToNSNull( decrypt( sentryDSN ) ),
#ifdef DEBUG
@"debug" : @(NO), //@(YES),
@"environment" : @"Development",
#elif PUBLIC
@"debug" : @(NO),
@"environment" : @"Public",
#else
@"debug" : @(NO),
@"environment" : @"Private",
#endif
@"enableAutoSessionTracking": @(YES),
}];
[SentrySDK configureScope:^(SentryScope *scope) {
[scope setExtraValue:[MPiOSConfig get].rememberLogin forKey:@"rememberLogin"];
[scope setExtraValue:[MPiOSConfig get].sendInfo forKey:@"sendInfo"];
@ -859,7 +861,7 @@ MP_LIBS_END
}
else {
[Countly.sharedInstance cancelConsentForFeatures:countlyFeatures];
[SentrySDK.currentHub getClient].options.enabled = @NO;
[SentrySDK close];
}
}

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17154" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="Q1S-vU-GGO">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19162" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="Q1S-vU-GGO">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17124"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19144"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<customFonts key="customFonts">
@ -69,7 +69,7 @@
</collectionViewFlowLayout>
<cells>
<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"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="215" height="667"/>
@ -410,21 +410,112 @@
<constraint firstItem="9u7-pu-Wtv" firstAttribute="leading" secondItem="rWM-08-aab" secondAttribute="leading" id="sez-BC-G3I"/>
</constraints>
</view>
<view opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tOT-TZ-yse" userLabel="Install Spectre Tip">
<rect key="frame" x="0.0" y="740" width="414" height="156"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ded-Ii-gyf" userLabel="Migrate">
<rect key="frame" x="8" y="8" width="398" height="106"/>
<state key="normal" backgroundImage="tip_alert_black"/>
<connections>
<action selector="upgradeSpectre:" destination="S8q-YF-Kt9" eventType="touchUpInside" id="Mmn-CK-C45"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bqa-qH-Bia">
<rect key="frame" x="80" y="15" width="267" height="84"/>
<string key="text">The next generation of password security is now called «Spectre»:
Tap to install the upgrade.
This app is now out of maintenance.</string>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="14"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" horizontalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tDY-IR-ak2" userLabel="Close">
<rect key="frame" x="347" y="20" width="47" height="31"/>
<buttonConfiguration key="configuration" style="plain" title=""/>
<connections>
<action selector="dismissSpectre:" destination="S8q-YF-Kt9" eventType="touchUpInside" id="7a6-W3-NIK"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="ded-Ii-gyf" firstAttribute="leading" secondItem="tOT-TZ-yse" secondAttribute="leadingMargin" id="3fy-Qc-KlM"/>
<constraint firstItem="bqa-qH-Bia" firstAttribute="top" secondItem="ded-Ii-gyf" secondAttribute="top" constant="7" id="8Rd-qC-ttx"/>
<constraint firstItem="bqa-qH-Bia" firstAttribute="bottom" secondItem="ded-Ii-gyf" secondAttribute="bottom" constant="-15" id="VLO-QZ-6Jf"/>
<constraint firstItem="ded-Ii-gyf" firstAttribute="top" secondItem="tOT-TZ-yse" secondAttribute="topMargin" id="Y6k-Ep-Skv"/>
<constraint firstAttribute="trailingMargin" secondItem="ded-Ii-gyf" secondAttribute="trailing" id="d8e-pL-U3v"/>
<constraint firstAttribute="trailing" secondItem="tDY-IR-ak2" secondAttribute="trailing" constant="20" symbolic="YES" id="lb2-4g-zJV"/>
<constraint firstItem="bqa-qH-Bia" firstAttribute="leading" secondItem="ded-Ii-gyf" secondAttribute="leading" constant="72" id="nD7-ie-dHF"/>
<constraint firstItem="tDY-IR-ak2" firstAttribute="top" secondItem="tOT-TZ-yse" secondAttribute="top" constant="20" symbolic="YES" id="pDc-SL-x9W"/>
<constraint firstItem="tDY-IR-ak2" firstAttribute="leading" secondItem="bqa-qH-Bia" secondAttribute="trailing" id="suM-kx-xRY"/>
<constraint firstAttribute="bottomMargin" secondItem="ded-Ii-gyf" secondAttribute="bottom" id="xzD-vT-p1O"/>
</constraints>
</view>
<view opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e7i-8u-nyd" userLabel="Migrate Spectre Tip">
<rect key="frame" x="0.0" y="740" width="414" height="156"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4s3-Ex-jpT" userLabel="Migrate">
<rect key="frame" x="8" y="8" width="398" height="106"/>
<state key="normal" backgroundImage="tip_alert_black"/>
<connections>
<action selector="upgradeSpectre:" destination="S8q-YF-Kt9" eventType="touchUpInside" id="059-Sa-0EF"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bWt-lb-7xL">
<rect key="frame" x="80" y="15" width="267" height="84"/>
<string key="text">The next generation of password security is now called «Spectre»:
Tap to copy your user into Spectre.
This app is now out of maintenance.</string>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="14"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" horizontalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3WO-6r-WEn" userLabel="Close">
<rect key="frame" x="347" y="20" width="47" height="31"/>
<buttonConfiguration key="configuration" style="plain" title=""/>
<connections>
<action selector="dismissSpectre:" destination="S8q-YF-Kt9" eventType="touchUpInside" id="aEC-nX-WeV"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="3WO-6r-WEn" firstAttribute="leading" secondItem="bWt-lb-7xL" secondAttribute="trailing" id="49f-Eg-XMb"/>
<constraint firstItem="bWt-lb-7xL" firstAttribute="leading" secondItem="4s3-Ex-jpT" secondAttribute="leading" constant="72" id="4rw-uH-p06"/>
<constraint firstItem="3WO-6r-WEn" firstAttribute="top" secondItem="e7i-8u-nyd" secondAttribute="top" constant="20" id="50L-TI-WJ8"/>
<constraint firstItem="bWt-lb-7xL" firstAttribute="top" secondItem="4s3-Ex-jpT" secondAttribute="top" constant="7" id="AwO-Pj-Wnr"/>
<constraint firstAttribute="bottomMargin" secondItem="4s3-Ex-jpT" secondAttribute="bottom" id="LWF-xQ-l5k"/>
<constraint firstItem="4s3-Ex-jpT" firstAttribute="leading" secondItem="e7i-8u-nyd" secondAttribute="leadingMargin" id="OKe-0I-vdR"/>
<constraint firstItem="4s3-Ex-jpT" firstAttribute="top" secondItem="e7i-8u-nyd" secondAttribute="topMargin" id="TRy-eS-Ch4"/>
<constraint firstAttribute="trailing" secondItem="3WO-6r-WEn" secondAttribute="trailing" constant="20" id="aPO-KL-k9X"/>
<constraint firstItem="bWt-lb-7xL" firstAttribute="bottom" secondItem="4s3-Ex-jpT" secondAttribute="bottom" constant="-15" id="cYX-vL-MKX"/>
<constraint firstAttribute="trailingMargin" secondItem="4s3-Ex-jpT" secondAttribute="trailing" id="lRd-Hq-SH2"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.1215686275" green="0.12941176469999999" blue="0.14117647059999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="VGz-R0-vMD" firstAttribute="top" secondItem="X8H-vh-j7B" secondAttribute="bottom" id="8Ed-3Y-ll0"/>
<constraint firstAttribute="trailing" secondItem="X8H-vh-j7B" secondAttribute="trailing" id="8Gr-Dq-UpZ"/>
<constraint firstAttribute="bottom" secondItem="rWM-08-aab" secondAttribute="bottom" id="9Yx-cj-wHh"/>
<constraint firstItem="tOT-TZ-yse" firstAttribute="leading" secondItem="DOr-Xu-P9q" secondAttribute="leading" id="CKQ-85-U4k"/>
<constraint firstAttribute="bottom" secondItem="e7i-8u-nyd" secondAttribute="bottom" id="G00-FW-tqE"/>
<constraint firstItem="X8H-vh-j7B" firstAttribute="top" secondItem="9u7-pu-Wtv" secondAttribute="centerY" priority="500" constant="180" id="Gp5-h6-53S"/>
<constraint firstItem="rWM-08-aab" firstAttribute="leading" secondItem="DOr-Xu-P9q" secondAttribute="leading" id="Il8-kg-Dra"/>
<constraint firstItem="X8H-vh-j7B" firstAttribute="top" secondItem="fUK-gJ-NRE" secondAttribute="centerY" priority="500" constant="180" id="PgC-ZL-cQo"/>
<constraint firstAttribute="trailing" secondItem="rWM-08-aab" secondAttribute="trailing" id="UPP-1n-zIe"/>
<constraint firstItem="X8H-vh-j7B" firstAttribute="top" secondItem="qp1-nX-o4i" secondAttribute="bottom" constant="20" id="WdK-tA-njz"/>
<constraint firstItem="e7i-8u-nyd" firstAttribute="leading" secondItem="DOr-Xu-P9q" secondAttribute="leading" id="au3-Bw-ioi"/>
<constraint firstItem="X8H-vh-j7B" firstAttribute="leading" secondItem="DOr-Xu-P9q" secondAttribute="leading" id="jbn-ko-MPq"/>
<constraint firstAttribute="trailing" secondItem="e7i-8u-nyd" secondAttribute="trailing" id="l3l-d3-Y68"/>
<constraint firstItem="zCP-wo-gTl" firstAttribute="top" secondItem="zp4-4O-wZI" secondAttribute="bottom" id="nAS-Jf-o5m"/>
<constraint firstAttribute="bottom" secondItem="tOT-TZ-yse" secondAttribute="bottom" id="oNx-xq-124"/>
<constraint firstAttribute="trailing" secondItem="tOT-TZ-yse" secondAttribute="trailing" id="wI5-eh-S2b"/>
<constraint firstAttribute="top" secondItem="rWM-08-aab" secondAttribute="top" id="xBe-1Q-mz2"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="ignoreTouches" value="YES"/>
</userDefinedRuntimeAttributes>
</view>
<simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="lightContent"/>
<connections>
@ -442,6 +533,8 @@
<outlet property="nextAvatarButton" destination="fUK-gJ-NRE" id="5qo-lK-rSa"/>
<outlet property="preferencesTipContainer" destination="0Um-Ot-hI6" id="Cv8-Bp-ZZs"/>
<outlet property="previousAvatarButton" destination="9u7-pu-Wtv" id="Hgv-lN-S1n"/>
<outlet property="spectreInstallAlert" destination="tOT-TZ-yse" id="2hk-xb-psR"/>
<outlet property="spectreMigrateAlert" destination="e7i-8u-nyd" id="6oI-L9-VgE"/>
<outlet property="storeLoadingActivity" destination="VDd-oM-ZOO" id="MJ7-2f-e8n"/>
<outlet property="thanksTipContainer" destination="069-Pu-yXe" id="wWf-2X-Ryw"/>
<outlet property="userSelectionContainer" destination="rWM-08-aab" id="Yme-hX-8P0"/>
@ -449,7 +542,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="8hZ-Tb-wZw" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2041" y="226"/>
<point key="canvasLocation" x="2040.5797101449277" y="225.66964285714283"/>
</scene>
<!--Web View Controller-->
<scene sceneID="JQz-u7-oA7">
@ -624,20 +717,20 @@
<tableViewSection id="FEv-Rb-jst">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="eth-Dc-JYn" userLabel="Show Help">
<rect key="frame" x="0.0" y="28" width="414" height="250"/>
<rect key="frame" x="0.0" y="44.5" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="eth-Dc-JYn" id="8m6-pP-lda">
<rect key="frame" x="0.0" y="0.0" width="383" height="250"/>
<rect key="frame" x="0.0" y="0.0" width="384.5" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Show Help" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="x9b-Qa-Pza">
<rect key="frame" x="20" y="20" width="343" height="20"/>
<rect key="frame" x="20" y="20" width="344.5" height="20"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" text="Open the short step-by-step guide which explains how to use Master Password." lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bKz-o1-gHv">
<rect key="frame" x="20" y="48" width="343" height="182"/>
<rect key="frame" x="20" y="48" width="344.5" height="182"/>
<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"/>
<nil key="highlightedColor"/>
@ -656,20 +749,20 @@
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="R30-AU-bR6" userLabel="Sign Out">
<rect key="frame" x="0.0" y="278" width="414" height="250"/>
<rect key="frame" x="0.0" y="294.5" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="R30-AU-bR6" id="f6h-Ff-2Qc">
<rect key="frame" x="0.0" y="0.0" width="383" height="250"/>
<rect key="frame" x="0.0" y="0.0" width="384.5" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Sign Out" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nr5-ze-6PW">
<rect key="frame" x="20" y="20" width="343" height="20"/>
<rect key="frame" x="20" y="20" width="344.5" height="20"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" text="Log yourself out and return to the user selection screen." lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0G1-cX-MT3">
<rect key="frame" x="20" y="48" width="343" height="182"/>
<rect key="frame" x="20" y="48" width="344.5" height="182"/>
<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"/>
<nil key="highlightedColor"/>
@ -688,7 +781,7 @@
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="B8R-iE-Ffe" userLabel="Default Password Type">
<rect key="frame" x="0.0" y="528" width="414" height="250"/>
<rect key="frame" x="0.0" y="544.5" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="B8R-iE-Ffe" id="8r5-Zc-TRj">
<rect key="frame" x="0.0" y="0.0" width="414" height="250"/>
@ -772,7 +865,7 @@
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="Sz1-JP-dw2" userLabel="Avatar">
<rect key="frame" x="0.0" y="778" width="414" height="250"/>
<rect key="frame" x="0.0" y="794.5" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Sz1-JP-dw2" id="R4X-LE-ir9">
<rect key="frame" x="0.0" y="0.0" width="414" height="250"/>
@ -847,25 +940,25 @@
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="fRZ-Uh-FR8" userLabel="Save Password">
<rect key="frame" x="0.0" y="1028" width="414" height="250"/>
<rect key="frame" x="0.0" y="1044.5" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fRZ-Uh-FR8" id="qCQ-L5-teL">
<rect key="frame" x="0.0" y="0.0" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" verticalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Jr5-mX-nw0">
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" verticalCompressionResistancePriority="751" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Jr5-mX-nw0">
<rect key="frame" x="182.5" y="199" width="51" height="31"/>
<connections>
<action selector="valueChanged:" destination="JFc-sj-awD" eventType="valueChanged" id="KMj-5x-BcK"/>
</connections>
</switch>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Save Password" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3fk-Io-xQI">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" ambiguous="YES" text="Save Password" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3fk-Io-xQI">
<rect key="frame" x="20" y="20" width="374" height="20"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</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="Z1N-JR-4fr">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" ambiguous="YES" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Z1N-JR-4fr">
<rect key="frame" x="20" y="48" width="374" height="143"/>
<string key="text">This will store your master password in your device's keychain. As a result, you'll be able to log in without entering your master password. This is somewhat less secure in the event of theft: anyone who figures out your device's PIN can get in. You can compensate for the reduced security by setting a more secure passcode for your device (in Settings, go to: General-&gt;Passcode Lock, disable "Simple Passcode") or by purchasing and enabling support for TouchID.</string>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="12"/>
@ -888,25 +981,25 @@
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="bKn-6f-TKE" userLabel="TouchID">
<rect key="frame" x="0.0" y="1278" width="414" height="250"/>
<rect key="frame" x="0.0" y="1294.5" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="bKn-6f-TKE" id="GBL-TP-VnH">
<rect key="frame" x="0.0" y="0.0" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" verticalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wOM-X3-jCG">
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" verticalCompressionResistancePriority="751" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wOM-X3-jCG">
<rect key="frame" x="182.5" y="199" width="51" height="31"/>
<connections>
<action selector="valueChanged:" destination="JFc-sj-awD" eventType="valueChanged" id="KmT-CO-GZh"/>
</connections>
</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" ambiguous="YES" text="Biometrics" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6xf-vt-aXd">
<rect key="frame" x="20" y="20" width="374" height="20"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</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" ambiguous="YES" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="URR-yZ-QuC">
<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 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>
@ -930,19 +1023,19 @@ Note that this feature requires you enable the Save Password option and have pur
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="9QG-lM-ymM" userLabel="Feedback">
<rect key="frame" x="0.0" y="1528" width="414" height="250"/>
<rect key="frame" x="0.0" y="1544.5" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="9QG-lM-ymM" id="hK8-XQ-lLz">
<rect key="frame" x="0.0" y="0.0" width="383" height="250"/>
<rect key="frame" x="0.0" y="0.0" width="396.5" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Feedback" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5zr-Nr-zRb">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" ambiguous="YES" text="Feedback" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5zr-Nr-zRb">
<rect key="frame" x="20" y="20" width="343" height="20"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" text="Contact me if you have a question, idea, praise or issue. Try to be as detailed as possible." lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8dg-Ew-Vy1">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" ambiguous="YES" text="Contact me if you have a question, idea, praise or issue. Try to be as detailed as possible." lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8dg-Ew-Vy1">
<rect key="frame" x="20" y="48" width="343" height="182"/>
<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"/>
@ -962,19 +1055,19 @@ Note that this feature requires you enable the Save Password option and have pur
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="UdB-BV-AHA" userLabel="Check Inconsistencies">
<rect key="frame" x="0.0" y="1778" width="414" height="250"/>
<rect key="frame" x="0.0" y="1794.5" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="UdB-BV-AHA" id="V2Y-nu-jhZ">
<rect key="frame" x="0.0" y="0.0" width="383" height="250"/>
<rect key="frame" x="0.0" y="0.0" width="396.5" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Check For Inconsistencies" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WXh-sg-l2h">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" ambiguous="YES" text="Check For Inconsistencies" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WXh-sg-l2h">
<rect key="frame" x="20" y="20" width="343" height="20"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" text="Perform a check to see if there are any inconsistencies in your site data that might cause issues." lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gTs-JA-zmL">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" ambiguous="YES" text="Perform a check to see if there are any inconsistencies in your site data that might cause issues." lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gTs-JA-zmL">
<rect key="frame" x="20" y="48" width="343" height="182"/>
<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"/>
@ -994,19 +1087,19 @@ Note that this feature requires you enable the Save Password option and have pur
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="IVT-Rs-nTu" userLabel="Export">
<rect key="frame" x="0.0" y="2028" width="414" height="250"/>
<rect key="frame" x="0.0" y="2044.5" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="IVT-Rs-nTu" id="Q5J-2f-mmz">
<rect key="frame" x="0.0" y="0.0" width="383" height="250"/>
<rect key="frame" x="0.0" y="0.0" width="396.5" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Export" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KEh-y5-Obc">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" ambiguous="YES" text="Export" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KEh-y5-Obc">
<rect key="frame" x="20" y="20" width="343" height="20"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</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="U77-XF-Bvb">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" ambiguous="YES" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="U77-XF-Bvb">
<rect key="frame" x="20" y="48" width="343" height="182"/>
<string key="text">An export saves all your sites and optionally their passwords to a file that you can store separately. It can function as a back-up or a way to move all your sites to a new device.</string>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="12"/>
@ -1027,19 +1120,19 @@ Note that this feature requires you enable the Save Password option and have pur
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="hmf-Wz-9l2" userLabel="Footer">
<rect key="frame" x="0.0" y="2278" width="414" height="250"/>
<rect key="frame" x="0.0" y="2294.5" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hmf-Wz-9l2" id="AL3-2q-tgO">
<rect key="frame" x="0.0" y="0.0" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="999" verticalCompressionResistancePriority="1000" text="© 2011-2020, Maarten Billemont (lhunath)" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sPw-mV-mFF">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="999" verticalCompressionResistancePriority="1000" ambiguous="YES" text="© 2011-2020, Maarten Billemont (lhunath)" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sPw-mV-mFF">
<rect key="frame" x="20" y="4" width="374" height="106"/>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="11"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Rl7-cr-FHf">
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Rl7-cr-FHf">
<rect key="frame" x="20" y="118" width="374" height="27"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
<state key="normal" title="Home Page">
@ -1049,7 +1142,7 @@ Note that this feature requires you enable the Save Password option and have pur
<action selector="homePageButton:" destination="JFc-sj-awD" eventType="touchUpInside" id="ptD-cv-NMr"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="epW-Rm-9St">
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="epW-Rm-9St">
<rect key="frame" x="20" y="153" width="374" height="27"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
<state key="normal" title="Understanding Master Password's Security">
@ -1059,7 +1152,7 @@ Note that this feature requires you enable the Save Password option and have pur
<action selector="securityButton:" destination="JFc-sj-awD" eventType="touchUpInside" id="Efv-cp-Xfh"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LTN-ch-h8D">
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LTN-ch-h8D">
<rect key="frame" x="20" y="188" width="374" height="27"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
<state key="normal" title="Get the Master Password source code">
@ -1069,7 +1162,7 @@ Note that this feature requires you enable the Save Password option and have pur
<action selector="sourceButton:" destination="JFc-sj-awD" eventType="touchUpInside" id="Y3O-di-CZo"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Z60-lc-Nka">
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Z60-lc-Nka">
<rect key="frame" x="20" y="223" width="374" height="27"/>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="12"/>
<state key="normal" title="Send Thanks">
@ -1594,9 +1687,9 @@ Note that this feature requires you enable the Save Password option and have pur
</constraints>
</view>
<visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cHF-cD-2Ge">
<rect key="frame" x="0.0" y="0.0" width="414" height="144"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="139"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="CkH-CQ-k0G">
<rect key="frame" x="0.0" y="0.0" width="414" height="144"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="139"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<navigationBar hidden="YES" opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" barStyle="black" translatesAutoresizingMaskIntoConstraints="NO" id="uuT-jm-2La" userLabel="Navigation" customClass="PearlUINavigationBar">
@ -1616,14 +1709,14 @@ Note that this feature requires you enable the Save Password option and have pur
</connections>
</button>
<searchBar contentMode="redraw" barStyle="black" searchBarStyle="minimal" placeholder="eg. apple.com" translatesAutoresizingMaskIntoConstraints="NO" id="aGs-1S-aC3">
<rect key="frame" x="0.0" y="88" width="414" height="56"/>
<rect key="frame" x="0.0" y="88" width="414" height="51"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="URL"/>
<connections>
<outlet property="delegate" destination="nkY-z6-8jd" id="ENG-q5-XwX"/>
</connections>
</searchBar>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LEX-BK-PdS" userLabel="Bad Name Tip">
<rect key="frame" x="57" y="116" width="300.5" height="75.5"/>
<rect key="frame" x="57" y="113.5" width="300.5" height="75.5"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black_top.png" translatesAutoresizingMaskIntoConstraints="NO" id="Rt5-v4-I0R">
<rect key="frame" x="0.0" y="0.0" width="300.5" height="75.5"/>
@ -1672,70 +1765,6 @@ eg. apple.com, rmitchell@twitter.com</string>
</view>
<blurEffect style="regular"/>
</visualEffectView>
<view opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3ve-eR-1IW">
<rect key="frame" x="0.0" y="740" width="414" height="156"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="PWC-I5-RSl">
<rect key="frame" x="8" y="8" width="398" height="106"/>
<state key="normal" backgroundImage="tip_alert_black"/>
<connections>
<action selector="upgradeSpectre:" destination="nkY-z6-8jd" eventType="touchUpInside" id="8KJ-vm-3D0"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XgC-Ky-oVC">
<rect key="frame" x="80" y="15" width="315" height="84"/>
<string key="text">The next generation of password security is now called «Spectre»:
Tap to install the upgrade.
This app is now out of maintenance.</string>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="14"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="PWC-I5-RSl" firstAttribute="top" secondItem="3ve-eR-1IW" secondAttribute="topMargin" id="0gi-j6-mfg"/>
<constraint firstItem="XgC-Ky-oVC" firstAttribute="leading" secondItem="PWC-I5-RSl" secondAttribute="leading" constant="72" id="E88-An-rzp"/>
<constraint firstAttribute="bottomMargin" secondItem="PWC-I5-RSl" secondAttribute="bottom" id="FrN-5c-k1V"/>
<constraint firstItem="XgC-Ky-oVC" firstAttribute="trailing" secondItem="PWC-I5-RSl" secondAttribute="trailing" constant="-11" id="Scl-zE-fTg"/>
<constraint firstAttribute="trailingMargin" secondItem="PWC-I5-RSl" secondAttribute="trailing" id="gwp-DL-I06"/>
<constraint firstItem="XgC-Ky-oVC" firstAttribute="bottom" secondItem="PWC-I5-RSl" secondAttribute="bottom" constant="-15" id="hFa-k3-yr9"/>
<constraint firstItem="PWC-I5-RSl" firstAttribute="leading" secondItem="3ve-eR-1IW" secondAttribute="leadingMargin" id="jod-TY-7Iu"/>
<constraint firstItem="XgC-Ky-oVC" firstAttribute="top" secondItem="PWC-I5-RSl" secondAttribute="top" constant="7" id="yjZ-x1-6JY"/>
</constraints>
</view>
<view opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="67c-5R-Foa">
<rect key="frame" x="0.0" y="740" width="414" height="156"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EZK-er-8ql">
<rect key="frame" x="8" y="8" width="398" height="106"/>
<state key="normal" backgroundImage="tip_alert_black"/>
<connections>
<action selector="upgradeSpectre:" destination="nkY-z6-8jd" eventType="touchUpInside" id="P4a-tL-9yX"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fLB-gA-32p">
<rect key="frame" x="80" y="15" width="315" height="84"/>
<string key="text">The next generation of password security is now called «Spectre»:
Tap to copy this user into Spectre.
This app is now out of maintenance.</string>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="14"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="EZK-er-8ql" secondAttribute="trailing" id="2v6-0n-EXu"/>
<constraint firstItem="fLB-gA-32p" firstAttribute="bottom" secondItem="EZK-er-8ql" secondAttribute="bottom" constant="-15" id="KET-Ct-225"/>
<constraint firstAttribute="bottomMargin" secondItem="EZK-er-8ql" secondAttribute="bottom" id="LqJ-v9-IDf"/>
<constraint firstItem="fLB-gA-32p" firstAttribute="trailing" secondItem="EZK-er-8ql" secondAttribute="trailing" constant="-11" id="ivM-cA-Fn9"/>
<constraint firstItem="fLB-gA-32p" firstAttribute="leading" secondItem="EZK-er-8ql" secondAttribute="leading" constant="72" id="iwL-1a-Tgo"/>
<constraint firstItem="fLB-gA-32p" firstAttribute="top" secondItem="EZK-er-8ql" secondAttribute="top" constant="7" id="mHI-WQ-tMx"/>
<constraint firstItem="EZK-er-8ql" firstAttribute="top" secondItem="67c-5R-Foa" secondAttribute="topMargin" id="xMX-Iy-gkw"/>
<constraint firstItem="EZK-er-8ql" firstAttribute="leading" secondItem="67c-5R-Foa" secondAttribute="leadingMargin" id="ycd-o8-QVl"/>
</constraints>
</view>
<view opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XNM-XQ-rMe" userLabel="Popdown">
<rect key="frame" x="0.0" y="-896" width="414" height="896"/>
<subviews>
@ -1779,13 +1808,8 @@ This app is now out of maintenance.</string>
</subviews>
<color key="backgroundColor" red="0.1215686275" green="0.12941176469999999" blue="0.14117647059999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="67c-5R-Foa" secondAttribute="trailing" id="0mY-Tq-ZT4"/>
<constraint firstItem="cHF-cD-2Ge" firstAttribute="top" secondItem="XNM-XQ-rMe" secondAttribute="bottom" id="6V9-tX-50t"/>
<constraint firstAttribute="trailing" secondItem="3ve-eR-1IW" secondAttribute="trailing" id="7hd-C3-Akk"/>
<constraint firstAttribute="bottom" secondItem="67c-5R-Foa" secondAttribute="bottom" id="8xp-Si-tWG"/>
<constraint firstAttribute="top" secondItem="XNM-XQ-rMe" secondAttribute="bottom" priority="750" id="BdD-Kc-eHl"/>
<constraint firstItem="67c-5R-Foa" firstAttribute="leading" secondItem="tI8-OT-LrO" secondAttribute="leading" id="Ftn-Yi-mdI"/>
<constraint firstAttribute="bottom" secondItem="3ve-eR-1IW" secondAttribute="bottom" id="GOa-ky-jfJ"/>
<constraint firstItem="uuT-jm-2La" firstAttribute="bottom" secondItem="S9X-2T-e1e" secondAttribute="bottom" priority="500" constant="44" id="HAi-jL-BdJ"/>
<constraint firstAttribute="trailing" secondItem="K2e-Gh-7hH" secondAttribute="trailing" id="Hnk-mU-GSd"/>
<constraint firstAttribute="top" secondItem="cHF-cD-2Ge" secondAttribute="bottom" priority="1" id="JO5-ph-0ce"/>
@ -1797,7 +1821,6 @@ This app is now out of maintenance.</string>
<constraint firstItem="cHF-cD-2Ge" firstAttribute="leading" secondItem="tI8-OT-LrO" secondAttribute="leading" id="TJC-eP-DDE"/>
<constraint firstItem="uuT-jm-2La" firstAttribute="bottom" secondItem="VOY-zU-XQR" secondAttribute="bottom" id="U4C-1P-lIR"/>
<constraint firstItem="K2e-Gh-7hH" firstAttribute="height" secondItem="tI8-OT-LrO" secondAttribute="height" id="Xfe-XT-eOn"/>
<constraint firstItem="3ve-eR-1IW" firstAttribute="leading" secondItem="tI8-OT-LrO" secondAttribute="leading" id="bKZ-qF-SL5"/>
<constraint firstAttribute="trailing" secondItem="XNM-XQ-rMe" secondAttribute="trailing" id="bgl-u9-shU"/>
<constraint firstItem="K2e-Gh-7hH" firstAttribute="top" secondItem="tI8-OT-LrO" secondAttribute="bottom" priority="1" id="dNt-uf-8BC"/>
<constraint firstItem="K2e-Gh-7hH" firstAttribute="top" secondItem="tI8-OT-LrO" secondAttribute="top" priority="500" id="vtB-e4-L8o"/>
@ -1816,8 +1839,6 @@ This app is now out of maintenance.</string>
<outlet property="popdownView" destination="XNM-XQ-rMe" id="FaW-4m-Fff"/>
<outlet property="searchBar" destination="aGs-1S-aC3" id="rTp-DP-rIz"/>
<outlet property="sitesToBottomConstraint" destination="dNt-uf-8BC" id="Ta6-eL-z7w"/>
<outlet property="spectreInstallAlert" destination="3ve-eR-1IW" id="Ah5-OX-XhQ"/>
<outlet property="spectreMigrateAlert" destination="67c-5R-Foa" id="aTi-fu-opO"/>
<segue destination="z9O-w0-6oR" kind="modal" identifier="guide" id="Ql4-wf-T8u"/>
<segue destination="Foa-Er-RBr" kind="custom" identifier="message" customClass="MPOverlaySegue" id="Xne-Sm-HQt"/>
</connections>
@ -2147,10 +2168,10 @@ This app is now out of maintenance.</string>
</items>
</navigationBar>
<pageControl opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" numberOfPages="3" translatesAutoresizingMaskIntoConstraints="NO" id="8A2-ly-WTX">
<rect key="frame" x="141" y="778.5" width="132" height="29.5"/>
<rect key="frame" x="129.5" y="782" width="155.5" height="26"/>
</pageControl>
<collectionView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" minimumZoomScale="0.0" maximumZoomScale="0.0" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="i2y-lo-HXR">
<rect key="frame" x="0.0" y="44" width="414" height="644.5"/>
<rect key="frame" x="0.0" y="44" width="414" height="648"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="m8O-kY-22j">
<size key="itemSize" width="320" height="458"/>
@ -2160,7 +2181,7 @@ This app is now out of maintenance.</string>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPGuideStepCell" id="oGu-pJ-3bQ" customClass="MPGuideStepCell">
<rect key="frame" x="0.0" y="93.5" width="320" height="458"/>
<rect key="frame" x="0.0" y="95" width="320" height="458"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="458"/>
@ -2189,13 +2210,13 @@ This app is now out of maintenance.</string>
</connections>
</collectionView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="To begin, tap the &quot;New User&quot; icon and add yourself as a user to the application." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ciw-56-nNy" userLabel="Caption">
<rect key="frame" x="8" y="696.5" width="398" height="82"/>
<rect key="frame" x="8" y="700" width="398" height="82"/>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="13"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label hidden="YES" opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Oop-Ff-gbz" userLabel="Caption Height Strut">
<rect key="frame" x="8" y="696.5" width="1" height="82"/>
<rect key="frame" x="8" y="700" width="1" height="82"/>
<string key="text" base64-UTF8="YES">
CgoKCgoKCgoKCgoKCg
</string>
@ -2611,7 +2632,7 @@ See </string>
<color key="separatorColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPStoreProductCell" id="JVW-tG-xxe" userLabel="Product" customClass="MPStoreProductCell">
<rect key="frame" x="0.0" y="28" width="414" height="380"/>
<rect key="frame" x="0.0" y="44.5" width="414" height="380"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="JVW-tG-xxe" id="CLQ-CW-NGn">
<rect key="frame" x="0.0" y="0.0" width="414" height="380"/>
@ -2679,7 +2700,7 @@ See </string>
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPStoreFuelProductCell" id="le3-Q5-MSO" userLabel="Fuel" customClass="MPStoreFuelProductCell">
<rect key="frame" x="0.0" y="408" width="414" height="380"/>
<rect key="frame" x="0.0" y="424.5" width="414" height="380"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="le3-Q5-MSO" id="SzQ-Y5-XIF">
<rect key="frame" x="0.0" y="0.0" width="414" height="380"/>
@ -2774,7 +2795,7 @@ Invested: 3.7 work hours</string>
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPStoreCellSpinner" rowHeight="170" id="LOh-72-Ifp" userLabel="Spinner">
<rect key="frame" x="0.0" y="788" width="414" height="170"/>
<rect key="frame" x="0.0" y="804.5" width="414" height="170"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="LOh-72-Ifp" id="gjr-8l-JJ0">
<rect key="frame" x="0.0" y="0.0" width="414" height="170"/>
@ -2801,19 +2822,19 @@ Invested: 3.7 work hours</string>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPStoreCellFooter" rowHeight="100" id="jsY-TE-4y5" userLabel="Footer">
<rect key="frame" x="0.0" y="958" width="414" height="100"/>
<rect key="frame" x="0.0" y="974.5" width="414" height="100"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="jsY-TE-4y5" id="guB-Eb-KpI">
<rect key="frame" x="0.0" y="0.0" width="414" height="100"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999998807907104" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="749" verticalCompressionResistancePriority="751" text="© 2012-2014, Maarten Billemont (lhunath)" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="26U-st-xNs">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999998807907104" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="749" verticalCompressionResistancePriority="751" ambiguous="YES" text="© 2012-2014, Maarten Billemont (lhunath)" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="26U-st-xNs">
<rect key="frame" x="20" y="4" width="374" height="22"/>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="11"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" verticalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lQ1-b9-Xp4">
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" verticalCompressionResistancePriority="751" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lQ1-b9-Xp4">
<rect key="frame" x="20" y="34" width="374" height="27"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
<state key="normal" title="Restore Previous Purchases">
@ -2823,7 +2844,7 @@ Invested: 3.7 work hours</string>
<action selector="restorePurchases:" destination="pdl-xv-zjX" eventType="touchUpInside" id="Q8M-ud-OHL"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eus-kQ-emn">
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eus-kQ-emn">
<rect key="frame" x="8" y="69" width="398" height="27"/>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="12"/>
<state key="normal" title="Send Thanks">
@ -2887,7 +2908,7 @@ Invested: 3.7 work hours</string>
<color key="separatorColor" red="0.37254901959999998" green="0.3921568627" blue="0.42745098040000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPGlobalAnswersCell" rowHeight="133" id="DT2-Vb-uXj" userLabel="Global Answer" customClass="MPGlobalAnswersCell">
<rect key="frame" x="0.0" y="28" width="414" height="133"/>
<rect key="frame" x="0.0" y="44.5" width="414" height="133"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="DT2-Vb-uXj" id="URA-cl-MJP">
<rect key="frame" x="0.0" y="0.0" width="414" height="133"/>
@ -2931,14 +2952,14 @@ Invested: 3.7 work hours</string>
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPSendAnswersCell" rowHeight="44" id="tvm-WZ-MDZ" userLabel="Send Answers" customClass="MPSendAnswersCell">
<rect key="frame" x="0.0" y="161" width="414" height="44"/>
<rect key="frame" x="0.0" y="177.5" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tvm-WZ-MDZ" id="BTm-Lm-V9p">
<rect key="frame" x="0.0" y="0.0" width="383" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="384.5" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="Send the answer(s) to my email" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AAV-yg-dfK">
<rect key="frame" x="8" y="8" width="367" height="28"/>
<rect key="frame" x="8" y="8" width="368.5" height="28"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -2954,14 +2975,14 @@ Invested: 3.7 work hours</string>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="checkmark" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPMultipleAnswersCell" rowHeight="44" id="5MB-qb-oPk" userLabel="Multiple Answers" customClass="MPMultipleAnswersCell">
<rect key="frame" x="0.0" y="205" width="414" height="44"/>
<rect key="frame" x="0.0" y="221.5" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="5MB-qb-oPk" id="4wX-xO-9QU">
<rect key="frame" x="0.0" y="0.0" width="370" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="373.5" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="This site needs different answers for each question" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="een-0g-CMy">
<rect key="frame" x="8" y="8" width="354" height="28"/>
<rect key="frame" x="8" y="8" width="357.5" height="28"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="12"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -2977,7 +2998,7 @@ Invested: 3.7 work hours</string>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPAnswersQuestionCell" rowHeight="130" id="iFm-3w-hOv" userLabel="Question" customClass="MPAnswersQuestionCell">
<rect key="frame" x="0.0" y="249" width="414" height="130"/>
<rect key="frame" x="0.0" y="265.5" width="414" height="130"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="iFm-3w-hOv" id="X5d-5g-uJa">
<rect key="frame" x="0.0" y="0.0" width="414" height="130"/>

View File

@ -14,9 +14,9 @@ echo "Cleaning .."
git clean -ffdx .
echo "Creating archive $mpwArchive .."
echo "$version" > VERSION
git show --show-signature --pretty=format:%H --quiet "$tag" > TAG
{ git ls-files -z .; printf '%s\0' VERSION TAG; } | xargs -0 tar -Lcvzf "$mpwArchive"
echo "$version" > cli/VERSION
git show --show-signature --pretty=format:%H --quiet "$tag" > cli/TAG
{ git ls-files -z .; printf '%s\0' cli/VERSION cli/TAG; } | xargs -0 tar -Lcvzf "$mpwArchive"
echo "Creating archive signature $mpwArchive.sig .."
gpg --detach-sign --local-user 5C2D1D61853F20F2FCDDCCB70EF21226F43EA6BC "$mpwArchive"

View File

@ -74,7 +74,7 @@ library {
link.linkerArgs = ['-lc', '-nodefaultlibs', '-flto']
} else if (toolChain in VisualCpp) {
// TODO: Should this be shared instead of static?
compile.compilerArgs = ['/TC', '/MT', '/Ox', '/DSODIUM_STATIC', '/DSODIUM_EXPORT=']
compile.compilerArgs = ['/TC', '/MT', '/Ox', '/DSODIUM_STATIC', '/DSODIUM_EXPORT=', '/std:c11']
}
}
}

View File

@ -122,7 +122,10 @@ const char *mpw_site_result(
return NULL;
}
if (resultType & MPResultTypeClassTemplate) {
if (resultType == MPResultTypeNone) {
return NULL;
}
else if (resultType & MPResultTypeClassTemplate) {
switch (algorithmVersion) {
case MPAlgorithmVersionV0:
return mpw_site_template_password_v0( masterKey, siteKey, resultType, resultParam );
@ -203,6 +206,10 @@ const char *mpw_site_state(
return NULL;
}
if (resultType == MPResultTypeNone) {
return NULL;
}
switch (algorithmVersion) {
case MPAlgorithmVersionV0:
return mpw_site_state_v0( masterKey, siteKey, resultType, resultParam );

View File

@ -169,7 +169,7 @@ const char *mpw_site_crypted_password_v0(
if (strlen( cipherText ) % 4 != 0) {
wrn( "Malformed encrypted state, not base64." );
// This can happen if state was stored in a non-encrypted form, eg. login in old mpsites.
return strdup( cipherText );
return mpw_strdup( cipherText );
}
// Base64-decode

View File

@ -93,7 +93,7 @@ MPMarshalledUser *mpw_marshal_user(
.fullName = mpw_strdup( fullName ),
.identicon = MPIdenticonUnset,
.keyID = NULL,
.defaultType = MPResultTypeDefault,
.defaultType = MPResultTypeDefaultResult,
.lastUsed = 0,
.sites_count = 0,
@ -122,7 +122,7 @@ MPMarshalledSite *mpw_marshal_site(
.resultType = resultType,
.resultState = NULL,
.loginType = MPResultTypeTemplateName,
.loginType = MPResultTypeDefaultLogin,
.loginState = NULL,
.url = NULL,
@ -250,7 +250,7 @@ void mpw_marshal_file_free(
MPMarshalledData *mpw_marshal_data_new() {
MPMarshalledData *data = malloc( sizeof( MPMarshalledData ) );
*data = (MPMarshalledData){};
*data = (MPMarshalledData){ 0 };
mpw_marshal_data_set_null( data, NULL );
data->is_null = false;
return data;
@ -864,7 +864,7 @@ static void mpw_marshal_read_flat(
char *fullName = NULL, *keyID = NULL;
MPAlgorithmVersion algorithm = MPAlgorithmVersionCurrent;
MPIdenticon identicon = MPIdenticonUnset;
MPResultType defaultType = MPResultTypeDefault;
MPResultType defaultType = MPResultTypeDefaultResult;
time_t exportDate = 0;
bool headerStarted = false, headerEnded = false, importRedacted = false;
for (const char *endOfLine, *positionInLine = in; (endOfLine = strstr( positionInLine, "\n" )); positionInLine = endOfLine + 1) {
@ -1014,13 +1014,14 @@ static void mpw_marshal_read_flat(
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site last used: %s: %s", siteName, str_lastUsed );
continue;
}
MPResultType siteLoginType = siteLoginState && strlen( siteLoginState )? MPResultTypeStatefulPersonal: MPResultTypeNone;
char dateString[21];
mpw_marshal_data_set_num( siteCounter, file->data, "sites", siteName, "counter", NULL );
mpw_marshal_data_set_num( siteAlgorithm, file->data, "sites", siteName, "algorithm", NULL );
mpw_marshal_data_set_num( siteType, file->data, "sites", siteName, "type", NULL );
mpw_marshal_data_set_str( siteResultState, file->data, "sites", siteName, "password", NULL );
mpw_marshal_data_set_num( MPResultTypeDefault, file->data, "sites", siteName, "login_type", NULL );
mpw_marshal_data_set_num( siteLoginType, file->data, "sites", siteName, "login_type", NULL );
mpw_marshal_data_set_str( siteLoginState, file->data, "sites", siteName, "login_name", NULL );
mpw_marshal_data_set_num( strtol( str_uses, NULL, 10 ), file->data, "sites", siteName, "uses", NULL );
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &siteLastUsed ) ))
@ -1150,7 +1151,7 @@ MPMarshalledUser *mpw_marshal_auth(
}
MPIdenticon identicon = mpw_identicon_encoded( mpw_marshal_data_get_str( file->data, "user", "identicon", NULL ) );
const char *keyID = mpw_marshal_data_get_str( file->data, "user", "key_id", NULL );
MPResultType defaultType = mpw_default_n( MPResultTypeDefault, mpw_marshal_data_get_num( file->data, "user", "default_type", NULL ) );
MPResultType defaultType = mpw_default_n( MPResultTypeDefaultResult, mpw_marshal_data_get_num( file->data, "user", "default_type", NULL ) );
if (!mpw_type_short_name( defaultType )) {
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid user default type: %u", defaultType );
return NULL;
@ -1216,7 +1217,7 @@ MPMarshalledUser *mpw_marshal_auth(
return 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( MPResultTypeDefaultLogin, mpw_marshal_data_get_num( siteData, "login_type", NULL ) );
if (!mpw_type_short_name( siteLoginType )) {
mpw_marshal_error( file, MPMarshalErrorIllegal, "Invalid site login type: %s: %u", siteName, siteLoginType );
mpw_free( &masterKey, MPMasterKeySize );
@ -1258,10 +1259,10 @@ MPMarshalledUser *mpw_marshal_auth(
return NULL;
}
if (siteResultState && strlen( siteResultState ))
if (siteResultState && strlen( siteResultState ) && masterKey)
site->resultState = mpw_site_state( masterKey, site->siteName, site->counter,
MPKeyPurposeAuthentication, NULL, site->resultType, siteResultState, site->algorithm );
if (siteLoginState && strlen( siteLoginState ))
if (siteLoginState && strlen( siteLoginState ) && masterKey)
site->loginState = mpw_site_state( masterKey, site->siteName, MPCounterValueInitial,
MPKeyPurposeIdentification, NULL, site->loginType, siteLoginState, site->algorithm );
}
@ -1282,7 +1283,7 @@ MPMarshalledUser *mpw_marshal_auth(
if (!user->redacted) {
// Clear Text
if (answerState && strlen( answerState ))
if (answerState && strlen( answerState ) && masterKey)
question->state = mpw_site_state( masterKey, site->siteName, MPCounterValueInitial,
MPKeyPurposeRecovery, question->keyword, question->type, answerState, site->algorithm );
}

View File

@ -38,6 +38,8 @@ const MPResultType mpw_type_named(const char *typeName) {
// Find what password type is represented by the type letter.
if (strlen( typeName ) == 1) {
if ('0' == typeName[0])
return MPResultTypeNone;
if ('x' == typeName[0])
return MPResultTypeTemplateMaximum;
if ('l' == typeName[0])
@ -63,6 +65,8 @@ const MPResultType mpw_type_named(const char *typeName) {
}
// Find what password type is represented by the type name.
if (mpw_strncasecmp( mpw_type_short_name( MPResultTypeNone ), typeName, strlen( typeName ) ) == OK)
return MPResultTypeNone;
if (mpw_strncasecmp( mpw_type_short_name( MPResultTypeTemplateMaximum ), typeName, strlen( typeName ) ) == OK)
return MPResultTypeTemplateMaximum;
if (mpw_strncasecmp( mpw_type_short_name( MPResultTypeTemplateLong ), typeName, strlen( typeName ) ) == OK)
@ -93,6 +97,8 @@ const MPResultType mpw_type_named(const char *typeName) {
const char *mpw_type_abbreviation(const MPResultType resultType) {
switch (resultType) {
case MPResultTypeNone:
return "no";
case MPResultTypeTemplateMaximum:
return "max";
case MPResultTypeTemplateLong:
@ -125,6 +131,8 @@ const char *mpw_type_abbreviation(const MPResultType resultType) {
const char *mpw_type_short_name(const MPResultType resultType) {
switch (resultType) {
case MPResultTypeNone:
return "none";
case MPResultTypeTemplateMaximum:
return "maximum";
case MPResultTypeTemplateLong:
@ -157,6 +165,8 @@ const char *mpw_type_short_name(const MPResultType resultType) {
const char *mpw_type_long_name(const MPResultType resultType) {
switch (resultType) {
case MPResultTypeNone:
return "None";
case MPResultTypeTemplateMaximum:
return "Maximum Security Password";
case MPResultTypeTemplateLong:

View File

@ -80,6 +80,9 @@ typedef mpw_opts( uint16_t, MPSiteFeature ) {
// bit 0-3 | MPResultTypeClass | MPSiteFeature
typedef mpw_enum( uint32_t, MPResultType ) {
/** 0: Don't produce a result */
MPResultTypeNone = 0,
/** 16: pg^VMAUBk5x3p%HP%i4= */
MPResultTypeTemplateMaximum = 0x0 | MPResultTypeClassTemplate | 0x0,
/** 17: BiroYena8:Kixa */
@ -105,7 +108,8 @@ typedef mpw_enum( uint32_t, MPResultType ) {
/** 4160: Derive a unique binary key. */
MPResultTypeDeriveKey = 0x0 | MPResultTypeClassDerive | MPSiteFeatureAlternative,
MPResultTypeDefault = MPResultTypeTemplateLong,
MPResultTypeDefaultResult = MPResultTypeTemplateLong,
MPResultTypeDefaultLogin = MPResultTypeTemplateName,
};
typedef mpw_enum ( uint32_t, MPCounterValue ) {

View File

@ -22,7 +22,6 @@ MP_LIBS_BEGIN
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <libgen.h>
#if MPW_CPERCIVA
#include <scrypt/crypto_scrypt.h>

View File

@ -86,6 +86,21 @@ void mpw_log_ssink(LogLevel level, const char *file, int line, const char *funct
//// Utilities
#ifndef OK
#define OK 0
#endif
#ifndef ERR
#define ERR -1
#endif
#ifndef stringify
#define stringify(s) #s
#endif
#ifndef stringify_def
#define stringify_def(s) stringify(s)
#endif
#if !__STRICT_ANSI__ && __GNUC__ >= 3
#ifndef min
#define min(a, b) ({ \
__typeof__ (a) _a = (a); \
@ -98,21 +113,18 @@ void mpw_log_ssink(LogLevel level, const char *file, int line, const char *funct
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#endif
#ifndef ERR
#define ERR -1
#define mpw_default(__default, __value) ({ __typeof__ (__value) _v = (__value); _v? _v: (__default); })
#define mpw_default_n(__default, __num) ({ __typeof__ (__num) _n = (__num); !isnan( _n )? (__typeof__ (__default))_n: (__default); })
#else
#ifndef min
#define min(a, b) ( (a) < (b) ? (a) : (b) )
#endif
#ifndef OK
#define OK 0
#ifndef max
#define max(a, b) ( (a) > (b) ? (a) : (b) )
#endif
#ifndef stringify
#define stringify(s) #s
#define mpw_default(__default, __value) ( (__value)? (__value): (__default) )
#define mpw_default_n(__default, __num) ( !isnan( (__num) )? (__num): (__default) )
#endif
#ifndef stringify_def
#define stringify_def(s) stringify(s)
#endif
#define mpw_default(__default, __value) ({ __typeof__ (__value) _v = __value; _v? _v: __default; })
#define mpw_default_n(__default, __num) ({ __typeof__ (__num) _n = (__num); !isnan( _n )? (__typeof__ (__default))_n: __default; })
//// Buffers and memory.

View File

@ -15,7 +15,7 @@ configurations {
dependencies {
implementation group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.7-p2'
implementation group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: '4.0.0-beta4'
implementation group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: '4.2.1'
api group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.9.8'
api group: 'org.jetbrains', name: 'annotations', version: '16.0.2'

View File

@ -12,7 +12,7 @@ dependencies {
implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.2'
implementation group: 'com.yuvimasory', name: 'orange-extensions', version: '1.3.0'
implementation group: 'com.github.tulskiy', name: 'jkeymaster', version: '1.2'
implementation group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: '4.0.0-beta4'
implementation group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: '4.2.1'
compile project( ':masterpassword-model' )
}

View File

@ -212,7 +212,7 @@ public abstract class Components {
@Override
public String getString(final int where, final int len)
throws BadLocationException {
return "";
return new String( new char[this.length()] );
}
} ), null, 0 ) {
{

View File

@ -459,7 +459,8 @@ public class UserContentPanel extends JPanel implements State.Listener, MPUser.L
char[] masterPassword = masterPasswordField.getPassword();
MPIdenticon identicon = ((masterPassword != null) && (masterPassword.length > 0))?
user.getAlgorithm().identicon( user.getFullName(), masterPassword ): null;
Arrays.fill( masterPassword, (char) 0 );
if (masterPassword != null)
Arrays.fill( masterPassword, (char) 0 );
Res.ui( () -> {
if (identicon != null) {
@ -900,6 +901,12 @@ public class UserContentPanel extends JPanel implements State.Listener, MPUser.L
private void showSiteItem(@Nullable final MPQuery.Result<? extends MPSite<?>> item) {
MPSite<?> site = (item != null)? item.getValue(): null;
Res.ui( getSiteResult( site, showLogin ), result -> {
settingsButton.setEnabled( site != null );
questionsButton.setEnabled( site != null );
editButton.setEnabled( site != null );
keyButton.setEnabled( site != null );
deleteButton.setEnabled( site != null );
if (!showLogin && (site != null))
resultLabel.setText( (result != null)? strf( "Your password for %s:", site.getSiteName() ): " " );
else if (showLogin && (site != null))
@ -911,11 +918,6 @@ public class UserContentPanel extends JPanel implements State.Listener, MPUser.L
resultField.setText( EACH_CHARACTER.matcher( result ).replaceAll( "" ) );
else
resultField.setText( result );
settingsButton.setEnabled( result != null );
questionsButton.setEnabled( result != null );
editButton.setEnabled( result != null );
keyButton.setEnabled( result != null );
deleteButton.setEnabled( result != null );
} );
}

View File

@ -7,7 +7,7 @@ description = 'Master Password Site Model'
dependencies {
implementation group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.7-p2'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.8'
implementation group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: '4.0.0-beta4'
implementation group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: '4.2.1'
api project( ':masterpassword-algorithm' )
api group: 'joda-time', name: 'joda-time', version: '2.10'

View File

@ -7,7 +7,7 @@ description = 'Master Password Test Suite'
dependencies {
implementation group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.7-p2'
implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
implementation group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: '4.0.0-beta4'
implementation group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: '4.2.1'
implementation project( ':masterpassword-algorithm' )
implementation project( ':masterpassword-model' )

View File

@ -1,6 +1,20 @@
#!/usr/bin/env bash
source bashlib
calc() { python -c "import math; print $1"; }
scale() {
local number=$1 precision=$2 definition unit weight; shift 2
for definition in "$@"; do
definition=$definition
weight=${definition#*:}
[[ ! $weight || $(calc "($number) > ($weight)") = True ]] || break
number=$(calc "(1.0 * $number) / (1.0 * ${weight:-1})") unit=${definition%:*}
done
printf "%'0.${precision}f %s" "$number" "$unit"
}
scaleTime() { scale "$1" "${2:-2}" 'Seconds:' "Hours:3600" "Days:24" "Months:30" "Years:356/30" "K Years:1000" "M Years:1000" "B Years:1000" "T Years:1000"; }
scaleEnergy() { scale "$1" "${2:-2}" 'Wh:' 'kWh:1000' 'MWh:1000' 'GWh:1000' 'TWh:1000'; }
scaleCost() { scale "$1" "${2:-2}" '$US:' 'K$US:1000' 'M$US:1000' 'B$US:1000' 'T$US:1000'; }
inf 'Calculate the maximum amount of time required to brute-force search for a password.'
@ -17,44 +31,45 @@ x="$a$n!@#\$%^&*()"
w="@words.txt"
## METRICS
# Last update: 2016-09
# GTX Titan X can generate about 402.7M HMAC-SHA-256 hashes per second (5301.7M SHA1). (ref. https://hashcat.net/forum/thread-4314.html)
# GTX Titan X can be bought for about 950$ used. (ref. amazon.com)
#hardwareName='GTX Titan X (SHA1)' hardwareSpeed='5302M'
#hardwareName='GTX Titan X (SHA1 @ 5k$)' hardwareSpeed='5302M * 5k / 950'
#hardwareName='GTX Titan X (SHA1 @ 20k$)' hardwareSpeed='5302M * 20k / 950'
#hardwareName='GTX Titan X (SHA1 @ 20M$)' hardwareSpeed='5302M * 20M / 950'
#hardwareName='GTX Titan X (SHA1 @ 5B$)' hardwareSpeed='5302M * 5B / 950'
hardwareName='GTX Titan X (HMAC-SHA-256 @ 950$)' hardwareSpeed='403M'
#hardwareName='GTX Titan X (HMAC-SHA-256 @ 5k$)' hardwareSpeed='403M * 5k / 950'
#hardwareName='GTX Titan X (HMAC-SHA-256 @ 20k$)' hardwareSpeed='403M * 20k / 950'
#hardwareName='GTX Titan X (HMAC-SHA-256 @ 20M$)' hardwareSpeed='403M * 20M / 950'
#hardwareName='GTX Titan X (HMAC-SHA-256 @ 5B$)' hardwareSpeed='403M * 5B / 950'
# GTX Titan X -- https://gist.github.com/epixoip/1f26f43e9036d9ce0eb8
#hardwareName='GTX Titan X (SHA1)' hardwareHPS='5302M' hardwareCost='950' hardwareWatt='250' # -mpl: 4.67 m
#hardwareName='GTX Titan X (HMAC-SHA-256)' hardwareHPS='2113M' hardwareCost='950' hardwareWatt='250' # -mpl: 0.99 y
#hardwareName='GTX Titan X (bcrypt-10)' hardwareHPS='14440/32' hardwareCost='950' hardwareWatt='250' # -mpl: 4.62 My
# GTX 980 Ti -- https://gist.github.com/epixoip/d34245293ccecbfcc7c7
#hardwareName='GTX 980 Ti (SHA1)' hardwareHPS='5366M' hardwareCost='450' hardwareWatt='250' # -mpl: 4.61 m
#hardwareName='GTX 980 Ti (SHA256)' hardwareHPS='2032M' hardwareCost='450' hardwareWatt='250' # -mpl: 1.03 y
#hardwareName='GTX 980 Ti (bcrypt-10)' hardwareHPS='14521/32' hardwareCost='450' hardwareWatt='250' # -mpl: 4.60 My
# GTX 1060 -- https://gist.github.com/derpasaurusz/817638385a35026383331b22e6f2d490
#hardwareName='GTX 1060 (SHA1)' hardwareHPS='4218M' hardwareCost='400' hardwareWatt='120' # -mpl: 5.87 m
#hardwareName='GTX 1060 (SHA256)' hardwareHPS='1632M' hardwareCost='400' hardwareWatt='120' # -mpl: 1.28 y
#hardwareName='GTX 1060 (bcrypt-10)' hardwareHPS='8046/32' hardwareCost='400' hardwareWatt='120' # -mpl: 8.30 My
# GTX 1080 Ti -- https://gist.github.com/epixoip/ace60d09981be09544fdd35005051505
#hardwareName='GTX 1080 Ti (SHA1)' hardwareHPS='12696M' hardwareCost='1200' hardwareWatt='250' # -mpl: 1.95 m
#hardwareName='GTX 1080 Ti (SHA256)' hardwareHPS='4967M' hardwareCost='1200' hardwareWatt='250' # -mpl: 4.99 m
#hardwareName='GTX 1080 Ti (bcrypt-10)' hardwareHPS='23266/32' hardwareCost='1200' hardwareWatt='250' # -mpl: 2.87 My
hardwareName='GTX 1080 Ti (mpw?)' hardwareHPS='56*3' hardwareCost='1200' hardwareWatt='250' # -mpl: 2.87 My
# ASICs
hardwareName='AntMiner L3+ (scrypt)' hardwareSpeed='1M'
#hardwareName='AntMiner L3+ (scrypt @ 5k$)' hardwareSpeed='1M * 5k / 2500'
#hardwareName='AntMiner L3+ (scrypt @ 20k$)' hardwareSpeed='1M * 20k / 2500'
#hardwareName='AntMiner L3+ (scrypt @ 20M$)' hardwareSpeed='1M * 20M / 2500'
#hardwareName='AntMiner L3+ (scrypt @ 5B$)' hardwareSpeed='1M * 5B / 2500'
hardwareName='AntMiner S9 (SHA256)' hardwareSpeed='14T'
#hardwareName='AntMiner S9 (SHA256 @ 5k$)' hardwareSpeed='14T * 5k / 1288'
#hardwareName='AntMiner S9 (SHA256 @ 20k$)' hardwareSpeed='14T * 20k / 1288'
#hardwareName='AntMiner S9 (SHA256 @ 20M$)' hardwareSpeed='14T * 20M / 1288'
#hardwareName='AntMiner S9 (SHA256 @ 5B$)' hardwareSpeed='14T * 5B / 1288'
#hardwareName='AntMiner L3+ (scrypt)' hardwareHPS='1M' hardwareCost='2500' hardwareWatt='800'
#hardwareName='AntMiner S9 (SHA256)' hardwareHPS='14T' hardwareCost='1288' hardwareWatt='1400'
# mpw-bench
#hardwareName='2.3 GHz i7, 8GB (MPW)' hardwareSpeed=7.46
#hardwareName='2.3 GHz i7, 8GB (MPW)' hardwareHPS=7.46
costPerKWh='0.1' # ~0.1$/kWh
hardwareQuantity=$(calc "5000000000 / ($hardwareCost)")
second='1'
secondsInHour='3600'
secondsInDay='3600 * 24'
secondsInMonth='3600 * 24 * 30'
secondsInYear='3600 * 24 * 356'
hardwareSpeed=${hardwareSpeed//k/000}
hardwareSpeed=${hardwareSpeed//M/000000}
hardwareSpeed=${hardwareSpeed//G/000000000}
hardwareSpeed=${hardwareSpeed//T/000000000000}
hardwareHPS=${hardwareHPS//k/000}
hardwareHPS=${hardwareHPS//M/000000}
hardwareHPS=${hardwareHPS//G/000000000}
hardwareHPS=${hardwareHPS//T/000000000000}
## SEARCH SPACE
hr
@ -74,7 +89,7 @@ for _c in V C v c A a n o x w; do
inf '%s: Class contains %d entities: %s' "$_c" "$cs" "$cc"
done
spaceString=${1:-$(ask -d "x ** 12" "Amount of space?")}
spaceString=${1:-$(ask -d "x ** 12" "Size of the space?")}
case "$spaceString" in
-mp*) mpmode=${spaceString#-mp} mpmode=${mpmode:-long}
case "$mpmode" in
@ -82,9 +97,18 @@ case "$spaceString" in
max|secure|x) spaceString='aonxxxxxxxxxxxxxxxxx+axxxxxxxxxxxxxxxxxon' ;;
med|m) spaceString='CvcnoCvc+CvcCvcno' ;;
basic|b) spaceString='aaanaaan+aannaaan+aaannaaa' ;;
*) ftl 'Unknown mode: %s' "$mpmode" || exit
esac ;;
-pw*) password=${spaceString#-pw} spaceString=
while read -N1 pwchar; do
for _c in v c a n x; do
cc=${!_c}
[[ $cc = *$pwchar* ]] && spaceString+=$_c && break
done || spaceString+=" 256 "
done <<< "$password"
;;
esac
space=$spaceString
spaceSize=$spaceString
for _c in V C v c A a n o x w; do
cc=${!_c}
if [[ $cc = @* ]]; then
@ -94,35 +118,39 @@ for _c in V C v c A a n o x w; do
cs=${#cc}
fi
space=${space//$_c/ 0$cs }
spaceSize=${spaceSize//$_c/ 0$cs }
done
# Replace sequences of numbers by multiplication of those numbers. Then, pretty-print.
space=$(sed -e 's/\([[:digit:]]\) *\([[:digit:]]\)/\1 * \2/g' -e 's/ 00*\([1-9]\)/ \1/g' <<< "$space")
space=$(tr -s ' ' <<< "$space") space=${space# } space=${space% }
spaceSize=$(sed -e 's/\([[:digit:]]\) *\([[:digit:]]\)/\1 * \2/g' -e 's/ 00*\([1-9]\)/ \1/g' <<< "$spaceSize")
spaceSize=$(tr -s ' ' <<< "$spaceSize") spaceSize=${spaceSize# } spaceSize=${spaceSize% }
inf ''
inf "Search space: %s = %s = %'.f possibilities to try (~%.1f bit)." "$spaceString" "$space" "$(calc "$space")" "$(bc -l <<< "l($(calc "$space")) / l(2)")"
inf "Search space: %s = %s = %'.f possibilities to try (~%.1f bit)." "$spaceString" "$spaceSize" "$(calc "$spaceSize")" "$(bc -l <<< "l($(calc "$spaceSize")) / l(2)")"
## CLUSTER SIZE
hr
inf 'CLUSTER SIZE'
inf "Simulating %s at a rate of about %'.1f attempts per second." "$hardwareName" "$(calc "$hardwareSpeed")"
cluster=$(ask -d 1 "Amount of GPUs?")
inf "Simulating %s at a rate of about %'.1f attempts per second." "$hardwareName" "$(calc "$hardwareHPS")"
cluster=$(ask -d "$hardwareQuantity" "Amount of units?")
## CALCULATE
hr
inf 'TIMING'
inf "Time to search the entire space using %d GPUs of type %s (rate=%'.1f/s)" "$cluster" "$hardwareName" "$(calc "$hardwareSpeed")"
inf "Time to search the entire space using %dx %s units (unit rate=%'.1f H/s)" "$cluster" "$hardwareName" "$(calc "$hardwareHPS")"
seconds=$(calc "(1.0 * $spaceSize) / (1.0 * $hardwareHPS * $cluster)")
inf "Time to crack: %s (ie. %s Seconds)" "$(scale "$seconds" 2 'Seconds:' "Hours:3600" "Days:24" "Months:30" "Years:356/30")" "$seconds"
timing() {
local title=$1 unit=$2 precision=$3 seconds=$4
time=$(calc "1.0 * ($space) / ($hardwareSpeed * $cluster) / ($seconds)")
percent=$(calc "100.0 * ($hardwareSpeed * $cluster) * ($seconds) / ($space)")
time=$(calc "(1.0 * $spaceSize) / (1.0 * $hardwareHPS * $cluster) / ($seconds)")
percent=$(calc "(100.0 * $hardwareHPS * $cluster * $seconds) / (1.0 * $spaceSize)")
amount=$(calc "$percent / 100.0")
if [[ $amount = 0.* ]]; then
inf "%10s to crack: %'0.${precision}f (search rate is %0.0f%% / %s)" \
if [[ $(calc "$percent < 100") = True ]]; then
inf " - %10s: %'0.${precision}f (ie. %0.1f%% / %s)" \
"$title" "$time" "$percent" "$unit"
else
inf "%10s to crack: %'0.${precision}f (completes %0.1fx / %s)" \
inf " - %10s: %'0.${precision}f (ie. %0.1fx / %s)" \
"$title" "$time" "$amount" "$unit"
fi
}
@ -131,3 +159,17 @@ timing Hours h 2 "$secondsInHour"
timing Days d 3 "$secondsInDay"
timing Months m 4 "$secondsInMonth"
timing Years y 4 "$secondsInYear"
hr
inf 'COST'
inf "Budget required to search the entire space using %dx %s units (unit cost=%s + %s / year => %s annum, %s / HPS)" \
"$cluster" "$hardwareName" "$(scaleCost "$hardwareCost")" "$(scaleCost "1.0 * $hardwareWatt * 356 * 24 * $costPerKWh / 1000")" "$(scaleCost "$hardwareCost + 1.0 * $hardwareWatt * 356 * 24 * $costPerKWh / 1000")" "$(scaleCost "$hardwareCost / (1.0 * $hardwareHPS)")"
fixedCost=$(calc "(1.0 * $cluster * $hardwareCost)")
energyCost=$(calc "(1.0 * $cluster * $hardwareWatt * $seconds) / 3600") # Wh
totalCost=$(calc "1.0 * $fixedCost + ($energyCost * $costPerKWh) / 1000.0")
inf "Time cost : %s" "$(scaleTime "$seconds")"
inf "Fixed costs: %s" "$(scaleCost "$fixedCost")"
inf "Energy cost: %s" "$(scaleEnergy "$energyCost")"
inf "Budget cost: %s" "$(scaleCost "$totalCost")"

@ -1 +1 @@
Subproject commit d7d7567c079dcf77343eceba5cc37ee5e1d123ad
Subproject commit 1e7491e0d9f39ac6d49e4078cf445ca69e71020a