Compare commits
189 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
954c4f8d63 | ||
|
|
529f1feace | ||
|
|
5cdff6f155 | ||
|
|
81358c16f9 | ||
|
|
4a555748cd | ||
|
|
698566a914 | ||
|
|
64a69856ac | ||
|
|
f76de9520c | ||
|
|
4b3662bbe9 | ||
|
|
b25130f4d2 | ||
|
|
d6617563fc | ||
|
|
8d24ec3250 | ||
|
|
bbcc250a5c | ||
|
|
4abb50ad9b | ||
|
|
30dac64d5d | ||
|
|
e4e2aaad95 | ||
|
|
835acf45eb | ||
|
|
c3f6796833 | ||
|
|
86f4e8ec06 | ||
|
|
0dddcef28e | ||
|
|
cc583c789d | ||
|
|
42d78da74e | ||
|
|
b5040a7786 | ||
|
|
b1698ee339 | ||
|
|
8ffc0ae350 | ||
|
|
8276d2f4e5 | ||
|
|
11cf86bc73 | ||
|
|
5084511404 | ||
|
|
fffec56d4e | ||
|
|
9a0828c1eb | ||
|
|
db967a1a16 | ||
|
|
f83896d89d | ||
|
|
683c0165e6 | ||
|
|
3853b6f180 | ||
|
|
bff3577ada | ||
|
|
4c48bfb1af | ||
|
|
a8263b276c | ||
|
|
11e32abb90 | ||
|
|
b6e6dce9f0 | ||
|
|
ada1c7f6ae | ||
|
|
1cbb584011 | ||
|
|
f9289a3e9e | ||
|
|
9a37253461 | ||
|
|
5a4456bf46 | ||
|
|
1d06dd65ed | ||
|
|
ed6c32811c | ||
|
|
9a564ff35e | ||
|
|
4909479b0f | ||
|
|
434a7cc280 | ||
|
|
50a48ae092 | ||
|
|
c3017069b1 | ||
|
|
c7425be681 | ||
|
|
249a1975cd | ||
|
|
190a241a25 | ||
|
|
aef8422102 | ||
|
|
c2aafd8602 | ||
|
|
8e41cba7ac | ||
|
|
9d29775b14 | ||
|
|
55bd9382bc | ||
|
|
687923da32 | ||
|
|
66e893fd83 | ||
|
|
cc5c45e3aa | ||
|
|
d472d975ce | ||
|
|
7a97a0b0c8 | ||
|
|
02aed778bc | ||
|
|
b748e607ad | ||
|
|
c801ff546a | ||
|
|
17185391ce | ||
|
|
4579095afc | ||
|
|
788d85178d | ||
|
|
af4d7c4bc9 | ||
|
|
a4bbfdf850 | ||
|
|
cef3d470bd | ||
|
|
0d37c45dbe | ||
|
|
e568b5a9da | ||
|
|
e7ac8661f9 | ||
|
|
882de547d0 | ||
|
|
6957d46ef9 | ||
|
|
3a9a518cb1 | ||
|
|
0900aff93a | ||
|
|
3974b70a83 | ||
|
|
498b7caecb | ||
|
|
0b26260124 | ||
|
|
bc0ffbd552 | ||
|
|
c08d3a0e8b | ||
|
|
5501f1f97d | ||
|
|
073ef4f439 | ||
|
|
a7f82d3148 | ||
|
|
831b475b28 | ||
|
|
728a4486d3 | ||
|
|
5035c52846 | ||
|
|
a0447298d3 | ||
|
|
0b044ab9a4 | ||
|
|
3b24e1d1b8 | ||
|
|
cc82e52c33 | ||
|
|
faf59875bf | ||
|
|
e12e14ef03 | ||
|
|
f41f07f0ae | ||
|
|
1cfc199541 | ||
|
|
c43cc73ad5 | ||
|
|
1bd61759bf | ||
|
|
cbf277c493 | ||
|
|
87b7afd587 | ||
|
|
2db0bb35d5 | ||
|
|
c51262ccc2 | ||
|
|
1b703515dd | ||
|
|
0aa7baf59e | ||
|
|
8bdf1755b7 | ||
|
|
bda1ac3bd4 | ||
|
|
8d7c351912 | ||
|
|
38a357cb28 | ||
|
|
f0d523fb35 | ||
|
|
1cb720da32 | ||
|
|
1031414ba2 | ||
|
|
cb74b1f3fc | ||
|
|
82e2d0b5ac | ||
|
|
33f2e0edda | ||
|
|
9c8566b537 | ||
|
|
10698284d2 | ||
|
|
11185725d1 | ||
|
|
71f1b3c130 | ||
|
|
dc19806e02 | ||
|
|
94ac8b1460 | ||
|
|
40a807c6af | ||
|
|
c115e9149c | ||
|
|
7123e97ef9 | ||
|
|
37fb672133 | ||
|
|
2771125eb5 | ||
|
|
a16cb19311 | ||
|
|
8f8920b91f | ||
|
|
1d913b7f78 | ||
|
|
5fe9106f6d | ||
|
|
8d9a3e0ab0 | ||
|
|
344771dbdf | ||
|
|
d38dba7272 | ||
|
|
409f005eec | ||
|
|
df7903e146 | ||
|
|
49edaef79d | ||
|
|
fcbed9ef01 | ||
|
|
3edb414d23 | ||
|
|
d779c21cc1 | ||
|
|
8d32bc56ae | ||
|
|
9d03ed06c3 | ||
|
|
ee290e5c14 | ||
|
|
789761b177 | ||
|
|
cd0876d58a | ||
|
|
bfae4da56c | ||
|
|
f342ed5940 | ||
|
|
c7373fee28 | ||
|
|
44b2955652 | ||
|
|
8a4af69008 | ||
|
|
6650382e19 | ||
|
|
a1f5e0ba1c | ||
|
|
035bb6b285 | ||
|
|
c0107fb90e | ||
|
|
138be9d14c | ||
|
|
61f474217b | ||
|
|
d31c5eed0a | ||
|
|
5060de689b | ||
|
|
b95424ddf3 | ||
|
|
e40a442a30 | ||
|
|
b5134a9faf | ||
|
|
a791d449ce | ||
|
|
43e1a9d539 | ||
|
|
e91f80d10e | ||
|
|
9db855c7fb | ||
|
|
2dc3636b26 | ||
|
|
4d9df012f6 | ||
|
|
ff9d0d75ef | ||
|
|
4e160b3b33 | ||
|
|
5048acc9f9 | ||
|
|
1841541bc4 | ||
|
|
11d9af3844 | ||
|
|
e30b618241 | ||
|
|
966327571d | ||
|
|
303d50c197 | ||
|
|
bcdfdec211 | ||
|
|
fb769d2ac5 | ||
|
|
f8043ae16d | ||
|
|
7150f2f5c5 | ||
|
|
81bd2e3065 | ||
|
|
78c9618807 | ||
|
|
bed8939b8a | ||
|
|
9443d93500 | ||
|
|
877eba66be | ||
|
|
3af8aba40c | ||
|
|
7ece02c73d | ||
|
|
ebbd2b3ac4 | ||
|
|
4f708809e5 |
28
.dockerignore
Normal file
28
.dockerignore
Normal file
@@ -0,0 +1,28 @@
|
||||
# OS-Specific junk.
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# Xcode IDE
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
|
||||
# Generated
|
||||
/platform-darwin/Resources/Media/Images.xcassets/
|
||||
/platform-darwin/Podfile.lock
|
||||
/platform-darwin/Pods/
|
||||
|
||||
# Gradle
|
||||
build
|
||||
.gradle
|
||||
local.properties
|
||||
/gradle/builds
|
||||
/platform-android/.externalNativeBuild
|
||||
|
||||
# Git
|
||||
.git
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -14,18 +14,12 @@ DerivedData/
|
||||
|
||||
# Generated
|
||||
/platform-darwin/Resources/Media/Images.xcassets/
|
||||
|
||||
# Media
|
||||
public/Press/Background.png
|
||||
public/Press/Front-Page.png
|
||||
public/Press/MasterPassword_PressKit/MasterPassword_pressrelease_*.pdf
|
||||
/platform-darwin/Podfile.lock
|
||||
/platform-darwin/Pods/
|
||||
|
||||
# Gradle
|
||||
build
|
||||
!/build
|
||||
.gradle
|
||||
local.properties
|
||||
|
||||
# Maven
|
||||
target
|
||||
dependency-reduced-pom.xml
|
||||
/gradle/builds
|
||||
/platform-android/.externalNativeBuild
|
||||
|
||||
18
.gitlab-ci.yml
Normal file
18
.gitlab-ci.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
variables:
|
||||
GIT_DEPTH: 3
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
|
||||
build_project:
|
||||
stage: build
|
||||
script:
|
||||
- "( brew bundle )"
|
||||
- "( ./lib/bin/build_libsodium-macos clean && ./lib/bin/build_libsodium-macos )"
|
||||
- "( ./lib/bin/build_libjson-c-macos clean && ./lib/bin/build_libjson-c-macos )"
|
||||
- "( cd ./platform-independent/c/cli && ./clean && targets=all ./build && ./mpw-tests && ./mpw-cli-tests )"
|
||||
- "( cd ./gradle && ./gradlew --stacktrace clean test )"
|
||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword iOS' -sdk iphonesimulator clean build )"
|
||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword macOS' clean build )"
|
||||
tags:
|
||||
- brew
|
||||
- java
|
||||
- xcode_9
|
||||
18
.gitmodules
vendored
18
.gitmodules
vendored
@@ -17,11 +17,17 @@
|
||||
path = platform-darwin/External/jrswizzle
|
||||
url = git://github.com/jonmarimba/jrswizzle.git
|
||||
[submodule "MasterPassword/Web/js/mpw-js"]
|
||||
path = platform-independent/web-js/js/mpw-js
|
||||
path = platform-independent/web/js/mpw-js
|
||||
url = https://github.com/tmthrgd/mpw-js.git
|
||||
[submodule "platform-darwin/External/libsodium"]
|
||||
path = platform-darwin/External/libsodium
|
||||
[submodule "lib/libsodium"]
|
||||
path = lib/libsodium
|
||||
url = https://github.com/jedisct1/libsodium.git
|
||||
[submodule "platform-darwin/External/libjson-c"]
|
||||
path = platform-darwin/External/libjson-c
|
||||
url = https://github.com/lhunath/json-c.git
|
||||
[submodule "lib/libjson-c"]
|
||||
path = lib/libjson-c
|
||||
url = https://github.com/json-c/json-c.git
|
||||
[submodule "public/site"]
|
||||
path = public/site
|
||||
url = https://github.com/Lyndir/MasterPassword.git
|
||||
branch = gh-pages
|
||||
shallow = true
|
||||
update = none
|
||||
|
||||
12
.travis.yml
12
.travis.yml
@@ -1,12 +0,0 @@
|
||||
language: objective-c
|
||||
os: osx
|
||||
osx_image: xcode8.3
|
||||
env: TERM=dumb SHLVL=0
|
||||
git:
|
||||
submodules: true
|
||||
script:
|
||||
- "( brew install libsodium json-c )"
|
||||
- "( cd ./platform-independent/cli-c && ./clean && targets='mpw mpw-bench mpw-tests' ./build && ./mpw-tests && ./mpw-cli-tests )"
|
||||
- "( cd ./gradle && ./gradlew --info clean test )"
|
||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword iOS' -sdk iphonesimulator )"
|
||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword macOS' )"
|
||||
6
Brewfile
Normal file
6
Brewfile
Normal file
@@ -0,0 +1,6 @@
|
||||
brew "libsodium"
|
||||
brew "json-c"
|
||||
|
||||
brew "libtool"
|
||||
brew "automake"
|
||||
brew "autoconf"
|
||||
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
||||
FROM alpine
|
||||
|
||||
# For i386
|
||||
#FROM i386/alpine
|
||||
#ENTRYPOINT ["linux32", "--"]
|
||||
|
||||
RUN apk add --no-cache git libtool automake autoconf make g++ bash openjdk8
|
||||
RUN git clone --depth=3 $(: --shallow-submodules) --recurse-submodules https://gitlab.com/MasterPassword/MasterPassword.git /mpw
|
||||
RUN cd /mpw/gradle && ./gradlew -i clean build
|
||||
21
README.md
21
README.md
@@ -1,11 +1,4 @@
|
||||
[](https://travis-ci.org/Lyndir/MasterPassword)
|
||||
[](https://gitter.im/lyndir/MasterPassword?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
|
||||
|
||||
|
||||
# [Master Password •••|](http://masterpasswordapp.com)
|
||||
# [Master Password •••|](http://masterpassword.app)
|
||||
|
||||
Master Password is a completely new way of thinking about passwords.
|
||||
|
||||
@@ -13,9 +6,9 @@ It consists of an algorithm that implements the core idea and applications for v
|
||||
|
||||
To skip the intro and go straight to the information on how to use the code, [click here](#source-code).
|
||||
|
||||
Master Password is available for [📲 iOS](https://itunes.apple.com/app/id510296984), [🖥 macOS](https://ssl.masterpasswordapp.com/masterpassword-mac.zip), [📲 Android](https://ssl.masterpasswordapp.com/masterpassword-android.apk), [🖥 Desktop](https://ssl.masterpasswordapp.com/masterpassword-gui.jar), and [⌨ Console](https://ssl.masterpasswordapp.com/masterpassword-cli.tar.gz).
|
||||
Master Password is available for [📲 iOS](https://itunes.apple.com/app/id510296984), [🖥 macOS](https://masterpassword.app/masterpassword-mac.zip), [📲 Android](https://masterpassword.app/masterpassword-android.apk), [🖥 Desktop](https://masterpassword.app/masterpassword-gui.jar), and [⌨ Console](https://masterpassword.app/masterpassword-cli.tar.gz).
|
||||
|
||||
Master Password is also available from the following package managers: [macOS: Homebrew](https://brew.sh/) (`brew install mpw`).
|
||||
Master Password is also available from: [macOS: Homebrew](https://brew.sh/) (`brew install mpw`) and [Docker](https://www.docker.com/) (`docker run -ti registry.gitlab.com/masterpassword/masterpassword`).
|
||||
Get in touch if you are interested in adding Master Password to any other package managers.
|
||||
|
||||
There are many reasons for using Master Password instead of an ordinary password manager, read below for the details, but if you want my personal favourites, they would be:
|
||||
@@ -90,7 +83,7 @@ Master Password is *not* a password manager. It does not store your website pas
|
||||
|
||||
## How does it work?
|
||||
|
||||
The details of how Master Password works [are available here](http://masterpasswordapp.com/algorithm.html).
|
||||
The details of how Master Password works [are available here](https://masterpassword.app/masterpassword-algorithm.pdf).
|
||||
|
||||
In short:
|
||||
|
||||
@@ -129,14 +122,14 @@ The `master-password` on the other hand, is only a simple phrase, which means it
|
||||
|
||||
5. I have another question.
|
||||
|
||||
Please don't hesitate to [get in touch](#support), we're more than happy to answer all your Master Password questions. Any problems or suggestions can be reported [as GitHub issues](https://github.com/Lyndir/MasterPassword/issues).
|
||||
Please don't hesitate to [get in touch](#support), we're more than happy to answer all your Master Password questions. Any problems or suggestions can be reported [as GitLab issues](https://gitlab.com/MasterPassword/MasterPassword/issues/).
|
||||
|
||||
|
||||
|
||||
|
||||
# Source Code
|
||||
|
||||
Master Password's algorithm is [documented](http://masterpasswordapp.com/algorithm.html) and its implementation is Free Software (GPLv3).
|
||||
Master Password's algorithm is [documented](https://masterpassword.app/masterpassword-algorithm.pdf) and its implementation is [Free Software (GPLv3)](LICENSE).
|
||||
|
||||
|
||||
|
||||
@@ -194,7 +187,7 @@ Note that in order to build the Android application, you will need to have the A
|
||||
|
||||
Go into the `platform-independent/cli-c` directory and run `./build`. The native command-line client will then be built.
|
||||
|
||||
For detailed instructions, see [the native CLI instructions](platform-independent/cli-c/README.md).
|
||||
For detailed instructions, see [the native CLI instructions](platform-independent/c/README.md).
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
description = 'Master Password Algorithm Implementation'
|
||||
|
||||
dependencies {
|
||||
compile (group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.6-p11') {
|
||||
exclude( module: 'joda-time' )
|
||||
}
|
||||
compile group: 'com.lyndir.lhunath.opal', name: 'opal-crypto', version: '1.6-p11'
|
||||
|
||||
compile group: 'com.lambdaworks', name: 'scrypt', version: '1.4.0'
|
||||
compile group: 'org.jetbrains', name: 'annotations', version: '13.0'
|
||||
compile group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1'
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password Algorithm Implementation</name>
|
||||
<description>The implementation of the Master Password algorithm</description>
|
||||
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<!-- DEPENDENCY MANAGEMENT -->
|
||||
<dependencies>
|
||||
|
||||
<!-- PROJECT REFERENCES -->
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||
<artifactId>opal-system</artifactId>
|
||||
<version>1.6-p11</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||
<artifactId>opal-crypto</artifactId>
|
||||
<version>1.6-p11</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EXTERNAL DEPENDENCIES -->
|
||||
<dependency>
|
||||
<groupId>com.lambdaworks</groupId>
|
||||
<artifactId>scrypt</artifactId>
|
||||
<version>1.4.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,99 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
|
||||
import com.lyndir.lhunath.opal.system.MessageDigests;
|
||||
import java.io.Serializable;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* @see MPMasterKey.Version
|
||||
*/
|
||||
public interface MPAlgorithm {
|
||||
|
||||
/**
|
||||
* mpw: validity for the time-based rolling counter.
|
||||
*/
|
||||
int mpw_otp_window = 5 * 60 /* s */;
|
||||
|
||||
/**
|
||||
* mpw: Key ID hash.
|
||||
*/
|
||||
MessageDigests mpw_hash = MessageDigests.SHA256;
|
||||
|
||||
/**
|
||||
* mpw: Site digest.
|
||||
*/
|
||||
MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256;
|
||||
|
||||
/**
|
||||
* mpw: Platform-agnostic byte order.
|
||||
*/
|
||||
ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN;
|
||||
|
||||
/**
|
||||
* mpw: Input character encoding.
|
||||
*/
|
||||
Charset mpw_charset = Charsets.UTF_8;
|
||||
|
||||
/**
|
||||
* mpw: Master key size (byte).
|
||||
*/
|
||||
int mpw_dkLen = 64;
|
||||
|
||||
/**
|
||||
* scrypt: Parallelization parameter.
|
||||
*/
|
||||
int scrypt_p = 2;
|
||||
|
||||
/**
|
||||
* scrypt: Memory cost parameter.
|
||||
*/
|
||||
int scrypt_r = 8;
|
||||
|
||||
/**
|
||||
* scrypt: CPU cost parameter.
|
||||
*/
|
||||
int scrypt_N = 32768;
|
||||
|
||||
MPMasterKey.Version getAlgorithmVersion();
|
||||
|
||||
byte[] masterKey(String fullName, char[] masterPassword);
|
||||
|
||||
byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||
@Nullable String keyContext);
|
||||
|
||||
String siteResult(byte[] masterKey, final byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
String sitePasswordFromTemplate(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
String sitePasswordFromCrypt(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
String sitePasswordFromDerive(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
String siteState(byte[] masterKey, final byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||
@Nullable String keyContext, MPResultType resultType, String resultParam);
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.masterpassword.MPUtils.*;
|
||||
|
||||
import com.google.common.base.*;
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lambdaworks.crypto.SCrypt;
|
||||
import com.lyndir.lhunath.opal.crypto.CryptUtils;
|
||||
import com.lyndir.lhunath.opal.system.*;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
||||
import java.nio.*;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2014-08-30
|
||||
* @see MPMasterKey.Version#V0
|
||||
*/
|
||||
public class MPAlgorithmV0 implements MPAlgorithm {
|
||||
|
||||
protected final Logger logger = Logger.get( getClass() );
|
||||
|
||||
@Override
|
||||
public MPMasterKey.Version getAlgorithmVersion() {
|
||||
|
||||
return MPMasterKey.Version.V0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
||||
|
||||
byte[] fullNameBytes = fullName.getBytes( mpw_charset );
|
||||
byte[] fullNameLengthBytes = bytesForInt( fullName.length() );
|
||||
|
||||
String keyScope = MPKeyPurpose.Authentication.getScope();
|
||||
logger.trc( "keyScope: %s", keyScope );
|
||||
|
||||
// Calculate the master key salt.
|
||||
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
||||
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
||||
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
||||
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
||||
|
||||
// Calculate the master key.
|
||||
logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
|
||||
scrypt_N, scrypt_r, scrypt_p );
|
||||
byte[] masterPasswordBytes = bytesForChars( masterPassword );
|
||||
byte[] masterKey = scrypt( masterKeySalt, masterPasswordBytes );
|
||||
Arrays.fill( masterKeySalt, (byte) 0 );
|
||||
Arrays.fill( masterPasswordBytes, (byte) 0 );
|
||||
logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
|
||||
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
||||
try {
|
||||
//if (isAllowNative())
|
||||
return SCrypt.scrypt( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
|
||||
//else
|
||||
// return SCrypt.scryptJ( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
|
||||
}
|
||||
catch (final GeneralSecurityException e) {
|
||||
throw logger.bug( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext) {
|
||||
|
||||
String keyScope = keyPurpose.getScope();
|
||||
logger.trc( "keyScope: %s", keyScope );
|
||||
|
||||
// OTP counter value.
|
||||
if (siteCounter.longValue() == 0)
|
||||
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (mpw_otp_window * 1000)) * mpw_otp_window );
|
||||
|
||||
// Calculate the site seed.
|
||||
byte[] siteNameBytes = siteName.getBytes( mpw_charset );
|
||||
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
|
||||
byte[] siteCounterBytes = bytesForInt( siteCounter );
|
||||
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( mpw_charset );
|
||||
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: bytesForInt( keyContextBytes.length );
|
||||
logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
|
||||
keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
|
||||
(keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
|
||||
|
||||
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
||||
if (keyContextBytes != null)
|
||||
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
|
||||
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
|
||||
|
||||
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
|
||||
byte[] sitePasswordSeedBytes = mpw_digest.of( masterKey, sitePasswordInfo );
|
||||
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
|
||||
|
||||
return sitePasswordSeedBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
|
||||
final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
|
||||
switch (resultType.getTypeClass()) {
|
||||
case Template:
|
||||
return sitePasswordFromTemplate( masterKey, siteKey, resultType, resultParam );
|
||||
case Stateful:
|
||||
return sitePasswordFromCrypt( masterKey, siteKey, resultType, resultParam );
|
||||
case Derive:
|
||||
return sitePasswordFromDerive( masterKey, siteKey, resultType, resultParam );
|
||||
}
|
||||
|
||||
throw logger.bug( "Unsupported result type class: %s", resultType.getTypeClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
||||
@Nullable final String resultParam) {
|
||||
|
||||
int[] _siteKey = new int[siteKey.length];
|
||||
for (int i = 0; i < siteKey.length; ++i) {
|
||||
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder );
|
||||
Arrays.fill( buf.array(), (byte) ((siteKey[i] > 0)? 0x00: 0xFF) );
|
||||
buf.position( 2 );
|
||||
buf.put( siteKey[i] ).rewind();
|
||||
_siteKey[i] = buf.getInt() & 0xFFFF;
|
||||
}
|
||||
|
||||
// Determine the template.
|
||||
Preconditions.checkState( _siteKey.length > 0 );
|
||||
int templateIndex = _siteKey[0];
|
||||
MPTemplate template = resultType.getTemplateAtRollingIndex( templateIndex );
|
||||
logger.trc( "template: %d => %s", templateIndex, template.getTemplateString() );
|
||||
|
||||
// Encode the password from the seed using the template.
|
||||
StringBuilder password = new StringBuilder( template.length() );
|
||||
for (int i = 0; i < template.length(); ++i) {
|
||||
int characterIndex = _siteKey[i + 1];
|
||||
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
|
||||
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
|
||||
logger.trc( " - class: %c, index: %5d (0x%2H) => character: %c",
|
||||
characterClass.getIdentifier(), characterIndex, _siteKey[i + 1], passwordCharacter );
|
||||
|
||||
password.append( passwordCharacter );
|
||||
}
|
||||
logger.trc( " => password: %s", password );
|
||||
|
||||
return password.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
||||
@Nullable final String resultParam) {
|
||||
|
||||
Preconditions.checkNotNull( resultParam );
|
||||
Preconditions.checkArgument( !resultParam.isEmpty() );
|
||||
|
||||
try {
|
||||
// Base64-decode
|
||||
byte[] cipherBuf = CryptUtils.decodeBase64( resultParam );
|
||||
logger.trc( "b64 decoded: %d bytes = %s", cipherBuf.length, CodeUtils.encodeHex( cipherBuf ) );
|
||||
|
||||
// Decrypt
|
||||
byte[] plainBuf = CryptUtils.decrypt( cipherBuf, masterKey, true );
|
||||
String plainText = mpw_charset.decode( ByteBuffer.wrap( plainBuf ) ).toString();
|
||||
logger.trc( "decrypted -> plainText: %d bytes = %s = %s", plainBuf.length, plainText, CodeUtils.encodeHex( plainBuf ) );
|
||||
|
||||
return plainText;
|
||||
}
|
||||
catch (final BadPaddingException e) {
|
||||
throw Throwables.propagate( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
||||
@Nullable final String resultParam) {
|
||||
|
||||
if (resultType == MPResultType.DeriveKey) {
|
||||
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
|
||||
if (resultParamInt == 0)
|
||||
resultParamInt = 512;
|
||||
if ((resultParamInt < 128) || (resultParamInt > 512) || ((resultParamInt % 8) != 0))
|
||||
throw logger.bug( "Parameter is not a valid key size (should be 128 - 512): %s", resultParam );
|
||||
int keySize = resultParamInt / 8;
|
||||
logger.trc( "keySize: %d", keySize );
|
||||
|
||||
// Derive key
|
||||
byte[] resultKey = null; // TODO: mpw_kdf_blake2b( keySize, siteKey, MPSiteKeySize, NULL, 0, 0, NULL );
|
||||
if (resultKey == null)
|
||||
throw logger.bug( "Could not derive result key." );
|
||||
|
||||
// Base64-encode
|
||||
String b64Key = Verify.verifyNotNull( CryptUtils.encodeBase64( resultKey ) );
|
||||
logger.trc( "b64 encoded -> key: %s", b64Key );
|
||||
|
||||
return b64Key;
|
||||
} else
|
||||
throw logger.bug( "Unsupported derived password type: %s", resultType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
|
||||
final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext, final MPResultType resultType, final String resultParam) {
|
||||
|
||||
try {
|
||||
// Encrypt
|
||||
byte[] cipherBuf = CryptUtils.encrypt( resultParam.getBytes( mpw_charset ), masterKey, true );
|
||||
logger.trc( "cipherBuf: %d bytes = %s", cipherBuf.length, CodeUtils.encodeHex( cipherBuf ) );
|
||||
|
||||
// Base64-encode
|
||||
String cipherText = Verify.verifyNotNull( CryptUtils.encodeBase64( cipherBuf ) );
|
||||
logger.trc( "b64 encoded -> cipherText: %s", cipherText );
|
||||
|
||||
return cipherText;
|
||||
}
|
||||
catch (final IllegalBlockSizeException e) {
|
||||
throw logger.bug( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* @see MPMasterKey.Version#V1
|
||||
*
|
||||
* @author lhunath, 2014-08-30
|
||||
*/
|
||||
public class MPAlgorithmV1 extends MPAlgorithmV0 {
|
||||
|
||||
@Override
|
||||
public MPMasterKey.Version getAlgorithmVersion() {
|
||||
|
||||
return MPMasterKey.Version.V1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
|
||||
// Determine the template.
|
||||
Preconditions.checkState( siteKey.length > 0 );
|
||||
int templateIndex = siteKey[0] & 0xFF; // Convert to unsigned int.
|
||||
MPTemplate template = resultType.getTemplateAtRollingIndex( templateIndex );
|
||||
logger.trc( "template: %d => %s", templateIndex, template.getTemplateString() );
|
||||
|
||||
// Encode the password from the seed using the template.
|
||||
StringBuilder password = new StringBuilder( template.length() );
|
||||
for (int i = 0; i < template.length(); ++i) {
|
||||
int characterIndex = siteKey[i + 1] & 0xFF; // Convert to unsigned int.
|
||||
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
|
||||
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
|
||||
logger.trc( " - class: %c, index: %3d (0x%2H) => character: %c",
|
||||
characterClass.getIdentifier(), characterIndex, siteKey[i + 1], passwordCharacter );
|
||||
|
||||
password.append( passwordCharacter );
|
||||
}
|
||||
logger.trc( " => password: %s", password );
|
||||
|
||||
return password.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.masterpassword.MPUtils.*;
|
||||
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* @see MPMasterKey.Version#V2
|
||||
*
|
||||
* @author lhunath, 2014-08-30
|
||||
*/
|
||||
public class MPAlgorithmV2 extends MPAlgorithmV1 {
|
||||
|
||||
@Override
|
||||
public MPMasterKey.Version getAlgorithmVersion() {
|
||||
|
||||
return MPMasterKey.Version.V2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext) {
|
||||
|
||||
String keyScope = keyPurpose.getScope();
|
||||
logger.trc( "keyScope: %s", keyScope );
|
||||
|
||||
// OTP counter value.
|
||||
if (siteCounter.longValue() == 0)
|
||||
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPAlgorithm.mpw_otp_window * 1000)) * MPAlgorithm.mpw_otp_window );
|
||||
|
||||
// Calculate the site seed.
|
||||
byte[] siteNameBytes = siteName.getBytes( MPAlgorithm.mpw_charset );
|
||||
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
|
||||
byte[] siteCounterBytes = bytesForInt( siteCounter );
|
||||
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( MPAlgorithm.mpw_charset );
|
||||
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: bytesForInt( keyContextBytes.length );
|
||||
logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
|
||||
keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
|
||||
(keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
|
||||
|
||||
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( MPAlgorithm.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
||||
if (keyContextBytes != null)
|
||||
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
|
||||
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
|
||||
|
||||
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
|
||||
byte[] sitePasswordSeedBytes = MPAlgorithm.mpw_digest.of( masterKey, sitePasswordInfo );
|
||||
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
|
||||
|
||||
return sitePasswordSeedBytes;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.masterpassword.MPUtils.*;
|
||||
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* @see MPMasterKey.Version#V3
|
||||
*
|
||||
* @author lhunath, 2014-08-30
|
||||
*/
|
||||
public class MPAlgorithmV3 extends MPAlgorithmV2 {
|
||||
|
||||
@Override
|
||||
public MPMasterKey.Version getAlgorithmVersion() {
|
||||
|
||||
return MPMasterKey.Version.V3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
||||
|
||||
byte[] fullNameBytes = fullName.getBytes( MPAlgorithm.mpw_charset );
|
||||
byte[] fullNameLengthBytes = MPUtils.bytesForInt( fullNameBytes.length );
|
||||
|
||||
String keyScope = MPKeyPurpose.Authentication.getScope();
|
||||
logger.trc( "keyScope: %s", keyScope );
|
||||
|
||||
// Calculate the master key salt.
|
||||
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
||||
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
||||
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( MPAlgorithm.mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
||||
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
||||
|
||||
// Calculate the master key.
|
||||
logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
|
||||
MPAlgorithm.scrypt_N, MPAlgorithm.scrypt_r, MPAlgorithm.scrypt_p );
|
||||
byte[] mpBytes = bytesForChars( masterPassword );
|
||||
byte[] masterKey = scrypt( masterKeySalt, mpBytes );
|
||||
Arrays.fill( masterKeySalt, (byte) 0 );
|
||||
Arrays.fill( mpBytes, (byte) 0 );
|
||||
logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
|
||||
|
||||
return masterKey;
|
||||
}
|
||||
}
|
||||
@@ -1,246 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.masterpassword.MPUtils.*;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumMap;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2014-08-30
|
||||
*/
|
||||
public class MPMasterKey {
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( MPMasterKey.class );
|
||||
|
||||
private final EnumMap<Version, byte[]> keyByVersion = new EnumMap<>( Version.class );
|
||||
private final String fullName;
|
||||
private final char[] masterPassword;
|
||||
|
||||
private boolean invalidated;
|
||||
|
||||
/**
|
||||
* @param masterPassword The characters of the user's master password. Note: this array is held by reference and its contents
|
||||
* invalidated on {@link #invalidate()}.
|
||||
*/
|
||||
@SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
|
||||
public MPMasterKey(final String fullName, final char[] masterPassword) {
|
||||
|
||||
this.fullName = fullName;
|
||||
this.masterPassword = masterPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive the master key for a user based on their name and master password.
|
||||
*
|
||||
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||
*/
|
||||
private byte[] masterKey(final Version algorithmVersion)
|
||||
throws MPInvalidatedException {
|
||||
Preconditions.checkArgument( masterPassword.length > 0 );
|
||||
|
||||
if (invalidated)
|
||||
throw new MPInvalidatedException();
|
||||
|
||||
byte[] key = keyByVersion.get( algorithmVersion );
|
||||
if (key == null) {
|
||||
logger.trc( "-- mpw_masterKey (algorithm: %d)", algorithmVersion.toInt() );
|
||||
logger.trc( "fullName: %s", fullName );
|
||||
logger.trc( "masterPassword.id: %s", CodeUtils.encodeHex( idForBytes( bytesForChars( masterPassword ) ) ) );
|
||||
|
||||
keyByVersion.put( algorithmVersion, key = algorithmVersion.getAlgorithm().masterKey( fullName, masterPassword ) );
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive the master key for a user based on their name and master password.
|
||||
*
|
||||
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||
*/
|
||||
private byte[] siteKey(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext, final Version algorithmVersion)
|
||||
throws MPInvalidatedException {
|
||||
Preconditions.checkArgument( !siteName.isEmpty() );
|
||||
|
||||
byte[] masterKey = masterKey( algorithmVersion );
|
||||
|
||||
logger.trc( "-- mpw_siteKey (algorithm: %d)", algorithmVersion.toInt() );
|
||||
logger.trc( "siteName: %s", siteName );
|
||||
logger.trc( "siteCounter: %s", siteCounter );
|
||||
logger.trc( "keyPurpose: %d (%s)", keyPurpose.toInt(), keyPurpose.getShortName() );
|
||||
logger.trc( "keyContext: %s", keyContext );
|
||||
|
||||
return algorithmVersion.getAlgorithm().siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a site result token.
|
||||
*
|
||||
* @param siteName A site identifier.
|
||||
* @param siteCounter The result identifier.
|
||||
* @param keyPurpose The intended purpose for this site result.
|
||||
* @param keyContext A site-scoped result modifier.
|
||||
* @param resultType The type of result to generate.
|
||||
* @param resultParam A parameter for the resultType. For stateful result types, the output of
|
||||
* {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}.
|
||||
*
|
||||
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||
*/
|
||||
public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
||||
final Version algorithmVersion)
|
||||
throws MPInvalidatedException {
|
||||
|
||||
byte[] masterKey = masterKey( algorithmVersion );
|
||||
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
|
||||
|
||||
logger.trc( "-- mpw_siteResult (algorithm: %d)", algorithmVersion.toInt() );
|
||||
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
||||
logger.trc( "resultParam: %s", resultParam );
|
||||
|
||||
return algorithmVersion.getAlgorithm().siteResult(
|
||||
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt a stateful site token for persistence.
|
||||
*
|
||||
* @param siteName A site identifier.
|
||||
* @param siteCounter The result identifier.
|
||||
* @param keyPurpose The intended purpose for the site token.
|
||||
* @param keyContext A site-scoped key modifier.
|
||||
* @param resultType The type of result token to encrypt.
|
||||
* @param resultParam The result token desired from
|
||||
* {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}.
|
||||
*
|
||||
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||
*/
|
||||
public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
||||
final Version algorithmVersion)
|
||||
throws MPInvalidatedException {
|
||||
|
||||
Preconditions.checkNotNull( resultParam );
|
||||
Preconditions.checkArgument( !resultParam.isEmpty() );
|
||||
|
||||
byte[] masterKey = masterKey( algorithmVersion );
|
||||
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
|
||||
|
||||
logger.trc( "-- mpw_siteState (algorithm: %d)", algorithmVersion.toInt() );
|
||||
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
||||
logger.trc( "resultParam: %d bytes = %s", resultParam.getBytes( MPAlgorithm.mpw_charset ).length, resultParam );
|
||||
|
||||
return algorithmVersion.getAlgorithm().siteState(
|
||||
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getFullName() {
|
||||
|
||||
return fullName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate an identifier for the master key.
|
||||
*
|
||||
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||
*/
|
||||
public byte[] getKeyID(final Version algorithmVersion)
|
||||
throws MPInvalidatedException {
|
||||
|
||||
return idForBytes( masterKey( algorithmVersion ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipe this key's secrets from memory, making the object permanently unusable.
|
||||
*/
|
||||
public void invalidate() {
|
||||
|
||||
invalidated = true;
|
||||
for (final byte[] key : keyByVersion.values())
|
||||
Arrays.fill( key, (byte) 0 );
|
||||
Arrays.fill( masterPassword, (char) 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* The algorithm iterations.
|
||||
*/
|
||||
public enum Version {
|
||||
|
||||
/**
|
||||
* bugs:
|
||||
* - does math with chars whose signedness was platform-dependent.
|
||||
* - miscounted the byte-length for multi-byte site names.
|
||||
* - miscounted the byte-length for multi-byte user names.
|
||||
*/
|
||||
V0( new MPAlgorithmV0() ),
|
||||
|
||||
/**
|
||||
* bugs:
|
||||
* - miscounted the byte-length for multi-byte site names.
|
||||
* - miscounted the byte-length for multi-byte user names.
|
||||
*/
|
||||
V1( new MPAlgorithmV1() ),
|
||||
|
||||
/**
|
||||
* bugs:
|
||||
* - miscounted the byte-length for multi-byte user names.
|
||||
*/
|
||||
V2( new MPAlgorithmV2() ),
|
||||
|
||||
/**
|
||||
* bugs:
|
||||
* - no known issues.
|
||||
*/
|
||||
V3( new MPAlgorithmV3() );
|
||||
|
||||
public static final Version CURRENT = V3;
|
||||
|
||||
private final MPAlgorithm algorithm;
|
||||
|
||||
Version(final MPAlgorithm algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
public MPAlgorithm getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
public static Version fromInt(final int algorithmVersion) {
|
||||
|
||||
return values()[algorithmVersion];
|
||||
}
|
||||
|
||||
public int toInt() {
|
||||
|
||||
return ordinal();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2017-09-20
|
||||
*/
|
||||
public final class MPUtils {
|
||||
|
||||
public static byte[] bytesForInt(final int number) {
|
||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithm.mpw_byteOrder ).putInt( number ).array();
|
||||
}
|
||||
|
||||
public static byte[] bytesForInt(final UnsignedInteger number) {
|
||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithm.mpw_byteOrder ).putInt( number.intValue() ).array();
|
||||
}
|
||||
|
||||
public static byte[] bytesForChars(final char[] characters) {
|
||||
ByteBuffer byteBuffer = MPAlgorithm.mpw_charset.encode( CharBuffer.wrap( characters ) );
|
||||
|
||||
byte[] bytes = new byte[byteBuffer.remaining()];
|
||||
byteBuffer.get( bytes );
|
||||
|
||||
Arrays.fill( byteBuffer.array(), (byte) 0 );
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static byte[] idForBytes(final byte[] bytes) {
|
||||
return MPAlgorithm.mpw_hash.of( bytes );
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'net.ltgt.apt' version '0.9'
|
||||
}
|
||||
|
||||
description = 'Master Password Site Model'
|
||||
|
||||
dependencies {
|
||||
compile project(':masterpassword-algorithm')
|
||||
|
||||
compile group: 'joda-time', name: 'joda-time', version:'2.4'
|
||||
compileOnly group: 'com.google.auto.value', name: 'auto-value', version: '1.2'
|
||||
apt group: 'com.google.auto.value', name: 'auto-value', version: '1.2'
|
||||
|
||||
testCompile group: 'org.testng', name: 'testng', version:'6.8.5'
|
||||
testCompile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2'
|
||||
}
|
||||
test.useTestNG()
|
||||
@@ -1,55 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password Site Model</name>
|
||||
<description>A persistence model for Master Password sites.</description>
|
||||
|
||||
<artifactId>masterpassword-model</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<!-- DEPENDENCY MANAGEMENT -->
|
||||
<dependencies>
|
||||
|
||||
<!-- PROJECT REFERENCES -->
|
||||
<dependency>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EXTERNAL DEPENDENCIES -->
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.value</groupId>
|
||||
<artifactId>auto-value</artifactId>
|
||||
<version>1.0-rc1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- TESTING -->
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,205 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword.model;
|
||||
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lyndir.masterpassword.*;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.Instant;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 14-12-05
|
||||
*/
|
||||
public class MPFileSite extends MPSite {
|
||||
|
||||
private final MPFileUser user;
|
||||
private String siteName;
|
||||
@Nullable
|
||||
private String siteContent;
|
||||
private UnsignedInteger siteCounter;
|
||||
private MPResultType resultType;
|
||||
private MPMasterKey.Version algorithmVersion;
|
||||
|
||||
@Nullable
|
||||
private String loginContent;
|
||||
@Nullable
|
||||
private MPResultType loginType;
|
||||
|
||||
@Nullable
|
||||
private String url;
|
||||
private int uses;
|
||||
private Instant lastUsed;
|
||||
|
||||
public MPFileSite(final MPFileUser user, final String siteName) {
|
||||
this( user, siteName, DEFAULT_COUNTER, MPResultType.DEFAULT, MPMasterKey.Version.CURRENT );
|
||||
}
|
||||
|
||||
public MPFileSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
|
||||
final MPMasterKey.Version algorithmVersion) {
|
||||
this.user = user;
|
||||
this.siteName = siteName;
|
||||
this.siteCounter = siteCounter;
|
||||
this.resultType = resultType;
|
||||
this.algorithmVersion = algorithmVersion;
|
||||
this.lastUsed = new Instant();
|
||||
}
|
||||
|
||||
protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteContent,
|
||||
final UnsignedInteger siteCounter,
|
||||
final MPResultType resultType, final MPMasterKey.Version algorithmVersion,
|
||||
@Nullable final String loginContent, @Nullable final MPResultType loginType,
|
||||
@Nullable final String url, final int uses, final Instant lastUsed) {
|
||||
this.user = user;
|
||||
this.siteName = siteName;
|
||||
this.siteContent = siteContent;
|
||||
this.siteCounter = siteCounter;
|
||||
this.resultType = resultType;
|
||||
this.algorithmVersion = algorithmVersion;
|
||||
this.loginContent = loginContent;
|
||||
this.loginType = loginType;
|
||||
this.url = url;
|
||||
this.uses = uses;
|
||||
this.lastUsed = lastUsed;
|
||||
}
|
||||
|
||||
public String resultFor(final MPMasterKey masterKey)
|
||||
throws MPInvalidatedException {
|
||||
|
||||
return resultFor( masterKey, MPKeyPurpose.Authentication, null );
|
||||
}
|
||||
|
||||
public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
|
||||
throws MPInvalidatedException {
|
||||
|
||||
return resultFor( masterKey, keyPurpose, keyContext, getSiteContent() );
|
||||
}
|
||||
|
||||
public String loginFor(final MPMasterKey masterKey)
|
||||
throws MPInvalidatedException {
|
||||
|
||||
if (loginType == null)
|
||||
loginType = MPResultType.GeneratedName;
|
||||
|
||||
return loginFor( masterKey, loginType, loginContent );
|
||||
}
|
||||
|
||||
public MPFileUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSiteName() {
|
||||
return siteName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSiteName(final String siteName) {
|
||||
this.siteName = siteName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getSiteContent() {
|
||||
return siteContent;
|
||||
}
|
||||
|
||||
public void setSitePassword(final MPMasterKey masterKey, @Nullable final MPResultType resultType, @Nullable final String result)
|
||||
throws MPInvalidatedException {
|
||||
this.resultType = resultType;
|
||||
if (result == null)
|
||||
this.siteContent = null;
|
||||
else
|
||||
this.siteContent = masterKey.siteState(
|
||||
getSiteName(), getSiteCounter(), MPKeyPurpose.Authentication, null, getResultType(), result, getAlgorithmVersion() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnsignedInteger getSiteCounter() {
|
||||
return siteCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSiteCounter(final UnsignedInteger siteCounter) {
|
||||
this.siteCounter = siteCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MPResultType getResultType() {
|
||||
return resultType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResultType(final MPResultType resultType) {
|
||||
this.resultType = resultType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MPMasterKey.Version getAlgorithmVersion() {
|
||||
return algorithmVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlgorithmVersion(final MPMasterKey.Version algorithmVersion) {
|
||||
this.algorithmVersion = algorithmVersion;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public MPResultType getLoginType() {
|
||||
return loginType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getLoginContent() {
|
||||
return loginContent;
|
||||
}
|
||||
|
||||
public void setLoginName(final MPMasterKey masterKey, @Nullable final MPResultType loginType, @Nullable final String result)
|
||||
throws MPInvalidatedException {
|
||||
this.loginType = loginType;
|
||||
if (this.loginType != null)
|
||||
if (result == null)
|
||||
this.loginContent = null;
|
||||
else
|
||||
this.loginContent = masterKey.siteState(
|
||||
siteName, DEFAULT_COUNTER, MPKeyPurpose.Identification, null, this.loginType, result, algorithmVersion );
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(@Nullable final String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public int getUses() {
|
||||
return uses;
|
||||
}
|
||||
|
||||
public Instant getLastUsed() {
|
||||
return lastUsed;
|
||||
}
|
||||
|
||||
public void use() {
|
||||
uses++;
|
||||
lastUsed = new Instant();
|
||||
user.use();
|
||||
}
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword.model;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import com.lyndir.masterpassword.*;
|
||||
import java.util.*;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.*;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 14-12-07
|
||||
*/
|
||||
public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileUser> {
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( MPFileUser.class );
|
||||
|
||||
private final String fullName;
|
||||
private final Collection<MPFileSite> sites = Sets.newHashSet();
|
||||
|
||||
@Nullable
|
||||
private byte[] keyID;
|
||||
private MPMasterKey.Version algorithmVersion;
|
||||
|
||||
private int avatar;
|
||||
private MPResultType defaultType;
|
||||
private ReadableInstant lastUsed;
|
||||
|
||||
public MPFileUser(final String fullName) {
|
||||
this( fullName, null, MPMasterKey.Version.CURRENT );
|
||||
}
|
||||
|
||||
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPMasterKey.Version algorithmVersion) {
|
||||
this( fullName, keyID, algorithmVersion, 0, MPResultType.DEFAULT, new Instant() );
|
||||
}
|
||||
|
||||
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPMasterKey.Version algorithmVersion, final int avatar,
|
||||
final MPResultType defaultType, final ReadableInstant lastUsed) {
|
||||
this.fullName = fullName;
|
||||
this.keyID = (keyID == null)? null: keyID.clone();
|
||||
this.algorithmVersion = algorithmVersion;
|
||||
this.avatar = avatar;
|
||||
this.defaultType = defaultType;
|
||||
this.lastUsed = lastUsed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MPMasterKey.Version getAlgorithmVersion() {
|
||||
return algorithmVersion;
|
||||
}
|
||||
|
||||
public void setAlgorithmVersion(final MPMasterKey.Version algorithmVersion) {
|
||||
this.algorithmVersion = algorithmVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
public void setAvatar(final int avatar) {
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
public MPResultType getDefaultType() {
|
||||
return defaultType;
|
||||
}
|
||||
|
||||
public void setDefaultType(final MPResultType defaultType) {
|
||||
this.defaultType = defaultType;
|
||||
}
|
||||
|
||||
public ReadableInstant getLastUsed() {
|
||||
return lastUsed;
|
||||
}
|
||||
|
||||
public void use() {
|
||||
lastUsed = new Instant();
|
||||
}
|
||||
|
||||
public Iterable<MPFileSite> getSites() {
|
||||
return sites;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSite(final MPFileSite site) {
|
||||
sites.add( site );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSite(final MPFileSite site) {
|
||||
sites.remove( site );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<MPFileSite> findSites(final String query) {
|
||||
ImmutableList.Builder<MPFileSite> results = ImmutableList.builder();
|
||||
for (final MPFileSite site : getSites())
|
||||
if (site.getSiteName().startsWith( query ))
|
||||
results.add( site );
|
||||
|
||||
return results.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an authentication attempt against the keyID for this user.
|
||||
*
|
||||
* Note: If this user doesn't have a keyID set yet, authentication will always succeed and the key ID will be set as a result.
|
||||
*
|
||||
* @param masterPassword The password to authenticate with.
|
||||
*
|
||||
* @return The master key for the user if authentication was successful.
|
||||
*
|
||||
* @throws MPIncorrectMasterPasswordException If authentication fails due to the given master password not matching the user's keyID.
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
public MPMasterKey authenticate(final char[] masterPassword)
|
||||
throws MPIncorrectMasterPasswordException {
|
||||
try {
|
||||
key = new MPMasterKey( getFullName(), masterPassword );
|
||||
if ((keyID == null) || (keyID.length == 0))
|
||||
keyID = key.getKeyID( algorithmVersion );
|
||||
else if (!Arrays.equals( key.getKeyID( algorithmVersion ), keyID ))
|
||||
throw new MPIncorrectMasterPasswordException( this );
|
||||
|
||||
return key;
|
||||
}
|
||||
catch (final MPInvalidatedException e) {
|
||||
throw logger.bug( e );
|
||||
}
|
||||
}
|
||||
|
||||
void save()
|
||||
throws MPInvalidatedException {
|
||||
MPFileUserManager.get().save( this, getMasterKey() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final MPFileUser o) {
|
||||
int comparison = getLastUsed().compareTo( o.getLastUsed() );
|
||||
if (comparison == 0)
|
||||
comparison = getFullName().compareTo( o.getFullName() );
|
||||
|
||||
return comparison;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword.model;
|
||||
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lyndir.masterpassword.*;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 14-12-16
|
||||
*/
|
||||
public abstract class MPSite {
|
||||
|
||||
public static final UnsignedInteger DEFAULT_COUNTER = UnsignedInteger.ONE;
|
||||
|
||||
public abstract String getSiteName();
|
||||
|
||||
public abstract void setSiteName(String siteName);
|
||||
|
||||
public abstract UnsignedInteger getSiteCounter();
|
||||
|
||||
public abstract void setSiteCounter(UnsignedInteger siteCounter);
|
||||
|
||||
public abstract MPResultType getResultType();
|
||||
|
||||
public abstract void setResultType(MPResultType resultType);
|
||||
|
||||
public abstract MPMasterKey.Version getAlgorithmVersion();
|
||||
|
||||
public abstract void setAlgorithmVersion(MPMasterKey.Version algorithmVersion);
|
||||
|
||||
public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
|
||||
@Nullable final String siteContent)
|
||||
throws MPInvalidatedException {
|
||||
|
||||
return masterKey.siteResult(
|
||||
getSiteName(), getSiteCounter(), keyPurpose, keyContext, getResultType(), siteContent, getAlgorithmVersion() );
|
||||
}
|
||||
|
||||
public String loginFor(final MPMasterKey masterKey, final MPResultType loginType, @Nullable final String loginContent)
|
||||
throws MPInvalidatedException {
|
||||
|
||||
return masterKey.siteResult(
|
||||
getSiteName(), DEFAULT_COUNTER, MPKeyPurpose.Identification, null, loginType, loginContent, getAlgorithmVersion() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return (this == obj) || ((obj instanceof MPSite) && Objects.equals( getSiteName(), ((MPSite) obj).getSiteName() ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode( getSiteName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return strf( "{%s: %s}", getClass().getSimpleName(), getSiteName() );
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword.model;
|
||||
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||
import com.lyndir.masterpassword.MPInvalidatedException;
|
||||
import com.lyndir.masterpassword.MPMasterKey;
|
||||
import java.util.*;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2014-06-08
|
||||
*/
|
||||
public abstract class MPUser<S extends MPSite> {
|
||||
|
||||
@Nullable
|
||||
protected MPMasterKey key;
|
||||
|
||||
public abstract String getFullName();
|
||||
|
||||
public boolean isMasterKeyAvailable() {
|
||||
return key != null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public MPMasterKey getMasterKey() {
|
||||
return Preconditions.checkNotNull( key, "User is not authenticated: " + getFullName() );
|
||||
}
|
||||
|
||||
public String exportKeyID()
|
||||
throws MPInvalidatedException {
|
||||
return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithmVersion() ) );
|
||||
}
|
||||
|
||||
public abstract MPMasterKey.Version getAlgorithmVersion();
|
||||
|
||||
public int getAvatar() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public abstract void addSite(S site);
|
||||
|
||||
public abstract void deleteSite(S site);
|
||||
|
||||
public abstract Collection<S> findSites(String query);
|
||||
|
||||
@Nonnull
|
||||
public abstract MPMasterKey authenticate(char[] masterPassword)
|
||||
throws MPIncorrectMasterPasswordException;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode( getFullName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return (this == obj) || ((obj instanceof MPUser) && Objects.equals( getFullName(), ((MPUser<?>) obj).getFullName() ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return strf( "{%s: %s}", getClass().getSimpleName(), getFullName() );
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
description = 'Master Password Test Suite'
|
||||
|
||||
dependencies {
|
||||
compile project(':masterpassword-algorithm')
|
||||
|
||||
testCompile group: 'org.testng', name: 'testng', version:'6.8.5'
|
||||
testCompile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2'
|
||||
}
|
||||
test.useTestNG()
|
||||
@@ -1,43 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password Test Suite</name>
|
||||
<description>The standard test suite to ensure the Master Password algorithm is operating as it should</description>
|
||||
|
||||
<artifactId>masterpassword-tests</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<!-- DEPENDENCY MANAGEMENT -->
|
||||
<dependencies>
|
||||
|
||||
<!-- PROJECT REFERENCES -->
|
||||
<dependency>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- TESTING -->
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1 +0,0 @@
|
||||
../../../../../mpw_tests.xml
|
||||
@@ -1,130 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.util.Random;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
||||
public class MPMasterKeyTest {
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( MPMasterKeyTest.class );
|
||||
|
||||
private MPTestSuite testSuite;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp()
|
||||
throws Exception {
|
||||
|
||||
testSuite = new MPTestSuite();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMasterKey()
|
||||
throws Exception {
|
||||
|
||||
testSuite.forEach( "testMasterKey", new MPTestSuite.TestCase() {
|
||||
@Override
|
||||
public boolean run(final MPTests.Case testCase)
|
||||
throws Exception {
|
||||
char[] masterPassword = testCase.getMasterPassword().toCharArray();
|
||||
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
|
||||
|
||||
// Test key
|
||||
assertEquals(
|
||||
CodeUtils.encodeHex( masterKey.getKeyID( testCase.getAlgorithm() ) ),
|
||||
testCase.getKeyID(),
|
||||
"[testMasterKey] keyID mismatch: " + testCase );
|
||||
|
||||
// Test invalidation
|
||||
masterKey.invalidate();
|
||||
try {
|
||||
masterKey.getKeyID( testCase.getAlgorithm() );
|
||||
fail( "[testMasterKey] invalidate ineffective: " + testCase );
|
||||
}
|
||||
catch (final MPInvalidatedException ignored) {
|
||||
}
|
||||
assertNotEquals(
|
||||
masterPassword,
|
||||
testCase.getMasterPassword().toCharArray(),
|
||||
"[testMasterKey] masterPassword not wiped: " + testCase );
|
||||
|
||||
return true;
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSiteResult()
|
||||
throws Exception {
|
||||
|
||||
testSuite.forEach( "testSiteResult", new MPTestSuite.TestCase() {
|
||||
@Override
|
||||
public boolean run(final MPTests.Case testCase)
|
||||
throws Exception {
|
||||
char[] masterPassword = testCase.getMasterPassword().toCharArray();
|
||||
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
|
||||
|
||||
// Test site result
|
||||
assertEquals(
|
||||
masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||
testCase.getKeyContext(), testCase.getResultType(),
|
||||
null, testCase.getAlgorithm() ),
|
||||
testCase.getResult(),
|
||||
"[testSiteResult] result mismatch: " + testCase );
|
||||
|
||||
return true;
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSiteState()
|
||||
throws Exception {
|
||||
|
||||
MPTests.Case testCase = testSuite.getTests().getDefaultCase();
|
||||
char[] masterPassword = testCase.getMasterPassword().toCharArray();
|
||||
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
|
||||
|
||||
Random random = new Random();
|
||||
StringBuilder password = new StringBuilder();
|
||||
for (int p = 0; p < 8; ++p)
|
||||
password.append( (char) (random.nextInt( Character.MAX_CODE_POINT - Character.MIN_CODE_POINT ) + Character.MIN_CODE_POINT) );
|
||||
|
||||
for (final MPMasterKey.Version version : MPMasterKey.Version.values()) {
|
||||
MPResultType resultType = MPResultType.StoredPersonal;
|
||||
|
||||
// Test site state
|
||||
String state = masterKey.siteState( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||
testCase.getKeyContext(), resultType, password.toString(), version );
|
||||
|
||||
assertEquals(
|
||||
masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||
testCase.getKeyContext(), resultType, state, version ),
|
||||
password.toString(),
|
||||
"[testSiteState] state mismatch: " + testCase );
|
||||
}
|
||||
}
|
||||
}
|
||||
9
gradle/.idea/codeStyleSettings.xml
generated
9
gradle/.idea/codeStyleSettings.xml
generated
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectCodeStyleSettingsManager">
|
||||
<option name="PER_PROJECT_SETTINGS">
|
||||
<value />
|
||||
</option>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Lhunath" />
|
||||
</component>
|
||||
</project>
|
||||
7
gradle/.idea/copyright/GPLv3.xml
generated
7
gradle/.idea/copyright/GPLv3.xml
generated
@@ -1,7 +0,0 @@
|
||||
<component name="CopyrightManager">
|
||||
<copyright>
|
||||
<option name="keyword" value="Copyright|License|WARRANTY" />
|
||||
<option name="myName" value="GPLv3" />
|
||||
<option name="notice" value="This file is part of &#36;project.name. Copyright (c) &#36;today.year. &#36;project.name is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. &#36;project.name is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You can find a copy of the GNU General Public License in the LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>." />
|
||||
</copyright>
|
||||
</component>
|
||||
13
gradle/.idea/copyright/profiles_settings.xml
generated
13
gradle/.idea/copyright/profiles_settings.xml
generated
@@ -1,13 +0,0 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings>
|
||||
<module2copyright>
|
||||
<element module="masterpassword" copyright="Master Password" />
|
||||
</module2copyright>
|
||||
<LanguageOptions name="__TEMPLATE__">
|
||||
<option name="block" value="false" />
|
||||
<option name="separateBefore" value="true" />
|
||||
<option name="separateAfter" value="true" />
|
||||
<option name="filler" value="=" />
|
||||
</LanguageOptions>
|
||||
</settings>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="projectProfile" value="Lhunath" />
|
||||
<option name="useProjectProfile" value="false" />
|
||||
<option name="PROJECT_PROFILE" value="Lhunath" />
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
15
gradle/.idea/misc.xml
generated
15
gradle/.idea/misc.xml
generated
@@ -1,12 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/../../opal/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="NullableNotNullManager">
|
||||
<option name="myDefaultNullable" value="javax.annotation.Nullable" />
|
||||
<option name="myDefaultNotNull" value="javax.annotation.Nonnull" />
|
||||
@@ -31,10 +24,10 @@
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/classes" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ThriftCompiler">
|
||||
<compilers />
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
||||
28
gradle/.idea/runConfigurations/Android.xml
generated
28
gradle/.idea/runConfigurations/Android.xml
generated
@@ -1,28 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Android" type="AndroidRunConfigurationType" factoryName="Android App">
|
||||
<module name="android" />
|
||||
<option name="DEPLOY" value="true" />
|
||||
<option name="ARTIFACT_NAME" value="" />
|
||||
<option name="PM_INSTALL_OPTIONS" value="" />
|
||||
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
|
||||
<option name="MODE" value="default_activity" />
|
||||
<option name="PREFERRED_AVD" value="" />
|
||||
<option name="CLEAR_LOGCAT" value="false" />
|
||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
|
||||
<option name="FORCE_STOP_RUNNING_APP" value="true" />
|
||||
<option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
|
||||
<option name="USE_LAST_SELECTED_DEVICE" value="false" />
|
||||
<option name="PREFERRED_AVD" value="" />
|
||||
<option name="DEBUGGER_TYPE" value="Java" />
|
||||
<Java />
|
||||
<Profilers>
|
||||
<option name="ENABLE_ADVANCED_PROFILING" value="false" />
|
||||
<option name="SUPPORT_LIB_ENABLED" value="true" />
|
||||
<option name="INSTRUMENTATION_ENABLED" value="true" />
|
||||
</Profilers>
|
||||
<option name="DEEP_LINK" value="" />
|
||||
<option name="ACTIVITY_CLASS" value="" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
16
gradle/.idea/runConfigurations/GUI.xml
generated
16
gradle/.idea/runConfigurations/GUI.xml
generated
@@ -1,16 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="GUI" type="Application" factoryName="Application" show_console_on_std_err="true">
|
||||
<option name="MAIN_CLASS_NAME" value="com.lyndir.masterpassword.gui.GUI" />
|
||||
<option name="VM_PARAMETERS" value="" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<option name="ENABLE_SWING_INSPECTOR" value="false" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<module name="masterpassword-gui" />
|
||||
<envs />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
29
gradle/.idea/runConfigurations/Tests.xml
generated
29
gradle/.idea/runConfigurations/Tests.xml
generated
@@ -1,29 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Tests" type="TestNG" factoryName="TestNG" show_console_on_std_err="true">
|
||||
<module name="" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<option name="SUITE_NAME" value="" />
|
||||
<option name="PACKAGE_NAME" value="com.lyndir.masterpassword" />
|
||||
<option name="MAIN_CLASS_NAME" value="" />
|
||||
<option name="METHOD_NAME" value="" />
|
||||
<option name="GROUP_NAME" value="" />
|
||||
<option name="TEST_OBJECT" value="PACKAGE" />
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../core/java/tests" />
|
||||
<option name="OUTPUT_DIRECTORY" value="" />
|
||||
<option name="ANNOTATION_TYPE" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="wholeProject" />
|
||||
</option>
|
||||
<option name="USE_DEFAULT_REPORTERS" value="false" />
|
||||
<option name="PROPERTIES_FILE" value="" />
|
||||
<envs />
|
||||
<properties />
|
||||
<listeners />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
3
gradle/.idea/scopes/masterpassword.xml
generated
3
gradle/.idea/scopes/masterpassword.xml
generated
@@ -1,3 +0,0 @@
|
||||
<component name="DependencyValidationManager">
|
||||
<scope name="masterpassword" pattern="com.lyndir.masterpassword..*" />
|
||||
</component>
|
||||
15
gradle/README.md
Normal file
15
gradle/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
To build a release distribution:
|
||||
|
||||
Desktop:
|
||||
|
||||
STORE_PW=$(mpw masterpassword.keystore) KEY_PW_DESKTOP=$(mpw masterpassword-desktop) gradle clean masterpassword-gui:shadowJar
|
||||
|
||||
Android:
|
||||
|
||||
STORE_PW=$(mpw masterpassword.keystore) KEY_PW_ANDROID=$(mpw masterpassword-android) gradle clean masterpassword-android:assembleRelease
|
||||
|
||||
|
||||
Note:
|
||||
|
||||
- At the time of writing, Android does not build with JDK 9+. As such, the above command must be ran with JAVA_HOME pointing to JDK 7-8.
|
||||
- The release keystores are not included in the repository. They are maintained by Maarten Billemont (lhunath@lyndir.com).
|
||||
@@ -1,34 +1,38 @@
|
||||
allprojects {
|
||||
//apply plugin: 'findbugs'
|
||||
apply plugin: 'findbugs'
|
||||
|
||||
group = 'com.lyndir.masterpassword'
|
||||
version = 'GIT-SNAPSHOT'
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
sourceCompatibility = '1.7'
|
||||
targetCompatibility = '1.7'
|
||||
tasks.withType( JavaCompile ) {
|
||||
options.encoding = 'UTF-8'
|
||||
sourceCompatibility = '1.8'
|
||||
targetCompatibility = '1.8'
|
||||
}
|
||||
tasks.withType(FindBugs) {
|
||||
tasks.withType( FindBugs ) {
|
||||
reports {
|
||||
xml.enabled false
|
||||
html.enabled true
|
||||
xml.enabled = false
|
||||
html.enabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath group: 'com.android.tools.build', name: 'gradle', version: '2.3.0'
|
||||
classpath group: 'com.android.tools.build', name: 'gradle', version: '3.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url 'http://maven.lyndir.com' }
|
||||
maven { url 'https://maven.lyndir.com' }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
org.gradle.daemon=true
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
|
||||
BIN
gradle/gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
@@ -1,6 +1,5 @@
|
||||
#Sun Mar 26 09:11:08 EDT 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
|
||||
|
||||
6
gradle/gradlew
vendored
6
gradle/gradlew
vendored
@@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS=""
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
@@ -155,7 +155,7 @@ if $cygwin ; then
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save ( ) {
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
|
||||
@@ -1,31 +1,40 @@
|
||||
class Mpw < Formula
|
||||
homepage "http://masterpasswordapp.com"
|
||||
url "https://ssl.masterpasswordapp.com/mpw-2.1-cli4-0-gf6b2287.tar.gz"
|
||||
sha1 "036b3d8f4bd6f0676ae16e7e9c3de65f6030874f"
|
||||
version "2.1-cli4"
|
||||
desc "Stateless/deterministic password and identity manager"
|
||||
homepage "https://masterpassword.app/"
|
||||
url "https://masterpassword.app/mpw-2.6-cli-5-0-g344771db.tar.gz"
|
||||
version "2.6-cli-5"
|
||||
sha256 "954c07b1713ecc2b30a07bead9c11e6204dd774ca67b5bdf7d2d6ad1c4eec170"
|
||||
revision 1
|
||||
head "https://gitlab.com/MasterPassword/MasterPassword.git"
|
||||
|
||||
depends_on "automake" => :build
|
||||
depends_on "autoconf" => :build
|
||||
depends_on "openssl"
|
||||
|
||||
resource "libscrypt" do
|
||||
url "http://masterpasswordapp.com/libscrypt-b12b554.tar.gz"
|
||||
sha1 "ee871e0f93a786c4e3622561f34565337cfdb815"
|
||||
bottle do
|
||||
cellar :any
|
||||
sha256 "46677cf8649983d5b77103d2ca56d9ad3697808ecc406f626a3462a089f932da" => :high_sierra
|
||||
sha256 "19bf22915b3c534ad3ee6f1dfc20f142d53ae6c0c88757ae2632b7b1daa6667f" => :sierra
|
||||
sha256 "7090c3d31289d2ac5529bd0a6bae2632a36ba7fcd4bb7974248bb36a15f67c7e" => :el_capitan
|
||||
end
|
||||
|
||||
option "without-json-c", "Disable JSON configuration support"
|
||||
option "without-ncurses", "Disable colorized identicon support"
|
||||
|
||||
depends_on "libsodium"
|
||||
depends_on "json-c" => :recommended
|
||||
depends_on "ncurses" => :recommended
|
||||
|
||||
def install
|
||||
resource("libscrypt").stage buildpath/"lib/scrypt"
|
||||
touch "lib/scrypt/.unpacked"
|
||||
cd "platform-independent/cli-c" if build.head?
|
||||
|
||||
ENV["targets"] = "mpw"
|
||||
ENV["mpw_json"] = build.with?("json-c") ? "1" : "0"
|
||||
ENV["mpw_color"] = build.with?("ncurses") ? "1" : "0"
|
||||
|
||||
ENV["targets"] = "mpw mpw-tests"
|
||||
system "./build"
|
||||
system "./mpw-tests"
|
||||
|
||||
system "./mpw-cli-tests"
|
||||
bin.install "mpw"
|
||||
end
|
||||
|
||||
test do
|
||||
assert_equal "Jejr5[RepuSosp",
|
||||
shell_output("mpw -u 'Robert Lee Mitchell' -P 'banana colored duckling' masterpasswordapp.com").strip
|
||||
shell_output("#{bin}/mpw -q -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c1 -a3 'masterpasswordapp.com'").strip
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.lhunath</groupId>
|
||||
<artifactId>lyndir</artifactId>
|
||||
<version>1.22</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password</name>
|
||||
<description>A Java implementation of the Master Password algorithm.</description>
|
||||
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>masterpassword-tests</module>
|
||||
<module>masterpassword-algorithm</module>
|
||||
<module>masterpassword-model</module>
|
||||
<module>masterpassword-gui</module>
|
||||
</modules>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<modules>
|
||||
<module>masterpassword-android</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>mod:android</id>
|
||||
<modules>
|
||||
<module>masterpassword-android</module>
|
||||
</modules>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<!-- REMOTE ARTIFACT REPOSITORIES -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>lyndir</id>
|
||||
<name>Lyndir Repository</name>
|
||||
<url>http://maven.lyndir.com</url>
|
||||
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
<updatePolicy>never</updatePolicy>
|
||||
</snapshots>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
<updatePolicy>never</updatePolicy>
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
@@ -1,26 +1,27 @@
|
||||
rootProject.name = 'masterpassword'
|
||||
|
||||
def local = new Properties();
|
||||
try {
|
||||
local.load(file('local.properties').newDataInputStream())
|
||||
} catch (FileNotFoundException ignored) {
|
||||
}
|
||||
def local = new Properties()
|
||||
def localFile = file( 'local.properties' )
|
||||
localFile.exists() && local.load( localFile.newDataInputStream() )
|
||||
|
||||
include 'masterpassword-core'
|
||||
project( ':masterpassword-core' ).projectDir = new File( '../platform-independent/c/core' )
|
||||
|
||||
include 'masterpassword-algorithm'
|
||||
project(':masterpassword-algorithm').projectDir = new File( '../core/java/algorithm' )
|
||||
project( ':masterpassword-algorithm' ).projectDir = new File( '../platform-independent/java/algorithm' )
|
||||
|
||||
include 'masterpassword-model'
|
||||
project(':masterpassword-model').projectDir = new File( '../core/java/model' )
|
||||
project( ':masterpassword-model' ).projectDir = new File( '../platform-independent/java/model' )
|
||||
|
||||
include 'masterpassword-tests'
|
||||
project(':masterpassword-tests').projectDir = new File( '../core/java/tests' )
|
||||
project( ':masterpassword-tests' ).projectDir = new File( '../platform-independent/java/tests' )
|
||||
|
||||
include 'masterpassword-gui'
|
||||
project(':masterpassword-gui').projectDir = new File( '../platform-independent/gui-java' )
|
||||
project( ':masterpassword-gui' ).projectDir = new File( '../platform-independent/java/gui' )
|
||||
|
||||
if (local.containsKey('sdk.dir')) {
|
||||
if (local.containsKey( 'sdk.dir' ) && file( local.getProperty( 'sdk.dir' ) ).exists()) {
|
||||
include 'masterpassword-android'
|
||||
project(':masterpassword-android').projectDir = new File( '../platform-android' )
|
||||
project( ':masterpassword-android' ).projectDir = new File( '../platform-android' )
|
||||
} else {
|
||||
logger.warn( "Skipping masterpassword-android since sdk.dir is not defined in local.properties." )
|
||||
}
|
||||
|
||||
371
lib/bin/build_lib
Executable file
371
lib/bin/build_lib
Executable file
@@ -0,0 +1,371 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Your build script should simply source this script, optionally override any build hooks and then invoke `build`.
|
||||
# The build product should be available under `build-<platform>~/out`, under the library path.
|
||||
#
|
||||
# Hook lifecycle:
|
||||
# - build
|
||||
# - initialize
|
||||
# - needs
|
||||
# - clean & exit (only if script was ran with "clean" argument)
|
||||
# - prepare
|
||||
# - clean
|
||||
# - config
|
||||
# - target
|
||||
# - prepare
|
||||
# - configure
|
||||
# - build
|
||||
# - finalize
|
||||
# - merge
|
||||
# - clean
|
||||
#
|
||||
# You can override any of these hooks to provide a custom implementation or call their underscore variant to delegate to the default implementation.
|
||||
# For example:
|
||||
# target_prepare() { make -s distclean; }
|
||||
# target_configure() { _target_configure "$@" --enable-minimal; }
|
||||
set -e
|
||||
|
||||
# needs <binary> ...
|
||||
#
|
||||
# Utility for ensuring all tools needed by the script are installed prior to starting.
|
||||
needs() { _needs "$@"; }
|
||||
_needs() {
|
||||
local failed=0
|
||||
for tool; do
|
||||
hash "$tool" || { echo >&2 "Missing: $tool. Please install this tool."; (( failed++ )); }
|
||||
done
|
||||
|
||||
return $failed
|
||||
}
|
||||
|
||||
# initialize <prefix> <platform>
|
||||
#
|
||||
# The build script invokes this once prior to all other actions if the user wants a clean slate.
|
||||
initialize() { _initialize "$@"; }
|
||||
_initialize() {
|
||||
initialize_needs "$@"
|
||||
}
|
||||
|
||||
# initialize_needs <prefix> <platform>
|
||||
#
|
||||
# Check if all tools needed for the default implementations are available.
|
||||
#
|
||||
# By default, this will check for `libtool` (for libtoolize), `automake` (for aclocal) and `autoconf` (for autoreconf).
|
||||
initialize_needs() { _initialize_needs "$@"; }
|
||||
_initialize_needs() {
|
||||
if [[ $platform = windows ]]; then
|
||||
needs cmd
|
||||
export VSINSTALLDIR="${VSINSTALLDIR:-$(cd "$(cygpath -F 0x002a)/Microsoft Visual Studio"/*/*/Common7/.. && pwd)}"
|
||||
[[ -e "$VSINSTALLDIR/Common7/Tools/VsMSBuildCmd.bat" ]] || { echo >&2 "Missing: msbuild. Please install 'Build Tools for Visual Studio'."; return 1; }
|
||||
else
|
||||
needs libtool automake autoconf
|
||||
fi
|
||||
}
|
||||
|
||||
# clean <prefix> <platform>
|
||||
#
|
||||
# Fully clean up the library code, restoring it to a pristine state.
|
||||
#
|
||||
# By default, this will wipe the prefix, run `make distclean` and `git clean -fdx`.
|
||||
clean() { _clean "$@"; }
|
||||
_clean() {
|
||||
if [[ $platform = windows ]]; then
|
||||
printf '"%%VSINSTALLDIR%%\Common7\Tools\VsMSBuildCmd.bat" && msbuild /t:Clean' > .clean.bat
|
||||
cmd //c .clean.bat
|
||||
rm -f .clean.bat
|
||||
elif [[ -e Makefile ]] && make -s distclean; then :
|
||||
elif [[ -e .git ]] && git clean -fdx; then :
|
||||
fi
|
||||
|
||||
rm -rf "$prefix"
|
||||
}
|
||||
|
||||
# prepare <prefix> <platform> [ <arch> ... ]
|
||||
#
|
||||
# Configure the library for building the <arch>s on this machine.
|
||||
# The build script invokes this once prior to building each of its targets.
|
||||
# The <prefix> has been newly created.
|
||||
#
|
||||
# By default, this will run `autoreconf`.
|
||||
prepare() { _prepare "$@"; }
|
||||
_prepare() {
|
||||
prepare_clean "$@"
|
||||
prepare_config "$@"
|
||||
}
|
||||
|
||||
# prepare_clean <prefix> <platform> [ <arch> ... ]
|
||||
#
|
||||
# Perform any necessary clean-up of the library code prior to building.
|
||||
#
|
||||
# By default, this will wipe and re-create the prefix.
|
||||
prepare_clean() { _prepare_clean "$@"; }
|
||||
_prepare_clean() {
|
||||
local prefix=$1 platform=$2; shift 2
|
||||
|
||||
rm -rf "$prefix"
|
||||
install -d "$prefix/out"
|
||||
}
|
||||
|
||||
# prepare_config <prefix> <platform> [ <arch> ... ]
|
||||
#
|
||||
# Configure the library for building the <arch>s on this machine.
|
||||
#
|
||||
# By default, this will run `autoreconf`.
|
||||
prepare_config() { _prepare_config "$@"; }
|
||||
_prepare_config() {
|
||||
local prefix=$1 platform=$2; shift 2
|
||||
|
||||
[[ -e "$prefix/out/.prepared" ]] && return
|
||||
|
||||
if [[ $platform = windows ]]; then :
|
||||
else
|
||||
autoreconf --verbose --install --force 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
|
||||
fi
|
||||
|
||||
touch "$prefix/out/.prepared"
|
||||
}
|
||||
|
||||
# target <prefix> <platform> <arch>
|
||||
#
|
||||
# Build the library for the given <arch> and <platform> into the given <prefix>.
|
||||
# The build script invokes this function when it's ready to build the library's code.
|
||||
# Generic platform-specific environment setup has been done.
|
||||
target() { _target "$@"; }
|
||||
_target() {
|
||||
target_prepare "$@"
|
||||
target_configure "$@"
|
||||
target_build "$@"
|
||||
}
|
||||
|
||||
# target_prepare <prefix> <platform> <arch>
|
||||
#
|
||||
# Prepare the library configuration for building the target.
|
||||
#
|
||||
# By default, this will run `make clean` if a Makefile is found.
|
||||
target_prepare() { _target_prepare "$@"; }
|
||||
_target_prepare() {
|
||||
local prefix=$1 platform=$2 arch=$3; shift 3
|
||||
|
||||
if [[ $platform = windows ]]; then :
|
||||
else
|
||||
[[ ! -e Makefile ]] || make -s clean
|
||||
fi
|
||||
}
|
||||
|
||||
# target_configure <prefix> <platform> <arch> [ <args> ... ]
|
||||
#
|
||||
# Configure the library for building the target.
|
||||
#
|
||||
# By default, this will run `./configure --host=<host> --prefix=<prefix>/<arch> <args>`.
|
||||
# By default, some platform-specific arguments will be passed in as well as
|
||||
# --enable-pic --disable-pie to ensure the resulting library can be linked again.
|
||||
target_configure() { _target_configure "$@"; }
|
||||
_target_configure() {
|
||||
local prefix=$1 platform=$2 arch=$3; shift 3
|
||||
|
||||
case "$platform" in
|
||||
'windows')
|
||||
return
|
||||
;;
|
||||
'android')
|
||||
host=( "$SDKROOT"/*-android* ) host=${host##*/}
|
||||
|
||||
set -- --with-sysroot="$SDKROOT/sysroot" "$@"
|
||||
;;
|
||||
'ios')
|
||||
[[ $arch = *arm* ]] && host=arm || host=$arch
|
||||
host+=-apple
|
||||
|
||||
set -- --disable-shared "$@"
|
||||
;;
|
||||
esac
|
||||
|
||||
./configure ${host:+--host="$host"} --enable-pic --disable-pie --prefix="$prefix/$arch" "$@"
|
||||
}
|
||||
|
||||
# target_build <prefix> <platform> <arch>
|
||||
#
|
||||
# Build the library code for the target.
|
||||
#
|
||||
# By default, this will run `make check install`.
|
||||
target_build() { _target_build "$@"; }
|
||||
_target_build() {
|
||||
local prefix=$1 platform=$2 arch=$3; shift 3
|
||||
|
||||
if [[ $platform = windows ]]; then
|
||||
# I cannot for the life of me figure out how to pass this command directly into cmd.
|
||||
printf '"%%VSINSTALLDIR%%\Common7\Tools\VsMSBuildCmd.bat" && msbuild /t:Rebuild /p:Configuration=ReleaseDLL;Platform=%s;OutDir=%s' "$arch" "$(cygpath -w "${prefix##$PWD/}/$arch/")" > .build.bat
|
||||
cmd //c .build.bat
|
||||
rm -f .build.bat
|
||||
else
|
||||
local cores=$(getconf NPROCESSORS_ONLN 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null ||:)
|
||||
make -j"${cores:-3}" install
|
||||
fi
|
||||
}
|
||||
|
||||
# finalize <prefix> <platform> [ <arch> ... ]
|
||||
#
|
||||
# Prepare the final build product.
|
||||
# The build script invokes this once after a successful build of all targets.
|
||||
finalize() { _finalize "$@"; }
|
||||
_finalize() {
|
||||
finalize_merge "$@"
|
||||
finalize_clean "$@"
|
||||
}
|
||||
|
||||
# finalize_merge <prefix> <platform> [ <arch> ... ]
|
||||
#
|
||||
# Merge all targets into a product the application can use, available at `<prefix>/out`.
|
||||
#
|
||||
# By default, this will copy the headers to `<prefix>/out/include`, install libraries into `<prefix>/out/lib` and mark the output product as successful.
|
||||
finalize_merge() { _finalize_merge "$@"; }
|
||||
_finalize_merge() {
|
||||
local prefix=$1 platform=$2; shift 2
|
||||
local archs=( "$@" )
|
||||
|
||||
[[ -e "$prefix/$archs/include" ]] && mv -f -- "$prefix/$archs/include" "$prefix/out/"
|
||||
|
||||
install -d "$prefix/out/lib"
|
||||
case "$platform" in
|
||||
'linux')
|
||||
for arch in "${archs[@]}"; do
|
||||
install -d "$prefix/out/lib/$arch"
|
||||
install -p "$prefix/$arch/lib/"*.a "$prefix/out/lib/$arch/"
|
||||
done
|
||||
;;
|
||||
'windows')
|
||||
for arch in "${archs[@]}"; do
|
||||
install -d "$prefix/out/lib/$arch"
|
||||
install -p "$prefix/$arch/"*.lib "$prefix/out/lib/$arch/"
|
||||
done
|
||||
;;
|
||||
'macos'|'ios')
|
||||
for lib in "$prefix/$archs/lib/"*; do
|
||||
if lipo -info "$lib" >/dev/null 2>&1; then
|
||||
local lib=("${lib##*/}") libs=("${archs[@]/#/$prefix/}") libs=("${libs[@]/%//lib/$lib}")
|
||||
lipo -create "${libs[@]}" -output "$prefix/out/lib/$lib"
|
||||
fi
|
||||
done
|
||||
;;
|
||||
'android')
|
||||
for arch in "${archs[@]}"; do
|
||||
local abi=$arch
|
||||
case "$arch" in
|
||||
'arm') abi='armeabi-v7a' ;;
|
||||
'arm64') abi='arm64-v8a' ;;
|
||||
esac
|
||||
install -d "$prefix/out/lib/$abi"
|
||||
install -p "$prefix/$arch/lib/"*.so "$prefix/out/lib/$abi"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
touch "$prefix/out/.success"
|
||||
}
|
||||
|
||||
# finalize_clean <prefix> [ <arch> ... ]
|
||||
#
|
||||
# Clean up the library after a successful build (eg. housekeeping of temporary files).
|
||||
#
|
||||
# By default, this will run `make clean`.
|
||||
finalize_clean() { _finalize_clean "$@"; }
|
||||
_finalize_clean() {
|
||||
[[ ! -e Makefile ]] || make -s clean
|
||||
}
|
||||
|
||||
# build <name> [<platform>]
|
||||
#
|
||||
# Build the library <name> (found at ../<name>) for platform <platform> (or "host" if unspecified).
|
||||
build() { _build "$@"; }
|
||||
_build() {
|
||||
local name=$1 platform=${2:-host}
|
||||
local path="../$name"
|
||||
[[ $path = /* ]] || path="${BASH_SOURCE%/*}/$path"
|
||||
cd "$path"
|
||||
|
||||
if [[ $platform = host ]]; then
|
||||
case "$(uname -s)" in
|
||||
'Darwin') platform='macos' archs=( "$(uname -m)" ) ;;
|
||||
esac
|
||||
fi
|
||||
if (( ! ${#archs[@]} )); then
|
||||
case "$platform" in
|
||||
'macos') archs=( 'x86_64' ) ;;
|
||||
'ios') archs=( 'i386' 'x86_64' 'armv7' 'armv7s' 'arm64' ) ;;
|
||||
'android') archs=( 'arm' 'arm64' 'x86' 'x86_64' ) ;;
|
||||
'windows') archs=( 'Win32' 'x64' ) ;;
|
||||
*) archs=( 'i386' 'x86_64' ) ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
local prefix="$PWD/build-$platform~"
|
||||
initialize "$prefix" "$platform"
|
||||
|
||||
# "clean" argument wipes the lib clean and exits. If .success exists in prefix output, skip build.
|
||||
if [[ ${BASH_ARGV[@]:(-1)} = clean ]]; then
|
||||
clean "$prefix" "$platform"
|
||||
exit
|
||||
elif [[ -e "$prefix"/out/.success ]]; then
|
||||
echo >&2 "Skipping build for $platform: output product already built successfully."
|
||||
exit
|
||||
fi
|
||||
|
||||
# Prepare the output location and build configuration.
|
||||
prepare "$prefix" "$platform" "${archs[@]}"
|
||||
|
||||
# Repeat the build for each individual architecture.
|
||||
for arch in "${archs[@]}"; do (
|
||||
|
||||
# Set up a base environment for the platform.
|
||||
case "$platform" in
|
||||
'windows')
|
||||
;;
|
||||
'macos')
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch $arch -flto -O2 -g -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $CFLAGS"
|
||||
export LDFLAGS="-arch $arch -flto -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
;;
|
||||
'ios')
|
||||
case "$arch" in
|
||||
*'arm'*)
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch $arch -mthumb -fembed-bitcode -flto -O2 -g -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $CFLAGS"
|
||||
export LDFLAGS="-arch $arch -mthumb -fembed-bitcode -flto -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
;;
|
||||
*)
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch $arch -flto -O2 -g -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $CFLAGS"
|
||||
export LDFLAGS="-arch $arch -flto -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
'android')
|
||||
[[ -x $ANDROID_NDK_HOME/build/ndk-build ]] || { echo >&2 "Android NDK not found. Please set ANDROID_NDK_HOME."; return 1; }
|
||||
|
||||
SDKROOT="$prefix/$arch/ndk"
|
||||
# Platform 21 is lowest that supports x86_64
|
||||
"$ANDROID_NDK_HOME/build/tools/make-standalone-toolchain.sh" --force --install-dir="$SDKROOT" --platform='android-21' --arch="$arch"
|
||||
export PATH="$SDKROOT/bin:$PATH"
|
||||
export CFLAGS="-O2 -g $CFLAGS"
|
||||
export LDFLAGS="-avoid-version $LDFLAGS"
|
||||
export CC='clang'
|
||||
|
||||
# For GCC:
|
||||
# arm CFLAGS="-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb" LDFLAGS="-Wl,--fix-cortex-a8"
|
||||
# arm64 CFLAGS="-march=armv8-a"
|
||||
# x86 CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
|
||||
# x86_64 CFLAGS="-march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel"
|
||||
;;
|
||||
esac
|
||||
|
||||
target "$prefix" "$platform" "$arch"
|
||||
); done
|
||||
|
||||
finalize "$prefix" "$platform" "${archs[@]}"
|
||||
}
|
||||
8
lib/bin/build_libjson-c-android
Executable file
8
lib/bin/build_libjson-c-android
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
source "${BASH_SOURCE%/*}/build_lib"
|
||||
|
||||
autoreconf() {
|
||||
command autoreconf -Iautoconf-archive/m4 "$@"
|
||||
}
|
||||
|
||||
build libjson-c android
|
||||
8
lib/bin/build_libjson-c-ios
Executable file
8
lib/bin/build_libjson-c-ios
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
source "${BASH_SOURCE%/*}/build_lib"
|
||||
|
||||
autoreconf() {
|
||||
command autoreconf -Iautoconf-archive/m4 "$@"
|
||||
}
|
||||
|
||||
build libjson-c ios
|
||||
8
lib/bin/build_libjson-c-linux
Executable file
8
lib/bin/build_libjson-c-linux
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
source "${BASH_SOURCE%/*}/build_lib"
|
||||
|
||||
autoreconf() {
|
||||
command autoreconf -Iautoconf-archive/m4 "$@"
|
||||
}
|
||||
|
||||
build libjson-c linux
|
||||
8
lib/bin/build_libjson-c-macos
Executable file
8
lib/bin/build_libjson-c-macos
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
source "${BASH_SOURCE%/*}/build_lib"
|
||||
|
||||
autoreconf() {
|
||||
command autoreconf -Iautoconf-archive/m4 "$@"
|
||||
}
|
||||
|
||||
build libjson-c macos
|
||||
8
lib/bin/build_libjson-c-windows
Normal file
8
lib/bin/build_libjson-c-windows
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
source "${BASH_SOURCE%/*}/build_lib"
|
||||
|
||||
autoreconf() {
|
||||
command autoreconf -Iautoconf-archive/m4 "$@"
|
||||
}
|
||||
|
||||
build libjson-c windows
|
||||
4
lib/bin/build_libsodium-android
Executable file
4
lib/bin/build_libsodium-android
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
source "${BASH_SOURCE%/*}/build_lib"
|
||||
|
||||
build libsodium android
|
||||
4
lib/bin/build_libsodium-ios
Executable file
4
lib/bin/build_libsodium-ios
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
source "${BASH_SOURCE%/*}/build_lib"
|
||||
|
||||
build libsodium ios
|
||||
4
lib/bin/build_libsodium-linux
Executable file
4
lib/bin/build_libsodium-linux
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
source "${BASH_SOURCE%/*}/build_lib"
|
||||
|
||||
build libsodium linux
|
||||
4
lib/bin/build_libsodium-macos
Executable file
4
lib/bin/build_libsodium-macos
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
source "${BASH_SOURCE%/*}/build_lib"
|
||||
|
||||
build libsodium macos
|
||||
4
lib/bin/build_libsodium-windows
Normal file
4
lib/bin/build_libsodium-windows
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
source "${BASH_SOURCE%/*}/build_lib"
|
||||
|
||||
build libsodium windows
|
||||
1
lib/libjson-c
Submodule
1
lib/libjson-c
Submodule
Submodule lib/libjson-c added at 3df1f98b4a
1
lib/libsodium
Submodule
1
lib/libsodium
Submodule
Submodule lib/libsodium added at 850edc1175
24
platform-android/CMakeLists.txt
Normal file
24
platform-android/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
project( mpw-core C )
|
||||
cmake_minimum_required( VERSION 3.0.0 )
|
||||
|
||||
add_library( mpw SHARED
|
||||
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/base64.c"
|
||||
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/aes.c"
|
||||
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-algorithm.c"
|
||||
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-types.c"
|
||||
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-util.c"
|
||||
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-marshal-util.c"
|
||||
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-marshal.c"
|
||||
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-jni.c" )
|
||||
|
||||
add_library( sodium SHARED IMPORTED )
|
||||
set_target_properties( sodium PROPERTIES IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../lib/libsodium/build-android~/out/lib/${ANDROID_ABI}/libsodium.so" )
|
||||
target_include_directories( mpw PRIVATE "${PROJECT_SOURCE_DIR}/../lib/libsodium/build-android~/out/include" )
|
||||
target_compile_definitions( mpw PRIVATE -DMPW_SODIUM=1 )
|
||||
target_link_libraries( mpw PRIVATE sodium )
|
||||
|
||||
add_library( json-c SHARED IMPORTED )
|
||||
set_target_properties( json-c PROPERTIES IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../lib/libjson-c/build-android~/out/lib/${ANDROID_ABI}/libjson-c.so" )
|
||||
target_include_directories( mpw PRIVATE "${PROJECT_SOURCE_DIR}/../lib/libjson-c/build-android~/out/include" )
|
||||
target_compile_definitions( mpw PRIVATE -DMPW_JSON=1 )
|
||||
target_link_libraries( mpw PRIVATE json-c )
|
||||
@@ -1,13 +0,0 @@
|
||||
To build this module, please ensure you've done the following setup:
|
||||
|
||||
1. Installed the Android SDK and fully downloaded the Android SDK platform 21 in it.
|
||||
2. Set the environment variable ANDROID_HOME in your shell or in ~/.mavenrc to point to the root of your Android SDK install.
|
||||
3. Installed the Android SDK into your Maven's local repository.
|
||||
3a. Clone the maven-android-sdk-deployer available from here: https://github.com/mosabua/maven-android-sdk-deployer.git
|
||||
3b. In the root of this project, run: mvn install -P 5.0
|
||||
|
||||
To build this module:
|
||||
|
||||
1. Build the parent, by going into 'MasterPassword/Java' and running: mvn clean install
|
||||
2. Build this module, by going into 'MasterPassword/Java/masterpassword-android' and running: mvn clean install
|
||||
3. You can then find the APK in: 'MasterPassword/Java/masterpassword-android/target'
|
||||
@@ -2,45 +2,76 @@ apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion '25.0.0'
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
buildToolsVersion '27.0.3'
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'com.lyndir.masterpassword'
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 25
|
||||
versionCode 20401
|
||||
versionName '2.4.1'
|
||||
versionCode 20701
|
||||
versionName '2.7.1'
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path 'CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
jniLibs.srcDirs "$rootDir/../lib/libsodium/build-android~/out/lib",
|
||||
"$rootDir/../lib/libjson-c/build-android~/out/lib"
|
||||
}
|
||||
}
|
||||
|
||||
// release with: STORE_PW=$(mpw masterpassword.keystore) KEY_PW=$(mpw masterpassword-android) gradle assembleRelease
|
||||
// release with: STORE_PW=$(mpw masterpassword.keystore) KEY_PW_ANDROID=$(mpw masterpassword-android) gradle masterpassword-android:assembleRelease
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file( 'masterpassword.keystore' )
|
||||
storePassword System.getenv( 'STORE_PW' )
|
||||
|
||||
keyAlias 'masterpassword-android'
|
||||
keyPassword System.getenv( 'KEY_PW' )
|
||||
keyPassword System.getenv( 'KEY_PW_ANDROID' )
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
if (System.getenv( 'STORE_PW' ) != null)
|
||||
if (System.getenv( 'KEY_PW_ANDROID' ) != null)
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project( ':masterpassword-algorithm' )
|
||||
compile project( ':masterpassword-tests' )
|
||||
api project( ':masterpassword-algorithm' )
|
||||
implementation group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.7-p2'
|
||||
|
||||
compile group: 'org.slf4j', name: 'slf4j-android', version:'1.7.13-underscore'
|
||||
compile group: 'com.jakewharton', name: 'butterknife', version:'8.5.1'
|
||||
annotationProcessor group: 'com.jakewharton', name: 'butterknife-compiler', version:'8.5.1'
|
||||
compile files( 'libs/scrypt-1.4.0-native.jar' )
|
||||
implementation group: 'org.slf4j', name: 'slf4j-android', version: '1.7.13-underscore'
|
||||
implementation group: 'com.jakewharton', name: 'butterknife', version: '8.5.1'
|
||||
annotationProcessor group: 'com.jakewharton', name: 'butterknife-compiler', version: '8.5.1'
|
||||
}
|
||||
|
||||
preBuild {
|
||||
dependsOn task( type: Exec, 'build_libsodium-android', {
|
||||
commandLine 'bash', "$rootDir/../lib/bin/build_libsodium-android"
|
||||
environment 'ANDROID_NDK_HOME', android.ndkDirectory
|
||||
} )
|
||||
dependsOn task( type: Exec, 'build_libjson-c-android', {
|
||||
commandLine 'bash', "$rootDir/../lib/bin/build_libjson-c-android"
|
||||
environment 'ANDROID_NDK_HOME', android.ndkDirectory
|
||||
} )
|
||||
}
|
||||
|
||||
clean {
|
||||
dependsOn task( type: Exec, 'clean_libsodium-android', {
|
||||
commandLine 'bash', "$rootDir/../lib/bin/build_libsodium-android", 'clean'
|
||||
environment 'ANDROID_NDK_HOME', android.ndkDirectory
|
||||
} )
|
||||
dependsOn task( type: Exec, 'clean_libjson-c-android', {
|
||||
commandLine 'bash', "$rootDir/../lib/bin/build_libjson-c-android", 'clean'
|
||||
environment 'ANDROID_NDK_HOME', android.ndkDirectory
|
||||
} )
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -1,145 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password Android</name>
|
||||
<description>An Android application to the Master Password algorithm</description>
|
||||
|
||||
<artifactId>masterpassword-android</artifactId>
|
||||
<packaging>apk</packaging>
|
||||
|
||||
<!-- BUILD CONFIGURATION -->
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
|
||||
<artifactId>android-maven-plugin</artifactId>
|
||||
|
||||
<configuration>
|
||||
<zipalign>
|
||||
<verbose>true</verbose>
|
||||
<skip>false</skip>
|
||||
</zipalign>
|
||||
<sdk>
|
||||
<platform>21</platform>
|
||||
</sdk>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
|
||||
<artifactId>android-maven-plugin</artifactId>
|
||||
|
||||
<configuration>
|
||||
<sign>
|
||||
<debug>false</debug>
|
||||
</sign>
|
||||
</configuration>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>manifest-update</id>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>manifest-update</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<manifestVersionCodeUpdateFromVersion>true</manifestVersionCodeUpdateFromVersion>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jarsigner-plugin</artifactId>
|
||||
<version>1.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>signing</id>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
<inherited>true</inherited>
|
||||
<configuration>
|
||||
<archiveDirectory />
|
||||
<includes>
|
||||
<include>target/*.apk</include>
|
||||
</includes>
|
||||
<keystore>release.jks</keystore>
|
||||
<storepass>${env.PASSWORD}</storepass>
|
||||
<keypass>${env.PASSWORD}</keypass>
|
||||
<alias>masterpassword-android</alias>
|
||||
<arguments>
|
||||
<argument>-sigalg</argument><argument>MD5withRSA</argument>
|
||||
<argument>-digestalg</argument><argument>SHA1</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<!-- DEPENDENCY MANAGEMENT -->
|
||||
<dependencies>
|
||||
|
||||
<!-- PROJECT REFERENCES -->
|
||||
<dependency>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-tests</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EXTERNAL DEPENDENCIES -->
|
||||
<dependency>
|
||||
<groupId>com.jakewharton</groupId>
|
||||
<artifactId>butterknife</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-android</artifactId>
|
||||
<version>1.7.13-underscore</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>android</groupId>
|
||||
<artifactId>android</artifactId>
|
||||
<version>5.0.1_r2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.lambdaworks</groupId>
|
||||
<artifactId>scrypt</artifactId>
|
||||
<version>1.4.0-android</version>
|
||||
<type>jar</type>
|
||||
<classifier>native</classifier>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
@@ -35,11 +35,12 @@ import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.google.common.util.concurrent.*;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.Executors;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
@@ -49,13 +50,16 @@ public class EmergencyActivity extends Activity {
|
||||
private static final Logger logger = Logger.get( EmergencyActivity.class );
|
||||
private static final ClipData EMPTY_CLIP = new ClipData( new ClipDescription( "", new String[0] ), new ClipData.Item( "" ) );
|
||||
private static final int PASSWORD_NOTIFICATION = 0;
|
||||
public static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S;
|
||||
private static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstants.MS_PER_S;
|
||||
|
||||
private final Preferences preferences = Preferences.get( this );
|
||||
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
||||
private final ImmutableList<MPResultType> allResultTypes = ImmutableList.copyOf( MPResultType.forClass( MPResultTypeClass.Template ) );
|
||||
private final ImmutableList<MPMasterKey.Version> allVersions = ImmutableList.copyOf( MPMasterKey.Version.values() );
|
||||
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator(
|
||||
Executors.newSingleThreadExecutor() );
|
||||
private final ImmutableList<MPResultType> allResultTypes = ImmutableList.copyOf(
|
||||
MPResultType.forClass( MPResultTypeClass.Template ) );
|
||||
private final ImmutableList<MPAlgorithm.Version> allVersions = ImmutableList.copyOf( MPAlgorithm.Version.values() );
|
||||
|
||||
@Nullable
|
||||
private MPMasterKey masterKey;
|
||||
|
||||
@BindView(R.id.progressView)
|
||||
@@ -96,6 +100,7 @@ public class EmergencyActivity extends Activity {
|
||||
|
||||
private int id_userName;
|
||||
private int id_masterPassword;
|
||||
@Nullable
|
||||
private String sitePassword;
|
||||
|
||||
public static void start(final Context context) {
|
||||
@@ -125,7 +130,7 @@ public class EmergencyActivity extends Activity {
|
||||
siteNameField.addTextChangedListener( new ValueChangedListener() {
|
||||
@Override
|
||||
void update() {
|
||||
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
|
||||
siteCounterButton.setText( MessageFormat.format( "{0}", UnsignedInteger.ONE ) );
|
||||
updateSitePassword();
|
||||
}
|
||||
} );
|
||||
@@ -150,11 +155,22 @@ public class EmergencyActivity extends Activity {
|
||||
updateSitePassword();
|
||||
}
|
||||
} );
|
||||
siteCounterButton.setOnLongClickListener( new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(final View v) {
|
||||
if (UnsignedInteger.valueOf( siteCounterButton.getText().toString() ).equals( UnsignedInteger.ONE ))
|
||||
return false;
|
||||
|
||||
siteCounterButton.setText( MessageFormat.format( "{0}", UnsignedInteger.ONE ) );
|
||||
updateSitePassword();
|
||||
return true;
|
||||
}
|
||||
} );
|
||||
siteVersionButton.setOnClickListener( new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
@SuppressWarnings("SuspiciousMethodCalls")
|
||||
MPMasterKey.Version siteVersion =
|
||||
MPAlgorithm.Version siteVersion =
|
||||
allVersions.get( (allVersions.indexOf( siteVersionButton.getTag() ) + 1) % allVersions.size() );
|
||||
preferences.setDefaultVersion( siteVersion );
|
||||
siteVersionButton.setTag( siteVersion );
|
||||
@@ -173,13 +189,13 @@ public class EmergencyActivity extends Activity {
|
||||
}
|
||||
} );
|
||||
|
||||
fullNameField.setTypeface( Res.get( this ).exo_Thin );
|
||||
fullNameField.setTypeface( Res.get( this ).exo_Thin() );
|
||||
fullNameField.setPaintFlags( fullNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
|
||||
masterPasswordField.setTypeface( Res.get( this ).sourceCodePro_ExtraLight );
|
||||
masterPasswordField.setTypeface( Res.get( this ).sourceCodePro_ExtraLight() );
|
||||
masterPasswordField.setPaintFlags( masterPasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
|
||||
siteNameField.setTypeface( Res.get( this ).exo_Regular );
|
||||
siteNameField.setTypeface( Res.get( this ).exo_Regular() );
|
||||
siteNameField.setPaintFlags( siteNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
|
||||
sitePasswordField.setTypeface( Res.get( this ).sourceCodePro_Black );
|
||||
sitePasswordField.setTypeface( Res.get( this ).sourceCodePro_Black() );
|
||||
sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
|
||||
|
||||
rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
||||
@@ -211,7 +227,7 @@ public class EmergencyActivity extends Activity {
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// FIXME: MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
||||
// FIXME: MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
||||
|
||||
fullNameField.setText( preferences.getFullName() );
|
||||
rememberFullNameField.setChecked( preferences.isRememberFullName() );
|
||||
@@ -221,10 +237,10 @@ public class EmergencyActivity extends Activity {
|
||||
MPResultType defaultResultType = preferences.getDefaultResultType();
|
||||
resultTypeButton.setTag( defaultResultType );
|
||||
resultTypeButton.setText( defaultResultType.getShortName() );
|
||||
MPMasterKey.Version defaultVersion = preferences.getDefaultVersion();
|
||||
MPAlgorithm.Version defaultVersion = preferences.getDefaultVersion();
|
||||
siteVersionButton.setTag( defaultVersion );
|
||||
siteVersionButton.setText( defaultVersion.name() );
|
||||
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
|
||||
siteCounterButton.setText( MessageFormat.format( "{0}", UnsignedInteger.ONE ) );
|
||||
|
||||
if (TextUtils.isEmpty( fullNameField.getText() ))
|
||||
fullNameField.requestFocus();
|
||||
@@ -254,8 +270,8 @@ public class EmergencyActivity extends Activity {
|
||||
}
|
||||
|
||||
private synchronized void updateMasterKey() {
|
||||
final String fullName = fullNameField.getText().toString();
|
||||
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
|
||||
String fullName = fullNameField.getText().toString();
|
||||
char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
|
||||
if ((id_userName == fullName.hashCode())
|
||||
&& (id_masterPassword == Arrays.hashCode( masterPassword )))
|
||||
if (masterKey != null)
|
||||
@@ -283,7 +299,7 @@ public class EmergencyActivity extends Activity {
|
||||
final String siteName = siteNameField.getText().toString();
|
||||
final MPResultType type = (MPResultType) resultTypeButton.getTag();
|
||||
final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() );
|
||||
final MPMasterKey.Version version = (MPMasterKey.Version) siteVersionButton.getTag();
|
||||
final MPAlgorithm.Version version = (MPAlgorithm.Version) siteVersionButton.getTag();
|
||||
|
||||
if ((masterKey == null) || siteName.isEmpty() || (type == null)) {
|
||||
sitePasswordField.setText( "" );
|
||||
@@ -300,7 +316,8 @@ public class EmergencyActivity extends Activity {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
sitePassword = masterKey.siteResult( siteName, counter, MPKeyPurpose.Authentication, null, type, null, version );
|
||||
sitePassword = masterKey.siteResult( siteName, version.getAlgorithm(), counter,
|
||||
MPKeyPurpose.Authentication, null, type, null );
|
||||
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
@@ -310,59 +327,59 @@ public class EmergencyActivity extends Activity {
|
||||
}
|
||||
} );
|
||||
}
|
||||
catch (final MPInvalidatedException ignored) {
|
||||
catch (final MPKeyUnavailableException ignored) {
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
}
|
||||
catch (final RuntimeException e) {
|
||||
catch (final MPAlgorithmException e) {
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
logger.err( e, "While generating site password." );
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public void integrityTests(final View view) {
|
||||
if (masterKey != null)
|
||||
masterKey = null;
|
||||
|
||||
TestActivity.startNoSkip( this );
|
||||
}
|
||||
|
||||
public void copySitePassword(final View view) {
|
||||
final String currentSitePassword = sitePassword;
|
||||
if (TextUtils.isEmpty( currentSitePassword ))
|
||||
return;
|
||||
|
||||
final ClipboardManager clipboardManager = (ClipboardManager) getSystemService( CLIPBOARD_SERVICE );
|
||||
final ClipboardManager clipboardManager = (ClipboardManager) getSystemService( CLIPBOARD_SERVICE );
|
||||
final NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
|
||||
if (clipboardManager == null)
|
||||
return;
|
||||
|
||||
String title = strf( "Password for %s", siteNameField.getText() );
|
||||
String title = strf( "Password for %s", siteNameField.getText() );
|
||||
ClipDescription description = new ClipDescription( title, new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN } );
|
||||
clipboardManager.setPrimaryClip( new ClipData( description, new ClipData.Item( currentSitePassword ) ) );
|
||||
|
||||
Notification.Builder notificationBuilder = new Notification.Builder( this ).setContentTitle( title )
|
||||
.setContentText( "Paste the password into your app." )
|
||||
.setSmallIcon( R.drawable.icon )
|
||||
.setAutoCancel( true );
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
notificationBuilder.setVisibility( Notification.VISIBILITY_SECRET )
|
||||
.setCategory( Notification.CATEGORY_RECOMMENDATION )
|
||||
.setLocalOnly( true );
|
||||
notificationManager.notify( PASSWORD_NOTIFICATION, notificationBuilder.build() );
|
||||
if (notificationManager != null) {
|
||||
Notification.Builder notificationBuilder = new Notification.Builder( this ).setContentTitle( title )
|
||||
.setContentText(
|
||||
"Paste the password into your app." )
|
||||
.setSmallIcon( R.drawable.icon )
|
||||
.setAutoCancel( true );
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
notificationBuilder.setVisibility( Notification.VISIBILITY_SECRET )
|
||||
.setCategory( Notification.CATEGORY_RECOMMENDATION )
|
||||
.setLocalOnly( true );
|
||||
notificationManager.notify( PASSWORD_NOTIFICATION, notificationBuilder.build() );
|
||||
}
|
||||
|
||||
final Timer timer = new Timer();
|
||||
timer.schedule( new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
ClipData clip = clipboardManager.getPrimaryClip();
|
||||
for (int i = 0; i < clip.getItemCount(); ++i)
|
||||
if (currentSitePassword.equals( clip.getItemAt( i ).coerceToText( EmergencyActivity.this ) )) {
|
||||
if (currentSitePassword.contentEquals( clip.getItemAt( i ).coerceToText( EmergencyActivity.this ) )) {
|
||||
clipboardManager.setPrimaryClip( EMPTY_CLIP );
|
||||
break;
|
||||
}
|
||||
notificationManager.cancel( PASSWORD_NOTIFICATION );
|
||||
|
||||
if (notificationManager != null)
|
||||
notificationManager.cancel( PASSWORD_NOTIFICATION );
|
||||
timer.cancel();
|
||||
}
|
||||
}, CLIPBOARD_CLEAR_DELAY );
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
/**
|
||||
* @author lhunath, 2017-09-21
|
||||
* @author lhunath, 2018-06-10
|
||||
*/
|
||||
public class MPInvalidatedException extends Exception {
|
||||
public class MPConstants {
|
||||
|
||||
public static final int MS_PER_S = 1000;
|
||||
}
|
||||
@@ -22,8 +22,10 @@ import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.*;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
|
||||
/**
|
||||
@@ -33,7 +35,7 @@ public class MainThreadExecutor extends AbstractExecutorService {
|
||||
|
||||
private final Handler mHandler = new Handler( Looper.getMainLooper() );
|
||||
private final Set<Runnable> commands = Sets.newLinkedHashSet();
|
||||
private boolean shutdown;
|
||||
private boolean shutdown;
|
||||
|
||||
@Override
|
||||
public void execute(final Runnable command) {
|
||||
@@ -63,6 +65,7 @@ public class MainThreadExecutor extends AbstractExecutorService {
|
||||
shutdown = true;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<Runnable> shutdownNow() {
|
||||
shutdown = true;
|
||||
|
||||
@@ -32,15 +32,15 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
public final class Preferences {
|
||||
|
||||
private static final String PREF_TESTS_PASSED = "integrityTestsPassed";
|
||||
private static final String PREF_NATIVE_KDF = "nativeKDF";
|
||||
private static final String PREF_REMEMBER_FULL_NAME = "rememberFullName";
|
||||
private static final String PREF_FORGET_PASSWORD = "forgetPassword";
|
||||
private static final String PREF_MASK_PASSWORD = "maskPassword";
|
||||
private static final String PREF_FULL_NAME = "fullName";
|
||||
private static final String PREF_RESULT_TYPE = "resultType";
|
||||
private static final String PREF_ALGORITHM_VERSION = "algorithmVersion";
|
||||
private static Preferences instance;
|
||||
private static final String PREF_TESTS_PASSED = "integrityTestsPassed";
|
||||
private static final String PREF_NATIVE_KDF = "nativeKDF";
|
||||
private static final String PREF_REMEMBER_FULL_NAME = "rememberFullName";
|
||||
private static final String PREF_FORGET_PASSWORD = "forgetPassword";
|
||||
private static final String PREF_MASK_PASSWORD = "maskPassword";
|
||||
private static final String PREF_FULL_NAME = "fullName";
|
||||
private static final String PREF_RESULT_TYPE = "resultType";
|
||||
private static final String PREF_ALGORITHM_VERSION = "algorithmVersion";
|
||||
private static Preferences instance;
|
||||
|
||||
private Context context;
|
||||
@Nullable
|
||||
@@ -86,7 +86,7 @@ public final class Preferences {
|
||||
}
|
||||
|
||||
public Set<String> getTestsPassed() {
|
||||
return prefs().getStringSet( PREF_TESTS_PASSED, ImmutableSet.<String>of() );
|
||||
return prefs().getStringSet( PREF_TESTS_PASSED, ImmutableSet.of() );
|
||||
}
|
||||
|
||||
public boolean setRememberFullName(final boolean enabled) {
|
||||
@@ -148,10 +148,11 @@ public final class Preferences {
|
||||
|
||||
@Nonnull
|
||||
public MPResultType getDefaultResultType() {
|
||||
return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, MPResultType.DEFAULT.ordinal() )];
|
||||
return MPResultType.values()[
|
||||
prefs().getInt( PREF_RESULT_TYPE, getDefaultVersion().getAlgorithm().mpw_default_result_type().ordinal() )];
|
||||
}
|
||||
|
||||
public boolean setDefaultVersion(final MPMasterKey.Version value) {
|
||||
public boolean setDefaultVersion(final MPAlgorithm.Version value) {
|
||||
if (getDefaultVersion() == value)
|
||||
return false;
|
||||
|
||||
@@ -160,7 +161,8 @@ public final class Preferences {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public MPMasterKey.Version getDefaultVersion() {
|
||||
return MPMasterKey.Version.values()[prefs().getInt( PREF_ALGORITHM_VERSION, MPMasterKey.Version.CURRENT.ordinal() )];
|
||||
public MPAlgorithm.Version getDefaultVersion() {
|
||||
return MPAlgorithm.Version.values()[
|
||||
prefs().getInt( PREF_ALGORITHM_VERSION, MPAlgorithm.Version.CURRENT.ordinal() )];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,21 +19,21 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Typeface;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2014-08-25
|
||||
*/
|
||||
@SuppressWarnings("NewMethodNamingConvention")
|
||||
public final class Res {
|
||||
|
||||
public final Typeface sourceCodePro_Black;
|
||||
public final Typeface sourceCodePro_ExtraLight;
|
||||
public final Typeface exo_Bold;
|
||||
public final Typeface exo_ExtraBold;
|
||||
public final Typeface exo_Regular;
|
||||
public final Typeface exo_Thin;
|
||||
private final Typeface sourceCodePro_Black;
|
||||
private final Typeface sourceCodePro_ExtraLight;
|
||||
private final Typeface exo_Bold;
|
||||
private final Typeface exo_ExtraBold;
|
||||
private final Typeface exo_Regular;
|
||||
private final Typeface exo_Thin;
|
||||
|
||||
private static Res res;
|
||||
|
||||
@@ -54,4 +54,28 @@ public final class Res {
|
||||
exo_Regular = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Regular.otf" );
|
||||
exo_Thin = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Thin.otf" );
|
||||
}
|
||||
|
||||
public Typeface sourceCodePro_Black() {
|
||||
return sourceCodePro_Black;
|
||||
}
|
||||
|
||||
public Typeface sourceCodePro_ExtraLight() {
|
||||
return sourceCodePro_ExtraLight;
|
||||
}
|
||||
|
||||
public Typeface exo_Bold() {
|
||||
return exo_Bold;
|
||||
}
|
||||
|
||||
public Typeface exo_ExtraBold() {
|
||||
return exo_ExtraBold;
|
||||
}
|
||||
|
||||
public Typeface exo_Regular() {
|
||||
return exo_Regular;
|
||||
}
|
||||
|
||||
public Typeface exo_Thin() {
|
||||
return exo_Thin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
//==============================================================================
|
||||
// This file is part of Master Password.
|
||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||
//
|
||||
// Master Password is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Master Password is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You can find a copy of the GNU General Public License in the
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.*;
|
||||
import android.view.View;
|
||||
import android.widget.*;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import com.google.common.base.*;
|
||||
import com.google.common.collect.*;
|
||||
import com.google.common.util.concurrent.*;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.util.concurrent.*;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
public class TestActivity extends Activity implements MPTestSuite.Listener {
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( TestActivity.class );
|
||||
|
||||
private final Preferences preferences = Preferences.get( this );
|
||||
private final ListeningExecutorService backgroundExecutor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
||||
private final ListeningExecutorService mainExecutor = MoreExecutors.listeningDecorator( new MainThreadExecutor() );
|
||||
|
||||
@BindView(R.id.progressView)
|
||||
ProgressBar progressView;
|
||||
|
||||
@BindView(R.id.statusView)
|
||||
TextView statusView;
|
||||
|
||||
@BindView(R.id.logView)
|
||||
TextView logView;
|
||||
|
||||
@BindView(R.id.actionButton)
|
||||
Button actionButton;
|
||||
|
||||
@BindView(R.id.nativeKDFField)
|
||||
CheckBox nativeKDFField;
|
||||
|
||||
private MPTestSuite testSuite;
|
||||
private ListenableFuture<Boolean> testFuture;
|
||||
private Runnable action;
|
||||
private ImmutableSet<String> testNames;
|
||||
|
||||
public static void startNoSkip(final Context context) {
|
||||
context.startActivity( new Intent( context, TestActivity.class ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate( savedInstanceState );
|
||||
|
||||
setContentView( R.layout.activity_test );
|
||||
ButterKnife.bind( this );
|
||||
|
||||
nativeKDFField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
|
||||
preferences.setNativeKDFEnabled( isChecked );
|
||||
// TODO: MasterKey.setAllowNativeByDefault( isChecked );
|
||||
}
|
||||
} );
|
||||
|
||||
try {
|
||||
setStatus( 0, 0, null );
|
||||
testSuite = new MPTestSuite();
|
||||
testSuite.setListener( this );
|
||||
testNames = FluentIterable.from( testSuite.getTests().getCases() ).transform(
|
||||
new Function<MPTests.Case, String>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public String apply(@Nullable final MPTests.Case input) {
|
||||
return (input == null)? null: input.identifier;
|
||||
}
|
||||
} ).filter( Predicates.notNull() ).toSet();
|
||||
}
|
||||
catch (final MPTestSuite.UnavailableException e) {
|
||||
logger.err( e, "While loading test suite" );
|
||||
setStatus( R.string.tests_unavailable, R.string.tests_btn_unavailable, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
finish();
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
nativeKDFField.setChecked( preferences.isAllowNativeKDF() );
|
||||
|
||||
if (testFuture == null)
|
||||
startTestSuite();
|
||||
}
|
||||
|
||||
private void startTestSuite() {
|
||||
if (testFuture != null)
|
||||
testFuture.cancel( true );
|
||||
|
||||
// TODO: MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
||||
|
||||
setStatus( R.string.tests_testing, R.string.tests_btn_testing, null );
|
||||
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable final Boolean result) {
|
||||
if ((result != null) && result)
|
||||
setStatus( R.string.tests_passed, R.string.tests_btn_passed, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
preferences.setTestsPassed( testNames );
|
||||
finish();
|
||||
}
|
||||
} );
|
||||
else
|
||||
setStatus( R.string.tests_failed, R.string.tests_btn_failed, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startTestSuite();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
logger.err( t, "While running test suite" );
|
||||
setStatus( R.string.tests_failed, R.string.tests_btn_failed, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
finish();
|
||||
}
|
||||
} );
|
||||
}
|
||||
}, mainExecutor );
|
||||
}
|
||||
|
||||
public void onAction(final View v) {
|
||||
if (action != null)
|
||||
action.run();
|
||||
}
|
||||
|
||||
private void setStatus(final int statusId, final int buttonId, @Nullable final Runnable action) {
|
||||
this.action = action;
|
||||
|
||||
if (statusId == 0)
|
||||
statusView.setText( null );
|
||||
else
|
||||
statusView.setText( statusId );
|
||||
|
||||
if (buttonId == 0)
|
||||
actionButton.setText( null );
|
||||
else
|
||||
actionButton.setText( buttonId );
|
||||
actionButton.setEnabled( action != null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void progress(final int current, final int max, final String messageFormat, final Object... args) {
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
logView.append( strf( "%n" + messageFormat, args ) );
|
||||
|
||||
progressView.setMax( max );
|
||||
progressView.setProgress( current );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,15 +253,6 @@
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textSize="16sp"
|
||||
android:text="@string/btn_tests"
|
||||
android:onClick="integrityTests"
|
||||
android:background="@android:color/transparent" />
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="0dp"
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="20dp"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/img_stats" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="8dp"
|
||||
tools:max="100"
|
||||
tools:progress="80"
|
||||
style="?android:progressBarStyleHorizontal" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/statusView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:labelFor="@id/sitePasswordField"
|
||||
android:gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/tests_testing" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/logView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="bottom"
|
||||
android:background="@android:color/transparent"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="9sp"
|
||||
android:textColor="@android:color/tertiary_text_dark" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/actionButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:enabled="false"
|
||||
android:text="@string/tests_btn_testing"
|
||||
android:onClick="onAction" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/nativeKDFField"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/nativeKDF" />
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
2
platform-darwin/External/Pearl
vendored
2
platform-darwin/External/Pearl
vendored
Submodule platform-darwin/External/Pearl updated: f513a4a63c...b713577cd6
1
platform-darwin/External/libjson-c
vendored
1
platform-darwin/External/libjson-c
vendored
Submodule platform-darwin/External/libjson-c deleted from 3e5ad38a83
1
platform-darwin/External/libsodium
vendored
1
platform-darwin/External/libsodium
vendored
Submodule platform-darwin/External/libsodium deleted from 4809639ae1
184
platform-darwin/MasterPassword-JNI.xcodeproj/project.pbxproj
Normal file
184
platform-darwin/MasterPassword-JNI.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,184 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
DA1554DE20B3928E00EA92C5 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = "<group>"; };
|
||||
DA1554DF20B3928E00EA92C5 /* mpw-algorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-algorithm.h"; sourceTree = "<group>"; };
|
||||
DA1554E020B3928E00EA92C5 /* base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base64.h; sourceTree = "<group>"; };
|
||||
DA1554E120B3928E00EA92C5 /* mpw-marshal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal.c"; sourceTree = "<group>"; };
|
||||
DA1554E220B3928E00EA92C5 /* mpw-algorithm_v2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v2.c"; sourceTree = "<group>"; };
|
||||
DA1554E320B3928E00EA92C5 /* mpw-types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-types.c"; sourceTree = "<group>"; };
|
||||
DA1554E420B3928E00EA92C5 /* mpw-marshal-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal-util.c"; sourceTree = "<group>"; };
|
||||
DA1554E520B3928E00EA92C5 /* mpw-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-util.c"; sourceTree = "<group>"; };
|
||||
DA1554E620B3928E00EA92C5 /* mpw-algorithm_v1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v1.c"; sourceTree = "<group>"; };
|
||||
DA1554E720B3928E00EA92C5 /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = "<group>"; };
|
||||
DA1554E820B3928E00EA92C5 /* mpw-marshal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal.h"; sourceTree = "<group>"; };
|
||||
DA1554E920B3928E00EA92C5 /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = base64.c; sourceTree = "<group>"; };
|
||||
DA1554EA20B3928E00EA92C5 /* mpw-algorithm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm.c"; sourceTree = "<group>"; };
|
||||
DA1554EB20B3928E00EA92C5 /* mpw-algorithm_v0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v0.c"; sourceTree = "<group>"; };
|
||||
DA1554EC20B3928E00EA92C5 /* mpw-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-types.h"; sourceTree = "<group>"; };
|
||||
DA1554ED20B3928E00EA92C5 /* mpw-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-util.h"; sourceTree = "<group>"; };
|
||||
DA1554EE20B3928E00EA92C5 /* mpw-marshal-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal-util.h"; sourceTree = "<group>"; };
|
||||
DA1554EF20B3928E00EA92C5 /* mpw-algorithm_v3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v3.c"; sourceTree = "<group>"; };
|
||||
DA1F44B020BCF0C200957B45 /* mpw-jni.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-jni.h"; sourceTree = "<group>"; };
|
||||
DA1F44B120BCF0C200957B45 /* mpw-jni.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-jni.c"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
DA1554D220B3924000EA92C5 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA1554DD20B3928E00EA92C5 /* core */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DA1554DD20B3928E00EA92C5 /* core */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA1554DE20B3928E00EA92C5 /* aes.c */,
|
||||
DA1554E720B3928E00EA92C5 /* aes.h */,
|
||||
DA1554E920B3928E00EA92C5 /* base64.c */,
|
||||
DA1554E020B3928E00EA92C5 /* base64.h */,
|
||||
DA1554EB20B3928E00EA92C5 /* mpw-algorithm_v0.c */,
|
||||
DA1554E620B3928E00EA92C5 /* mpw-algorithm_v1.c */,
|
||||
DA1554E220B3928E00EA92C5 /* mpw-algorithm_v2.c */,
|
||||
DA1554EF20B3928E00EA92C5 /* mpw-algorithm_v3.c */,
|
||||
DA1554EA20B3928E00EA92C5 /* mpw-algorithm.c */,
|
||||
DA1554DF20B3928E00EA92C5 /* mpw-algorithm.h */,
|
||||
DA1F44B120BCF0C200957B45 /* mpw-jni.c */,
|
||||
DA1F44B020BCF0C200957B45 /* mpw-jni.h */,
|
||||
DA1554E420B3928E00EA92C5 /* mpw-marshal-util.c */,
|
||||
DA1554EE20B3928E00EA92C5 /* mpw-marshal-util.h */,
|
||||
DA1554E120B3928E00EA92C5 /* mpw-marshal.c */,
|
||||
DA1554E820B3928E00EA92C5 /* mpw-marshal.h */,
|
||||
DA1554E320B3928E00EA92C5 /* mpw-types.c */,
|
||||
DA1554EC20B3928E00EA92C5 /* mpw-types.h */,
|
||||
DA1554E520B3928E00EA92C5 /* mpw-util.c */,
|
||||
DA1554ED20B3928E00EA92C5 /* mpw-util.h */,
|
||||
);
|
||||
name = core;
|
||||
path = "../platform-independent/c/core/src";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXLegacyTarget section */
|
||||
DA1554D720B3924000EA92C5 /* MasterPassword-JNI */ = {
|
||||
isa = PBXLegacyTarget;
|
||||
buildArgumentsString = ":masterpassword-algorithm:nativeGenHeaders";
|
||||
buildConfigurationList = DA1554DA20B3924000EA92C5 /* Build configuration list for PBXLegacyTarget "MasterPassword-JNI" */;
|
||||
buildPhases = (
|
||||
);
|
||||
buildToolPath = gradle;
|
||||
buildWorkingDirectory = /Users/lhunath/Documents/workspace/lyndir/MasterPassword/gradle;
|
||||
dependencies = (
|
||||
);
|
||||
name = "MasterPassword-JNI";
|
||||
passBuildSettingsInEnvironment = 1;
|
||||
productName = "MasterPassword-JNI";
|
||||
};
|
||||
/* End PBXLegacyTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
DA1554D320B3924000EA92C5 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0930;
|
||||
ORGANIZATIONNAME = "Maarten Billemont";
|
||||
TargetAttributes = {
|
||||
DA1554D720B3924000EA92C5 = {
|
||||
CreatedOnToolsVersion = 9.3.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = DA1554D620B3924000EA92C5 /* Build configuration list for PBXProject "MasterPassword-JNI" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = DA1554D220B3924000EA92C5;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
DA1554D720B3924000EA92C5 /* MasterPassword-JNI */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
DA1554D820B3924000EA92C5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
DA1554D920B3924000EA92C5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
DA1554DB20B3924000EA92C5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(PROJECT_DIR)/../lib/libsodium/build-ios~/out/include\"",
|
||||
"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
|
||||
);
|
||||
JAVA_HOME = /Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home;
|
||||
OTHER_CFLAGS = (
|
||||
"-DMPW_SODIUM=1",
|
||||
"-DMPW_CPERCIVA=0",
|
||||
);
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
DA1554DC20B3924000EA92C5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(PROJECT_DIR)/../lib/libsodium/build-ios~/out/include\"",
|
||||
"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
|
||||
);
|
||||
JAVA_HOME = /Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home;
|
||||
OTHER_CFLAGS = (
|
||||
"-DMPW_SODIUM=1",
|
||||
"-DMPW_CPERCIVA=0",
|
||||
);
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
DA1554D620B3924000EA92C5 /* Build configuration list for PBXProject "MasterPassword-JNI" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
DA1554D820B3924000EA92C5 /* Debug */,
|
||||
DA1554D920B3924000EA92C5 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
DA1554DA20B3924000EA92C5 /* Build configuration list for PBXLegacyTarget "MasterPassword-JNI" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
DA1554DB20B3924000EA92C5 /* Debug */,
|
||||
DA1554DC20B3924000EA92C5 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = DA1554D320B3924000EA92C5 /* Project object */;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0830"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -45,6 +46,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0830"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -45,6 +46,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0830"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -45,6 +46,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0830"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -45,6 +46,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0830"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -45,6 +46,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "YES"
|
||||
customWorkingDirectory = "/Users/lhunath/Documents/workspace/lyndir/MasterPassword/platform-independent/cli-c"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:MasterPassword-JNI.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:MasterPassword-iOS.xcodeproj">
|
||||
</FileRef>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?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>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -66,12 +66,6 @@
|
||||
# readwhile command [args]
|
||||
# Outputs the characters typed by the user into the terminal's input buffer while running the given command.
|
||||
#
|
||||
# pushqueue element ...
|
||||
# Pushes the given arguments as elements onto the queue.
|
||||
#
|
||||
# popqueue
|
||||
# Pops one element off the queue.
|
||||
#
|
||||
# log [format] [arguments...]
|
||||
# Log an event at a certain importance level.
|
||||
# The event is expressed as a printf(1) format argument.
|
||||
@@ -85,7 +79,7 @@
|
||||
# reverse [-0|-d delimitor] [elements ...] [<<< elements]
|
||||
# Reverse the order of the given elements.
|
||||
#
|
||||
# order [-0|-d char] [-[cC] isAscending|-n] [-t number] [elements ...] [<<< elements]
|
||||
# order [-0|-d char] [-[cC] comparator|-n] [-t number] [elements ...] [<<< elements]
|
||||
# Orders the elements in ascending order.
|
||||
#
|
||||
# mutex file
|
||||
@@ -180,6 +174,9 @@ genToc() {
|
||||
# | .: GLOBAL DECLARATIONS :. |
|
||||
# |______________________________________________________________________|
|
||||
|
||||
# Environment
|
||||
export TMPDIR=${TMPDIR:-/tmp} TMPDIR=${TMPDIR%/} TERM=${TERM:-dumb}
|
||||
|
||||
# Variables for convenience sequences.
|
||||
bobber=( '.' 'o' 'O' 'o' )
|
||||
spinner=( '-' \\ '|' '/' )
|
||||
@@ -190,8 +187,8 @@ runner=( '> >' \
|
||||
|
||||
# Variables for terminal requests.
|
||||
[[ -t 2 && $TERM != dumb ]] && {
|
||||
COLUMNS=$( tput cols || tput co ) # Columns in a line
|
||||
LINES=$( tput lines || tput li ) # Lines on screen
|
||||
COLUMNS=$({ tput cols || tput co;} 2>&3) # Columns in a line
|
||||
LINES=$({ tput lines || tput li;} 2>&3) # Lines on screen
|
||||
alt=$( tput smcup || tput ti ) # Start alt display
|
||||
ealt=$( tput rmcup || tput te ) # End alt display
|
||||
hide=$( tput civis || tput vi ) # Hide cursor
|
||||
@@ -230,7 +227,7 @@ runner=( '> >' \
|
||||
tput eA; tput as;
|
||||
tput ac; tput ae; } ) # Drawing characters
|
||||
back=$'\b'
|
||||
} ||:
|
||||
} 3>&2 2>/dev/null ||:
|
||||
|
||||
|
||||
|
||||
@@ -264,7 +261,10 @@ chr() {
|
||||
# Outputs the decimal ASCII value of the given character.
|
||||
#
|
||||
ord() {
|
||||
printf '%d' "'$1"
|
||||
local str=$1 s
|
||||
for (( s=0; s < ${#str}; ++s )); do
|
||||
printf '%d' "'${str:s:1}"
|
||||
done
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
@@ -277,7 +277,10 @@ ord() {
|
||||
# Outputs the hexadecimal ASCII value of the given character.
|
||||
#
|
||||
hex() {
|
||||
printf '%x' "'$1"
|
||||
local str=$1 s
|
||||
for (( s=0; s < ${#str}; ++s )); do
|
||||
printf '%02X' "'${str:s:1}"
|
||||
done
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
@@ -290,7 +293,10 @@ hex() {
|
||||
# Outputs the character that has the given hexadecimal ASCII value.
|
||||
#
|
||||
unhex() {
|
||||
printf "\\x$1"
|
||||
local hex=$1 h
|
||||
for (( h=0; h < ${#hex}; h+=2 )); do
|
||||
printf "\\x${hex:h:2}"
|
||||
done
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
@@ -329,6 +335,26 @@ min() {
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ si ________________________________________________________________|
|
||||
#
|
||||
# si number
|
||||
#
|
||||
# Output a human-readable version of the number using SI units.
|
||||
#
|
||||
si() {
|
||||
local number=$1
|
||||
|
||||
if (( number >= 1000000000000000 )); then printf '%dM' "$((number / 1000000000000000))"
|
||||
elif (( number >= 1000000000000 )); then printf '%dM' "$((number / 1000000000000))"
|
||||
elif (( number >= 1000000000 )); then printf '%dM' "$((number / 1000000000))"
|
||||
elif (( number >= 1000000 )); then printf '%dM' "$((number / 1000000))"
|
||||
elif (( number >= 1000 )); then printf '%dk' "$((number / 1000))"
|
||||
else printf '%d' "$number"; fi
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ totime ____________________________________________________________|
|
||||
#
|
||||
@@ -528,6 +554,50 @@ iterate() (
|
||||
fi
|
||||
) # _____________________________________________________________________
|
||||
|
||||
|
||||
|
||||
# _______________________________________________________________________
|
||||
# |__ csvline ____________________________________________________________|
|
||||
#
|
||||
# csvline [-d delimiter] [-D line-delimiter]
|
||||
#
|
||||
# Parse a CSV record from standard input, storing the fields in the CSVLINE array.
|
||||
#
|
||||
# By default, a single line of input is read and parsed into comma-delimited fields.
|
||||
# Fields can optionally contain double-quoted data, including field delimiters.
|
||||
#
|
||||
# A different field delimiter can be specified using -d. You can use -D
|
||||
# to change the definition of a "record" (eg. to support NULL-delimited records).
|
||||
#
|
||||
csvline() {
|
||||
CSVLINE=()
|
||||
local line field quoted=0 delimiter=, lineDelimiter=$'\n' c
|
||||
local OPTIND=1 arg
|
||||
while getopts :d: arg; do
|
||||
case $arg in
|
||||
d) delimiter=$OPTARG ;;
|
||||
esac
|
||||
done
|
||||
|
||||
IFS= read -d "$lineDelimiter" -r line || return
|
||||
while IFS= read -rn1 c; do
|
||||
case $c in
|
||||
'"')
|
||||
(( quoted = !quoted ))
|
||||
continue ;;
|
||||
$delimiter)
|
||||
if (( ! quoted )); then
|
||||
CSVLINE+=( "$field" ) field=
|
||||
continue
|
||||
fi ;;
|
||||
esac
|
||||
field+=$c
|
||||
done <<< "$line"
|
||||
[[ $field ]] && CSVLINE+=( "$field" ) ||:
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ Logging ___________________________________________________________|
|
||||
#
|
||||
@@ -551,11 +621,11 @@ iterate() (
|
||||
# The closing statement also takes a format and arguments, which are displayed in the spinner.
|
||||
#
|
||||
log() {
|
||||
local exitcode=$? level=${level:-inf} supported=0 end=$'\n' type=msg conMsg= logMsg= format= colorFormat= date= info= arg= args=() colorArgs=() ruler=
|
||||
local exitcode=$? result=0 level=${level:-inf} supported=0 end=$'\n' type=msg conMsg= logMsg= format= colorFormat= date= info= arg= args=() colorArgs=() ruler=
|
||||
|
||||
# Handle options.
|
||||
local OPTIND=1
|
||||
while getopts :tpuPrR:d:n arg; do
|
||||
while getopts :tpuPrR:d:nx arg; do
|
||||
case $arg in
|
||||
p)
|
||||
end='.. '
|
||||
@@ -573,13 +643,14 @@ log() {
|
||||
end=$OPTARG ;;
|
||||
n)
|
||||
end= ;;
|
||||
t)
|
||||
date=$(date +"${_logDate:-%H:%M}") ;;
|
||||
x)
|
||||
result=$exitcode ;;
|
||||
esac
|
||||
done
|
||||
shift "$((OPTIND-1))"
|
||||
format=$1 args=( "${@:2}" )
|
||||
(( ! ${#args[@]} )) && [[ $format ]] && { args=("$format") format=%s; local bold=; }
|
||||
date=${_logDate+$(date +"${_logDate:-%H:%M}")}
|
||||
|
||||
# Level-specific settings.
|
||||
local logLevelColor
|
||||
@@ -600,17 +671,17 @@ log() {
|
||||
log FTL 'Log level %s does not exist' "$level"
|
||||
exit 1 ;;
|
||||
esac
|
||||
(( ! supported )) && return "$exitcode"
|
||||
(( ! supported )) && return "$result"
|
||||
local logColor=${_logColor:+$logLevelColor}
|
||||
|
||||
# Generate the log message.
|
||||
case $type in
|
||||
msg|startProgress)
|
||||
printf -v logMsg "[${date:+%s }%-3s] $format$end" ${date:+"$date"} "$level" "${args[@]}"
|
||||
printf -v logMsg "${date:+%s }${_logLevel:+%-3s }$format$end" ${date:+"$date"} ${_logLevel:+"$level"} "${args[@]}"
|
||||
if (( _logColor )); then
|
||||
colorFormat=$(sed ${reset:+-e "s/$(requote "$reset")/$reset$logColor/g"} -e "s/%[^a-z]*[a-z]/$reset$bold$logColor&$reset$logColor/g" <<< "$format")
|
||||
colorArgs=("${args[@]//$reset/$reset$bold$logColor}")
|
||||
printf -v conMsg "$reset[${date:+%s }$logColor$bold%-3s$reset] $logColor$colorFormat$reset$black\$$reset$end$save" ${date:+"$date"} "$level" "${colorArgs[@]}"
|
||||
colorFormat=$(sed ${reset:+-e "s/$(requote "$reset")/$reset$_logAttributes$logColor/g"} -e "s/%[^a-z]*[a-z]/$reset$_logAttributes$bold$logColor&$reset$_logAttributes$logColor/g" <<< "$format")
|
||||
colorArgs=("${args[@]//$reset/$reset$_logAttributes$bold$logColor}")
|
||||
printf -v conMsg "$reset$_logAttributes${date:+%s }${_logLevel:+$logColor$bold%-3s$reset $_logAttributes}$logColor$colorFormat$reset$_logAttributes$black\$$reset$end$save" ${date:+"$date"} ${_logLevel:+"$level"} "${colorArgs[@]}"
|
||||
else
|
||||
conMsg=$logMsg
|
||||
fi
|
||||
@@ -619,15 +690,17 @@ log() {
|
||||
updateProgress)
|
||||
printf -v logMsg printf " [$format]" "${args[@]}"
|
||||
if (( _logColor )); then
|
||||
colorFormat=$(sed ${reset:+-e "s/$(requote "$reset")/$reset$logColor/g"} -e "s/%[^a-z]*[a-z]/$reset$bold$logColor&$reset$logColor/g" <<< "$format")
|
||||
colorArgs=("${args[@]//$reset/$reset$bold$logColor}")
|
||||
printf -v conMsg "$load$eel$blue$bold[$reset$logColor$colorFormat$reset$blue$bold]$reset$end" "${colorArgs[@]}"
|
||||
colorFormat=$(sed ${reset:+-e "s/$(requote "$reset")/$reset$_logAttributes$logColor/g"} -e "s/%[^a-z]*[a-z]/$reset$_logAttributes$bold$logColor&$reset$_logAttributes$logColor/g" <<< "$format")
|
||||
colorArgs=("${args[@]//$reset/$reset$_logAttributes$bold$logColor}")
|
||||
printf -v conMsg "$load$eel$blue$bold[$reset$_logAttributes$logColor$colorFormat$reset$_logAttributes$blue$bold]$reset$end" "${colorArgs[@]}"
|
||||
else
|
||||
conMsg=$logMsg
|
||||
fi
|
||||
;;
|
||||
|
||||
stopProgress)
|
||||
! kill -0 "$_logSpinner" 2>/dev/null && return
|
||||
|
||||
case $exitcode in
|
||||
0) printf -v logMsg "done${format:+ ($format)}.\n" "${args[@]}"
|
||||
if (( _logColor )); then
|
||||
@@ -653,15 +726,17 @@ log() {
|
||||
|
||||
# Create the log file.
|
||||
if [[ $_logFile && ! -e $_logFile ]]; then
|
||||
[[ $_logFile = */* ]] || $_logFile=./$logFile
|
||||
[[ $_logFile = */* ]] || _logFile=./$_logFile
|
||||
mkdir -p "${_logFile%/*}" && touch "$_logFile"
|
||||
fi
|
||||
|
||||
# Stop the spinner.
|
||||
if [[ $type = stopProgress && $_logSpinner ]]; then
|
||||
kill "$_logSpinner"
|
||||
wait "$_logSpinner" 2>/dev/null
|
||||
unset _logSpinner
|
||||
{
|
||||
kill "$_logSpinner" ||:
|
||||
wait "$_logSpinner" ||:
|
||||
unset _logSpinner
|
||||
} 2>/dev/null
|
||||
fi
|
||||
|
||||
# Output the ruler.
|
||||
@@ -685,9 +760,10 @@ log() {
|
||||
while printf >&2 "$eel$blue$bold[$reset%s$reset$blue$bold]$reset\b\b\b" "${spinner[s++ % ${#spinner[@]}]}" && sleep .1
|
||||
do :; done
|
||||
} & _logSpinner=$!
|
||||
addtrap EXIT 'level=%q _logSpinner=%q golp' "$level" "$_logSpinner"
|
||||
fi
|
||||
|
||||
return $exitcode
|
||||
return $result
|
||||
}
|
||||
trc() { level=TRC log "$@"; }
|
||||
dbg() { level=DBG log "$@"; }
|
||||
@@ -718,6 +794,8 @@ rrep() { level=ERR golp "$@"; }
|
||||
ltfp() { level=FTL golp "$@"; }
|
||||
_logColor=${_logColor:-$([[ -t 2 ]] && echo 1)} _logVerbosity=2
|
||||
_logTrcColor=$grey _logDbgColor=$blue _logInfColor=$white _logWrnColor=$yellow _logErrColor=$red _logFtlColor=$bold$red
|
||||
#_logDate=%H:%M # Set this to enable date output in log messages.
|
||||
#_logLevel=1 # Set this to enable level output in log messages.
|
||||
# _______________________________________________________________________
|
||||
|
||||
|
||||
@@ -794,10 +872,10 @@ ask() {
|
||||
printf '%s' "$muteChar" >&$fd
|
||||
done
|
||||
REPLY=$reply
|
||||
[[ $options && $REPLY ]] || (( silent )) && printf '\n' >&$fd
|
||||
else
|
||||
read -u8 -e ${options:+-n1} ${silent:+-s}
|
||||
fi
|
||||
[[ $options && $REPLY ]] || (( silent )) && printf '\n' >&$fd
|
||||
|
||||
# Evaluate the reply.
|
||||
while true; do
|
||||
@@ -886,7 +964,7 @@ reverse() {
|
||||
# ______________________________________________________________________
|
||||
# |__ Order _____________________________________________________________|
|
||||
#
|
||||
# order [-0|-d char] [-[fF] isDesired] [-[cC] isAscending|-n|-r|-t] [-T number] [-a array|elements ...] [<<< elements]
|
||||
# order [-0|-d char] [-[fF] isDesired] [-[cC] comparator|-n|-R|-t] [-r] [-T number] [-a array|elements ...] [<<< elements]
|
||||
#
|
||||
# Orders the elements in ascending order.
|
||||
# Elements are read from command arguments or standard input if no element
|
||||
@@ -895,21 +973,23 @@ reverse() {
|
||||
#
|
||||
# By default, the elements will be ordered using lexicographic comparison.
|
||||
# If the -n option is given, the elements will be ordered numerically.
|
||||
# If the -r option is given, the elements will be ordered randomly.
|
||||
# If the -R option is given, the elements will be ordered randomly.
|
||||
# If the -t option is given, the elements are ordered by file mtime.
|
||||
# If the -f option is given, the command name following it will be used
|
||||
# as a filter.
|
||||
# If the -c option is given, the command name following it will be used
|
||||
# as a comparator.
|
||||
# If the -C option is given, the bash code following it will be used
|
||||
# as a comparator.
|
||||
# If the -t option is given, only the first number results are returned.
|
||||
# If the -r option is given, the ordering will be reversed.
|
||||
# If the -T option is given, only the first number results are returned.
|
||||
# If the -a option is given, the elements in array are ordered instead and
|
||||
# array is mutated to contain the result.
|
||||
# If number is 0, all results are returned.
|
||||
#
|
||||
# isDesired is a command name which will get one parameter. The parameter
|
||||
# is an element which will only be included if the command exits successfully.
|
||||
# isAscending is a command name which will be executed for each element
|
||||
# comparator is a command name which will be executed for each element
|
||||
# comparison and will be passed two element arguments. The command should
|
||||
# succeed if the first argument is less than the second argument for the
|
||||
# purpose of this sort.
|
||||
@@ -924,59 +1004,61 @@ reverse() {
|
||||
order() {
|
||||
|
||||
# Initialize the vars.
|
||||
local delimitor=$'\n' i isDesired=true isAscending=string_ascends top=0 arrayName= array=
|
||||
local _delimitor=$'\n' _i _j _isDesired=true _comparator=string_ascends _comparator_ascends=1 _top=0 _arrayName= _array=
|
||||
|
||||
# Parse the options.
|
||||
local OPTIND=1
|
||||
while getopts :0nrd:f:F:c:C:tT:a: opt; do
|
||||
while getopts :0nrRd:f:F:c:C:tT:a: opt; do
|
||||
case $opt in
|
||||
0) delimitor=$'\0' ;;
|
||||
d) delimitor=$OPTARG ;;
|
||||
n) isAscending=number_ascends ;;
|
||||
r) isAscending=random_ascends ;;
|
||||
t) isAscending=mtime_ascends ;;
|
||||
f) isDesired=$OPTARG ;;
|
||||
F) isDesired=bash_desired bash_desired_code=$OPTARG ;;
|
||||
c) isAscending=$OPTARG ;;
|
||||
C) isAscending=bash_ascends bash_ascends_code=$OPTARG ;;
|
||||
T) top=$OPTARG ;;
|
||||
a) arrayName=$OPTARG array=$arrayName[@] ;;
|
||||
0) _delimitor=$'\0' ;;
|
||||
d) _delimitor=$OPTARG ;;
|
||||
n) _comparator=number_ascends ;;
|
||||
R) _comparator=random_ascends ;;
|
||||
t) _comparator=mtime_ascends ;;
|
||||
f) _isDesired=$OPTARG ;;
|
||||
F) _isDesired=bash_desired _bash_desired_code=$OPTARG ;;
|
||||
c) _comparator=$OPTARG ;;
|
||||
C) _comparator=bash_ascends _bash_ascends_code=$OPTARG ;;
|
||||
r) _comparator_ascends=0 ;;
|
||||
T) _top=$OPTARG ;;
|
||||
a) _arrayName=$OPTARG _array=$_arrayName[@] ;;
|
||||
esac
|
||||
done
|
||||
shift "$((OPTIND-1))"
|
||||
|
||||
# Get the elements.
|
||||
local elements=() element
|
||||
if [[ $arrayName ]]; then
|
||||
for element in "${!array}"; do
|
||||
"$isDesired" "$element" && elements+=("$element")
|
||||
local _elements=() _element
|
||||
if [[ $_arrayName ]]; then
|
||||
for _element in "${!_array}"; do
|
||||
"$_isDesired" "$_element" && _elements+=("$_element")
|
||||
done
|
||||
elif (( $# )); then
|
||||
for element; do
|
||||
"$isDesired" "$element" && elements+=("$element")
|
||||
for _element; do
|
||||
"$_isDesired" "$_element" && _elements+=("$_element")
|
||||
done
|
||||
else
|
||||
while IFS= read -r -d "$delimitor" element; do
|
||||
"$isDesired" "$element" && elements+=("$element")
|
||||
while IFS= read -r -d "$_delimitor" _element; do
|
||||
"$_isDesired" "$_element" && _elements+=("$_element")
|
||||
done
|
||||
fi
|
||||
|
||||
# Iterate in reverse order.
|
||||
for (( i = 1; i < ${#elements[@]}; ++i )); do
|
||||
for (( j = i; j > 0; --j )); do
|
||||
element=${elements[j]}
|
||||
if "$isAscending" "$element" "${elements[j-1]}"; then
|
||||
elements[j]=${elements[j-1]}
|
||||
elements[j-1]=$element
|
||||
for (( _i = 1; _i < ${#_elements[@]}; ++_i )); do
|
||||
for (( _j = _i; _j > 0; --_j )); do
|
||||
_element=${_elements[_j]}
|
||||
if ( (( _comparator_ascends )) && "$_comparator" "$_element" "${_elements[_j-1]}" ) ||
|
||||
( (( ! _comparator_ascends )) && ! "$_comparator" "$_element" "${_elements[_j-1]}" ); then
|
||||
_elements[_j]=${_elements[_j-1]}
|
||||
_elements[_j-1]=$_element
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
(( top )) || top=${#elements[@]}
|
||||
if [[ $array ]]; then
|
||||
declare -ga "$array=($(printf '%q ' "${elements[@]:0:top}"))"
|
||||
(( _top )) || _top=${#_elements[@]}
|
||||
if [[ $_array ]]; then
|
||||
declare -ga "$_array=($(printf '%q ' "${_elements[@]:0:_top}"))"
|
||||
else
|
||||
printf "%s${delimitor:-\0}" "${elements[@]:0:top}"
|
||||
printf "%s${_delimitor:-\0}" "${_elements[@]:0:_top}"
|
||||
fi
|
||||
} # _____________________________________________________________________
|
||||
string_ascends() { [[ $1 < $2 ]]; }
|
||||
@@ -987,8 +1069,28 @@ exists_desired() { [[ -e $1 ]]; }
|
||||
line_desired() { [[ $1 ]]; }
|
||||
code_desired() { line_desired "$1" && ! comment_desired "$1"; }
|
||||
comment_desired() { line_desired "$1" && [[ $1 = @(#|//|/\*)* ]]; }
|
||||
bash_desired() { bash -c "$bash_desired_code" -- "$@"; }
|
||||
bash_ascends() { bash -c "$bash_ascends_code" -- "$@"; }
|
||||
bash_desired() { bash -c "$_bash_desired_code" -- "$@"; }
|
||||
bash_ascends() { bash -c "$_bash_ascends_code" -- "$@"; }
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ AddTrap _____________________________________________________________|
|
||||
#
|
||||
# addtrap signal command-format [args...]
|
||||
#
|
||||
# Add a command to the current commands executed when a signal is received by the bash process.
|
||||
#
|
||||
# The command-format is a printf-style format for the command to execute. The optional
|
||||
# args are interpolated into the command-format by bash's built-in printf.
|
||||
#
|
||||
addtrap() {
|
||||
local signal=$1 cmd=$2; shift 2
|
||||
printf -v cmd "$cmd" "$@"
|
||||
|
||||
read _ _ oldtrap <<< "$(trap -p "$signal")"
|
||||
eval "declare oldtrap=${oldtrap% *}"
|
||||
trap "$oldtrap${oldtrap:+; }$cmd" "$signal"
|
||||
}
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
@@ -1119,9 +1221,10 @@ options() {
|
||||
while getopts "$optstring" arg; do
|
||||
if [[ $arg = h && ! ${options[h]} ]]; then
|
||||
# Show usage message.
|
||||
[[ -t 1 ]]; local fd=$(( $? + 1 )) optarg
|
||||
[[ -t 1 ]] && local fd=1 || local fd=2
|
||||
|
||||
# Print out the app usage.
|
||||
local optarg
|
||||
printf " Usage: $reset$bold%s$reset" "${BASH_SOURCE[1]##*/}" >&$fd
|
||||
for optchar in "${!options[@]}"; do
|
||||
[[ $optchar = *: ]] && optarg=" arg" || optarg=
|
||||
@@ -1172,7 +1275,7 @@ showHelp() {
|
||||
(( cols = ${cols:-80} - 10 ))
|
||||
|
||||
# Figure out what FD to use for our messages.
|
||||
[[ -t 1 ]]; local fd=$(( $? + 1 ))
|
||||
[[ -t 1 ]] && local fd=1 || local fd=2
|
||||
|
||||
# Print out the help header.
|
||||
printf "$reset$bold\n" >&$fd
|
||||
@@ -1214,18 +1317,17 @@ showHelp() {
|
||||
shquote() {
|
||||
|
||||
# Initialize the defaults.
|
||||
local arg escape=0 sq="'\\''" dq='\"' quotedArgs=() type=single always=0
|
||||
local OPTIND=1 arg escape=0 sq="'\\''" dq='\"' quotedArgs=() type=single always=0
|
||||
|
||||
# Parse the options.
|
||||
while [[ $1 = -* ]]; do
|
||||
case $1 in
|
||||
-e) type=escape ;;
|
||||
-d) type=double ;;
|
||||
-a) always=1 ;;
|
||||
--) shift; break ;;
|
||||
while getopts :eda arg; do
|
||||
case $arg in
|
||||
e) type=escape ;;
|
||||
d) type=double ;;
|
||||
a) always=1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
shift "$((OPTIND-1))"
|
||||
|
||||
# Print out each argument, quoting it properly.
|
||||
for arg; do
|
||||
@@ -1330,6 +1432,29 @@ shorten() {
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ CdSource ________________________________________________________________|
|
||||
#
|
||||
# cdsource [file]
|
||||
#
|
||||
# Change the current directory into the directory where the file is located, resolving symlinks.
|
||||
#
|
||||
cdsource() {
|
||||
local source=${1:-${BASH_SOURCE[1]}}
|
||||
|
||||
while [[ $source ]]; do
|
||||
[[ $source = */* ]] && cd "${source%/*}"
|
||||
|
||||
if [[ -L ${source##*/} ]]; then
|
||||
source=$(readlink "${source##*/}")
|
||||
else
|
||||
source=
|
||||
fi
|
||||
done
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ Up ________________________________________________________________|
|
||||
#
|
||||
@@ -1405,7 +1530,34 @@ inArray() {
|
||||
|
||||
# Perform the search.
|
||||
for element
|
||||
do [[ $element = $search ]] && return 0; done
|
||||
do [[ "$element" = "$search" ]] && return 0; done
|
||||
return 1
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ IndexOf ___________________________________________________________|
|
||||
#
|
||||
# indexOf element array
|
||||
#
|
||||
# Outputs the index of the given element in the given array.
|
||||
#
|
||||
# element The element to search the array for.
|
||||
# array This is a list of elements to search through.
|
||||
#
|
||||
indexOf() {
|
||||
|
||||
# Parse the options.
|
||||
local element index=0
|
||||
local search=$1; shift
|
||||
|
||||
# Perform the search.
|
||||
for element
|
||||
do
|
||||
[[ $element = $search ]] && echo "$index" && return 0
|
||||
let ++index
|
||||
done
|
||||
return 1
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
cd "${BASH_SOURCE%/*}/../External/libjson-c"
|
||||
[[ -e "${prefix=$PWD/libjson-c-ios}/lib/libjson-c.a" ]] && exit
|
||||
|
||||
# Prepare
|
||||
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
|
||||
rm -rf "${prefix=$PWD/libjson-c-ios}"
|
||||
mkdir -p "$prefix/lib" \
|
||||
"${prefix_i386=$prefix/tmp/i386}" \
|
||||
"${prefix_x86_64=$prefix/tmp/x86_64}" \
|
||||
"${prefix_armv7=$prefix/tmp/armv7}" \
|
||||
"${prefix_armv7s=$prefix/tmp/armv7s}" \
|
||||
"${prefix_arm64=$prefix/tmp/arm64}"
|
||||
|
||||
# Targets
|
||||
(
|
||||
## ARCH: i386
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||
export LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s clean
|
||||
./configure --host=i686-apple --disable-shared --prefix="$prefix_i386"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: x86_64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s clean
|
||||
./configure --host=x86_64-apple --disable-shared --prefix="$prefix_x86_64"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: armv7
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s clean
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: armv7s
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s clean
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7s"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: arm64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s clean
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_arm64"
|
||||
make -j3 install
|
||||
)
|
||||
|
||||
# Merge Binaries
|
||||
mv -f -- "$prefix_arm64/include" "$prefix/"
|
||||
lipo -create \
|
||||
"$prefix_i386/lib/libjson-c.a" \
|
||||
"$prefix_x86_64/lib/libjson-c.a" \
|
||||
"$prefix_armv7/lib/libjson-c.a" \
|
||||
"$prefix_armv7s/lib/libjson-c.a" \
|
||||
"$prefix_arm64/lib/libjson-c.a" \
|
||||
-output "$prefix/lib/libjson-c.a"
|
||||
|
||||
# Cleanup
|
||||
rm -rf -- "$prefix/tmp"
|
||||
make -s really-clean
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
cd "${BASH_SOURCE%/*}/../External/libjson-c"
|
||||
[[ -e "${prefix=$PWD/libjson-c-osx}/lib/libjson-c.a" ]] && exit
|
||||
|
||||
# Prepare
|
||||
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
|
||||
rm -rf "${prefix=$PWD/libjson-c-osx}"
|
||||
mkdir -p "$prefix"
|
||||
|
||||
# Targets
|
||||
(
|
||||
## ARCH: x86_64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -O2 -g $CFLAGS" # -flto
|
||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $LDFLAGS" # -flto
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s clean
|
||||
./configure --disable-shared --prefix="$prefix"
|
||||
make -j3 check
|
||||
make -j3 install
|
||||
)
|
||||
|
||||
# Cleanup
|
||||
make -s really-clean
|
||||
@@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
cd "${BASH_SOURCE%/*}/../External/libsodium"
|
||||
[[ -e "${prefix=$PWD/libsodium-ios}/lib/libsodium.a" ]] && exit
|
||||
|
||||
# Prepare
|
||||
autoreconf --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
|
||||
rm -rf "${prefix=$PWD/libsodium-ios}"
|
||||
mkdir -p "$prefix/lib" \
|
||||
"${prefix_i386=$prefix/tmp/i386}" \
|
||||
"${prefix_x86_64=$prefix/tmp/x86_64}" \
|
||||
"${prefix_armv7=$prefix/tmp/armv7}" \
|
||||
"${prefix_armv7s=$prefix/tmp/armv7s}" \
|
||||
"${prefix_arm64=$prefix/tmp/arm64}"
|
||||
|
||||
# Targets
|
||||
(
|
||||
## ARCH: i386
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --host=i686-apple --disable-shared --enable-minimal --prefix="$prefix_i386"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: x86_64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --host=x86_64-apple --disable-shared --enable-minimal --prefix="$prefix_x86_64"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: armv7
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_armv7"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: armv7s
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_armv7s"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: arm64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_arm64"
|
||||
make -j3 install
|
||||
)
|
||||
|
||||
# Merge Binaries
|
||||
mv -f -- "$prefix_arm64/include" "$prefix/"
|
||||
lipo -create \
|
||||
"$prefix_i386/lib/libsodium.a" \
|
||||
"$prefix_x86_64/lib/libsodium.a" \
|
||||
"$prefix_armv7/lib/libsodium.a" \
|
||||
"$prefix_armv7s/lib/libsodium.a" \
|
||||
"$prefix_arm64/lib/libsodium.a" \
|
||||
-output "$prefix/lib/libsodium.a"
|
||||
|
||||
# Cleanup
|
||||
rm -rf -- "$prefix/tmp"
|
||||
make -s distclean
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
cd "${BASH_SOURCE%/*}/../External/libsodium"
|
||||
[[ -e "${prefix=$PWD/libsodium-osx}/lib/libsodium.a" ]] && exit
|
||||
|
||||
# Inspired by libsodium/dist-build/osx.sh
|
||||
# Prepare
|
||||
autoreconf --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
|
||||
rm -rf "${prefix=$PWD/libsodium-osx}"
|
||||
mkdir -p "$prefix"
|
||||
|
||||
# Targets
|
||||
(
|
||||
## ARCH: x86_64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --disable-shared --enable-minimal --prefix="$prefix"
|
||||
make -j3 check
|
||||
make -j3 install
|
||||
)
|
||||
|
||||
# Cleanup
|
||||
make -s distclean
|
||||
@@ -2,6 +2,7 @@
|
||||
# See https://developer.apple.com/library/ios/qa/qa1686/_index.html
|
||||
cd "${BASH_SOURCE%/*}"
|
||||
source bashlib
|
||||
trap 'echo >&2 "ERROR: $?: $BASH_COMMAND"' ERR
|
||||
set -e
|
||||
cd ..
|
||||
export PATH+=:/usr/local/bin
|
||||
@@ -97,26 +98,18 @@ if [[ "$(latest "$ios_icon"/*)" -nt "$appiconset/Contents.json" ]] ||
|
||||
source=$ios_icon/$filename
|
||||
if [[ ! -e $source ]]; then
|
||||
source=$mac_icon/$filename
|
||||
if [[ ! -e $source ]]; then
|
||||
err 'No icon for: %s' "$filename"
|
||||
exit 1
|
||||
fi
|
||||
[[ -e $source ]] || ftl 'No icon for: %s' "$filename"
|
||||
fi
|
||||
|
||||
if imageProps=$(copyImage "$source" "$appiconset/$filename"); then
|
||||
printf '%s{"size":"%dx%d","filename":"%s","scale":"%sx"' \
|
||||
"$comma" "$pt" "$pt" "$filename" "$scale"
|
||||
[[ $idiom ]] && printf ',"idiom":"%s"' "$idiom"
|
||||
[[ $os ]] && printf ',"minimum-system-version":"%s"' "$os"
|
||||
[[ $imageProps ]] && printf '%s' "$imageProps"
|
||||
printf '}'
|
||||
|
||||
comma=,
|
||||
else
|
||||
rm "$appiconset/Contents.json"
|
||||
exit
|
||||
fi
|
||||
imageProps=$(copyImage "$source" "$appiconset/$filename")
|
||||
printf '%s{"size":"%dx%d","filename":"%s","scale":"%sx"' \
|
||||
"$comma" "$pt" "$pt" "$filename" "$scale"
|
||||
[[ $idiom ]] && printf ',"idiom":"%s"' "$idiom"
|
||||
[[ $os ]] && printf ',"minimum-system-version":"%s"' "$os"
|
||||
[[ $imageProps ]] && printf '%s' "$imageProps"
|
||||
printf '}'
|
||||
|
||||
comma=,
|
||||
done
|
||||
printf '],"info":{"version":1,"author":"genassets"},"properties":{"pre-rendered":true}}\n'
|
||||
} > "$appiconset/Contents.json"
|
||||
@@ -137,20 +130,16 @@ if [[ "$(latest "$ios_launch"/*)" -nt "$launchimage/Contents.json" ]]; then
|
||||
esac
|
||||
filename="Default${os:+-$os}${subtype:+-$subtype}${scale:+@${scale}x}${idiom:+~$idiom}.png"
|
||||
|
||||
if imageProps=$(copyImage "$ios_launch/$name${scale:+@${scale}x}.png" "$launchimage/$filename"); then
|
||||
printf '%s{"extent":"full-screen","filename":"%s","orientation":"portrait","scale":"%sx"' \
|
||||
"$comma" "$filename" "${scale:-1}"
|
||||
[[ $idiom ]] && printf ',"idiom":"%s"' "$idiom"
|
||||
[[ $os ]] && printf ',"minimum-system-version":"%s"' "$os"
|
||||
[[ $subtype ]] && printf ',"subtype":"%s"' "$subtype"
|
||||
[[ $imageProps ]] && printf '%s' "$imageProps"
|
||||
printf '}'
|
||||
imageProps=$(copyImage "$ios_launch/$name${scale:+@${scale}x}.png" "$launchimage/$filename")
|
||||
printf '%s{"extent":"full-screen","filename":"%s","orientation":"portrait","scale":"%sx"' \
|
||||
"$comma" "$filename" "${scale:-1}"
|
||||
[[ $idiom ]] && printf ',"idiom":"%s"' "$idiom"
|
||||
[[ $os ]] && printf ',"minimum-system-version":"%s"' "$os"
|
||||
[[ $subtype ]] && printf ',"subtype":"%s"' "$subtype"
|
||||
[[ $imageProps ]] && printf '%s' "$imageProps"
|
||||
printf '}'
|
||||
|
||||
comma=,
|
||||
else
|
||||
rm "$launchimage/Contents.json"
|
||||
exit
|
||||
fi
|
||||
comma=,
|
||||
done
|
||||
printf '],"info":{"version":1,"author":"genassets"}}\n'
|
||||
} > "$launchimage/Contents.json"
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# This script should be in the 'Scripts' directory under the git repository's root.
|
||||
cd "${BASH_SOURCE%/*}/.."
|
||||
shopt -s extglob
|
||||
|
||||
|
||||
## Submodules that need to be checked out.
|
||||
dependencies=( External/{InAppSettingsKit,Pearl{,:External/jrswizzle,:External/uicolor-utilities},RHStatusItemView} )
|
||||
|
||||
## Custom migration.
|
||||
# None yet.
|
||||
|
||||
|
||||
################################################################################
|
||||
isCheckedOut() {
|
||||
local modulePath=$1
|
||||
! git submodule status | grep -q "^-[^ ]* $modulePath"
|
||||
}
|
||||
|
||||
# git submodule sync -- A bug causes this to init ALL external dependencies.
|
||||
git submodule sync $(git submodule status | awk '/^ / { print $2 }')
|
||||
|
||||
|
||||
# Check out our missing dependencies
|
||||
for dependency in "${dependencies[@]}"; do
|
||||
[[ $dependency = *:* ]] && root=${dependency%%:*} || root=.
|
||||
path=${dependency#*:}
|
||||
( cd "$root"; git submodule update --init "$path" )
|
||||
done
|
||||
|
||||
|
||||
# Update our modules
|
||||
git submodule update
|
||||
|
||||
|
||||
# Our modules may define a custom update script, if so, run it.
|
||||
find !(Scripts)/ -name "${BASH_SOURCE##*/}" -exec {} \;
|
||||
|
||||
|
||||
# Finally, for our modules that haven't got a custom update script, update them recursively.
|
||||
git submodule update --recursive --rebase
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
cd "${BASH_SOURCE%/*}"
|
||||
source ./bashlib
|
||||
trap 'echo >&2 "ERROR: $?: $BASH_COMMAND"' ERR
|
||||
set -e
|
||||
cd ..
|
||||
export PATH+=:/usr/libexec
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
+ (BOOL)managedObjectContextForMainThreadPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *mainContext))mocBlock;
|
||||
+ (BOOL)managedObjectContextPerformBlock:(void ( ^ )(NSManagedObjectContext *context))mocBlock;
|
||||
+ (BOOL)managedObjectContextPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *context))mocBlock;
|
||||
+ (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock;
|
||||
- (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock;
|
||||
|
||||
- (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context;
|
||||
- (void)deleteAndResetStore;
|
||||
|
||||
@@ -133,12 +133,11 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock {
|
||||
- (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock {
|
||||
|
||||
NSManagedObjectContext *privateManagedObjectContextIfReady = [[self get] privateManagedObjectContextIfReady];
|
||||
NSManagedObjectContext *privateManagedObjectContextIfReady = [self privateManagedObjectContextIfReady];
|
||||
if (!privateManagedObjectContextIfReady)
|
||||
return nil;
|
||||
|
||||
return PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, privateManagedObjectContextIfReady, nil,
|
||||
^(id host, NSNotification *note) {
|
||||
NSMutableDictionary *affectedObjects = [NSMutableDictionary new];
|
||||
@@ -217,7 +216,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
|
||||
self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
||||
self.mainManagedObjectContext.parentContext = self.privateManagedObjectContext;
|
||||
if ([self.mainManagedObjectContext respondsToSelector:@selector( automaticallyMergesChangesFromParent )]) // iOS 10+
|
||||
if (@available(iOS 10.0, macOS 10.12, *))
|
||||
self.mainManagedObjectContext.automaticallyMergesChangesFromParent = YES;
|
||||
else
|
||||
// When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
- (IBAction)androidPlayStore:(id)sender {
|
||||
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://masterpasswordapp.com"]];
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://masterpassword.app"]];
|
||||
[self close];
|
||||
}
|
||||
|
||||
|
||||
@@ -166,41 +166,66 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
|
||||
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES;
|
||||
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_MISSING_PARENTHESES = YES;
|
||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_SIGN_COMPARE = NO;
|
||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VALUE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
PRODUCT_NAME = "${TARGET_NAME}";
|
||||
@@ -231,17 +256,31 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
@@ -259,20 +298,30 @@
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
|
||||
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES;
|
||||
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_MISSING_PARENTHESES = YES;
|
||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_SIGN_COMPARE = NO;
|
||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = NO;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VALUE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
@@ -292,41 +341,66 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
|
||||
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES;
|
||||
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_MISSING_PARENTHESES = YES;
|
||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_SIGN_COMPARE = NO;
|
||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VALUE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
PRODUCT_NAME = "${TARGET_NAME}";
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
#import <objc/NSObjCRuntime.h>
|
||||
#import <stdlib.h>
|
||||
|
||||
#define log(level, format, ...) \
|
||||
#define mpw_log(level, format, ...) \
|
||||
do { \
|
||||
void (*_sendMsg)(id, SEL, CFStringRef, NSInteger, CFStringRef, NSUInteger, CFStringRef) = (void *)objc_msgSend; \
|
||||
char *_msg = NULL; \
|
||||
@@ -64,11 +64,11 @@
|
||||
CFRelease( msgStr ); \
|
||||
} while (0)
|
||||
|
||||
#define trc(format, ...) log( 0, format, ##__VA_ARGS__ );
|
||||
#define dbg(format, ...) log( 1, format, ##__VA_ARGS__ );
|
||||
#define inf(format, ...) log( 2, format, ##__VA_ARGS__ );
|
||||
#define wrn(format, ...) log( 3, format, ##__VA_ARGS__ );
|
||||
#define err(format, ...) log( 4, format, ##__VA_ARGS__ );
|
||||
#define ftl(format, ...) log( 5, format, ##__VA_ARGS__ );
|
||||
#define trc(format, ...) mpw_log( 0, format, ##__VA_ARGS__ );
|
||||
#define dbg(format, ...) mpw_log( 1, format, ##__VA_ARGS__ );
|
||||
#define inf(format, ...) mpw_log( 2, format, ##__VA_ARGS__ );
|
||||
#define wrn(format, ...) mpw_log( 3, format, ##__VA_ARGS__ );
|
||||
#define err(format, ...) mpw_log( 4, format, ##__VA_ARGS__ );
|
||||
#define ftl(format, ...) mpw_log( 5, format, ##__VA_ARGS__ );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Prefix header for all source files of the 'Pearl' target in the 'Pearl' project
|
||||
//
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#define PEARL_WITH_MESSAGEUI
|
||||
|
||||
#define PEARL
|
||||
#define PEARL_CRYPTO
|
||||
#if TARGET_OS_IOS
|
||||
#define PEARL_UIKIT
|
||||
#elif TARGET_OS_OSX
|
||||
#define PEARL_COCOA
|
||||
#endif
|
||||
|
||||
#import "Pearl.h"
|
||||
#import "Pearl-Crypto.h"
|
||||
#if TARGET_OS_IOS
|
||||
#import "Pearl-UIKit.h"
|
||||
#elif TARGET_OS_OSX
|
||||
#import "Pearl-Cocoa.h"
|
||||
#endif
|
||||
#endif
|
||||
@@ -225,7 +225,7 @@
|
||||
- (void)copyAnswer:(NSString *)answer {
|
||||
|
||||
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
||||
if ([pasteboard respondsToSelector:@selector( setItems:options: )]) {
|
||||
if (@available(iOS 10.0, *)) {
|
||||
[pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: answer } ]
|
||||
options:@{
|
||||
UIPasteboardOptionLocalOnly : @NO,
|
||||
|
||||
@@ -55,20 +55,21 @@
|
||||
[self.views[self.nextView++] setVisible:YES];
|
||||
}];
|
||||
|
||||
self.viewTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 block:^(NSTimer *timer) {
|
||||
self.viewProgress.progress += 1.0f / 50;
|
||||
|
||||
if (self.viewProgress.progress == 1)
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.viewProgress.progress = 0;
|
||||
[self.views[self.nextView++] setVisible:YES];
|
||||
|
||||
if (self.nextView >= [self.views count]) {
|
||||
[self.viewTimer invalidate];
|
||||
self.viewProgress.visible = NO;
|
||||
}
|
||||
}];
|
||||
} repeats:YES];
|
||||
if (@available(iOS 10.0, *))
|
||||
self.viewTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 repeats:YES block:^(NSTimer *timer) {
|
||||
self.viewProgress.progress += 1.0f / 50;
|
||||
|
||||
if (self.viewProgress.progress == 1)
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.viewProgress.progress = 0;
|
||||
[self.views[self.nextView++] setVisible:YES];
|
||||
|
||||
if (self.nextView >= [self.views count]) {
|
||||
[self.viewTimer invalidate];
|
||||
self.viewProgress.visible = NO;
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user