2
0

Compare commits

..

43 Commits

Author SHA1 Message Date
Maarten Billemont
10f100186c Remove pushqueue for bash 3 compatibility. 2014-10-20 08:51:58 -04:00
Maarten Billemont
2af2351ebf Make usage text a bit more obvious. 2014-10-19 00:58:13 -04:00
Maarten Billemont
49b3fe7913 Add support for login names and security answers to C app. 2014-10-19 00:55:26 -04:00
Maarten Billemont
9d926be8ae Support for pre-downloaded dependency packages and digest verification.
[UPDATED]   Allow overriding of targets to build at command-line via target=X ./build
[ADDED]     Support pre-downloaded packages for integration with package managers.
[ADDED]     Support for package digest verification.
[UPDATED]   Skip fetching on in a method-specific way, more reliable.
2014-10-18 20:56:28 -04:00
Maarten Billemont
c3474de2ff FreeBSD build fixes. 2014-10-18 18:22:29 -04:00
Maarten Billemont
68b9b4e09a Fix git-svn/git checkouts of dependencies. 2014-10-18 17:13:01 -04:00
Maarten Billemont
b810c1032b Include signed version in release package. 2014-10-18 15:56:31 -04:00
Maarten Billemont
a4ab3c7bc9 Script to distribute C packages. 2014-10-18 15:42:49 -04:00
Maarten Billemont
039547b735 Check the presence of tools needed to build the C targets. 2014-10-18 15:38:51 -04:00
Maarten Billemont
6f741f6f2f Merge branch 'master' of github.com:Lyndir/MasterPassword 2014-10-18 15:30:58 -04:00
Maarten Billemont
38d4b761b7 Remove binaries. I don't intend to maintain binary distributions at this point. 2014-10-18 14:36:05 -04:00
Maarten Billemont
18f8ebb9dc Fix check for whether a dependency was built + improved mpw-bench output. 2014-10-17 17:10:43 -04:00
Maarten Billemont
794d064a99 Merge pull request #91 from linwiz/master
Added information to the output of mpw-bench
2014-10-17 09:19:05 -04:00
linwiz
090b274363 Added information to the output of mpw-bench 2014-10-17 08:52:15 -04:00
Maarten Billemont
25ba87f119 Make mpw-bench optional. 2014-10-15 22:18:16 -04:00
Maarten Billemont
f0b659a0c7 Add bcrypt dependency and ability to compile arbitrary dependencies in C build script. 2014-10-15 22:17:49 -04:00
Maarten Billemont
7736788920 Disable debug verbosity by default. 2014-10-15 16:27:33 -04:00
Maarten Billemont
e3be98f3ad Added mpw-bench as an extra target. 2014-10-15 16:26:09 -04:00
Maarten Billemont
d9b1b44de0 Replace editline and readline with getpass. 2014-10-15 16:03:46 -04:00
Maarten Billemont
c3c2de5d14 Ensure master password isn't lost after ending editline context. 2014-10-15 15:37:29 -04:00
Maarten Billemont
6aa50bac04 Ensure we use the correct C language standard. 2014-10-15 15:32:10 -04:00
Maarten Billemont
5268039c3d A bunch of cross-platform fixes for mpw.c + make config file optional and read master password from input instead. 2014-10-15 14:00:44 -04:00
Maarten Billemont
0d66d4660e Add code to the build script for automatically fetching and building libscrypt. 2014-10-15 08:44:41 -04:00
Maarten Billemont
e981df3c8b Fixed type of level 3 attacker.
[FIXED]     Type of level 3 attacker was string instead of integer.
2014-10-13 23:39:07 -04:00
Maarten Billemont
543ebd4bac Update provisioning profiles. 2014-10-13 22:08:36 -04:00
Maarten Billemont
e6d21e1c1d Add new question cells and fix sizing issue with store cells.
[FIXED]     Cell sizing of autosized the store cells.
[IMPROVED]  Add new question rows as soon as the last question row is used.
2014-10-13 21:56:46 -04:00
Maarten Billemont
a3ebcf0608 Fix a few spelling mistakes. 2014-10-12 12:03:57 -04:00
Maarten Billemont
556d1d3d58 Make the site more mobile-friendly. 2014-10-07 19:55:36 -04:00
Maarten Billemont
979d3a2a5a Add fallback in case the video doesn't work. 2014-10-06 23:30:41 -04:00
Maarten Billemont
480e7f192a Added a new introduction video to the Master Password website. 2014-10-06 22:03:18 -04:00
Maarten Billemont
a18793b161 Update of the site to simplify understanding Master Password and how to use it. 2014-10-05 01:22:28 -04:00
Maarten Billemont
9b24efa65c Fix iOS 8 bug causing site search field to be auto-capitalized. 2014-10-01 07:35:57 -04:00
Maarten Billemont
3e217d5a69 Project configuration update. 2014-09-30 08:33:46 -04:00
Maarten Billemont
c8ca1c80e6 Remove generated resources from repository. 2014-09-30 08:25:47 -04:00
Maarten Billemont
88c18db010 Optimize icons. 2014-09-30 08:24:29 -04:00
Maarten Billemont
f909cdbae4 More icon fixes + don't delete store rows... 2014-09-30 08:20:35 -04:00
Maarten Billemont
8b8d5d325e Fix some warnings. 2014-09-30 00:09:40 -04:00
Maarten Billemont
c7670f47db Record the amount of fuel consumed and show status + icon update & genassets run script. 2014-09-30 00:01:33 -04:00
Maarten Billemont
f3f25f5890 Add question about hiding passwords to setup flow. 2014-09-28 22:57:38 -04:00
Maarten Billemont
3065433a37 Stop showing thanks tips after user opens thanks page. 2014-09-28 22:25:48 -04:00
Maarten Billemont
41b3964363 Lots of UI improvements and tips + parental gate, guide update.
[IMPROVED]  Emergency VC can now scroll when keyboard is up.
[IMPROVED]  Language of the guide + new updated screenshots.
[FIXED]     Size of guide cells on different devices.
[IMPROVED]  Don't show messages claiming login name was updated when nothing changed.
[FIXED]     Weird back-toggle bug when toggling site settings.
[ADDED]     Lots of handy tips throughout.
[ADDED]     Notification of new store features.
[FIXED]     Weird sizing issue & animation with store cells.
[ADDED]     Loading spinner while loading store products.
[ADDED]     Thanks link to store footer.
[FIXED]     Bought products should not respond to click, non-bought ones should.
[FIXED]     Fuel elapsed time counter was backward.
[ADDED]     Parental gate when deleting or resetting users.
[UPDATED]   App Icon background texture.
2014-09-28 22:15:55 -04:00
Maarten Billemont
5e8810c535 Dismiss popdown on sign out, fuel check date not recorded, avatar improvements. 2014-09-28 10:05:36 -04:00
Maarten Billemont
8c3dfc8510 Update of icon and launch image + background for iPhone 6 / 6+ 2014-09-28 01:53:50 -04:00
199 changed files with 4034 additions and 2151 deletions

6
.gitignore vendored
View File

@@ -16,6 +16,9 @@
xcuserdata/
/DerivedData/
# Generated
MasterPassword/Resources/Media/Images.xcassets/
# Media
Press/Background.png
Press/Front-Page.png
@@ -29,7 +32,10 @@ Press/MasterPassword_PressKit/MasterPassword_pressrelease_*.pdf
MasterPassword/Java/**/target
# C
MasterPassword/C/VERSION
MasterPassword/C/*.o
MasterPassword/C/mpw-*.tar.gz
MasterPassword/C/mpw
MasterPassword/C/mpw-bench
MasterPassword/C/lib/*/*
!MasterPassword/C/lib/*/.source

9
.gitmodules vendored
View File

@@ -10,3 +10,12 @@
[submodule "External/KCOrderedAccessorFix"]
path = External/KCOrderedAccessorFix
url = https://github.com/CFKevinRef/KCOrderedAccessorFix.git
[submodule "External/AttributedMarkdown"]
path = External/AttributedMarkdown
url = https://github.com/dreamwieber/AttributedMarkdown.git
[submodule "External/uicolor-utilities"]
path = External/uicolor-utilities
url = git://github.com/lhunath/uicolor-utilities.git
[submodule "External/jrswizzle"]
path = External/jrswizzle
url = git://github.com/jonmarimba/jrswizzle.git

1
External/AttributedMarkdown vendored Submodule

2
External/Pearl vendored

1
External/jrswizzle vendored Submodule

Submodule External/jrswizzle added at 98d18aee73

1
External/uicolor-utilities vendored Submodule

View File

@@ -22,6 +22,8 @@
<string>https://github.com/CFKevinRef/KCOrderedAccessorFix.git</string>
<key>3E67FB08419C920516AAC3B00DAAF23073B8CF77</key>
<string>git://github.com/lhunath/RHStatusItemView.git</string>
<key>3ED8592497DB6A564366943C9AAD5A46341B5076</key>
<string>https://github.com/dreamwieber/AttributedMarkdown.git</string>
<key>4DDCFFD91B41F00326AD14553BD66CFD366ABD91</key>
<string>ssh://github.com/Lyndir/Pearl.git</string>
<key>8A15A8EA0B3D0B497C4883425BC74DF995224BB3</key>
@@ -44,9 +46,11 @@
<key>2FE140B36B7D26140DC8D5E5C639DC5900EFCF35</key>
<string>../External/Pearl/External/uicolor-utilities</string>
<key>304AD0F97EA7B4893D91DFB8C3413D4E627B9472</key>
<string>../External/KCOrderedAccessorFix/</string>
<string>../External/KCOrderedAccessorFix</string>
<key>3E67FB08419C920516AAC3B00DAAF23073B8CF77</key>
<string>../External/RHStatusItemView</string>
<key>3ED8592497DB6A564366943C9AAD5A46341B5076</key>
<string>../External/AttributedMarkdown</string>
<key>4DDCFFD91B41F00326AD14553BD66CFD366ABD91</key>
<string>../External/Pearl</string>
<key>8A15A8EA0B3D0B497C4883425BC74DF995224BB3</key>
@@ -72,6 +76,14 @@
<key>IDESourceControlWCCName</key>
<string></string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>3ED8592497DB6A564366943C9AAD5A46341B5076</string>
<key>IDESourceControlWCCName</key>
<string>AttributedMarkdown</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,258 @@
#!/usr/bin/env bash
# Run with -DDEBUG to enable trace-level output.
#
# TROUBLESHOOTING
# - To enable verbose algorithm/implementation debugging, use ./build -DDEBUG
# - If you see 'undefined reference to `clock_gettime'', try ./build -lrt instead
#
# BUGS
# masterpassword@lyndir.com
#
# AUTHOR
# Maarten Billemont
#
cd "${BASH_SOURCE%/*}"
shopt -s extglob
set -e
[[ -e lib/scrypt/scryptenc.o ]] || { echo >&2 "Missing scrypt. First get and build the scrypt source in lib/scrypt from <$(<lib/scrypt/.source)>.\n"; exit 1; }
deps=( -I"lib/scrypt/lib" -I"lib/scrypt/libcperciva" -l "crypto_aesctr.o" -l "sha256.o" -l "crypto_scrypt-nosse.o" -l "memlimit.o" -l "scryptenc_cpuperf.o" -l"scryptenc.o" -l"crypto" -L"." -L"lib/scrypt" )
### CONFIGURATION
gcc "${deps[@]}" -Qunused-arguments -c types.c -o types.o "$@"
gcc "${deps[@]}" -Qunused-arguments -l"types.o" mpw.c -o mpw "$@"
# Targets to build.
if [[ $targets ]]; then
read -ra targets <<< "$targets"
else
# Default targets.
# Modify here or override using targets='mpw mpw-bench' ./build
targets=(
mpw # C CLI version of Master Password.
#mpw-bench # C CLI Master Password benchmark utility.
)
fi
### DEPENDENCIES
fetch() {
if hash wget 2>/dev/null; then
wget -O "${1##*/}" "$1"
elif hash curl 2>/dev/null; then
curl "$1" > "${1##*/}"
fi
}
unpack() {
if [[ $1 = *.tar.gz || $1 = *.tgz ]]; then
tar -xvzf "$1"
elif [[ $1 = *.tar.bz2 || $1 = *.tbz2 ]]; then
tar -xvjf "$1"
elif [[ $1 = *.tar ]]; then
tar -xvf "$1"
else
echo 2>&1 "Don't know how to unpack: $1"
fi
printf 'Verifying package: %s, against digest: %s...' "$1" "$2"
[[ $(openssl sha < "$1") = $2 ]] || {
printf ' mismatch!\n'
echo 2>&1 "Downloaded package doesn't match digest."
exit 1
}
printf ' OK!\n'
files=( !("$1") )
if [[ -d $files ]] && (( ${#files[@]} == 1 )); then
mv "$files"/* .
rmdir "$files"
fi
}
fetchSource() (
source .source
if [[ $pkg && -e "${pkg##*/}" ]]; then
files=( !("${pkg##*/}") )
[[ -e $files ]] || {
echo
echo "Unpacking: ${PWD##*/}, using package..."
unpack "${pkg##*/}" "$pkg_sha"
}
elif [[ $git ]] && hash git 2>/dev/null; then
[[ -e .git ]] || {
echo
echo "Fetching: ${PWD##*/}, using git..."
git clone "$svn" .
printf '%s' "$(git describe --always)" > "${PWD##*/}-version"
}
elif [[ $svn ]] && hash git 2>/dev/null && [[ -x "$(git --exec-path)/git-svn" ]]; then
[[ -e .git ]] || {
echo
echo "Fetching: ${PWD##*/}, using git-svn..."
git svn clone --prefix=origin/ --stdlayout "$svn" .
printf '%s' "$(git describe --always)" > "${PWD##*/}-version"
}
elif [[ $svn ]] && hash svn 2>/dev/null; then
[[ -e .svn ]] || {
echo
echo "Fetching: ${PWD##*/}, using svn..."
svn checkout "$svn/trunk" .
printf 'r%s' "$(svn info | awk '/^Revision:/{ print $2 }')" > "${PWD##*/}-version"
}
elif [[ $pkg ]]; then
files=( !("${pkg##*/}") )
[[ -e $files ]] || {
echo
echo "Fetching: ${PWD##*/}, using package..."
fetch "$pkg"
unpack "${pkg##*/}" "$pkg_sha"
}
else
echo >&2 "error: Missing git-svn or svn."
echo >&2 "error: Please install either or manually check out the sources"
echo >&2 "error: from: $home"
echo >&2 "error: into: $PWD"
exit 1
fi
)
depend() {
echo
echo "Checking dependency: $1..."
[[ -e "lib/$1/.built" ]] && return
pushd "lib/$1"
fetchSource
echo
echo "Configuring dependency: $1..."
if [[ -e configure.ac ]]; then
if [[ ! -e configure ]]; then
# create configure using autotools.
if ! hash aclocal || ! hash automake; then
echo >&2 "Need autotools to build $1. Please install automake and autoconf."
exit 1
fi
aclocal
autoheader
autoconf
mkdir -p config.aux
automake --add-missing
fi
fi
if [[ -e configure ]]; then
./configure
fi
echo
echo "Building dependency: $1..."
if [[ -e Makefile ]]; then
if ! hash make; then
echo >&2 "Need make to build $1. Please install GNU make."
exit 1
fi
make
date > .built
else
echo >&2 "error: Don't know how to build: $1"
exit 1
fi
popd
}
### MPW
mpw() {
depend scrypt
echo
echo "Building target: $target..."
CFLAGS=(
# include paths
-I"lib/scrypt/lib" -I"lib/scrypt/libcperciva"
)
LDFLAGS=(
# library paths
-L"." -L"lib/scrypt"
# link libraries
-l"crypto"
# scrypt
"lib/scrypt/scrypt-crypto_aesctr.o"
"lib/scrypt/scrypt-sha256.o"
"lib/scrypt/scrypt-crypto_scrypt-nosse.o"
"lib/scrypt/scrypt-memlimit.o"
"lib/scrypt/scrypt-scryptenc_cpuperf.o"
"lib/scrypt/scrypt-scryptenc.o"
)
cc "${CFLAGS[@]}" -c types.c -o types.o "$@"
cc "${CFLAGS[@]}" "${LDFLAGS[@]}" "types.o" mpw.c -o mpw "$@"
echo "done! Now run ./install or use ./mpw"
}
### MPW-BENCH
mpw-bench() {
depend scrypt
depend bcrypt
echo
echo "Building target: $target..."
CFLAGS=(
# include paths
-I"lib/scrypt/lib" -I"lib/scrypt/libcperciva"
-I"lib/bcrypt"
)
LDFLAGS=(
# library paths
-L"." -L"lib/scrypt"
-L"lib/bcrypt"
# libraries
-l"crypto"
# scrypt
"lib/scrypt/scrypt-crypto_aesctr.o"
"lib/scrypt/scrypt-sha256.o"
"lib/scrypt/scrypt-crypto_scrypt-nosse.o"
"lib/scrypt/scrypt-memlimit.o"
"lib/scrypt/scrypt-scryptenc_cpuperf.o"
"lib/scrypt/scrypt-scryptenc.o"
# bcrypt
"lib/bcrypt/crypt_blowfish.o"
"lib/bcrypt/crypt_gensalt.o"
"lib/bcrypt/wrapper.o"
"lib/bcrypt/x86.o"
)
cc "${CFLAGS[@]}" -c types.c -o types.o "$@"
cc "${CFLAGS[@]}" "${LDFLAGS[@]}" "types.o" mpw-bench.c -o mpw-bench "$@"
echo "done! Now use ./mpw-bench"
}
### TARGETS
cc() {
if hash llvm-gcc 2>/dev/null; then
llvm-gcc "$@"
elif hash gcc 2>/dev/null; then
gcc -std=gnu99 "$@"
elif hash clang 2>/dev/null; then
clang "$@"
else
echo >&2 "Need a compiler. Please install GCC or LLVM."
exit 1
fi
}
echo "Will build targets: ${targets[*]}..."
for target in "${targets[@]}"; do
"$target" "$@"
done

20
MasterPassword/C/distribute Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e
cd "${BASH_SOURCE%/*}"
tag=$(git describe)
commit=$(git describe --long --dirty)
[[ $tag && $commit = $tag-* ]] || exit 1
git show --show-signature --pretty=format:%H --quiet "$tag" > VERSION
mpwArchive=mpw-$commit.tar.gz
[[ -e $mpwArchive ]] && echo "WARNING: $mpwArchive already exists. Will overwrite."
read -n1 -p "Will prepare and release $mpwArchive. Press a key to continue or ^C to abort."
git ls-files -z . | xargs -0 tar -cvzf "$mpwArchive"
echo "$mpwArchive ready, SHA256: $(openssl sha -sha256 < "$mpwArchive")"
cd ../../Site/current
ln -sf "../../MasterPassword/C/$mpwArchive"
[[ -e $_ ]]
echo "Linked from site, please update your hyperlinks to point to http://masterpasswordapp.com/$mpwArchive"

View File

@@ -0,0 +1,3 @@
home=http://www.openwall.com/crypt/
pkg=http://www.openwall.com/crypt/crypt_blowfish-1.3.tar.gz
pkg_sha=7253c86c8fe890e67ec782749f95ce3f1517b065

View File

@@ -1 +1,4 @@
https://code.google.com/p/scrypt/
home=https://code.google.com/p/scrypt/
svn=http://scrypt.googlecode.com/svn
pkg=http://masterpasswordapp.com/libscrypt-b12b554.tar.gz
pkg_sha=a86445c3e031392d20652f4163adfd3fb0b1994e

View File

@@ -0,0 +1,187 @@
#include <sys/time.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <pwd.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <alg/sha256.h>
#include <crypto/crypto_scrypt.h>
#include <ow-crypt.h>
#include "types.h"
#define MP_N 32768
#define MP_r 8
#define MP_p 2
#define MP_dkLen 64
#define MP_hash PearlHashSHA256
int main(int argc, char *const argv[]) {
char *userName = "Robert Lee Mitchel";
char *masterPassword = "banana colored duckling";
char *siteName = "masterpasswordapp.com";
uint32_t siteCounter = 1;
MPElementType siteType = MPElementTypeGeneratedLong;
// Start MP
struct timeval startTime;
if (gettimeofday(&startTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
int iterations = 100;
for (int i = 0; i < iterations; ++i) {
// Calculate the master key salt.
char *mpNameSpace = "com.lyndir.masterpassword";
const uint32_t n_userNameLength = htonl(strlen(userName));
const size_t masterKeySaltLength = strlen(mpNameSpace) + sizeof(n_userNameLength) + strlen(userName);
char *masterKeySalt = malloc( masterKeySaltLength );
if (!masterKeySalt) {
fprintf(stderr, "Could not allocate master key salt: %d\n", errno);
return 1;
}
char *mKS = masterKeySalt;
memcpy(mKS, mpNameSpace, strlen(mpNameSpace)); mKS += strlen(mpNameSpace);
memcpy(mKS, &n_userNameLength, sizeof(n_userNameLength)); mKS += sizeof(n_userNameLength);
memcpy(mKS, userName, strlen(userName)); mKS += strlen(userName);
if (mKS - masterKeySalt != masterKeySaltLength)
abort();
trc("masterKeySalt ID: %s\n", IDForBuf(masterKeySalt, masterKeySaltLength));
// Calculate the master key.
uint8_t *masterKey = malloc( MP_dkLen );
if (!masterKey) {
fprintf(stderr, "Could not allocate master key: %d\n", errno);
return 1;
}
if (crypto_scrypt( (const uint8_t *)masterPassword, strlen(masterPassword), (const uint8_t *)masterKeySalt, masterKeySaltLength, MP_N, MP_r, MP_p, masterKey, MP_dkLen ) < 0) {
fprintf(stderr, "Could not generate master key: %d\n", errno);
return 1;
}
memset(masterKeySalt, 0, masterKeySaltLength);
free(masterKeySalt);
// Calculate the site seed.
const uint32_t n_siteNameLength = htonl(strlen(siteName));
const uint32_t n_siteCounter = htonl(siteCounter);
const size_t sitePasswordInfoLength = strlen(mpNameSpace) + sizeof(n_siteNameLength) + strlen(siteName) + sizeof(n_siteCounter);
char *sitePasswordInfo = malloc( sitePasswordInfoLength );
if (!sitePasswordInfo) {
fprintf(stderr, "Could not allocate site seed: %d\n", errno);
return 1;
}
char *sPI = sitePasswordInfo;
memcpy(sPI, mpNameSpace, strlen(mpNameSpace)); sPI += strlen(mpNameSpace);
memcpy(sPI, &n_siteNameLength, sizeof(n_siteNameLength)); sPI += sizeof(n_siteNameLength);
memcpy(sPI, siteName, strlen(siteName)); sPI += strlen(siteName);
memcpy(sPI, &n_siteCounter, sizeof(n_siteCounter)); sPI += sizeof(n_siteCounter);
if (sPI - sitePasswordInfo != sitePasswordInfoLength)
abort();
uint8_t sitePasswordSeed[32];
HMAC_SHA256_Buf(masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoLength, sitePasswordSeed);
memset(masterKey, 0, MP_dkLen);
memset(sitePasswordInfo, 0, sitePasswordInfoLength);
free(masterKey);
free(sitePasswordInfo);
// Determine the cipher.
const char *cipher = CipherForType(siteType, sitePasswordSeed[0]);
trc("type %d, cipher: %s\n", siteType, cipher);
if (strlen(cipher) > 32)
abort();
// Encode the password from the seed using the cipher.
char *sitePassword = calloc(strlen(cipher) + 1, sizeof(char));
for (int c = 0; c < strlen(cipher); ++c) {
sitePassword[c] = CharacterFromClass(cipher[c], sitePasswordSeed[c + 1]);
trc("class %c, character: %c\n", cipher[c], sitePassword[c]);
}
memset(sitePasswordSeed, 0, sizeof(sitePasswordSeed));
if (i % 1 == 0)
fprintf( stderr, "\rmpw: iteration %d / %d..", i, iterations );
}
// Output timing results.
struct timeval endTime;
if (gettimeofday(&endTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
long long secs = (endTime.tv_sec - startTime.tv_sec);
long long usecs = (endTime.tv_usec - startTime.tv_usec);
double elapsed = secs + usecs / 1000000.0;
double mpwSpeed = iterations / elapsed;
fprintf( stdout, " done. %d iterations in %llds %lldµs -> %.2f/s\n", iterations, secs, usecs, mpwSpeed );
// Start SHA-256
if (gettimeofday(&startTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
iterations = 50000000;
uint8_t hash[32];
for (int i = 0; i < iterations; ++i) {
SHA256_Buf(masterPassword, strlen(masterPassword), hash);
if (i % 1000 == 0)
fprintf( stderr, "\rsha256: iteration %d / %d..", i, iterations );
}
// Output timing results.
if (gettimeofday(&endTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
secs = (endTime.tv_sec - startTime.tv_sec);
usecs = (endTime.tv_usec - startTime.tv_usec);
elapsed = secs + usecs / 1000000.0;
double sha256Speed = iterations / elapsed;
fprintf( stdout, " done. %d iterations in %llds %lldµs -> %.2f/s\n", iterations, secs, usecs, sha256Speed );
// Start BCrypt
if (gettimeofday(&startTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
int bcrypt_cost = 9;
iterations = 600;
for (int i = 0; i < iterations; ++i) {
crypt(masterPassword, crypt_gensalt("$2b$", bcrypt_cost, userName, strlen(userName)));
if (i % 10 == 0)
fprintf( stderr, "\rbcrypt (cost %d): iteration %d / %d..", bcrypt_cost, i, iterations );
}
// Output timing results.
if (gettimeofday(&endTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
secs = (endTime.tv_sec - startTime.tv_sec);
usecs = (endTime.tv_usec - startTime.tv_usec);
elapsed = secs + usecs / 1000000.0;
double bcrypt9Speed = iterations / elapsed;
fprintf( stdout, " done. %d iterations in %llds %lldµs -> %.2f/s\n", iterations, secs, usecs, bcrypt9Speed );
// Summarize.
fprintf( stdout, "\n== SUMMARY ==\nOn this machine,\n" );
fprintf( stdout, "mpw is %f times slower than sha256\n", sha256Speed / mpwSpeed );
fprintf( stdout, "mpw is %f times slower than bcrypt (cost 9)\n", bcrypt9Speed / mpwSpeed );
return 0;
}

View File

@@ -1,4 +1,5 @@
#define _WITH_GETLINE
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
@@ -23,6 +24,12 @@
#include <crypto/crypto_scrypt.h>
#include "types.h"
#if defined(READLINE)
#include <readline/readline.h>
#elif defined(EDITLINE)
#include <histedit.h>
#endif
#define MP_N 32768
#define MP_r 8
#define MP_p 2
@@ -52,7 +59,14 @@ void usage() {
fprintf(stderr, " -v variant The kind of content to generate.\n"
" Defaults to 'password'.\n"
" p, password | The password to log in with.\n"
" l, login | The username to log in as.\n\n");
" l, login | The username to log in as.\n"
" a, answer | The answer to a security question.\n\n");
fprintf(stderr, " -C context A variant-specific context.\n"
" Defaults to empty.\n"
" -v p, password | Doesn't currently use a context.\n"
" -v l, login | Doesn't currently use a context.\n"
" -v a, answer | Empty for a universal site answer or\n"
" | the most significant word(s) of the question.\n\n");
exit(0);
}
@@ -94,27 +108,30 @@ int main(int argc, char *const argv[]) {
const char *siteTypeString = getenv( MP_env_sitetype );
MPElementVariant siteVariant = MPElementVariantPassword;
const char *siteVariantString = NULL;
const char *siteContextString = NULL;
uint32_t siteCounter = 1;
const char *siteCounterString = getenv( MP_env_sitecounter );
// Read the options.
char opt;
while ((opt = getopt(argc, argv, "u:t:c:v:h")) != -1)
for (int opt; (opt = getopt(argc, argv, "u:t:c:v:C:h")) != -1;)
switch (opt) {
case 'h':
usage();
break;
case 'u':
userName = optarg;
break;
case 't':
siteTypeString = optarg;
break;
case 'c':
siteCounterString = optarg;
break;
case 'v':
siteVariantString = optarg;
break;
case 'c':
siteCounterString = optarg;
case 'C':
siteContextString = optarg;
break;
case 'h':
usage();
break;
case '?':
switch (optopt) {
@@ -160,6 +177,8 @@ int main(int argc, char *const argv[]) {
trc("siteVariant: %d (%s)\n", siteVariant, siteVariantString);
if (siteVariant == MPElementVariantLogin)
siteType = MPElementTypeGeneratedName;
if (siteVariant == MPElementVariantAnswer)
siteType = MPElementTypeGeneratedPhrase;
if (siteTypeString)
siteType = TypeWithName( siteTypeString );
trc("siteType: %d (%s)\n", siteType, siteTypeString);
@@ -172,31 +191,27 @@ int main(int argc, char *const argv[]) {
}
trc("mpwConfigPath: %s\n", mpwConfigPath);
FILE *mpwConfig = fopen(mpwConfigPath, "r");
if (!mpwConfig) {
fprintf(stderr, "Couldn't open configuration file: %s: %d\n", mpwConfigPath, errno);
return 1;
}
free(mpwConfigPath);
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
while ((linelen = getline(&line, &linecap, mpwConfig)) > 0)
if (strcmp(strsep(&line, ":"), userName) == 0) {
masterPassword = strsep(&line, "\n");
break;
}
if (!masterPassword) {
fprintf(stderr, "Missing master password for user: %s\n", userName);
return 1;
if (mpwConfig) {
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
while ((linelen = getline(&line, &linecap, mpwConfig)) > 0)
if (strcmp(strsep(&line, ":"), userName) == 0) {
masterPassword = strsep(&line, "\n");
break;
}
}
while (!masterPassword)
masterPassword = getpass( "Your master password: " );
trc("masterPassword: %s\n", masterPassword);
// Calculate the master key salt.
const char *mpKeyScope = ScopeForVariant(MPElementVariantPassword);
trc("key scope: %s\n", mpKeyScope);
const uint32_t n_userNameLength = htonl(strlen(userName));
size_t masterKeySaltLength = strlen(mpKeyScope) + sizeof(n_userNameLength) + strlen(userName);
char *masterKeySalt = malloc( masterKeySaltLength );
const size_t masterKeySaltLength = strlen(mpKeyScope) + sizeof(n_userNameLength) + strlen(userName);
char *masterKeySalt = (char *)malloc( masterKeySaltLength );
if (!masterKeySalt) {
fprintf(stderr, "Could not allocate master key salt: %d\n", errno);
return 1;
@@ -211,7 +226,7 @@ int main(int argc, char *const argv[]) {
trc("masterKeySalt ID: %s\n", IDForBuf(masterKeySalt, masterKeySaltLength));
// Calculate the master key.
uint8_t *masterKey = malloc( MP_dkLen );
uint8_t *masterKey = (uint8_t *)malloc( MP_dkLen );
if (!masterKey) {
fprintf(stderr, "Could not allocate master key: %d\n", errno);
return 1;
@@ -228,11 +243,14 @@ int main(int argc, char *const argv[]) {
// Calculate the site seed.
const char *mpSiteScope = ScopeForVariant(siteVariant);
trc("site scope: %s\n", mpSiteScope);
trc("site scope: %s, context: %s\n", mpSiteScope, siteContextString == NULL? "<empty>": siteContextString);
const uint32_t n_siteNameLength = htonl(strlen(siteName));
const uint32_t n_siteCounter = htonl(siteCounter);
const uint32_t n_siteContextLength = siteContextString == NULL? 0: htonl(strlen(siteContextString));
size_t sitePasswordInfoLength = strlen(mpSiteScope) + sizeof(n_siteNameLength) + strlen(siteName) + sizeof(n_siteCounter);
char *sitePasswordInfo = malloc( sitePasswordInfoLength );
if (siteContextString)
sitePasswordInfoLength += sizeof(n_siteContextLength) + strlen(siteContextString);
char *sitePasswordInfo = (char *)malloc( sitePasswordInfoLength );
if (!sitePasswordInfo) {
fprintf(stderr, "Could not allocate site seed: %d\n", errno);
return 1;
@@ -243,9 +261,13 @@ int main(int argc, char *const argv[]) {
memcpy(sPI, &n_siteNameLength, sizeof(n_siteNameLength)); sPI += sizeof(n_siteNameLength);
memcpy(sPI, siteName, strlen(siteName)); sPI += strlen(siteName);
memcpy(sPI, &n_siteCounter, sizeof(n_siteCounter)); sPI += sizeof(n_siteCounter);
if (siteContextString) {
memcpy(sPI, &n_siteContextLength, sizeof(n_siteContextLength)); sPI += sizeof(n_siteContextLength);
memcpy(sPI, siteContextString, strlen(siteContextString)); sPI += strlen(siteContextString);
}
if (sPI - sitePasswordInfo != sitePasswordInfoLength)
abort();
trc("seed from: hmac-sha256(masterKey, %s | %s | %s | %s)\n", mpSiteScope, Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter)));
trc("seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n", mpSiteScope, Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter)), Hex(&n_siteContextLength, sizeof(n_siteContextLength)), siteContextString);
trc("sitePasswordInfo ID: %s\n", IDForBuf(sitePasswordInfo, sitePasswordInfoLength));
uint8_t sitePasswordSeed[32];
@@ -263,7 +285,7 @@ int main(int argc, char *const argv[]) {
abort();
// Encode the password from the seed using the cipher.
char *sitePassword = calloc(strlen(cipher) + 1, sizeof(char));
char *sitePassword = (char *)calloc(strlen(cipher) + 1, sizeof(char));
for (int c = 0; c < strlen(cipher); ++c) {
sitePassword[c] = CharacterFromClass(cipher[c], sitePasswordSeed[c + 1]);
trc("class %c, character: %c\n", cipher[c], sitePassword[c]);

View File

@@ -50,19 +50,19 @@ const char *CipherForType(MPElementType type, uint8_t seedByte) {
switch (type) {
case MPElementTypeGeneratedMaximum: {
char *ciphers[] = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" };
const char *ciphers[] = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" };
return ciphers[seedByte % 2];
}
case MPElementTypeGeneratedLong: {
char *ciphers[] = { "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno", "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno", "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno", "CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno", "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno", "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno", "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" };
const char *ciphers[] = { "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno", "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno", "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno", "CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno", "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno", "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno", "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" };
return ciphers[seedByte % 21];
}
case MPElementTypeGeneratedMedium: {
char *ciphers[] = { "CvcnoCvc", "CvcCvcno" };
const char *ciphers[] = { "CvcnoCvc", "CvcCvcno" };
return ciphers[seedByte % 2];
}
case MPElementTypeGeneratedBasic: {
char *ciphers[] = { "aaanaaan", "aannaaan", "aaannaaa" };
const char *ciphers[] = { "aaanaaan", "aannaaan", "aaannaaa" };
return ciphers[seedByte % 3];
}
case MPElementTypeGeneratedShort: {
@@ -75,7 +75,7 @@ const char *CipherForType(MPElementType type, uint8_t seedByte) {
return "cvccvcvcv";
}
case MPElementTypeGeneratedPhrase: {
char *ciphers[] = { "cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" };
const char *ciphers[] = { "cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" };
return ciphers[seedByte % 3];
}
default: {
@@ -95,6 +95,8 @@ const MPElementVariant VariantWithName(const char *variantName) {
return MPElementVariantPassword;
if (0 == strcmp(lowerVariantName, "l") || 0 == strcmp(lowerVariantName, "login"))
return MPElementVariantLogin;
if (0 == strcmp(lowerVariantName, "a") || 0 == strcmp(lowerVariantName, "answer"))
return MPElementVariantAnswer;
fprintf(stderr, "Not a variant name: %s", lowerVariantName);
abort();
@@ -108,6 +110,9 @@ const char *ScopeForVariant(MPElementVariant variant) {
case MPElementVariantLogin: {
return "com.lyndir.masterpassword.login";
}
case MPElementVariantAnswer: {
return "com.lyndir.masterpassword.answer";
}
default: {
fprintf(stderr, "Unknown variant: %d", variant);
abort();
@@ -170,7 +175,7 @@ const char *IDForBuf(const void *buf, size_t length) {
uint8_t hash[32];
SHA256_Buf(buf, length, hash);
char *id = calloc(65, sizeof(char));
char *id = (char *)calloc(65, sizeof(char));
for (int kH = 0; kH < 32; kH++)
sprintf(&(id[kH * 2]), "%02X", hash[kH]);
@@ -178,7 +183,7 @@ const char *IDForBuf(const void *buf, size_t length) {
}
const char *Hex(const void *buf, size_t length) {
char *id = calloc(length*2+1, sizeof(char));
char *id = (char *)calloc(length*2+1, sizeof(char));
for (int kH = 0; kH < length; kH++)
sprintf(&(id[kH * 2]), "%02X", ((const uint8_t*)buf)[kH]);
return id;

View File

@@ -11,6 +11,8 @@ typedef enum {
MPElementVariantPassword,
/** Generate the login name to log in as. */
MPElementVariantLogin,
/** Generate the answer to a security question. */
MPElementVariantAnswer,
} MPElementVariant;
typedef enum {

View File

@@ -11,6 +11,8 @@
#define MPProductGenerateLogins @"com.lyndir.masterpassword.products.generatelogins"
#define MPProductGenerateAnswers @"com.lyndir.masterpassword.products.generateanswers"
#define MPProductOSIntegration @"com.lyndir.masterpassword.products.osintegration"
#define MPProductTouchID @"com.lyndir.masterpassword.products.touchid"
#define MPProductFuel @"com.lyndir.masterpassword.products.fuel"
#define MP_FUEL_HOURLY_RATE 30.f /* Tier 1 purchases/h ~> USD/h */

View File

@@ -81,6 +81,16 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
- (void)purchaseProductWithIdentifier:(NSString *)productIdentifier quantity:(NSInteger)quantity {
#if TARGET_OS_IPHONE
if (![[MPAppDelegate_Shared get] canMakePayments]) {
[PearlAlert showAlertWithTitle:@"Store Not Set Up" message:
@"Try logging using the App Store or from Settings."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:nil cancelTitle:@"Thanks" otherTitles:nil];
return;
}
#endif
for (SKProduct *product in self.products)
if ([product.productIdentifier isEqualToString:productIdentifier]) {
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
@@ -129,9 +139,11 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
case SKPaymentTransactionStatePurchased: {
inf( @"purchased: %@", transaction.payment.productIdentifier );
if ([transaction.payment.productIdentifier isEqualToString:MPProductFuel]) {
float currentFuel = [[MPiOSConfig get].developmentFuel floatValue];
float currentFuel = [[MPiOSConfig get].developmentFuelRemaining floatValue];
float purchasedFuel = transaction.payment.quantity / MP_FUEL_HOURLY_RATE;
[MPiOSConfig get].developmentFuel = @(currentFuel + purchasedFuel);
[MPiOSConfig get].developmentFuelRemaining = @(currentFuel + purchasedFuel);
if (![MPiOSConfig get].developmentFuelChecked || !currentFuel)
[MPiOSConfig get].developmentFuelChecked = [NSDate date];
}
[[NSUserDefaults standardUserDefaults] setObject:transaction.transactionIdentifier
forKey:transaction.payment.productIdentifier];

View File

@@ -89,8 +89,6 @@
DACA22BC1705DE7D002C6C22 /* NSError+UbiquityStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */; };
DACA22BD1705DE7D002C6C22 /* NSError+UbiquityStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA22B91705DE7D002C6C22 /* NSError+UbiquityStoreManager.m */; };
DACA22BE1705DE7D002C6C22 /* UbiquityStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA22BA1705DE7D002C6C22 /* UbiquityStoreManager.h */; };
DACA26F91705DF81002C6C22 /* background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA24171705DF7D002C6C22 /* background@2x.png */; };
DACA26FA1705DF81002C6C22 /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA24181705DF7D002C6C22 /* background.png */; };
DACA26FE1705DF81002C6C22 /* logo-bare.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA241C1705DF7D002C6C22 /* logo-bare.png */; };
DACA27121705DF81002C6C22 /* avatar-13@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA24321705DF7D002C6C22 /* avatar-13@2x.png */; };
DACA27131705DF81002C6C22 /* avatar-3@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA24331705DF7D002C6C22 /* avatar-3@2x.png */; };
@@ -751,8 +749,6 @@
DACA22B81705DE7D002C6C22 /* NSError+UbiquityStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+UbiquityStoreManager.h"; sourceTree = "<group>"; };
DACA22B91705DE7D002C6C22 /* NSError+UbiquityStoreManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+UbiquityStoreManager.m"; sourceTree = "<group>"; };
DACA22BA1705DE7D002C6C22 /* UbiquityStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UbiquityStoreManager.h; sourceTree = "<group>"; };
DACA24171705DF7D002C6C22 /* background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "background@2x.png"; sourceTree = "<group>"; };
DACA24181705DF7D002C6C22 /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = background.png; sourceTree = "<group>"; };
DACA241C1705DF7D002C6C22 /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-bare.png"; sourceTree = "<group>"; };
DACA24321705DF7D002C6C22 /* avatar-13@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-13@2x.png"; sourceTree = "<group>"; };
DACA24331705DF7D002C6C22 /* avatar-3@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-3@2x.png"; sourceTree = "<group>"; };
@@ -1550,7 +1546,6 @@
DA2509271951B86C00AC23F1 /* screen.png */,
DA0933CF1747B91B00DE1CEF /* appstore.png */,
DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */,
DACA24161705DF7D002C6C22 /* Background */,
DACA24311705DF7D002C6C22 /* Avatars */,
DACA241C1705DF7D002C6C22 /* logo-bare.png */,
DACA24581705DF7D002C6C22 /* menu-icon.png */,
@@ -1559,15 +1554,6 @@
path = Media;
sourceTree = "<group>";
};
DACA24161705DF7D002C6C22 /* Background */ = {
isa = PBXGroup;
children = (
DACA24171705DF7D002C6C22 /* background@2x.png */,
DACA24181705DF7D002C6C22 /* background.png */,
);
path = Background;
sourceTree = "<group>";
};
DACA24311705DF7D002C6C22 /* Avatars */ = {
isa = PBXGroup;
children = (
@@ -2006,8 +1992,6 @@
buildActionMask = 2147483647;
files = (
DAFE4A5A1503982E003ABA7C /* Pearl.strings in Resources */,
DACA26F91705DF81002C6C22 /* background@2x.png in Resources */,
DACA26FA1705DF81002C6C22 /* background.png in Resources */,
DACA26FE1705DF81002C6C22 /* logo-bare.png in Resources */,
DACA27121705DF81002C6C22 /* avatar-13@2x.png in Resources */,
DACA27131705DF81002C6C22 /* avatar-3@2x.png in Resources */,

View File

@@ -0,0 +1,13 @@
//
// AttributedMarkdown.h
// AttributedMarkdown
//
// Created by Maarten Billemont on 2014-09-28.
// Copyright (c) 2014 Lyndir. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface AttributedMarkdown : NSObject
@end

View File

@@ -0,0 +1,13 @@
//
// AttributedMarkdown.m
// AttributedMarkdown
//
// Created by Maarten Billemont on 2014-09-28.
// Copyright (c) 2014 Lyndir. All rights reserved.
//
#import "AttributedMarkdown.h"
@implementation AttributedMarkdown
@end

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.lyndir.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@@ -41,6 +41,6 @@
@property(nonatomic) IBOutlet UITextField *questionField;
@property(nonatomic) IBOutlet UITextField *answerField;
- (void)setQuestion:(MPSiteQuestionEntity *)question forSite:(MPSiteEntity *)site;
- (void)setQuestion:(MPSiteQuestionEntity *)question forSite:(MPSiteEntity *)site inVC:(MPAnswersViewController *)VC;
@end

View File

@@ -92,7 +92,7 @@
if (!_multiple)
return 0;
return MAX( 2, [[self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].questions count] );
return [[self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].questions count] + 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
@@ -118,7 +118,7 @@
MPSiteQuestionEntity *question = nil;
if ([site.questions count] > indexPath.item)
question = site.questions[indexPath.item];
[cell setQuestion:question forSite:site];
[cell setQuestion:question forSite:site inVC:self];
return cell;
}
@@ -217,6 +217,17 @@
} );
}
- (void)didAddQuestion:(MPSiteQuestionEntity *)question toSite:(MPSiteEntity *)site {
NSUInteger newQuestionRow = [site.questions count];
PearlMainQueue( ^{
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:newQuestionRow inSection:1] ]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
} );
}
@end
@implementation MPGlobalAnswersCell
@@ -247,14 +258,16 @@
@implementation MPAnswersQuestionCell {
NSManagedObjectID *_siteOID;
NSManagedObjectID *_questionOID;
__weak MPAnswersViewController *_answersVC;
}
#pragma mark - State
- (void)setQuestion:(MPSiteQuestionEntity *)question forSite:(MPSiteEntity *)site {
- (void)setQuestion:(MPSiteQuestionEntity *)question forSite:(MPSiteEntity *)site inVC:(MPAnswersViewController *)answersVC {
_siteOID = site.objectID;
_questionOID = question.objectID;
_answersVC = answersVC;
[self updateAnswerForQuestion:question ofSite:site];
}
@@ -272,9 +285,11 @@
NSString *keyword = textField.text;
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
BOOL didAddQuestionObject = NO;
MPSiteEntity *site = [MPSiteEntity existingObjectWithID:_siteOID inContext:context];
MPSiteQuestionEntity *question = [MPSiteQuestionEntity existingObjectWithID:_questionOID inContext:context];
if (!question) {
didAddQuestionObject = YES;
[site addQuestionsObject:question = [MPSiteQuestionEntity insertNewObjectInContext:context]];
question.site = site;
}
@@ -291,6 +306,9 @@
_questionOID = question.objectID;
[self updateAnswerForQuestion:question ofSite:site];
if (didAddQuestionObject)
[_answersVC didAddQuestion:question toSite:site];
}
}];
}

View File

@@ -30,6 +30,7 @@ const long MPAvatarAdd = 10000;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarSizeConstraint;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarToTopConstraint;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarRaisedConstraint;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *keyboardHeightConstraint;
@end
@@ -66,6 +67,12 @@ const long MPAvatarAdd = 10000;
[self observeKeyPath:@"highlighted" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *_self) {
[_self updateAnimated:_self.superview != nil];
}];
PearlAddNotificationObserver( UIKeyboardWillShowNotification, nil, [NSOperationQueue mainQueue],
^(MPAvatarCell *self, NSNotification *note) {
CGRect keyboardRect = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat keyboardHeight = CGRectGetHeight( self.window.screen.bounds ) - CGRectGetMinY( keyboardRect );
[self.keyboardHeightConstraint updateConstant:keyboardHeight];
} );
CABasicAnimation *toShadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
toShadowOpacityAnimation.toValue = @0.2f;
@@ -99,6 +106,7 @@ const long MPAvatarAdd = 10000;
- (void)dealloc {
[self removeKeyPathObservers];
PearlRemoveNotificationObservers();
}
#pragma mark - Properties
@@ -214,18 +222,20 @@ const long MPAvatarAdd = 10000;
switch (self.mode) {
case MPAvatarModeLowered: {
[self.avatarSizeConstraint updateConstant:self.avatarImageView.image.size.height];
[self.avatarSizeConstraint updateConstant:
self.avatarImageView.image.size.height * (self.visibility * 0.3f + 0.7f)];
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow];
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow];
self.nameContainer.alpha = self.visibility;
self.nameContainer.backgroundColor = [UIColor clearColor];
self.avatarImageView.alpha = self.visibility / 0.7f + 0.3f;
self.avatarImageView.alpha = self.visibility * 0.7f + 0.3f;
self.avatarImageView.layer.shadowRadius = 15 * self.visibility * self.visibility;
break;
}
case MPAvatarModeRaisedButInactive: {
[self.avatarSizeConstraint updateConstant:self.avatarImageView.image.size.height];
[self.avatarSizeConstraint updateConstant:
self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow];
@@ -236,7 +246,8 @@ const long MPAvatarAdd = 10000;
break;
}
case MPAvatarModeRaisedAndActive: {
[self.avatarSizeConstraint updateConstant:self.avatarImageView.image.size.height];
[self.avatarSizeConstraint updateConstant:
self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
@@ -247,7 +258,8 @@ const long MPAvatarAdd = 10000;
break;
}
case MPAvatarModeRaisedAndHidden: {
[self.avatarSizeConstraint updateConstant:self.avatarImageView.image.size.height];
[self.avatarSizeConstraint updateConstant:
self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
@@ -260,7 +272,7 @@ const long MPAvatarAdd = 10000;
case MPAvatarModeRaisedAndMinimized: {
[self.avatarSizeConstraint updateConstant:36];
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow];
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultHigh];
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultHigh + 2];
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
self.nameContainer.alpha = 0;
self.nameContainer.backgroundColor = [UIColor blackColor];

View File

@@ -19,6 +19,7 @@
@interface MPEmergencyViewController : UIViewController <UITextFieldDelegate>
@property(weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property(weak, nonatomic) IBOutlet UIView *dialogView;
@property(weak, nonatomic) IBOutlet UIView *containerView;
@property(weak, nonatomic) IBOutlet UITextField *userNameField;

View File

@@ -45,6 +45,8 @@
^(MPEmergencyViewController *self, NSNotification *note) {
[self performSegueWithIdentifier:@"unwind-popover" sender:self];
} );
[self.scrollView automaticallyAdjustInsetsForKeyboard];
}
- (void)viewDidDisappear:(BOOL)animated {
@@ -52,6 +54,7 @@
[super viewDidDisappear:animated];
PearlRemoveNotificationObservers();
PearlRemoveNotificationObserversFrom( self.scrollView );
[self reset];
}

View File

@@ -7,6 +7,8 @@
//
#import "MPGuideViewController.h"
#import "markdown_lib.h"
#import "NSString+MPMarkDown.h"
@interface MPGuideStep : NSObject
@@ -37,28 +39,50 @@
[super viewDidLoad];
self.steps = @[
[MPGuideStep stepWithImage:[UIImage imageNamed:@"image-0"] caption:
@"To begin, tap the \"New User\" icon and add yourself as a user to the application."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"image-1"] caption:
@"Enter your full name. Double-check that you have spelled your name correctly and capitalized it appropriately. Your passwords will depend on it."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"image-2"] caption:
@"Choose a master password: Use something new and long. A short sentence is ideal.\nDO NOT FORGET THIS ONE PASSWORD."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"image-3"] caption:
@"After logging in, you'll see an empty screen with a search box.\nTap the search box to begin adding sites."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"image-4"] caption:
@"To add a site, just enter its name fully and tap the result. Names can be anything, but we recommend using a site's bare domain name."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"image-5"] caption:
@"Your sites are easy to find and sorted by recency.\nTap any site to copy its password.\nYou can now switch and paste it in another app."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"image-6"] caption:
@"The user icon lets you save your site's login.\nThis is useful if you find it hard to remember the user name for this site."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"image-7"] caption:
[MPGuideStep stepWithImage:[UIImage imageNamed:@"initial"] caption:
@"To begin, tap the *New User* icon and add yourself as a user to the application."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"name_new"] caption:
@"Enter your full name. \n"
@"**Double-check** that you have spelled your name correctly and capitalized it appropriately. \n"
@"Your passwords will depend on it."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"mpw_new"] caption:
@"Choose a master password: Make it *new* and *long*. \n"
@"A short phrase makes a great password. \n"
@"**DO NOT FORGET THIS ONE PASSWORD**."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"login_new"] caption:
@"After logging in, you'll see an empty screen with a search box. \n"
@"Tap the search box to begin adding sites."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"site_new"] caption:
@"To add a site, just enter its name and tap the result. \n"
@"*We recommend* always using a site's **bare** domain name: eg. *apple.com*. \n"
@"(NOT *www.*apple.com or *store.*apple.com)"],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"copy_pw"] caption:
@"Tap any site to copy its password. \n"
@"The first time, change your site's old password into this new one."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"settings"] caption:
@"To make changes to the site password, tap the settings icon or swipe left to reveal extra buttons."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"image-8"] caption:
@"If you ever need a new password for the site, just tap the plus icon to increment its counter.\nYou can hold down to reset it back to 1."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"image-9"] caption:
@"Use the list icon to upgrade or downgrade your password's complexity.\nSome sites won't let you use complex passwords."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"image-10"] caption:
@"If you have a password that you cannot change, you can save it as a Personal password. Device Private means the site will not be backed up."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"login_name"] caption:
@"You can save the login name for the site. \n"
@"This is useful if you find it hard to remember your user name for this site."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"counter"] caption:
@"If you ever need a new password for the site, just tap the plus icon to increment its counter. \n"
@"You can hold down to reset it back to 1."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"choose_type"] caption:
@"Use the list icon to upgrade or downgrade your password's complexity. \n"
@"Some sites won't let you use complex passwords."],
[MPGuideStep stepWithImage:[UIImage imageNamed:@"personal_pw"] caption:
@"If you have a password that you cannot change, you can save it as a *personal* password. "
@"*Device private* means the site will not be backed up."],
];
}
@@ -68,9 +92,10 @@
[self.pageControl observeKeyPath:@"currentPage"
withBlock:^(id from, id to, NSKeyValueChange cause, UIPageControl *pageControl) {
MPGuideStep *activeStep = self.steps[pageControl.currentPage];
self.captionLabel.text = activeStep.caption;
}];
MPGuideStep *activeStep = self.steps[pageControl.currentPage];
self.captionLabel.attributedText =
[activeStep.caption attributedMarkdownStringWithFontSize:self.captionLabel.font.pointSize];
}];
[self.collectionView setContentOffset:CGPointZero];
self.pageControl.currentPage = 0;
@@ -117,6 +142,7 @@
MPGuideStepCell *cell = [MPGuideStepCell dequeueCellFromCollectionView:collectionView indexPath:indexPath];
cell.imageView.image = ((MPGuideStep *)self.steps[indexPath.item]).image;
cell.contentView.frame = cell.bounds;
return cell;
}

View File

@@ -226,12 +226,15 @@
else if (textField == self.loginNameField &&
((site.loginGenerated && ![text length]) ||
(!site.loginGenerated && ![text isEqualToString:site.loginName]))) {
site.loginName = text;
site.loginGenerated = NO;
if ([text length])
[PearlOverlay showTemporaryOverlayWithTitle:@"Login Name Saved" dismissAfter:2];
else
[PearlOverlay showTemporaryOverlayWithTitle:@"Login Name Cleared" dismissAfter:2];
if (site.loginGenerated || !([site.loginName isEqualToString:text] || (!text && !site.loginName))) {
site.loginGenerated = NO;
site.loginName = text;
if ([text length])
[PearlOverlay showTemporaryOverlayWithTitle:@"Login Name Saved" dismissAfter:2];
else
[PearlOverlay showTemporaryOverlayWithTitle:@"Login Name Cleared" dismissAfter:2];
}
}
[context saveToStore];
@@ -310,8 +313,6 @@
[self setMode:MPPasswordCellModePassword animated:YES];
break;
}
[self updateAnimated:YES];
}
- (IBAction)doUpgrade:(UIButton *)sender {
@@ -499,6 +500,9 @@
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPSiteEntity *site = [self siteInContext:context];
MPKey *key = [MPiOSAppDelegate get].key;
if (!key)
return;
NSString *password, *loginName = [site resolveLoginUsingKey:key];
if (self.transientSite)
password = [MPAlgorithmDefault generatePasswordForSiteNamed:self.transientSite ofType:
@@ -512,7 +516,7 @@
TimeToCrack timeToCrack;
NSString *timeToCrackString = nil;
id<MPAlgorithm> algorithm = site.algorithm?: MPAlgorithmDefault;
MPAttacker attackHardware = [[MPConfig get].siteAttacker unsignedIntegerValue];
MPAttacker attackHardware = [[MPConfig get].siteAttacker integerValue];
if ([algorithm timeToCrack:&timeToCrack passwordOfType:site.type byAttacker:attackHardware] ||
[algorithm timeToCrack:&timeToCrack passwordString:password byAttacker:attackHardware])
timeToCrackString = NSStringFromTimeToCrack( timeToCrack );

View File

@@ -27,6 +27,7 @@
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *passwordsToBottomConstraint;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *navigationBarToTopConstraint;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *popdownToTopConstraint;
@property(strong, nonatomic) IBOutlet UIView *badNameTipContainer;
@property(strong, nonatomic) IBOutlet UIView *popdownView;
@property(strong, nonatomic) IBOutlet UIView *popdownContainer;

View File

@@ -24,6 +24,10 @@
#import "MPPasswordCell.h"
#import "MPAnswersViewController.h"
typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
MPPasswordsBadNameTip = 1 << 0,
};
@interface MPPasswordsViewController()<NSFetchedResultsControllerDelegate>
@property(nonatomic, strong) IBOutlet UINavigationBar *navigationBar;
@@ -39,6 +43,7 @@
__weak UIViewController *_popdownVC;
BOOL _showTransientItem;
NSUInteger _transientItem;
NSCharacterSet *_siteNameAcceptableCharactersSet;
}
#pragma mark - Life
@@ -47,16 +52,25 @@
[super viewDidLoad];
NSMutableCharacterSet *siteNameAcceptableCharactersSet = [[NSCharacterSet alphanumericCharacterSet] mutableCopy];
[siteNameAcceptableCharactersSet formIntersectionWithCharacterSet:[[NSCharacterSet uppercaseLetterCharacterSet] invertedSet]];
[siteNameAcceptableCharactersSet addCharactersInString:@"@.-+~&_;:/"];
_siteNameAcceptableCharactersSet = siteNameAcceptableCharactersSet;
_backgroundColor = self.passwordCollectionView.backgroundColor;
_darkenedBackgroundColor = [_backgroundColor colorWithAlphaComponent:0.6f];
_transientItem = NSNotFound;
self.view.backgroundColor = [UIColor clearColor];
[self.passwordCollectionView automaticallyAdjustInsetsForKeyboard];
[self.passwordsSearchBar enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
if ([subview isKindOfClass:[UITextField class]])
((UITextField *)subview).keyboardAppearance = UIKeyboardAppearanceDark;
} recurse:YES];
self.passwordsSearchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
if ([self.passwordsSearchBar respondsToSelector:@selector(keyboardAppearance)])
self.passwordsSearchBar.keyboardAppearance = UIKeyboardAppearanceDark;
else
[self.passwordsSearchBar enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
if ([subview isKindOfClass:[UITextField class]])
((UITextField *)subview).keyboardAppearance = UIKeyboardAppearanceDark;
} recurse:YES];
}
- (void)viewWillAppear:(BOOL)animated {
@@ -232,12 +246,32 @@
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchBar == self.passwordsSearchBar)
if (searchBar == self.passwordsSearchBar) {
if ([self.query length] && [[self.query stringByTrimmingCharactersInSet:_siteNameAcceptableCharactersSet] length])
[self showTips:MPPasswordsBadNameTip];
[self updatePasswords];
}
}
#pragma mark - Private
- (void)showTips:(MPPasswordsTips)showTips {
[UIView animateWithDuration:0.3f animations:^{
if (showTips & MPPasswordsBadNameTip)
self.badNameTipContainer.alpha = 1;
} completion:^(BOOL finished) {
if (finished)
PearlMainQueueAfter( 5, ^{
[UIView animateWithDuration:0.3f animations:^{
if (showTips & MPPasswordsBadNameTip)
self.badNameTipContainer.alpha = 0;
}];
} );
}];
}
- (void)fetchedItemsDidUpdate {
NSString *query = self.query;

View File

@@ -1,12 +1,12 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPPopdownSegue.h
@@ -22,6 +22,8 @@
@implementation MPPopdownSegue {
}
static char UnwindingObserverKey;
- (void)perform {
MPPasswordsViewController *passwordsVC;
@@ -35,17 +37,30 @@
[passwordsVC addChildViewController:popdownVC];
[passwordsVC.popdownContainer addSubview:popdownView];
[passwordsVC.popdownContainer addConstraintsWithVisualFormats:@[ @"H:|[popdownView]|", @"V:|[popdownView]|" ] options:0
metrics:nil views:NSDictionaryOfVariableBindings(popdownView)];
metrics:nil views:NSDictionaryOfVariableBindings( popdownView )];
[UIView animateWithDuration:0.3f animations:^{
[[passwordsVC.popdownToTopConstraint updatePriority:1] layoutIfNeeded];
} completion:^(BOOL finished) {
} completion:^(BOOL finished) {
[popdownVC didMoveToParentViewController:passwordsVC];
id<NSObject> observer = [[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
[[[MPPopdownSegue alloc] initWithIdentifier:@"unwind-popdown" source:popdownVC
destination:passwordsVC] perform];
}];
objc_setAssociatedObject( popdownVC, &UnwindingObserverKey, observer, OBJC_ASSOCIATION_RETAIN );
}];
}
else if ([self.destinationViewController isKindOfClass:[MPPasswordsViewController class]]) {
else {
popdownVC = self.sourceViewController;
passwordsVC = self.destinationViewController;
for (passwordsVC = self.sourceViewController; passwordsVC && ![(id)passwordsVC isKindOfClass:[MPPasswordsViewController class]];
passwordsVC = (id)passwordsVC.parentViewController);
NSAssert( passwordsVC, @"Couldn't find passwords VC to pop back to." );
[[NSNotificationCenter defaultCenter] removeObserver:objc_getAssociatedObject( popdownVC, &UnwindingObserverKey )];
objc_setAssociatedObject( popdownVC, &UnwindingObserverKey, nil, OBJC_ASSOCIATION_RETAIN );
[popdownVC willMoveToParentViewController:nil];
[UIView animateWithDuration:0.3f delay:0 options:UIViewAnimationOptionOverrideInheritedDuration animations:^{

View File

@@ -31,6 +31,7 @@
inf( @"Preferences will appear" );
[super viewWillAppear:animated];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"tipped.passwordsPreferences"];
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForMainThread];
self.generatedTypeControl.selectedSegmentIndex = [self generatedSegmentIndexForType:activeUser.defaultType];

View File

@@ -21,6 +21,7 @@
@interface MPSetupViewController : UIViewController
@property(weak, nonatomic) IBOutlet UISwitch *rememberLoginSwitch;
@property(weak, nonatomic) IBOutlet UISwitch *showPasswordsSwitch;
- (IBAction)close:(UIBarButtonItem *)sender;

View File

@@ -28,6 +28,8 @@
if (self.rememberLoginSwitch)
self.rememberLoginSwitch.on = [[MPiOSConfig get].rememberLogin boolValue];
if (self.showPasswordsSwitch)
self.showPasswordsSwitch.on = ![[MPiOSConfig get].hidePasswords boolValue];
}
- (void)viewWillDisappear:(BOOL)animated {
@@ -36,6 +38,8 @@
if (self.rememberLoginSwitch)
[MPiOSConfig get].rememberLogin = @(self.rememberLoginSwitch.on);
if (self.showPasswordsSwitch)
[MPiOSConfig get].hidePasswords = @(!self.showPasswordsSwitch.on);
}
- (IBAction)close:(UIBarButtonItem *)sender {

View File

@@ -17,8 +17,12 @@
@property(weak, nonatomic) IBOutlet MPStoreProductCell *iOSIntegrationCell;
@property(weak, nonatomic) IBOutlet MPStoreProductCell *touchIDCell;
@property(weak, nonatomic) IBOutlet MPStoreProductCell *fuelCell;
@property(weak, nonatomic) IBOutlet UITableViewCell *loadingCell;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *fuelMeterConstraint;
@property(weak, nonatomic) IBOutlet UIButton *fuelSpeedButton;
@property(weak, nonatomic) IBOutlet UILabel *fuelStatusLabel;
+ (NSString *)latestStoreFeatures;
@end

View File

@@ -10,6 +10,7 @@
#import "MPiOSAppDelegate.h"
#import "UIColor+Expanded.h"
#import "MPAppDelegate_InApp.h"
#import "MPPasswordsViewController.h"
PearlEnum( MPDevelopmentFuelConsumption,
MPDevelopmentFuelConsumptionQuarterly, MPDevelopmentFuelConsumptionMonthly, MPDevelopmentFuelWeekly );
@@ -23,6 +24,22 @@ PearlEnum( MPDevelopmentFuelConsumption,
@implementation MPStoreViewController
+ (NSString *)latestStoreFeatures {
NSMutableString *features = [NSMutableString string];
NSArray *storeVersions = @[
@"Generated Usernames\nSecurity Question Answers"
];
NSInteger storeVersion = [[NSUserDefaults standardUserDefaults] integerForKey:@"storeVersion"];
for (; storeVersion < [storeVersions count]; ++storeVersion)
[features appendFormat:@"%@\n", storeVersions[storeVersion]];
if (![features length])
return nil;
[[NSUserDefaults standardUserDefaults] setInteger:storeVersion forKey:@"storeVersion"];
return features;
}
- (void)viewDidLoad {
[super viewDidLoad];
@@ -32,7 +49,6 @@ PearlEnum( MPDevelopmentFuelConsumption,
self.tableView.tableHeaderView = [UIView new];
self.tableView.tableFooterView = [UIView new];
self.tableView.estimatedRowHeight = 400;
self.view.backgroundColor = [UIColor clearColor];
}
@@ -42,7 +58,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
self.tableView.contentInset = UIEdgeInsetsMake( 64, 0, 49, 0 );
[self reloadCellsHiding:self.allCellsBySection[0] showing:nil];
[self reloadCellsHiding:self.allCellsBySection[0] showing:@[ self.loadingCell ]];
[self.allCellsBySection[0] enumerateObjectsUsingBlock:^(MPStoreProductCell *cell, NSUInteger idx, BOOL *stop) {
if ([cell isKindOfClass:[MPStoreProductCell class]]) {
cell.purchasedIndicator.alpha = 0;
@@ -66,21 +82,26 @@ PearlEnum( MPDevelopmentFuelConsumption,
PearlRemoveNotificationObservers();
}
#pragma mark - UITableViewDelegate
#pragma mark - UITableViewDataSource
- (MPStoreProductCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MPStoreProductCell *cell = (MPStoreProductCell *)[super tableView:tableView cellForRowAtIndexPath:indexPath];
if (cell.contentView.translatesAutoresizingMaskIntoConstraints) {
cell.contentView.translatesAutoresizingMaskIntoConstraints = NO;
[cell addConstraint:
[NSLayoutConstraint constraintWithItem:cell attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual
toItem:cell.contentView attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
[cell addConstraints:@[
[NSLayoutConstraint constraintWithItem:cell attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
toItem:cell.contentView attribute:NSLayoutAttributeTop multiplier:1 constant:0],
[NSLayoutConstraint constraintWithItem:cell attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
toItem:cell.contentView attribute:NSLayoutAttributeRight multiplier:1 constant:0],
[NSLayoutConstraint constraintWithItem:cell attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
toItem:cell.contentView attribute:NSLayoutAttributeLeft multiplier:1 constant:0],
]];
}
if (indexPath.section == 0)
cell.selectionStyle = [[MPiOSAppDelegate get] isFeatureUnlocked:[self productForCell:cell].productIdentifier]?
UITableViewCellSelectionStyleDefault: UITableViewCellSelectionStyleNone;
UITableViewCellSelectionStyleNone: UITableViewCellSelectionStyleDefault;
if (cell.selectionStyle != UITableViewCellSelectionStyleNone) {
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.bounds];
@@ -90,28 +111,30 @@ PearlEnum( MPDevelopmentFuelConsumption,
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
[cell layoutIfNeeded];
[cell layoutIfNeeded];
return cell.contentView.bounds.size.height;
dbg_return_tr( cell.contentView.bounds.size.height, @, indexPath );
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (![[MPAppDelegate_Shared get] canMakePayments]) {
[PearlAlert showAlertWithTitle:@"Store Not Set Up" message:
@"Try logging using the App Store or from Settings."
viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:nil cancelTitle:@"Thanks" otherTitles:nil];
return;
}
MPStoreProductCell *cell = (MPStoreProductCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
SKProduct *product = [self productForCell:cell];
if (cell.selectionStyle == UITableViewCellSelectionStyleNone)
return;
if (product)
SKProduct *product = [self productForCell:cell];
if (product && ![[MPAppDelegate_Shared get] isFeatureUnlocked:product.productIdentifier])
[[MPAppDelegate_Shared get] purchaseProductWithIdentifier:product.productIdentifier
quantity:[self quantityForProductIdentifier:product.productIdentifier]];
@@ -140,6 +163,12 @@ PearlEnum( MPDevelopmentFuelConsumption,
} cancelTitle:@"Cancel" otherTitles:@"Find Purchases", nil];
}
- (IBAction)sendThanks:(id)sender {
[[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender:
[NSURL URLWithString:@"http://thanks.lhunath.com"]];
}
#pragma mark - MPInAppDelegate
- (void)updateWithProducts:(NSArray *)products {
@@ -176,6 +205,18 @@ PearlEnum( MPDevelopmentFuelConsumption,
#pragma mark - Private
- (MPPasswordsViewController *)dismissPopup {
for (UIViewController *vc = self; (vc = vc.parentViewController);)
if ([vc isKindOfClass:[MPPasswordsViewController class]]) {
MPPasswordsViewController *passwordsVC = (MPPasswordsViewController *)vc;
[passwordsVC dismissPopdown:self];
return passwordsVC;
}
return nil;
}
- (SKProduct *)productForCell:(MPStoreProductCell *)cell {
for (SKProduct *product in self.products)
@@ -191,6 +232,10 @@ PearlEnum( MPDevelopmentFuelConsumption,
return self.generateLoginCell;
if ([productIdentifier isEqualToString:MPProductGenerateAnswers])
return self.generateAnswersCell;
if ([productIdentifier isEqualToString:MPProductOSIntegration])
return self.iOSIntegrationCell;
if ([productIdentifier isEqualToString:MPProductTouchID])
return self.touchIDCell;
if ([productIdentifier isEqualToString:MPProductFuel])
return self.fuelCell;
@@ -202,33 +247,41 @@ PearlEnum( MPDevelopmentFuelConsumption,
NSMutableArray *showCells = [NSMutableArray array];
NSMutableArray *hideCells = [NSMutableArray array];
[hideCells addObjectsFromArray:self.allCellsBySection[0]];
[hideCells addObject:self.loadingCell];
for (SKProduct *product in self.products) {
[self showCellForProductWithIdentifier:MPProductGenerateLogins ifProduct:product showingCells:showCells];
[self showCellForProductWithIdentifier:MPProductGenerateAnswers ifProduct:product showingCells:showCells];
[self showCellForProductWithIdentifier:MPProductOSIntegration ifProduct:product showingCells:showCells];
[self showCellForProductWithIdentifier:MPProductTouchID ifProduct:product showingCells:showCells];
[self showCellForProductWithIdentifier:MPProductFuel ifProduct:product showingCells:showCells];
}
[hideCells removeObjectsInArray:showCells];
if ([self.tableView numberOfRowsInSection:0])
[self updateCellsHiding:hideCells showing:showCells animation:UITableViewRowAnimationAutomatic];
else
[self updateCellsHiding:hideCells showing:showCells animation:UITableViewRowAnimationNone];
[self reloadCellsHiding:hideCells showing:showCells];
}
- (void)updateFuel {
CGFloat weeklyFuelConsumption = [self weeklyFuelConsumption]; /* consume x fuel / week */
CGFloat fuel = [[MPiOSConfig get].developmentFuel floatValue]; /* x fuel left */
NSTimeInterval fuelSecondsElapsed = [[MPiOSConfig get].developmentFuelChecked timeIntervalSinceNow];
if (fuelSecondsElapsed > 3600) {
CGFloat fuelRemaining = [[MPiOSConfig get].developmentFuelRemaining floatValue]; /* x fuel left */
CGFloat fuelInvested = [[MPiOSConfig get].developmentFuelInvested floatValue]; /* x fuel left */
NSDate *now = [NSDate date];
NSTimeInterval fuelSecondsElapsed = -[[MPiOSConfig get].developmentFuelChecked timeIntervalSinceDate:now];
if (fuelSecondsElapsed > 3600 || ![MPiOSConfig get].developmentFuelChecked) {
NSTimeInterval weeksElapsed = fuelSecondsElapsed / (3600 * 24 * 7 /* 1 week */); /* x weeks elapsed */
fuel -= weeklyFuelConsumption * weeksElapsed;
[MPiOSConfig get].developmentFuel = @(fuel);
NSTimeInterval fuelConsumed = weeklyFuelConsumption * weeksElapsed;
fuelRemaining -= fuelConsumed;
fuelInvested += fuelConsumed;
[MPiOSConfig get].developmentFuelChecked = now;
[MPiOSConfig get].developmentFuelRemaining = @(fuelRemaining);
[MPiOSConfig get].developmentFuelInvested = @(fuelInvested);
}
CGFloat fuelRatio = weeklyFuelConsumption == 0? 0: fuel / weeklyFuelConsumption; /* x weeks worth of fuel left */
CGFloat fuelRatio = weeklyFuelConsumption == 0? 0: fuelRemaining / weeklyFuelConsumption; /* x weeks worth of fuel left */
[self.fuelMeterConstraint updateConstant:MIN( 0.5f, fuelRatio - 0.5f ) * 160]; /* -80pt = 0 weeks left, 80pt = >=1 week left */
self.fuelStatusLabel.text = strf( @"fuel left: %0.1f work hours\ninvested: %0.1f work hours", fuelRemaining, fuelInvested );
self.fuelStatusLabel.hidden = (fuelRemaining + fuelInvested) == 0;
}
- (CGFloat)weeklyFuelConsumption {
@@ -267,7 +320,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
- (NSInteger)quantityForProductIdentifier:(NSString *)productIdentifier {
if ([productIdentifier isEqualToString:MPProductFuel])
return (NSInteger)(MP_FUEL_HOURLY_RATE * [self weeklyFuelConsumption]);
return (NSInteger)(MP_FUEL_HOURLY_RATE * [self weeklyFuelConsumption] + .5f);
return 1;
}

View File

@@ -16,25 +16,27 @@
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
@interface MPUsersViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UITextFieldDelegate>
@property(weak, nonatomic) IBOutlet UIView *userSelectionContainer;
@property(weak, nonatomic) IBOutlet UIButton *marqueeButton;
@property(weak, nonatomic) IBOutlet UIView *gitTipTip;
@property(weak, nonatomic) IBOutlet UITextField *entryField;
@property(weak, nonatomic) IBOutlet UILabel *entryLabel;
@property(weak, nonatomic) IBOutlet UILabel *entryTipTitleLabel;
@property(weak, nonatomic) IBOutlet UILabel *entryTipSubtitleLabel;
@property(weak, nonatomic) IBOutlet UIView *entryTipContainer;
@property(weak, nonatomic) IBOutlet UIView *entryContainer;
@property(weak, nonatomic) IBOutlet UIView *footerContainer;
@property(weak, nonatomic) IBOutlet UIActivityIndicatorView *storeLoadingActivity;
@property(weak, nonatomic) IBOutlet UICollectionView *avatarCollectionView;
@property (strong, nonatomic) IBOutlet UIButton *nextAvatarButton;
@property (strong, nonatomic) IBOutlet UIButton *previousAvatarButton;
@property(weak, nonatomic) IBOutlet UIView *avatarTipContainer;
@property(weak, nonatomic) IBOutlet UIView *entryTipContainer;
@property(weak, nonatomic) IBOutlet UIView *preferencesTipContainer;
@property(weak, nonatomic) IBOutlet UIView *thanksTipContainer;
@property(weak, nonatomic) IBOutlet UIButton *nextAvatarButton;
@property(weak, nonatomic) IBOutlet UIButton *previousAvatarButton;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *keyboardHeightConstraint;
@property(assign, nonatomic) BOOL active;
@property(assign, nonatomic, readonly) BOOL active;
- (void)setActive:(BOOL)active animated:(BOOL)animated;
- (IBAction)changeAvatar:(UIButton *)sender;

View File

@@ -24,6 +24,13 @@
#import "MPAppDelegate_Key.h"
#import "MPWebViewController.h"
typedef NS_OPTIONS( NSUInteger, MPUsersTips ) {
MPUsersThanksTip = 1 << 0,
MPUsersAvatarTip = 1 << 1,
MPUsersMasterPasswordTip = 1 << 2,
MPUsersPreferencesTip = 1 << 3,
};
typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
/** The users are all inactive */
MPActiveUserStateNone,
@@ -69,7 +76,11 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
self.avatarCollectionView.allowsMultipleSelection = YES;
[self.entryField addTarget:self action:@selector( textFieldEditingChanged: ) forControlEvents:UIControlEventEditingChanged];
self.preferencesTipContainer.alpha = 0;
[self setActive:YES animated:NO];
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"tipped.thanks"])
[self showTips:MPUsersThanksTip];
}
- (void)viewWillAppear:(BOOL)animated {
@@ -391,34 +402,23 @@ referenceSizeForFooterInSection:(NSInteger)section {
if (buttonIndex == [sheet destructiveButtonIndex]) {
// Delete User
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity *user_ = [MPUserEntity existingObjectWithID:userID inContext:context];
if (!user_)
return;
[context deleteObject:user_];
[context saveToStore];
[self reloadUsers]; // I do NOT understand why our ObjectsDidChangeNotification isn't firing on saveToStore.
}];
[PearlAlert showParentalGateWithTitle:@"Deleting User" message:
@"The user and its sites will be deleted.\nPlease confirm by solving:"
completion:^(BOOL continuing) {
if (continuing)
[self deleteUser:userID];
}];
return;
}
if (buttonIndex == [sheet firstOtherButtonIndex])
// Reset Password
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity *user_ = [MPUserEntity existingObjectWithID:userID inContext:context];
if (!user_)
return;
[[MPiOSAppDelegate get] changeMasterPasswordFor:user_ saveInContext:context didResetBlock:^{
PearlMainQueue( ^{
NSIndexPath *avatarIndexPath = [self.avatarCollectionView indexPathForCell:avatarCell];
[self.avatarCollectionView selectItemAtIndexPath:avatarIndexPath animated:NO
scrollPosition:UICollectionViewScrollPositionNone];
[self collectionView:self.avatarCollectionView didSelectItemAtIndexPath:avatarIndexPath];
} );
}];
}];
[PearlAlert showParentalGateWithTitle:@"Resetting User" message:
@"The user's master password will be reset.\nPlease confirm by solving:"
completion:^(BOOL continuing) {
if (continuing)
[self resetUser:userID avatar:avatarCell];
}];
} cancelTitle:[PearlStrings get].commonButtonCancel
destructiveTitle:@"Delete User" otherTitles:@"Reset Password", nil];
}
@@ -441,6 +441,66 @@ referenceSizeForFooterInSection:(NSInteger)section {
#pragma mark - Private
- (void)deleteUser:(NSManagedObjectID *)userID {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity
*user_ = [MPUserEntity existingObjectWithID:userID inContext:context];
if (!user_)
return;
[context deleteObject:user_];
[context saveToStore];
[self reloadUsers]; // I do NOT understand why our ObjectsDidChangeNotification isn't firing on saveToStore.
}];
}
- (void)resetUser:(NSManagedObjectID *)userID avatar:(MPAvatarCell *)avatarCell {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity *user_ = [MPUserEntity existingObjectWithID:userID inContext:context];
if (!user_)
return;
[[MPiOSAppDelegate get] changeMasterPasswordFor:user_ saveInContext:context didResetBlock:^{
PearlMainQueue( ^{
NSIndexPath *avatarIndexPath = [self.avatarCollectionView indexPathForCell:avatarCell];
[self.avatarCollectionView selectItemAtIndexPath:avatarIndexPath animated:NO
scrollPosition:UICollectionViewScrollPositionNone];
[self collectionView:self.avatarCollectionView didSelectItemAtIndexPath:avatarIndexPath];
} );
}];
}];
}
- (void)showTips:(MPUsersTips)showTips {
[UIView animateWithDuration:0.3f animations:^{
if (showTips & MPUsersThanksTip)
self.thanksTipContainer.alpha = 1;
if (showTips & MPUsersAvatarTip)
self.avatarTipContainer.alpha = 1;
if (showTips & MPUsersMasterPasswordTip)
self.entryTipContainer.alpha = 1;
if (showTips & MPUsersPreferencesTip)
self.preferencesTipContainer.alpha = 1;
} completion:^(BOOL finished) {
if (finished)
PearlMainQueueAfter( 5, ^{
[UIView animateWithDuration:0.3f animations:^{
if (showTips & MPUsersThanksTip)
self.thanksTipContainer.alpha = 0;
if (showTips & MPUsersAvatarTip)
self.avatarTipContainer.alpha = 0;
if (showTips & MPUsersMasterPasswordTip)
self.entryTipContainer.alpha = 0;
if (showTips & MPUsersPreferencesTip)
self.preferencesTipContainer.alpha = 0;
}];
} );
}];
}
- (void)showEntryTip:(NSString *)message {
NSUInteger newlineIndex = [message rangeOfString:@"\n"].location;
@@ -448,17 +508,7 @@ referenceSizeForFooterInSection:(NSInteger)section {
NSString *messageSubtitle = newlineIndex == NSNotFound? nil: [message substringFromIndex:newlineIndex];
self.entryTipTitleLabel.text = messageTitle;
self.entryTipSubtitleLabel.text = messageSubtitle;
[UIView animateWithDuration:0.3f animations:^{
self.entryTipContainer.alpha = 1;
} completion:^(BOOL finished) {
if (finished)
PearlMainQueueAfter( 4, ^{
[UIView animateWithDuration:0.3f animations:^{
self.entryTipContainer.alpha = 0;
}];
} );
}];
[self showTips:MPUsersMasterPasswordTip];
}
- (void)firedMarqueeTimer:(NSTimer *)timer {
@@ -599,6 +649,12 @@ referenceSizeForFooterInSection:(NSInteger)section {
self.userSelectionContainer.alpha = 1;
}];
} );
PearlAddNotificationObserver( UIKeyboardWillShowNotification, nil, [NSOperationQueue mainQueue],
^(MPUsersViewController *self, NSNotification *note) {
CGRect keyboardRect = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat keyboardHeight = CGRectGetHeight( self.view.window.screen.bounds ) - CGRectGetMinY( keyboardRect );
[self.keyboardHeightConstraint updateConstant:keyboardHeight];
} );
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
[UIView animateWithDuration:0.3f animations:^{
@@ -610,16 +666,16 @@ referenceSizeForFooterInSection:(NSInteger)section {
[self.storeLoadingActivity startAnimating];
if (mainContext)
PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, mainContext, [NSOperationQueue mainQueue],
^(MPUsersViewController *self, NSNotification *note) {
NSSet *insertedObjects = note.userInfo[NSInsertedObjectsKey];
NSSet *deletedObjects = note.userInfo[NSDeletedObjectsKey];
if ([[NSSetUnion( insertedObjects, deletedObjects )
filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [evaluatedObject isKindOfClass:[MPUserEntity class]];
}]] count])
[self reloadUsers];
} );
PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, mainContext, [NSOperationQueue mainQueue],
^(MPUsersViewController *self, NSNotification *note) {
NSSet *insertedObjects = note.userInfo[NSInsertedObjectsKey];
NSSet *deletedObjects = note.userInfo[NSDeletedObjectsKey];
if ([[NSSetUnion( insertedObjects, deletedObjects )
filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [evaluatedObject isKindOfClass:[MPUserEntity class]];
}]] count])
[self reloadUsers];
} );
PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, nil, [NSOperationQueue mainQueue],
^(MPUsersViewController *self, NSNotification *note) {
self.userIDs = nil;
@@ -657,11 +713,6 @@ referenceSizeForFooterInSection:(NSInteger)section {
#pragma mark - Properties
- (void)setActive:(BOOL)active {
[self setActive:active animated:NO];
}
- (void)setActive:(BOOL)active animated:(BOOL)animated {
_active = active;
@@ -777,6 +828,29 @@ referenceSizeForFooterInSection:(NSInteger)section {
}
}
// Manage tip visibility.
switch (activeUserState) {
case MPActiveUserStateNone:
case MPActiveUserStateMasterPasswordConfirmation:
case MPActiveUserStateLogin: {
break;
}
case MPActiveUserStateUserName: {
[self showTips:MPUsersAvatarTip];
break;
}
case MPActiveUserStateMasterPasswordChoice: {
[self showEntryTip:strl( @"A short phrase makes a strong, memorable password." )];
break;
}
case MPActiveUserStateMinimized: {
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"tipped.passwordsPreferences"])
[self showTips:MPUsersPreferencesTip];
break;
}
}
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
[_afterUpdates setSuspended:NO];

View File

@@ -50,6 +50,9 @@
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
if ([[request.URL absoluteString] rangeOfString:@"thanks.lhunath.com"].location != NSNotFound)
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"tipped.thanks"];
if ([request.URL isEqual:request.mainDocumentURL]) {
self.webNavigationItem.title = request.URL.host;
self.webNavigationItem.prompt = strl( @"Loading" );

View File

@@ -10,6 +10,7 @@
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "IASKSettingsReader.h"
#import "MPStoreViewController.h"
@interface MPiOSAppDelegate()<UIDocumentInteractionControllerDelegate>
@@ -130,6 +131,14 @@
[self.navigationController performSegueWithIdentifier:@"setup" sender:self];
} );
NSString *latestFeatures = [MPStoreViewController latestStoreFeatures];
if (latestFeatures)
[PearlAlert showAlertWithTitle:@"New Features" message:
strf( @"The following features are now available in the store:\n\n%@•••\n\n"
@"Find the store from the user pulldown after logging in.", latestFeatures )
viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil
cancelTitle:@"Thanks" otherTitles:nil];
MPCheckpoint( MPCheckpointStarted, @{
@"simulator" : PearlStringB( [PearlDeviceUtils isSimulator] ),
@"encrypted" : PearlStringB( [PearlDeviceUtils isAppEncrypted] ),
@@ -286,7 +295,8 @@
NSString *importHeader = @"# Master Password site export";
NSString *importedSitesString = [UIPasteboard generalPasteboard].string;
if ([[importedSitesString substringToIndex:[importHeader length]] isEqualToString:importHeader])
if ([importedSitesString length] > [importHeader length] &&
[[importedSitesString substringToIndex:[importHeader length]] isEqualToString:importHeader])
[PearlAlert showAlertWithTitle:@"Import Sites?" message:
@"We've detected Master Password import sites on your pasteboard, would you like to import them?"
viewStyle:UIAlertViewStyleDefault initAlert:nil

View File

@@ -18,7 +18,8 @@
@property(nonatomic, retain) NSNumber *loginNameTipShown;
@property(nonatomic, retain) NSNumber *traceMode;
@property(nonatomic, retain) NSNumber *dictationSearch;
@property(nonatomic, retain) NSNumber *developmentFuel;
@property(nonatomic, retain) NSNumber *developmentFuelRemaining;
@property(nonatomic, retain) NSNumber *developmentFuelInvested;
@property(nonatomic, retain) NSNumber *developmentFuelConsumption;
@property(nonatomic, retain) NSDate *developmentFuelChecked;

View File

@@ -9,7 +9,7 @@
@implementation MPiOSConfig
@dynamic helpHidden, siteInfoHidden, showSetup, actionsTipShown, typeTipShown, loginNameTipShown, traceMode, dictationSearch;
@dynamic developmentFuel, developmentFuelConsumption, developmentFuelChecked;
@dynamic developmentFuelRemaining, developmentFuelInvested, developmentFuelConsumption, developmentFuelChecked;
- (id)init {

View File

@@ -14,7 +14,9 @@
<string>mpsites</string>
</array>
<key>CFBundleTypeIconFiles</key>
<array/>
<array>
<string>Icon-Small</string>
</array>
<key>CFBundleTypeName</key>
<string>Master Password sites</string>
<key>LSHandlerRank</key>
@@ -44,7 +46,7 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>© 2011-2013, Lyndir</string>
<string>© 2011-2014, Lyndir</string>
<key>UIAppFonts</key>
<array>
<string>Exo2.0-Bold.otf</string>
@@ -105,9 +107,9 @@
<key>UTTypeIdentifier</key>
<string>com.lyndir.masterpassword.sites</string>
<key>UTTypeSize320IconFile</key>
<string></string>
<string>Icon-320.png</string>
<key>UTTypeSize64IconFile</key>
<string></string>
<string>Icon-64.png</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>

View File

@@ -13,6 +13,7 @@
93D39262A8A97DB748213309 /* PearlEMail.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D393BB973253D4BAAC84AA /* PearlEMail.m */; };
93D392A8777DC30C11361647 /* UITextView+PearlAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39AA10CD00D05937671B1 /* UITextView+PearlAttributes.h */; };
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */; };
93D392FD5E2052F7D7DB3774 /* NSString+MPMarkDown.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39C41A27AA42D044D68AE /* NSString+MPMarkDown.m */; };
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */; };
93D39392DEDA376F93C6C718 /* MPCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39BAA71DE51B4D8A1286C /* MPCell.m */; };
93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3957D76F71A652716EECC /* MPStoreViewController.m */; };
@@ -57,28 +58,13 @@
DA071BF3190187FE00179766 /* empty@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA071BF1190187FE00179766 /* empty@2x.png */; };
DA071BF4190187FE00179766 /* empty.png in Resources */ = {isa = PBXBuildFile; fileRef = DA071BF2190187FE00179766 /* empty.png */; };
DA095E75172F4CD8001C948B /* MPLogsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3979190DACEBD1F6AE9F4 /* MPLogsViewController.m */; };
DA2509FD1956484D00AC23F1 /* image-10@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509E31956484D00AC23F1 /* image-10@2x.png */; };
DA2509FE1956484D00AC23F1 /* image-10.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509E41956484D00AC23F1 /* image-10.png */; };
DA2509FF1956484D00AC23F1 /* image-9@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509E51956484D00AC23F1 /* image-9@2x.png */; };
DA250A001956484D00AC23F1 /* image-9.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509E61956484D00AC23F1 /* image-9.png */; };
DA250A011956484D00AC23F1 /* image-8@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509E71956484D00AC23F1 /* image-8@2x.png */; };
DA250A021956484D00AC23F1 /* image-8.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509E81956484D00AC23F1 /* image-8.png */; };
DA250A031956484D00AC23F1 /* image-7@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509E91956484D00AC23F1 /* image-7@2x.png */; };
DA250A041956484D00AC23F1 /* image-7.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509EA1956484D00AC23F1 /* image-7.png */; };
DA250A051956484D00AC23F1 /* image-6@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509EB1956484D00AC23F1 /* image-6@2x.png */; };
DA250A061956484D00AC23F1 /* image-6.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509EC1956484D00AC23F1 /* image-6.png */; };
DA250A071956484D00AC23F1 /* image-5@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509ED1956484D00AC23F1 /* image-5@2x.png */; };
DA250A081956484D00AC23F1 /* image-5.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509EE1956484D00AC23F1 /* image-5.png */; };
DA250A091956484D00AC23F1 /* image-4@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509EF1956484D00AC23F1 /* image-4@2x.png */; };
DA250A0A1956484D00AC23F1 /* image-4.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509F01956484D00AC23F1 /* image-4.png */; };
DA250A0B1956484D00AC23F1 /* image-3@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509F11956484D00AC23F1 /* image-3@2x.png */; };
DA250A0C1956484D00AC23F1 /* image-3.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509F21956484D00AC23F1 /* image-3.png */; };
DA250A0D1956484D00AC23F1 /* image-2@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509F31956484D00AC23F1 /* image-2@2x.png */; };
DA250A0E1956484D00AC23F1 /* image-2.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509F41956484D00AC23F1 /* image-2.png */; };
DA250A0F1956484D00AC23F1 /* image-1@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509F51956484D00AC23F1 /* image-1@2x.png */; };
DA250A101956484D00AC23F1 /* image-1.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509F61956484D00AC23F1 /* image-1.png */; };
DA250A111956484D00AC23F1 /* image-0@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509F71956484D00AC23F1 /* image-0@2x.png */; };
DA250A121956484D00AC23F1 /* image-0.png in Resources */ = {isa = PBXBuildFile; fileRef = DA2509F81956484D00AC23F1 /* image-0.png */; };
DA24EBAE19DAD08900FF010B /* tip_basic_black_top.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38941711E29700CF925C /* tip_basic_black_top.png */; };
DA24EBAF19DAD08C00FF010B /* tip_basic_black_top@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38951711E29700CF925C /* tip_basic_black_top@2x.png */; };
DA24EBE819DAD6DE00FF010B /* Icon-320.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBE619DAD6DE00FF010B /* Icon-320.png */; };
DA24EBE919DAD6DE00FF010B /* Icon-64.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBE719DAD6DE00FF010B /* Icon-64.png */; };
DA24EBEA19DAD6EE00FF010B /* Icon-Small.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBBA19DAD4D000FF010B /* Icon-Small.png */; };
DA24EBEB19DAD6EE00FF010B /* Icon-Small@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBBB19DAD4D000FF010B /* Icon-Small@2x.png */; };
DA24EBEC19DAD6EE00FF010B /* Icon-Small@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBBC19DAD4D000FF010B /* Icon-Small@3x.png */; };
DA250A17195665A100AC23F1 /* UITableView+PearlReloadFromArray.m in Sources */ = {isa = PBXBuildFile; fileRef = DA250A13195665A100AC23F1 /* UITableView+PearlReloadFromArray.m */; };
DA250A18195665A100AC23F1 /* UITableView+PearlReloadFromArray.h in Headers */ = {isa = PBXBuildFile; fileRef = DA250A14195665A100AC23F1 /* UITableView+PearlReloadFromArray.h */; };
DA250A19195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m in Sources */ = {isa = PBXBuildFile; fileRef = DA250A15195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m */; };
@@ -136,6 +122,9 @@
DA32D05119D3D107004F3F0E /* icon_meter.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37BA1711E29600CF925C /* icon_meter.png */; };
DA32D05219D3D107004F3F0E /* icon_meter@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37BB1711E29600CF925C /* icon_meter@2x.png */; };
DA32D05519D741DC004F3F0E /* MPSiteQuestionEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA32D05419D741DC004F3F0E /* MPSiteQuestionEntity.m */; };
DA32D07A19D7D784004F3F0E /* background@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D07719D7D784004F3F0E /* background@3x.png */; };
DA32D07B19D7D784004F3F0E /* background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D07819D7D784004F3F0E /* background@2x.png */; };
DA32D07C19D7D784004F3F0E /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D07919D7D784004F3F0E /* background.png */; };
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3509FC15F101A500C14A8E /* PearlQueue.h */; };
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3509FD15F101A500C14A8E /* PearlQueue.m */; };
DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */; };
@@ -187,6 +176,38 @@
DAA141201922FF020032B392 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA1411C1922FF020032B392 /* PearlTween.m */; };
DAA141211922FF020032B392 /* PearlTween.h in Headers */ = {isa = PBXBuildFile; fileRef = DAA1411D1922FF020032B392 /* PearlTween.h */; };
DAA141221922FF020032B392 /* map-macro.h in Headers */ = {isa = PBXBuildFile; fileRef = DAA1411F1922FF020032B392 /* map-macro.h */; };
DAA175F519D86C620044227B /* markdown_lib.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA175B719D86C620044227B /* markdown_lib.m */; };
DAA175F619D86C620044227B /* markdown_output.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA175B819D86C620044227B /* markdown_output.m */; };
DAA175F719D86C620044227B /* markdown_parser.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA175BA19D86C620044227B /* markdown_parser.m */; };
DAA1761B19D86D0D0044227B /* libAttributedMarkdown.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA1757D19D86BE70044227B /* libAttributedMarkdown.a */; };
DAA1762319D89B600044227B /* thumb_touch_id@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1761D19D89B600044227B /* thumb_touch_id@3x.png */; };
DAA1762419D89B610044227B /* thumb_touch_id@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1761E19D89B600044227B /* thumb_touch_id@2x.png */; };
DAA1762519D89B610044227B /* thumb_touch_id.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1761F19D89B600044227B /* thumb_touch_id.png */; };
DAA1762619D89B610044227B /* thumb_ios_integration@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1762019D89B600044227B /* thumb_ios_integration@3x.png */; };
DAA1762719D89B610044227B /* thumb_ios_integration@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1762119D89B600044227B /* thumb_ios_integration@2x.png */; };
DAA1762819D89B610044227B /* thumb_ios_integration.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1762219D89B600044227B /* thumb_ios_integration.png */; };
DAA1763F19D8B82B0044227B /* site_new@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1762919D8B82B0044227B /* site_new@2x.png */; };
DAA1764019D8B82B0044227B /* site_new.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1762A19D8B82B0044227B /* site_new.png */; };
DAA1764119D8B82B0044227B /* settings@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1762B19D8B82B0044227B /* settings@2x.png */; };
DAA1764219D8B82B0044227B /* settings.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1762C19D8B82B0044227B /* settings.png */; };
DAA1764319D8B82B0044227B /* personal_pw@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1762D19D8B82B0044227B /* personal_pw@2x.png */; };
DAA1764419D8B82B0044227B /* personal_pw.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1762E19D8B82B0044227B /* personal_pw.png */; };
DAA1764519D8B82B0044227B /* name_new@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1762F19D8B82B0044227B /* name_new@2x.png */; };
DAA1764619D8B82B0044227B /* name_new.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763019D8B82B0044227B /* name_new.png */; };
DAA1764719D8B82B0044227B /* mpw_new@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763119D8B82B0044227B /* mpw_new@2x.png */; };
DAA1764819D8B82B0044227B /* mpw_new.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763219D8B82B0044227B /* mpw_new.png */; };
DAA1764919D8B82B0044227B /* login_new@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763319D8B82B0044227B /* login_new@2x.png */; };
DAA1764A19D8B82B0044227B /* login_new.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763419D8B82B0044227B /* login_new.png */; };
DAA1764B19D8B82B0044227B /* login_name@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763519D8B82B0044227B /* login_name@2x.png */; };
DAA1764C19D8B82B0044227B /* login_name.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763619D8B82B0044227B /* login_name.png */; };
DAA1764D19D8B82B0044227B /* initial@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763719D8B82B0044227B /* initial@2x.png */; };
DAA1764E19D8B82B0044227B /* initial.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763819D8B82B0044227B /* initial.png */; };
DAA1764F19D8B82B0044227B /* counter@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763919D8B82B0044227B /* counter@2x.png */; };
DAA1765019D8B82B0044227B /* counter.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763A19D8B82B0044227B /* counter.png */; };
DAA1765119D8B82B0044227B /* copy_pw@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763B19D8B82B0044227B /* copy_pw@2x.png */; };
DAA1765219D8B82B0044227B /* copy_pw.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763C19D8B82B0044227B /* copy_pw.png */; };
DAA1765319D8B82B0044227B /* choose_type@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763D19D8B82B0044227B /* choose_type@2x.png */; };
DAA1765419D8B82B0044227B /* choose_type.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763E19D8B82B0044227B /* choose_type.png */; };
DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DABB981515100B4000B05417 /* SystemConfiguration.framework */; };
DABD39371711E29700CF925C /* avatar-0.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366C1711E29400CF925C /* avatar-0.png */; };
DABD39381711E29700CF925C /* avatar-0@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366D1711E29400CF925C /* avatar-0@2x.png */; };
@@ -226,8 +247,6 @@
DABD395A1711E29700CF925C /* avatar-8@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD368F1711E29400CF925C /* avatar-8@2x.png */; };
DABD395B1711E29700CF925C /* avatar-9.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD36901711E29400CF925C /* avatar-9.png */; };
DABD395C1711E29700CF925C /* avatar-9@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD36911711E29400CF925C /* avatar-9@2x.png */; };
DABD395D1711E29700CF925C /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD36931711E29400CF925C /* background.png */; };
DABD395E1711E29700CF925C /* background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD36941711E29400CF925C /* background@2x.png */; };
DABD39871711E29700CF925C /* SourceCodePro-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = DABD36BF1711E29500CF925C /* SourceCodePro-Black.otf */; };
DABD39881711E29700CF925C /* SourceCodePro-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = DABD36C01711E29500CF925C /* SourceCodePro-ExtraLight.otf */; };
DABD39A01711E29700CF925C /* icon_action.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD36DA1711E29500CF925C /* icon_action.png */; };
@@ -420,6 +439,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
DAA1757B19D86BE70044227B /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
@@ -441,6 +469,7 @@
93D393310223DDB35218467A /* MPCombinedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCombinedViewController.m; sourceTree = "<group>"; };
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; };
93D393CB0B1F4EC8C17CFE43 /* NSString+MPMarkDown.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+MPMarkDown.h"; sourceTree = "<group>"; };
93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = "<group>"; };
93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIResponder+PearlFirstResponder.h"; sourceTree = "<group>"; };
@@ -477,6 +506,7 @@
93D39B381350802A194BF332 /* MPAvatarCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAvatarCell.m; sourceTree = "<group>"; };
93D39B455A71EC98C749E623 /* MPOverlayViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOverlayViewController.h; sourceTree = "<group>"; };
93D39BAA71DE51B4D8A1286C /* MPCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCell.m; sourceTree = "<group>"; };
93D39C41A27AA42D044D68AE /* NSString+MPMarkDown.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+MPMarkDown.m"; sourceTree = "<group>"; };
93D39C426E03358384018E85 /* MPAnswersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAnswersViewController.m; sourceTree = "<group>"; };
93D39C44361BE57AF0B3071F /* MPPasswordsSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordsSegue.h; sourceTree = "<group>"; };
93D39C86E984EC65DA5ACB1D /* MPAppSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppSettingsViewController.h; sourceTree = "<group>"; };
@@ -496,28 +526,32 @@
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>"; };
DA2509E31956484D00AC23F1 /* image-10@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-10@2x.png"; sourceTree = "<group>"; };
DA2509E41956484D00AC23F1 /* image-10.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-10.png"; sourceTree = "<group>"; };
DA2509E51956484D00AC23F1 /* image-9@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-9@2x.png"; sourceTree = "<group>"; };
DA2509E61956484D00AC23F1 /* image-9.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-9.png"; sourceTree = "<group>"; };
DA2509E71956484D00AC23F1 /* image-8@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-8@2x.png"; sourceTree = "<group>"; };
DA2509E81956484D00AC23F1 /* image-8.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-8.png"; sourceTree = "<group>"; };
DA2509E91956484D00AC23F1 /* image-7@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-7@2x.png"; sourceTree = "<group>"; };
DA2509EA1956484D00AC23F1 /* image-7.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-7.png"; sourceTree = "<group>"; };
DA2509EB1956484D00AC23F1 /* image-6@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-6@2x.png"; sourceTree = "<group>"; };
DA2509EC1956484D00AC23F1 /* image-6.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-6.png"; sourceTree = "<group>"; };
DA2509ED1956484D00AC23F1 /* image-5@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-5@2x.png"; sourceTree = "<group>"; };
DA2509EE1956484D00AC23F1 /* image-5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-5.png"; sourceTree = "<group>"; };
DA2509EF1956484D00AC23F1 /* image-4@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-4@2x.png"; sourceTree = "<group>"; };
DA2509F01956484D00AC23F1 /* image-4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-4.png"; sourceTree = "<group>"; };
DA2509F11956484D00AC23F1 /* image-3@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-3@2x.png"; sourceTree = "<group>"; };
DA2509F21956484D00AC23F1 /* image-3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-3.png"; sourceTree = "<group>"; };
DA2509F31956484D00AC23F1 /* image-2@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-2@2x.png"; sourceTree = "<group>"; };
DA2509F41956484D00AC23F1 /* image-2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-2.png"; sourceTree = "<group>"; };
DA2509F51956484D00AC23F1 /* image-1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-1@2x.png"; sourceTree = "<group>"; };
DA2509F61956484D00AC23F1 /* image-1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-1.png"; sourceTree = "<group>"; };
DA2509F71956484D00AC23F1 /* image-0@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-0@2x.png"; sourceTree = "<group>"; };
DA2509F81956484D00AC23F1 /* image-0.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-0.png"; sourceTree = "<group>"; };
DA24EBB219DAD4D000FF010B /* Icon-60.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60.png"; sourceTree = "<group>"; };
DA24EBB319DAD4D000FF010B /* Icon-60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60@2x.png"; sourceTree = "<group>"; };
DA24EBB419DAD4D000FF010B /* Icon-60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60@3x.png"; sourceTree = "<group>"; };
DA24EBB519DAD4D000FF010B /* Icon-76.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-76.png"; sourceTree = "<group>"; };
DA24EBB619DAD4D000FF010B /* Icon-76@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-76@2x.png"; sourceTree = "<group>"; };
DA24EBB719DAD4D000FF010B /* Icon-Small-40.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-40.png"; sourceTree = "<group>"; };
DA24EBB819DAD4D000FF010B /* Icon-Small-40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-40@2x.png"; sourceTree = "<group>"; };
DA24EBB919DAD4D000FF010B /* Icon-Small-40@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-40@3x.png"; sourceTree = "<group>"; };
DA24EBBA19DAD4D000FF010B /* Icon-Small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small.png"; sourceTree = "<group>"; };
DA24EBBB19DAD4D000FF010B /* Icon-Small@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small@2x.png"; sourceTree = "<group>"; };
DA24EBBC19DAD4D000FF010B /* Icon-Small@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small@3x.png"; sourceTree = "<group>"; };
DA24EBBD19DAD4D000FF010B /* iTunesArtwork.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = iTunesArtwork.png; sourceTree = "<group>"; };
DA24EBBE19DAD4D000FF010B /* iTunesArtwork@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "iTunesArtwork@2x.png"; sourceTree = "<group>"; };
DA24EBBF19DAD4D000FF010B /* icon.sketch */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = icon.sketch; sourceTree = "<group>"; };
DA24EBC119DAD4D000FF010B /* 32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 32.png; sourceTree = "<group>"; };
DA24EBC219DAD4D000FF010B /* 320-480.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "320-480.png"; sourceTree = "<group>"; };
DA24EBC319DAD4D000FF010B /* 320-480@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "320-480@2x.png"; sourceTree = "<group>"; };
DA24EBC419DAD4D000FF010B /* 320-568@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "320-568@2x.png"; sourceTree = "<group>"; };
DA24EBC519DAD4D000FF010B /* 375-667@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "375-667@2x.png"; sourceTree = "<group>"; };
DA24EBC619DAD4D000FF010B /* 414-736@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "414-736@3x.png"; sourceTree = "<group>"; };
DA24EBC719DAD4D000FF010B /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = background.png; sourceTree = "<group>"; };
DA24EBC819DAD4D000FF010B /* background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "background@2x.png"; sourceTree = "<group>"; };
DA24EBC919DAD4D000FF010B /* background@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "background@3x.png"; sourceTree = "<group>"; };
DA24EBCA19DAD4D000FF010B /* launch.sketch */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = launch.sketch; sourceTree = "<group>"; };
DA24EBE619DAD6DE00FF010B /* Icon-320.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-320.png"; sourceTree = "<group>"; };
DA24EBE719DAD6DE00FF010B /* Icon-64.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-64.png"; sourceTree = "<group>"; };
DA250A13195665A100AC23F1 /* UITableView+PearlReloadFromArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+PearlReloadFromArray.m"; sourceTree = "<group>"; };
DA250A14195665A100AC23F1 /* UITableView+PearlReloadFromArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+PearlReloadFromArray.h"; sourceTree = "<group>"; };
DA250A15195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UICollectionReusableView+PearlDequeue.m"; sourceTree = "<group>"; };
@@ -570,6 +604,9 @@
DA32D04D19D2F59B004F3F0E /* meter_fuel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = meter_fuel.png; sourceTree = "<group>"; };
DA32D05319D741DC004F3F0E /* MPSiteQuestionEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSiteQuestionEntity.h; sourceTree = "<group>"; };
DA32D05419D741DC004F3F0E /* MPSiteQuestionEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSiteQuestionEntity.m; sourceTree = "<group>"; };
DA32D07719D7D784004F3F0E /* background@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "background@3x.png"; path = "ios/launch/background@3x.png"; sourceTree = "<group>"; };
DA32D07819D7D784004F3F0E /* background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "background@2x.png"; path = "ios/launch/background@2x.png"; sourceTree = "<group>"; };
DA32D07919D7D784004F3F0E /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = background.png; path = ios/launch/background.png; sourceTree = "<group>"; };
DA3509FC15F101A500C14A8E /* PearlQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlQueue.h; sourceTree = "<group>"; };
DA3509FD15F101A500C14A8E /* PearlQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlQueue.m; sourceTree = "<group>"; };
DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = "<group>"; };
@@ -604,6 +641,48 @@
DAA1411C1922FF020032B392 /* PearlTween.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlTween.m; sourceTree = "<group>"; };
DAA1411D1922FF020032B392 /* PearlTween.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlTween.h; sourceTree = "<group>"; };
DAA1411F1922FF020032B392 /* map-macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "map-macro.h"; sourceTree = "<group>"; };
DAA1757D19D86BE70044227B /* libAttributedMarkdown.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAttributedMarkdown.a; sourceTree = BUILT_PRODUCTS_DIR; };
DAA175B119D86C620044227B /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
DAA175B619D86C620044227B /* markdown_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = markdown_lib.h; sourceTree = "<group>"; };
DAA175B719D86C620044227B /* markdown_lib.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = markdown_lib.m; sourceTree = "<group>"; };
DAA175B819D86C620044227B /* markdown_output.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = markdown_output.m; sourceTree = "<group>"; };
DAA175B919D86C620044227B /* markdown_parser.leg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = markdown_parser.leg; sourceTree = "<group>"; };
DAA175BA19D86C620044227B /* markdown_parser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = markdown_parser.m; sourceTree = "<group>"; };
DAA175BB19D86C620044227B /* markdown_peg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = markdown_peg.h; sourceTree = "<group>"; };
DAA175EB19D86C620044227B /* parsing_functions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = parsing_functions.m; sourceTree = "<group>"; };
DAA175EC19D86C620044227B /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = platform.h; sourceTree = "<group>"; };
DAA175ED19D86C620044227B /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.markdown; sourceTree = "<group>"; };
DAA175EE19D86C620044227B /* README_PEG-MARKDWON.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = "README_PEG-MARKDWON.markdown"; sourceTree = "<group>"; };
DAA175EF19D86C620044227B /* utility_functions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = utility_functions.m; sourceTree = "<group>"; };
DAA1761C19D86E800044227B /* attributed-markdown.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "attributed-markdown.pch"; sourceTree = "<group>"; };
DAA1761D19D89B600044227B /* thumb_touch_id@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_touch_id@3x.png"; sourceTree = "<group>"; };
DAA1761E19D89B600044227B /* thumb_touch_id@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_touch_id@2x.png"; sourceTree = "<group>"; };
DAA1761F19D89B600044227B /* thumb_touch_id.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thumb_touch_id.png; sourceTree = "<group>"; };
DAA1762019D89B600044227B /* thumb_ios_integration@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_ios_integration@3x.png"; sourceTree = "<group>"; };
DAA1762119D89B600044227B /* thumb_ios_integration@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_ios_integration@2x.png"; sourceTree = "<group>"; };
DAA1762219D89B600044227B /* thumb_ios_integration.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thumb_ios_integration.png; sourceTree = "<group>"; };
DAA1762919D8B82B0044227B /* site_new@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "site_new@2x.png"; sourceTree = "<group>"; };
DAA1762A19D8B82B0044227B /* site_new.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = site_new.png; sourceTree = "<group>"; };
DAA1762B19D8B82B0044227B /* settings@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "settings@2x.png"; sourceTree = "<group>"; };
DAA1762C19D8B82B0044227B /* settings.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = settings.png; sourceTree = "<group>"; };
DAA1762D19D8B82B0044227B /* personal_pw@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "personal_pw@2x.png"; sourceTree = "<group>"; };
DAA1762E19D8B82B0044227B /* personal_pw.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = personal_pw.png; sourceTree = "<group>"; };
DAA1762F19D8B82B0044227B /* name_new@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "name_new@2x.png"; sourceTree = "<group>"; };
DAA1763019D8B82B0044227B /* name_new.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = name_new.png; sourceTree = "<group>"; };
DAA1763119D8B82B0044227B /* mpw_new@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "mpw_new@2x.png"; sourceTree = "<group>"; };
DAA1763219D8B82B0044227B /* mpw_new.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = mpw_new.png; sourceTree = "<group>"; };
DAA1763319D8B82B0044227B /* login_new@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login_new@2x.png"; sourceTree = "<group>"; };
DAA1763419D8B82B0044227B /* login_new.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = login_new.png; sourceTree = "<group>"; };
DAA1763519D8B82B0044227B /* login_name@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "login_name@2x.png"; sourceTree = "<group>"; };
DAA1763619D8B82B0044227B /* login_name.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = login_name.png; sourceTree = "<group>"; };
DAA1763719D8B82B0044227B /* initial@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "initial@2x.png"; sourceTree = "<group>"; };
DAA1763819D8B82B0044227B /* initial.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = initial.png; sourceTree = "<group>"; };
DAA1763919D8B82B0044227B /* counter@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "counter@2x.png"; sourceTree = "<group>"; };
DAA1763A19D8B82B0044227B /* counter.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = counter.png; sourceTree = "<group>"; };
DAA1763B19D8B82B0044227B /* copy_pw@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "copy_pw@2x.png"; sourceTree = "<group>"; };
DAA1763C19D8B82B0044227B /* copy_pw.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = copy_pw.png; sourceTree = "<group>"; };
DAA1763D19D8B82B0044227B /* choose_type@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "choose_type@2x.png"; sourceTree = "<group>"; };
DAA1763E19D8B82B0044227B /* choose_type.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = choose_type.png; sourceTree = "<group>"; };
DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
DABB981515100B4000B05417 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
DABD360F1711E29400CF925C /* ui_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ui_background.png; sourceTree = "<group>"; };
@@ -736,8 +815,6 @@
DABD368F1711E29400CF925C /* avatar-8@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-8@2x.png"; sourceTree = "<group>"; };
DABD36901711E29400CF925C /* avatar-9.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-9.png"; sourceTree = "<group>"; };
DABD36911711E29400CF925C /* avatar-9@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-9@2x.png"; sourceTree = "<group>"; };
DABD36931711E29400CF925C /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = background.png; sourceTree = "<group>"; };
DABD36941711E29400CF925C /* background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "background@2x.png"; sourceTree = "<group>"; };
DABD36BF1711E29500CF925C /* SourceCodePro-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Black.otf"; sourceTree = "<group>"; };
DABD36C01711E29500CF925C /* SourceCodePro-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-ExtraLight.otf"; sourceTree = "<group>"; };
DABD36DA1711E29500CF925C /* icon_action.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_action.png; sourceTree = "<group>"; };
@@ -1431,6 +1508,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DAA1761B19D86D0D0044227B /* libAttributedMarkdown.a in Frameworks */,
DA32D03E19D11293004F3F0E /* libKCOrderedAccessorFix.a in Frameworks */,
DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */,
DAE2725A19C93B8E007C5262 /* StoreKit.framework in Frameworks */,
@@ -1455,6 +1533,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
DAA1757A19D86BE70044227B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
DAC6325A1486805C0075AEA5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -1493,31 +1578,80 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
DA24EBB019DAD4D000FF010B /* ios */ = {
isa = PBXGroup;
children = (
DA24EBB119DAD4D000FF010B /* icon */,
DA24EBBF19DAD4D000FF010B /* icon.sketch */,
DA24EBC019DAD4D000FF010B /* launch */,
DA24EBCA19DAD4D000FF010B /* launch.sketch */,
);
path = ios;
sourceTree = "<group>";
};
DA24EBB119DAD4D000FF010B /* icon */ = {
isa = PBXGroup;
children = (
DA24EBE619DAD6DE00FF010B /* Icon-320.png */,
DA24EBE719DAD6DE00FF010B /* Icon-64.png */,
DA24EBB219DAD4D000FF010B /* Icon-60.png */,
DA24EBB319DAD4D000FF010B /* Icon-60@2x.png */,
DA24EBB419DAD4D000FF010B /* Icon-60@3x.png */,
DA24EBB519DAD4D000FF010B /* Icon-76.png */,
DA24EBB619DAD4D000FF010B /* Icon-76@2x.png */,
DA24EBB719DAD4D000FF010B /* Icon-Small-40.png */,
DA24EBB819DAD4D000FF010B /* Icon-Small-40@2x.png */,
DA24EBB919DAD4D000FF010B /* Icon-Small-40@3x.png */,
DA24EBBA19DAD4D000FF010B /* Icon-Small.png */,
DA24EBBB19DAD4D000FF010B /* Icon-Small@2x.png */,
DA24EBBC19DAD4D000FF010B /* Icon-Small@3x.png */,
DA24EBBD19DAD4D000FF010B /* iTunesArtwork.png */,
DA24EBBE19DAD4D000FF010B /* iTunesArtwork@2x.png */,
);
path = icon;
sourceTree = "<group>";
};
DA24EBC019DAD4D000FF010B /* launch */ = {
isa = PBXGroup;
children = (
DA24EBC119DAD4D000FF010B /* 32.png */,
DA24EBC219DAD4D000FF010B /* 320-480.png */,
DA24EBC319DAD4D000FF010B /* 320-480@2x.png */,
DA24EBC419DAD4D000FF010B /* 320-568@2x.png */,
DA24EBC519DAD4D000FF010B /* 375-667@2x.png */,
DA24EBC619DAD4D000FF010B /* 414-736@3x.png */,
DA24EBC719DAD4D000FF010B /* background.png */,
DA24EBC819DAD4D000FF010B /* background@2x.png */,
DA24EBC919DAD4D000FF010B /* background@3x.png */,
);
path = launch;
sourceTree = "<group>";
};
DA2509B619563E1E00AC23F1 /* Guide */ = {
isa = PBXGroup;
children = (
DA2509E31956484D00AC23F1 /* image-10@2x.png */,
DA2509E41956484D00AC23F1 /* image-10.png */,
DA2509E51956484D00AC23F1 /* image-9@2x.png */,
DA2509E61956484D00AC23F1 /* image-9.png */,
DA2509E71956484D00AC23F1 /* image-8@2x.png */,
DA2509E81956484D00AC23F1 /* image-8.png */,
DA2509E91956484D00AC23F1 /* image-7@2x.png */,
DA2509EA1956484D00AC23F1 /* image-7.png */,
DA2509EB1956484D00AC23F1 /* image-6@2x.png */,
DA2509EC1956484D00AC23F1 /* image-6.png */,
DA2509ED1956484D00AC23F1 /* image-5@2x.png */,
DA2509EE1956484D00AC23F1 /* image-5.png */,
DA2509EF1956484D00AC23F1 /* image-4@2x.png */,
DA2509F01956484D00AC23F1 /* image-4.png */,
DA2509F11956484D00AC23F1 /* image-3@2x.png */,
DA2509F21956484D00AC23F1 /* image-3.png */,
DA2509F31956484D00AC23F1 /* image-2@2x.png */,
DA2509F41956484D00AC23F1 /* image-2.png */,
DA2509F51956484D00AC23F1 /* image-1@2x.png */,
DA2509F61956484D00AC23F1 /* image-1.png */,
DA2509F71956484D00AC23F1 /* image-0@2x.png */,
DA2509F81956484D00AC23F1 /* image-0.png */,
DAA1762919D8B82B0044227B /* site_new@2x.png */,
DAA1762A19D8B82B0044227B /* site_new.png */,
DAA1762B19D8B82B0044227B /* settings@2x.png */,
DAA1762C19D8B82B0044227B /* settings.png */,
DAA1762D19D8B82B0044227B /* personal_pw@2x.png */,
DAA1762E19D8B82B0044227B /* personal_pw.png */,
DAA1762F19D8B82B0044227B /* name_new@2x.png */,
DAA1763019D8B82B0044227B /* name_new.png */,
DAA1763119D8B82B0044227B /* mpw_new@2x.png */,
DAA1763219D8B82B0044227B /* mpw_new.png */,
DAA1763319D8B82B0044227B /* login_new@2x.png */,
DAA1763419D8B82B0044227B /* login_new.png */,
DAA1763519D8B82B0044227B /* login_name@2x.png */,
DAA1763619D8B82B0044227B /* login_name.png */,
DAA1763719D8B82B0044227B /* initial@2x.png */,
DAA1763819D8B82B0044227B /* initial.png */,
DAA1763919D8B82B0044227B /* counter@2x.png */,
DAA1763A19D8B82B0044227B /* counter.png */,
DAA1763B19D8B82B0044227B /* copy_pw@2x.png */,
DAA1763C19D8B82B0044227B /* copy_pw.png */,
DAA1763D19D8B82B0044227B /* choose_type@2x.png */,
DAA1763E19D8B82B0044227B /* choose_type.png */,
);
path = Guide;
sourceTree = "<group>";
@@ -1545,6 +1679,8 @@
93D39D6604447D7708039155 /* MPAnswersViewController.h */,
93D399493FEDDE74DD1A0C15 /* MPRootSegue.m */,
93D3924D6F77E6BF41AC32D3 /* MPRootSegue.h */,
93D39C41A27AA42D044D68AE /* NSString+MPMarkDown.m */,
93D393CB0B1F4EC8C17CFE43 /* NSString+MPMarkDown.h */,
);
sourceTree = "<group>";
};
@@ -1557,6 +1693,7 @@
DAC6326C148680650075AEA5 /* libjrswizzle.a */,
DAFC5655172C573B00CB5CC5 /* libInAppSettingsKit.a */,
DA32D02019D111C6004F3F0E /* libKCOrderedAccessorFix.a */,
DAA1757D19D86BE70044227B /* libAttributedMarkdown.a */,
);
name = Products;
sourceTree = "<group>";
@@ -1623,9 +1760,39 @@
path = include;
sourceTree = "<group>";
};
DAA1759319D86C610044227B /* AttributedMarkdown */ = {
isa = PBXGroup;
children = (
DAA1761C19D86E800044227B /* attributed-markdown.pch */,
DAA175B119D86C620044227B /* LICENSE */,
DAA175B619D86C620044227B /* markdown_lib.h */,
DAA175B719D86C620044227B /* markdown_lib.m */,
DAA175B819D86C620044227B /* markdown_output.m */,
DAA175B919D86C620044227B /* markdown_parser.leg */,
DAA175BA19D86C620044227B /* markdown_parser.m */,
DAA175BB19D86C620044227B /* markdown_peg.h */,
DAA175EB19D86C620044227B /* parsing_functions.m */,
DAA175EC19D86C620044227B /* platform.h */,
DAA175EE19D86C620044227B /* README_PEG-MARKDWON.markdown */,
DAA175ED19D86C620044227B /* README.markdown */,
DAA175EF19D86C620044227B /* utility_functions.m */,
);
path = AttributedMarkdown;
sourceTree = "<group>";
};
DABD360D1711E29400CF925C /* Media */ = {
isa = PBXGroup;
children = (
DA24EBB019DAD4D000FF010B /* ios */,
DAA1761D19D89B600044227B /* thumb_touch_id@3x.png */,
DAA1761E19D89B600044227B /* thumb_touch_id@2x.png */,
DAA1761F19D89B600044227B /* thumb_touch_id.png */,
DAA1762019D89B600044227B /* thumb_ios_integration@3x.png */,
DAA1762119D89B600044227B /* thumb_ios_integration@2x.png */,
DAA1762219D89B600044227B /* thumb_ios_integration.png */,
DA32D07719D7D784004F3F0E /* background@3x.png */,
DA32D07819D7D784004F3F0E /* background@2x.png */,
DA32D07919D7D784004F3F0E /* background.png */,
DA32D04B19D2F59B004F3F0E /* meter_fuel@3x.png */,
DA32D04C19D2F59B004F3F0E /* meter_fuel@2x.png */,
DA32D04D19D2F59B004F3F0E /* meter_fuel.png */,
@@ -1650,7 +1817,6 @@
DA5A09DE171A70E4005284AB /* play@2x.png */,
DABD360E1711E29400CF925C /* Automaton */,
DABD366B1711E29400CF925C /* Avatars */,
DABD36921711E29400CF925C /* Background */,
DABD36BB1711E29500CF925C /* Fonts */,
DABD36D91711E29500CF925C /* Insignia */,
DABD38751711E29700CF925C /* Tooltips */,
@@ -1817,15 +1983,6 @@
path = Avatars;
sourceTree = "<group>";
};
DABD36921711E29400CF925C /* Background */ = {
isa = PBXGroup;
children = (
DABD36931711E29400CF925C /* background.png */,
DABD36941711E29400CF925C /* background@2x.png */,
);
path = Background;
sourceTree = "<group>";
};
DABD36BB1711E29500CF925C /* Fonts */ = {
isa = PBXGroup;
children = (
@@ -2442,8 +2599,6 @@
DAFE45FC15039823003ABA7C /* Pearl-Crypto */,
DAFE460715039823003ABA7C /* Pearl-UIKit */,
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */,
DACA29751705E2BD002C6C22 /* jrswizzle */,
DACA29B41705E2DE002C6C22 /* uicolor-utilities */,
);
path = Pearl;
sourceTree = "<group>";
@@ -2451,9 +2606,12 @@
DACA22121705DDC5002C6C22 /* External */ = {
isa = PBXGroup;
children = (
DAA1759319D86C610044227B /* AttributedMarkdown */,
DA32D03719D111EB004F3F0E /* KCOrderedAccessorFix */,
DAA141181922FED80032B392 /* iOS */,
DAFC5662172C57EC00CB5CC5 /* InAppSettingsKit */,
DACA29751705E2BD002C6C22 /* jrswizzle */,
DACA29B41705E2DE002C6C22 /* uicolor-utilities */,
DAC77CAF148291A600BCF976 /* Pearl */,
);
name = External;
@@ -2495,8 +2653,7 @@
DACA29771705E2BD002C6C22 /* JRSwizzle.h */,
DACA298C1705E2BD002C6C22 /* JRSwizzle.m */,
);
name = jrswizzle;
path = External/jrswizzle;
path = jrswizzle;
sourceTree = "<group>";
};
DACA29B41705E2DE002C6C22 /* uicolor-utilities */ = {
@@ -2507,8 +2664,7 @@
DACA29BA1705E2DE002C6C22 /* UIColor+Expanded.m */,
DACA29BB1705E2DE002C6C22 /* UIColor+HSV.m */,
);
name = "uicolor-utilities";
path = "External/uicolor-utilities";
path = "uicolor-utilities";
sourceTree = "<group>";
};
DAFC5662172C57EC00CB5CC5 /* InAppSettingsKit */ = {
@@ -2884,6 +3040,7 @@
isa = PBXNativeTarget;
buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword" */;
buildPhases = (
DA8D88E019DA412A00B189D0 /* Run Script: genassets */,
DA5BFA40147E415C00F98B1E /* Sources */,
DA5BFA41147E415C00F98B1E /* Frameworks */,
DA5BFA42147E415C00F98B1E /* Resources */,
@@ -2899,6 +3056,23 @@
productReference = DA5BFA44147E415C00F98B1E /* MasterPassword.app */;
productType = "com.apple.product-type.application";
};
DAA1757C19D86BE70044227B /* AttributedMarkdown */ = {
isa = PBXNativeTarget;
buildConfigurationList = DAA1758B19D86BE80044227B /* Build configuration list for PBXNativeTarget "AttributedMarkdown" */;
buildPhases = (
DAA1757919D86BE70044227B /* Sources */,
DAA1757A19D86BE70044227B /* Frameworks */,
DAA1757B19D86BE70044227B /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = AttributedMarkdown;
productName = AttributedMarkdown;
productReference = DAA1757D19D86BE70044227B /* libAttributedMarkdown.a */;
productType = "com.apple.product-type.library.static";
};
DAC6325C1486805C0075AEA5 /* uicolor-utilities */ = {
isa = PBXNativeTarget;
buildConfigurationList = DAC632651486805C0075AEA5 /* Build configuration list for PBXNativeTarget "uicolor-utilities" */;
@@ -2996,6 +3170,9 @@
};
};
};
DAA1757C19D86BE70044227B = {
CreatedOnToolsVersion = 6.0;
};
};
};
buildConfigurationList = DA5BFA3E147E415C00F98B1E /* Build configuration list for PBXProject "MasterPassword-iOS" */;
@@ -3101,6 +3278,7 @@
DAC6326B148680650075AEA5 /* jrswizzle */,
DAFC5654172C573B00CB5CC5 /* InAppSettingsKit */,
DA32D01F19D111C6004F3F0E /* KCOrderedAccessorFix */,
DAA1757C19D86BE70044227B /* AttributedMarkdown */,
);
};
/* End PBXProject section */
@@ -3114,7 +3292,6 @@
DACA296F1705DF81002C6C22 /* Crashlytics.plist in Resources */,
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */,
DA32D04F19D2F59B004F3F0E /* meter_fuel@2x.png in Resources */,
DA250A0F1956484D00AC23F1 /* image-1@2x.png in Resources */,
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */,
DA854C8318D4CFBF00106317 /* avatar-add@2x.png in Resources */,
@@ -3127,84 +3304,94 @@
DA32D04919D2F417004F3F0E /* thumb_fuel@2x.png in Resources */,
DABD39371711E29700CF925C /* avatar-0.png in Resources */,
DABD39381711E29700CF925C /* avatar-0@2x.png in Resources */,
DA250A041956484D00AC23F1 /* image-7.png in Resources */,
DAA1764819D8B82B0044227B /* mpw_new.png in Resources */,
DA25C5FC197CCAF70046CDCF /* icon_list-names.png in Resources */,
DABD39391711E29700CF925C /* avatar-1.png in Resources */,
DA7304E5194E025900E72520 /* tip_basic_black.png in Resources */,
DABD393A1711E29700CF925C /* avatar-10.png in Resources */,
DABD393B1711E29700CF925C /* avatar-10@2x.png in Resources */,
DA24EBAE19DAD08900FF010B /* tip_basic_black_top.png in Resources */,
DABD393C1711E29700CF925C /* avatar-11.png in Resources */,
DA250A0A1956484D00AC23F1 /* image-4.png in Resources */,
DABD393D1711E29700CF925C /* avatar-11@2x.png in Resources */,
DA73049D194E022700E72520 /* ui_spinner.png in Resources */,
DABD393E1711E29700CF925C /* avatar-12.png in Resources */,
DABD393F1711E29700CF925C /* avatar-12@2x.png in Resources */,
DA67461018DE7F0C00DFE240 /* Exo2.0-Bold.otf in Resources */,
DABD39401711E29700CF925C /* avatar-13.png in Resources */,
DA32D07C19D7D784004F3F0E /* background.png in Resources */,
DA24EBE919DAD6DE00FF010B /* Icon-64.png in Resources */,
DABD39411711E29700CF925C /* avatar-13@2x.png in Resources */,
DABD39421711E29700CF925C /* avatar-14.png in Resources */,
DABD39431711E29700CF925C /* avatar-14@2x.png in Resources */,
DA24EBE819DAD6DE00FF010B /* Icon-320.png in Resources */,
DAA1764419D8B82B0044227B /* personal_pw.png in Resources */,
DABD39441711E29700CF925C /* avatar-15.png in Resources */,
DABD39451711E29700CF925C /* avatar-15@2x.png in Resources */,
DAA1762419D89B610044227B /* thumb_touch_id@2x.png in Resources */,
DABD39461711E29700CF925C /* avatar-16.png in Resources */,
DABD39471711E29700CF925C /* avatar-16@2x.png in Resources */,
DA7304E7194E027C00E72520 /* Square-bottom.png in Resources */,
DA250A091956484D00AC23F1 /* image-4@2x.png in Resources */,
DAA1762319D89B600044227B /* thumb_touch_id@3x.png in Resources */,
DAA1764E19D8B82B0044227B /* initial.png in Resources */,
DABD39481711E29700CF925C /* avatar-17.png in Resources */,
DABD39491711E29700CF925C /* avatar-17@2x.png in Resources */,
DA25C5FD197CCAF70046CDCF /* icon_list-names@2x.png in Resources */,
DAC8DF47192831E100BA7D71 /* icon_key.png in Resources */,
DA250A071956484D00AC23F1 /* image-5@2x.png in Resources */,
DAC8DF48192831E100BA7D71 /* icon_key@2x.png in Resources */,
DABD394A1711E29700CF925C /* avatar-18.png in Resources */,
DAA1764919D8B82B0044227B /* login_new@2x.png in Resources */,
DABD394B1711E29700CF925C /* avatar-18@2x.png in Resources */,
DABD394C1711E29700CF925C /* avatar-1@2x.png in Resources */,
DA32D07A19D7D784004F3F0E /* background@3x.png in Resources */,
DA32D04319D27093004F3F0E /* thumb_generated_answers@2x.png in Resources */,
DA29993319C9214600AF7DF1 /* icon_star-hollow.png in Resources */,
DAA1764D19D8B82B0044227B /* initial@2x.png in Resources */,
DA29993019C86F5700AF7DF1 /* thumb_generated_login.png in Resources */,
DAA1764319D8B82B0044227B /* personal_pw@2x.png in Resources */,
DAA1764A19D8B82B0044227B /* login_new.png in Resources */,
DA071BF3190187FE00179766 /* empty@2x.png in Resources */,
DA32D04219D27093004F3F0E /* thumb_generated_answers@3x.png in Resources */,
DAA1764119D8B82B0044227B /* settings@2x.png in Resources */,
DA67460E18DE7F0C00DFE240 /* Exo2.0-Regular.otf in Resources */,
DAA1763F19D8B82B0044227B /* site_new@2x.png in Resources */,
DABD394D1711E29700CF925C /* avatar-2.png in Resources */,
DABD394E1711E29700CF925C /* avatar-2@2x.png in Resources */,
DA250A061956484D00AC23F1 /* image-6.png in Resources */,
DA32D04A19D2F417004F3F0E /* thumb_fuel.png in Resources */,
DABD394F1711E29700CF925C /* avatar-3.png in Resources */,
DA67460F18DE7F0C00DFE240 /* Exo2.0-ExtraBold.otf in Resources */,
DAA1765019D8B82B0044227B /* counter.png in Resources */,
DABD39501711E29700CF925C /* avatar-3@2x.png in Resources */,
DAA1764719D8B82B0044227B /* mpw_new@2x.png in Resources */,
DA25C600197DBF260046CDCF /* icon_trash.png in Resources */,
DA32D05219D3D107004F3F0E /* icon_meter@2x.png in Resources */,
DABD39511711E29700CF925C /* avatar-4.png in Resources */,
DA2509FD1956484D00AC23F1 /* image-10@2x.png in Resources */,
DABD39521711E29700CF925C /* avatar-4@2x.png in Resources */,
DABD39531711E29700CF925C /* avatar-5.png in Resources */,
DA73049E194E022700E72520 /* ui_spinner@2x.png in Resources */,
DABD39541711E29700CF925C /* avatar-5@2x.png in Resources */,
DA32D05019D2F59B004F3F0E /* meter_fuel.png in Resources */,
DA250A031956484D00AC23F1 /* image-7@2x.png in Resources */,
DA25C5FA197CCAE00046CDCF /* icon_delete.png in Resources */,
DA25C601197DBF260046CDCF /* icon_trash@2x.png in Resources */,
DABD39551711E29700CF925C /* avatar-6.png in Resources */,
DAA1764C19D8B82B0044227B /* login_name.png in Resources */,
DA32D00919CF5C55004F3F0E /* icon_question.png in Resources */,
DABD39561711E29700CF925C /* avatar-6@2x.png in Resources */,
DA32D07B19D7D784004F3F0E /* background@2x.png in Resources */,
DABD39571711E29700CF925C /* avatar-7.png in Resources */,
DABD39581711E29700CF925C /* avatar-7@2x.png in Resources */,
DABD39591711E29700CF925C /* avatar-8.png in Resources */,
DA250A0D1956484D00AC23F1 /* image-2@2x.png in Resources */,
DA32D00A19CF5C55004F3F0E /* icon_question@2x.png in Resources */,
DA250A051956484D00AC23F1 /* image-6@2x.png in Resources */,
DAA1764019D8B82B0044227B /* site_new.png in Resources */,
DABD395A1711E29700CF925C /* avatar-8@2x.png in Resources */,
DABD395B1711E29700CF925C /* avatar-9.png in Resources */,
DAA1765419D8B82B0044227B /* choose_type.png in Resources */,
DABD395C1711E29700CF925C /* avatar-9@2x.png in Resources */,
DABD395D1711E29700CF925C /* background.png in Resources */,
DAA1762519D89B610044227B /* thumb_touch_id.png in Resources */,
DA45224719062899008F650A /* icon_settings.png in Resources */,
DABD395E1711E29700CF925C /* background@2x.png in Resources */,
DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */,
DA32D04E19D2F59B004F3F0E /* meter_fuel@3x.png in Resources */,
DA250A101956484D00AC23F1 /* image-1.png in Resources */,
DA25C5FE197DBF200046CDCF /* icon_thumbs-up.png in Resources */,
DABD39871711E29700CF925C /* SourceCodePro-Black.otf in Resources */,
DA2509FE1956484D00AC23F1 /* image-10.png in Resources */,
DABD39881711E29700CF925C /* SourceCodePro-ExtraLight.otf in Resources */,
DABD39A01711E29700CF925C /* icon_action.png in Resources */,
DABD39A11711E29700CF925C /* icon_action@2x.png in Resources */,
@@ -3214,28 +3401,28 @@
DA29992F19C86F5700AF7DF1 /* thumb_generated_login@2x.png in Resources */,
DA73049F194E022B00E72520 /* ui_textfield.png in Resources */,
DABD39F31711E29700CF925C /* icon_cancel@2x.png in Resources */,
DA250A0C1956484D00AC23F1 /* image-3.png in Resources */,
DABD3A261711E29700CF925C /* icon_edit.png in Resources */,
DABD3A271711E29700CF925C /* icon_edit@2x.png in Resources */,
DA24EBAF19DAD08C00FF010B /* tip_basic_black_top@2x.png in Resources */,
DABD3A3A1711E29700CF925C /* icon_find.png in Resources */,
DABD3A3B1711E29700CF925C /* icon_find@2x.png in Resources */,
DAA1765319D8B82B0044227B /* choose_type@2x.png in Resources */,
DABD3AA01711E29800CF925C /* icon_pause.png in Resources */,
DABD3AA11711E29800CF925C /* icon_pause@2x.png in Resources */,
DAA1764219D8B82B0044227B /* settings.png in Resources */,
DABD3AAA1711E29800CF925C /* icon_person.png in Resources */,
DAA1762719D89B610044227B /* thumb_ios_integration@2x.png in Resources */,
DABD3AAB1711E29800CF925C /* icon_person@2x.png in Resources */,
DABD3ABC1711E29800CF925C /* icon_play.png in Resources */,
DABD3ABD1711E29800CF925C /* icon_play@2x.png in Resources */,
DABD3ABE1711E29800CF925C /* icon_plus.png in Resources */,
DA250A081956484D00AC23F1 /* image-5.png in Resources */,
DABD3ABF1711E29800CF925C /* icon_plus@2x.png in Resources */,
DA69540717D975D900BF294E /* icon_gears@2x.png in Resources */,
DABD3B1C1711E29800CF925C /* icon_up.png in Resources */,
DA32D04419D27093004F3F0E /* thumb_generated_answers.png in Resources */,
DABD3B1D1711E29800CF925C /* icon_up@2x.png in Resources */,
DA3BCFCB19BD09D5006B2681 /* SourceCodePro-Regular.otf in Resources */,
DA250A121956484D00AC23F1 /* image-0.png in Resources */,
DA4522441902355C008F650A /* icon_book.png in Resources */,
DA2509FF1956484D00AC23F1 /* image-9@2x.png in Resources */,
DABD3B8D1711E29800CF925C /* keypad.png in Resources */,
DABD3B8E1711E29800CF925C /* logo-bare.png in Resources */,
DA7304E6194E025900E72520 /* tip_basic_black@2x.png in Resources */,
@@ -3245,35 +3432,40 @@
DABD3B951711E29800CF925C /* pull-down.png in Resources */,
DABD3B961711E29800CF925C /* pull-down@2x.png in Resources */,
DABD3B971711E29800CF925C /* pull-up.png in Resources */,
DA24EBEA19DAD6EE00FF010B /* Icon-Small.png in Resources */,
DABD3B981711E29800CF925C /* pull-up@2x.png in Resources */,
DA7304A0194E022B00E72520 /* ui_textfield@2x.png in Resources */,
DAA1765119D8B82B0044227B /* copy_pw@2x.png in Resources */,
DA32D04819D2F417004F3F0E /* thumb_fuel@3x.png in Resources */,
DA452249190628A1008F650A /* icon_wrench.png in Resources */,
DAA1764519D8B82B0044227B /* name_new@2x.png in Resources */,
DA45224819062899008F650A /* icon_settings@2x.png in Resources */,
DA250A001956484D00AC23F1 /* image-9.png in Resources */,
DA854C8418D4CFBF00106317 /* avatar-add.png in Resources */,
DA24EBEB19DAD6EE00FF010B /* Icon-Small@2x.png in Resources */,
DAA1764B19D8B82B0044227B /* login_name@2x.png in Resources */,
DABD3C241711E2DC00CF925C /* MasterPassword.entitlements in Resources */,
DABD3C251711E2DC00CF925C /* Settings.bundle in Resources */,
DABD3C261711E2DC00CF925C /* InfoPlist.strings in Resources */,
DA32D05119D3D107004F3F0E /* icon_meter.png in Resources */,
DAA1765219D8B82B0044227B /* copy_pw.png in Resources */,
DA25C5F8197AFFB40046CDCF /* icon_tools.png in Resources */,
DA250A0B1956484D00AC23F1 /* image-3@2x.png in Resources */,
DABD3FCA1712446200CF925C /* cloud.png in Resources */,
DABD3FCB1712446200CF925C /* cloud@2x.png in Resources */,
DABD3FCE1714F45C00CF925C /* identity.png in Resources */,
DAA1762619D89B610044227B /* thumb_ios_integration@3x.png in Resources */,
DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */,
DAA1764619D8B82B0044227B /* name_new.png in Resources */,
DA45224B190628B2008F650A /* icon_gear.png in Resources */,
DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */,
DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */,
DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */,
DA250A021956484D00AC23F1 /* image-8.png in Resources */,
DA5A09DF171A70E4005284AB /* play.png in Resources */,
DA24EBEC19DAD6EE00FF010B /* Icon-Small@3x.png in Resources */,
DA5A09E0171A70E4005284AB /* play@2x.png in Resources */,
DA5A09EA171BB0F7005284AB /* unlocked.png in Resources */,
DA250A0E1956484D00AC23F1 /* image-2.png in Resources */,
DAA1762819D89B610044227B /* thumb_ios_integration.png in Resources */,
DA5A09EB171BB0F7005284AB /* unlocked@2x.png in Resources */,
DA250A011956484D00AC23F1 /* image-8@2x.png in Resources */,
DA250A111956484D00AC23F1 /* image-0@2x.png in Resources */,
DAA1764F19D8B82B0044227B /* counter@2x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3294,6 +3486,21 @@
shellPath = "/bin/bash -e";
shellScript = "PATH+=:/usr/libexec\n\naddPlistWithKey() {\n local key=$1 type=$2 value=$3 plist=${4:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Delete :'$key'\" \"$plist\" 2>/dev/null || true\n PlistBuddy -c \"Add :'$key' '$type' '$value'\" \"$plist\"\n}\nsetPlistWithKey() {\n local key=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Set :'$key' '$value'\" \"$plist\"\n}\ngetPlistWithKey() {\n local key=$1 plist=${2:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Print :'$key'\" \"$plist\"\n}\nsetSettingWithTitle() {\n local i title=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Settings.bundle/Root.plist\"}\n \n for (( i=0; 1; ++i )); do\n PlistBuddy -c \"Print :PreferenceSpecifiers:$i\" \"$plist\" &>/dev/null || break\n echo \"Checking preference specifier $i\"\n \n [[ $(PlistBuddy -c \"Print :PreferenceSpecifiers:$i:Title\" \"$plist\" 2>/dev/null) = $title ]] || continue\n \n echo \"Correct title, setting value.\"\n PlistBuddy -c \"Set :PreferenceSpecifiers:$i:DefaultValue $value\" \"$plist\"\n break\n done\n}\n\ndescription=$(git describe --always --dirty --long)\nversion=${description%-g*}\nIFS=- read major minor <<< \"$version\"\nprintf -v version '%s.%02d' \"$major\" \"$minor\"\nprintf -v commit '%09d' \"$((16#${description##*-g}))\"\n\naddPlistWithKey GITDescription string \"$description\"\nsetPlistWithKey CFBundleVersion \"${version//.}$commit\" # No separator between version and commit because I had already submitted a CFBundleVersion with a really high major. Cry.\nsetPlistWithKey CFBundleShortVersionString \"$version\"\n\nsetSettingWithTitle \"Build\" \"$commit\"\nsetSettingWithTitle \"Version\" \"$version\"\nsetSettingWithTitle \"Copyright\" \"$(getPlistWithKey NSHumanReadableCopyright)\"\n\nif [[ $DEPLOYMENT_LOCATION = YES ]]; then\n # This build is a release. Do some release checks.\n passed=1\n [[ $description != *-dirty ]] || \\\n { passed=0; echo >&2 \"ERROR: Cannot release a dirty version, first commit any changes.\"; }\n [[ $(PlistBuddy -c \"Print :'API Key'\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Crashlytics.plist\") ]] || \\\n { passed=0; echo >&2 \"ERROR: Cannot release: Crashlytics API key is missing.\"; }\n (( passed )) || \\\n { echo >&2 \"Failed to pass release checks. Fix the above errors and re-try. Aborting.\"; exit 1; }\nfi";
};
DA8D88E019DA412A00B189D0 /* Run Script: genassets */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script: genassets";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/bin/sh -e";
shellScript = "exec env PATH=\"/usr/local/bin:$PATH\" ../../../Scripts/genassets";
showEnvVarsInLog = 0;
};
DAD3125D155288AA00A3F9ED /* Run Script: Crashlytics */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -3367,6 +3574,17 @@
93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */,
93D39A27F2506C6FEEF9C588 /* MPAlgorithmV2.m in Sources */,
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */,
93D392FD5E2052F7D7DB3774 /* NSString+MPMarkDown.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DAA1757919D86BE70044227B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DAA175F519D86C620044227B /* markdown_lib.m in Sources */,
DAA175F719D86C620044227B /* markdown_parser.m in Sources */,
DAA175F619D86C620044227B /* markdown_output.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3712,7 +3930,7 @@
Reveal,
);
PROVISIONING_PROFILE = "";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "78fbee53-abe7-4a47-b917-c223df3a6952";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "3251b7d3-04df-4c8e-a410-d020ffc92d10";
SKIP_INSTALL = NO;
TARGETED_DEVICE_FAMILY = 1;
};
@@ -3738,7 +3956,7 @@
"$(inherited)",
);
PROVISIONING_PROFILE = "";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "7142c408-252a-43c0-94c6-1ae1f43173f4";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "59b587d0-3ef3-4691-9f12-c48f7f283002";
SKIP_INSTALL = NO;
STRIP_INSTALLED_PRODUCT = YES;
TARGETED_DEVICE_FAMILY = 1;
@@ -3845,7 +4063,7 @@
"$(inherited)",
);
PROVISIONING_PROFILE = "";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "48f9bae8-b80e-41c7-8792-663102bed54f";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "a1d8cfc8-b8db-4544-af34-28cc75e46c40";
SKIP_INSTALL = NO;
STRIP_INSTALLED_PRODUCT = YES;
TARGETED_DEVICE_FAMILY = 1;
@@ -3888,6 +4106,30 @@
};
name = "AppStore-iOS";
};
DAA1758C19D86BE80044227B /* Debug-iOS */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_PREFIX_HEADER = "../../../External/AttributedMarkdown/attributed-markdown.pch";
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
};
name = "Debug-iOS";
};
DAA1758D19D86BE80044227B /* AdHoc-iOS */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_PREFIX_HEADER = "../../../External/AttributedMarkdown/attributed-markdown.pch";
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
};
name = "AdHoc-iOS";
};
DAA1758E19D86BE80044227B /* AppStore-iOS */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_PREFIX_HEADER = "../../../External/AttributedMarkdown/attributed-markdown.pch";
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
};
name = "AppStore-iOS";
};
DAC632661486805C0075AEA5 /* Debug-iOS */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -4017,6 +4259,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = "AdHoc-iOS";
};
DAA1758B19D86BE80044227B /* Build configuration list for PBXNativeTarget "AttributedMarkdown" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DAA1758C19D86BE80044227B /* Debug-iOS */,
DAA1758D19D86BE80044227B /* AdHoc-iOS */,
DAA1758E19D86BE80044227B /* AppStore-iOS */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = "AdHoc-iOS";
};
DAC632651486805C0075AEA5 /* Build configuration list for PBXNativeTarget "uicolor-utilities" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@@ -26,18 +26,8 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "AppStore-iOS">
buildConfiguration = "Debug-iOS">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DADEF42E1810D5530052CA3E"
BuildableName = "LoveLyndirTests.xctest"
BlueprintName = "LoveLyndirTests"
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
@@ -54,7 +44,7 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "AppStore-iOS"
buildConfiguration = "Debug-iOS"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
@@ -74,7 +64,7 @@
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "AppStore-iOS"
buildConfiguration = "Debug-iOS"
debugDocumentVersioning = "YES">
<BuildableProductRunnable>
<BuildableReference

View File

@@ -0,0 +1,25 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// NSString(MPMarkDown).h
// NSString(MPMarkDown)
//
// Created by lhunath on 2014-09-28.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSString(MPMarkDown)
- (NSAttributedString *)attributedMarkdownStringWithFontSize:(CGFloat)fontSize;
@end

View File

@@ -0,0 +1,56 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// NSString(MPMarkDown).h
// NSString(MPMarkDown)
//
// Created by lhunath on 2014-09-28.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import "NSString+MPMarkDown.h"
#import "markdown_lib.h"
#import "markdown_peg.h"
@implementation NSString(MPMarkDown)
- (NSAttributedString *)attributedMarkdownStringWithFontSize:(CGFloat)fontSize {
NSMutableAttributedString *attributedString = markdown_to_attr_string( self, 0, @{
@(EMPH) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-Bold" size:fontSize] },
@(STRONG) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-ExtraBold" size:fontSize] },
@(EMPH | STRONG) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-ExtraBold" size:fontSize] },
@(PLAIN) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-Regular" size:fontSize] },
@(H1) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-Thin" size:fontSize * 2.f] },
@(H2) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-Thin" size:fontSize * 1.5f] },
@(H3) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-Thin" size:fontSize * 1.17f] },
@(H4) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-Thin" size:fontSize * 1.f] },
@(H5) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-Thin" size:fontSize * .83f] },
@(H6) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-Thin" size:fontSize * .75f] },
@(BLOCKQUOTE) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-Thin" size:fontSize * 1.17f] },
@(CODE) : @{ NSFontAttributeName : [UIFont fontWithName:@"SourceCodePro-Regular" size:fontSize] },
@(VERBATIM) : @{ NSFontAttributeName : [UIFont fontWithName:@"SourceCodePro-Regular" size:fontSize] },
@(NOTE) : @{ NSFontAttributeName : [UIFont fontWithName:@"Exo2.0-Thin" size:fontSize * 1.17f] },
} );
// Trim trailing newlines.
NSCharacterSet *trimSet = [NSCharacterSet newlineCharacterSet];
while (YES) {
NSRange range = [attributedString.string rangeOfCharacterFromSet:trimSet options:NSBackwardsSearch];
if (!range.length || NSMaxRange( range ) != attributedString.length)
break;
[attributedString replaceCharactersInRange:range withString:@""];
}
return attributedString;
}
@end

View File

@@ -56,7 +56,7 @@
<key>FooterText</key>
<string>When enabled, you will not be logged out when switching out of the application. This will help you get to your passwords faster, but when someone finds your device unlocked, they can too.</string>
<key>Title</key>
<string>Master Password</string>
<string>Security</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
@@ -70,24 +70,6 @@
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Enabling support for dictation in the site search box will enable the dictation button next to the space bar at the bottom of the keyboard. Press this button and speak the name of your site to look it up. Enabling dictation will change your keyboard which might make it slightly more difficult to enter a site name manually.</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<false/>
<key>Key</key>
<string>dictationSearch</string>
<key>Title</key>
<string>Dictation Search</string>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>This will keep your site&apos;s passwords hidden from view. Enable this if you&apos;re worried about people watching your screen while you use the app.
@@ -110,7 +92,7 @@ To see a site&apos;s password anyway, tap and hold your finger down for a while
</dict>
<dict>
<key>FooterText</key>
<string>The password strength indicator estimates the time necessary to break the password from a stolen database of SHA-1 hashes. Use this setting to choose the budget the attacker is willing to devote to breaking your site password.</string>
<string>The password strength indicator estimates the time necessary to break the password from a stolen database of SHA-1 hashes. Use this setting to choose the budget the attacker is willing to devote exclusively to breaking your site password.</string>
<key>Title</key>
<string></string>
<key>Type</key>
@@ -144,15 +126,34 @@ To see a site&apos;s password anyway, tap and hold your finger down for a while
<integer>0</integer>
<integer>1</integer>
<integer>2</integer>
<integer>3</integer>
</array>
</dict>
<dict>
<key>FooterText</key>
<string>Enabling support for dictation in the site search box will enable the dictation button next to the space bar at the bottom of the keyboard. Press this button and speak the name of your site to look it up. Enabling dictation will change your keyboard which might make it slightly more difficult to enter a site name manually.</string>
<key>Title</key>
<string>Miscellaneous</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<false/>
<key>Key</key>
<string>dictationSearch</string>
<key>Title</key>
<string>Dictation Search</string>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
</dict>
<dict>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>Title</key>
<string></string>
<key>FooterText</key>
<string>If the app tends to crash on login, enable this to check if there are any inconsistencies in your site data. It may slow down login a bit, so keep it off when no issues are reported on login.</string>
<string>Enable this if the app crashes when you log in. Master Password will scan for and repair any inconsistencies in your sites history.</string>
</dict>
<dict>
<key>Type</key>

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View File

@@ -1,130 +0,0 @@
{
"images" : [
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-Small@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-40@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-60@2x.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-Small~ipad.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-Small~ipad@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-40~ipad.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-40~ipad@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76~ipad.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76~ipad@2x.png",
"scale" : "2x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "icon_16x16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "icon_16x16@2x.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "icon_32x32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "icon_32x32@2x.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "icon_128x128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "icon_128x128@2x.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "icon_256x256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "icon_256x256@2x.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "icon_512x512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "icon_512x512@2x.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"pre-rendered" : true
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Some files were not shown because too many files have changed in this diff Show More