Compare commits
12 Commits
2.4-releas
...
2.4-java
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f21d0f7cfc | ||
|
|
7eb10cb5a6 | ||
|
|
64829c99d8 | ||
|
|
0269c2741a | ||
|
|
f5638ea798 | ||
|
|
6a1768a50d | ||
|
|
b346b3be65 | ||
|
|
060ec0b5cd | ||
|
|
7f8a36e32e | ||
|
|
024899f311 | ||
|
|
6ffef78469 | ||
|
|
b574158d92 |
1
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -5,7 +5,6 @@
|
||||
<inspection_tool class="Convert to string" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="FunctionImplicitDeclarationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ImplicitIntegerAndEnumConversion" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LossyEncoding" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="MethodIsLaterInTheScope" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="OCNotLocalizedStringInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="OCUnusedMacroInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "mpw-types.h"
|
||||
#include "mpw-util.h"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "mpw-types.h"
|
||||
#include "mpw-util.h"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "mpw-types.h"
|
||||
#include "mpw-util.h"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "mpw-types.h"
|
||||
#include "mpw-util.h"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password Algorithm Implementation</name>
|
||||
|
||||
@@ -16,12 +16,12 @@ import org.jetbrains.annotations.Contract;
|
||||
*/
|
||||
public enum MPSiteType {
|
||||
|
||||
GeneratedMaximum( "20 characters, contains symbols.", //
|
||||
GeneratedMaximum( "Max", "20 characters, contains symbols.", //
|
||||
ImmutableList.of( "x", "max", "maximum" ), //
|
||||
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ), new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
|
||||
MPSiteTypeClass.Generated, 0x0 ),
|
||||
|
||||
GeneratedLong( "Copy-friendly, 14 characters, contains symbols.", //
|
||||
GeneratedLong( "Long", "Copy-friendly, 14 characters, contains symbols.", //
|
||||
ImmutableList.of( "l", "long" ), //
|
||||
ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ),
|
||||
new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
|
||||
@@ -36,49 +36,50 @@ public enum MPSiteType {
|
||||
new MPTemplate( "CvccCvcvCvccno" ) ), //
|
||||
MPSiteTypeClass.Generated, 0x1 ),
|
||||
|
||||
GeneratedMedium( "Copy-friendly, 8 characters, contains symbols.", //
|
||||
GeneratedMedium( "Medium", "Copy-friendly, 8 characters, contains symbols.", //
|
||||
ImmutableList.of( "m", "med", "medium" ), //
|
||||
ImmutableList.of( new MPTemplate( "CvcnoCvc" ), new MPTemplate( "CvcCvcno" ) ), //
|
||||
MPSiteTypeClass.Generated, 0x2 ),
|
||||
|
||||
GeneratedBasic( "8 characters, no symbols.", //
|
||||
GeneratedBasic( "Basic", "8 characters, no symbols.", //
|
||||
ImmutableList.of( "b", "basic" ), //
|
||||
ImmutableList.of( new MPTemplate( "aaanaaan" ), new MPTemplate( "aannaaan" ), new MPTemplate( "aaannaaa" ) ), //
|
||||
MPSiteTypeClass.Generated, 0x3 ),
|
||||
|
||||
GeneratedShort( "Copy-friendly, 4 characters, no symbols.", //
|
||||
GeneratedShort( "Short", "Copy-friendly, 4 characters, no symbols.", //
|
||||
ImmutableList.of( "s", "short" ), //
|
||||
ImmutableList.of( new MPTemplate( "Cvcn" ) ), //
|
||||
MPSiteTypeClass.Generated, 0x4 ),
|
||||
|
||||
GeneratedPIN( "4 numbers.", //
|
||||
GeneratedPIN( "PIN", "4 numbers.", //
|
||||
ImmutableList.of( "i", "pin" ), //
|
||||
ImmutableList.of( new MPTemplate( "nnnn" ) ), //
|
||||
MPSiteTypeClass.Generated, 0x5 ),
|
||||
|
||||
GeneratedName( "9 letter name.", //
|
||||
GeneratedName( "Name", "9 letter name.", //
|
||||
ImmutableList.of( "n", "name" ), //
|
||||
ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), //
|
||||
MPSiteTypeClass.Generated, 0xE ),
|
||||
|
||||
GeneratedPhrase( "20 character sentence.", //
|
||||
GeneratedPhrase( "Phrase", "20 character sentence.", //
|
||||
ImmutableList.of( "p", "phrase" ), //
|
||||
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ), new MPTemplate( "cvc cvccvcvcv cvcv" ),
|
||||
new MPTemplate( "cv cvccv cvc cvcvccv" ) ), //
|
||||
MPSiteTypeClass.Generated, 0xF ),
|
||||
|
||||
StoredPersonal( "AES-encrypted, exportable.", //
|
||||
StoredPersonal( "Personal", "AES-encrypted, exportable.", //
|
||||
ImmutableList.of( "personal" ), //
|
||||
ImmutableList.<MPTemplate>of(), //
|
||||
MPSiteTypeClass.Stored, 0x0, MPSiteFeature.ExportContent ),
|
||||
|
||||
StoredDevicePrivate( "AES-encrypted, not exported.", //
|
||||
StoredDevicePrivate( "Device", "AES-encrypted, not exported.", //
|
||||
ImmutableList.of( "device" ), //
|
||||
ImmutableList.<MPTemplate>of(), //
|
||||
MPSiteTypeClass.Stored, 0x1, MPSiteFeature.DevicePrivate );
|
||||
|
||||
static final Logger logger = Logger.get( MPSiteType.class );
|
||||
|
||||
private final String shortName;
|
||||
private final String description;
|
||||
private final List<String> options;
|
||||
private final List<MPTemplate> templates;
|
||||
@@ -86,9 +87,10 @@ public enum MPSiteType {
|
||||
private final int typeIndex;
|
||||
private final Set<MPSiteFeature> typeFeatures;
|
||||
|
||||
MPSiteType(final String description, final List<String> options, final List<MPTemplate> templates, final MPSiteTypeClass typeClass,
|
||||
final int typeIndex, final MPSiteFeature... typeFeatures) {
|
||||
MPSiteType(final String shortName, final String description, final List<String> options, final List<MPTemplate> templates,
|
||||
final MPSiteTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
|
||||
|
||||
this.shortName = shortName;
|
||||
this.description = description;
|
||||
this.options = options;
|
||||
this.templates = templates;
|
||||
@@ -102,6 +104,10 @@ public enum MPSiteType {
|
||||
this.typeFeatures = typeFeaturesBuilder.build();
|
||||
}
|
||||
|
||||
public String getShortName() {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
|
||||
return description;
|
||||
|
||||
@@ -16,10 +16,12 @@ import org.jetbrains.annotations.NotNull;
|
||||
public abstract class MasterKey {
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( MasterKey.class );
|
||||
private static final Logger logger = Logger.get( MasterKey.class );
|
||||
private static boolean allowNativeByDefault = true;
|
||||
|
||||
@Nonnull
|
||||
private final String fullName;
|
||||
private boolean allowNative = allowNativeByDefault;
|
||||
|
||||
@Nullable
|
||||
private byte[] masterKey;
|
||||
@@ -46,6 +48,23 @@ public abstract class MasterKey {
|
||||
throw new UnsupportedOperationException( "Unsupported version: " + version );
|
||||
}
|
||||
|
||||
public static boolean isAllowNativeByDefault() {
|
||||
return allowNativeByDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Native libraries are useful for speeding up the performance of cryptographical functions.
|
||||
* Sometimes, however, we may prefer to use Java-only code.
|
||||
* For instance, for auditability / trust or because the native code doesn't work on our CPU/platform.
|
||||
* <p/>
|
||||
* This setter affects the default setting for any newly created {@link MasterKey}s.
|
||||
*
|
||||
* @param allowNative false to disallow the use of native libraries.
|
||||
*/
|
||||
public static void setAllowNativeByDefault(final boolean allowNative) {
|
||||
allowNativeByDefault = allowNative;
|
||||
}
|
||||
|
||||
protected MasterKey(@NotNull final String fullName) {
|
||||
|
||||
this.fullName = fullName;
|
||||
@@ -63,6 +82,15 @@ public abstract class MasterKey {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
public boolean isAllowNative() {
|
||||
return allowNative;
|
||||
}
|
||||
|
||||
public MasterKey setAllowNative(final boolean allowNative) {
|
||||
this.allowNative = allowNative;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected byte[] getKey() {
|
||||
|
||||
|
||||
@@ -65,8 +65,15 @@ public class MasterKeyV0 extends MasterKey {
|
||||
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
|
||||
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
|
||||
|
||||
return scrypt( masterKeySalt, mpBytes );
|
||||
}
|
||||
|
||||
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
||||
try {
|
||||
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||
if (isAllowNative())
|
||||
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||
else
|
||||
return SCrypt.scryptJ( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
logger.bug( e );
|
||||
|
||||
@@ -14,7 +14,7 @@ import javax.annotation.Nullable;
|
||||
/**
|
||||
* bugs:
|
||||
* - no known issues.
|
||||
*
|
||||
*
|
||||
* @author lhunath, 2014-08-30
|
||||
*/
|
||||
public class MasterKeyV3 extends MasterKeyV2 {
|
||||
@@ -46,17 +46,8 @@ public class MasterKeyV3 extends MasterKeyV2 {
|
||||
ByteBuffer mpBytesBuf = MP_charset.encode( CharBuffer.wrap( masterPassword ) );
|
||||
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
|
||||
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
|
||||
Arrays.fill( mpBytesBuf.array(), (byte)0 );
|
||||
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
|
||||
|
||||
try {
|
||||
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
logger.bug( e );
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
Arrays.fill( mpBytes, (byte) 0 );
|
||||
}
|
||||
return scrypt( masterKeySalt, mpBytes );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,15 @@
|
||||
<application
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name"
|
||||
android:allowBackup="true">
|
||||
<activity android:name=".TestActivity" android:theme="@style/MPTheme">
|
||||
android:allowBackup="true"
|
||||
android:debuggable="true">
|
||||
<activity android:name=".EmergencyActivity" android:theme="@style/MPTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".EmergencyActivity" android:theme="@style/MPTheme" />
|
||||
<activity android:name=".TestActivity" android:theme="@style/MPTheme" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password Android</name>
|
||||
@@ -67,6 +67,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jarsigner-plugin</artifactId>
|
||||
<version>1.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>signing</id>
|
||||
@@ -104,13 +105,13 @@
|
||||
<dependency>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-tests</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EXTERNAL DEPENDENCIES -->
|
||||
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 697 B |
@@ -1,5 +1,6 @@
|
||||
<?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"
|
||||
@@ -17,6 +18,13 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/img_identity" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/fullNameField"
|
||||
android:layout_width="match_parent"
|
||||
@@ -26,14 +34,14 @@
|
||||
android:hint="@string/fullName_hint"
|
||||
android:gravity="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="26sp" />
|
||||
android:textSize="16sp" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/rememberFullNameField"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nextFocusForward="@+id/rememberPasswordField"
|
||||
android:textSize="14sp"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/remember" />
|
||||
|
||||
@@ -46,16 +54,24 @@
|
||||
android:hint="@string/masterPassword_hint"
|
||||
android:gravity="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="18sp" />
|
||||
android:textSize="16sp" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@id/rememberPasswordField"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/forgetOnClose" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/img_key" />
|
||||
|
||||
<EditText
|
||||
android:id="@id/siteNameField"
|
||||
android:layout_width="match_parent"
|
||||
@@ -65,7 +81,7 @@
|
||||
android:hint="@string/siteName_hint"
|
||||
android:gravity="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="18sp" />
|
||||
android:textSize="16sp" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -76,8 +92,9 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="20dp"
|
||||
android:indeterminate="true" />
|
||||
android:visibility="invisible"
|
||||
android:indeterminate="true"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -89,12 +106,12 @@
|
||||
android:id="@id/sitePasswordField"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nextFocusForward="@+id/siteTypeField"
|
||||
android:nextFocusForward="@+id/siteTypeButton"
|
||||
android:gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="32sp"
|
||||
android:text="LuxdZozvDuma4["
|
||||
android:textSize="28sp"
|
||||
tools:text="LuxdZozvDuma4["
|
||||
android:onClick="copySitePassword" />
|
||||
|
||||
<TextView
|
||||
@@ -104,7 +121,7 @@
|
||||
android:labelFor="@id/sitePasswordField"
|
||||
android:gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:textSize="14sp"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/sitePassword_hint" />
|
||||
|
||||
@@ -115,54 +132,136 @@
|
||||
android:id="@+id/maskPasswordField"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/maskPassword" />
|
||||
|
||||
<Spinner
|
||||
android:id="@id/siteTypeField"
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nextFocusForward="@+id/counterField"
|
||||
android:gravity="center" />
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/divider" />
|
||||
|
||||
<EditText
|
||||
android:id="@id/counterField"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nextFocusForward="@+id/siteVersionField"
|
||||
android:gravity="center"
|
||||
android:inputType="text|textNoSuggestions"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="18sp"
|
||||
android:text="1" />
|
||||
style="?android:buttonBarStyle"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:labelFor="@id/counterField"
|
||||
android:gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/siteCounter_hint" />
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<Spinner
|
||||
android:id="@id/siteVersionField"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nextFocusForward="@id/rememberFullNameField"
|
||||
android:gravity="center" />
|
||||
<Button
|
||||
android:id="@id/siteTypeButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
style="?android:buttonBarButtonStyle"
|
||||
android:nextFocusForward="@+id/counterField"
|
||||
android:gravity="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="16sp"
|
||||
android:drawableStart="@drawable/icon_key"
|
||||
android:drawablePadding="8dp"
|
||||
android:background="@android:color/transparent"
|
||||
tools:text="Long" />
|
||||
|
||||
<TextView
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:labelFor="@id/siteTypeButton"
|
||||
android:gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/siteType_hint" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<Button
|
||||
android:id="@id/counterField"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
style="?android:buttonBarButtonStyle"
|
||||
android:nextFocusForward="@+id/siteVersionButton"
|
||||
android:gravity="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="16sp"
|
||||
android:drawableStart="@drawable/icon_plus"
|
||||
android:drawablePadding="8dp"
|
||||
android:background="@android:color/transparent"
|
||||
tools:text="1" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:labelFor="@id/siteVersionButton"
|
||||
android:gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/siteCounter_hint" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<Button
|
||||
android:id="@id/siteVersionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
style="?android:buttonBarButtonStyle"
|
||||
android:nextFocusForward="@+id/rememberFullNameField"
|
||||
android:gravity="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="16sp"
|
||||
android:drawableStart="@drawable/icon_gears"
|
||||
android:drawablePadding="8dp"
|
||||
android:background="@android:color/transparent"
|
||||
tools:text="3" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:labelFor="@id/siteVersionButton"
|
||||
android:gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/siteVersion_hint" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:labelFor="@id/siteVersionField"
|
||||
android:gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/siteVersion_hint" />
|
||||
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"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?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"
|
||||
@@ -17,22 +18,31 @@
|
||||
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"
|
||||
style="@android:style/Widget.ProgressBar.Horizontal" />
|
||||
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="14sp"
|
||||
android:textColor="@android:color/secondary_text_dark"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/tests_testing" />
|
||||
|
||||
<TextView
|
||||
@@ -53,8 +63,15 @@
|
||||
android:layout_marginTop="8dp"
|
||||
android:enabled="false"
|
||||
android:text="@string/tests_btn_testing"
|
||||
android:onClick="onAction"/>
|
||||
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>
|
||||
|
||||
@@ -8,15 +8,18 @@
|
||||
<string name="masterPassword_hint">Your master password</string>
|
||||
<string name="siteName_hint">eg. google.com</string>
|
||||
<string name="sitePassword_hint">Tap to copy</string>
|
||||
<string name="siteCounter_hint">Password #</string>
|
||||
<string name="siteType_hint">Type</string>
|
||||
<string name="siteCounter_hint">Counter</string>
|
||||
<string name="siteVersion_hint">Algorithm</string>
|
||||
<string name="empty" />
|
||||
<string name="btn_tests">Integrity Tests ❯</string>
|
||||
<string name="tests_unavailable">Test suite unavailable.</string>
|
||||
<string name="tests_btn_unavailable">Exit</string>
|
||||
<string name="tests_btn_unavailable">Retest</string>
|
||||
<string name="tests_testing">Testing device\'s password generation integrity…</string>
|
||||
<string name="tests_btn_testing">Please Stand By…</string>
|
||||
<string name="tests_failed">Incompatible device or OS.</string>
|
||||
<string name="tests_btn_failed">Exit</string>
|
||||
<string name="tests_btn_failed">Retest</string>
|
||||
<string name="tests_passed">Integrity checks passed!</string>
|
||||
<string name="tests_btn_passed">Continue</string>
|
||||
<string name="tests_btn_passed">Close</string>
|
||||
<string name="nativeKDF">Use native key derivation</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||
|
||||
import android.app.*;
|
||||
@@ -17,9 +16,11 @@ import android.widget.*;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.InjectView;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.google.common.util.concurrent.*;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -32,19 +33,10 @@ public class EmergencyActivity extends Activity {
|
||||
private static final ClipData EMPTY_CLIP = new ClipData( new ClipDescription( "", new String[0] ), new ClipData.Item( "" ) );
|
||||
private static final int PASSWORD_NOTIFICATION = 0;
|
||||
|
||||
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
||||
private final ValueChangedListener updateMasterKey = new ValueChangedListener() {
|
||||
@Override
|
||||
void update() {
|
||||
updateMasterKey();
|
||||
}
|
||||
};
|
||||
private final ValueChangedListener updateSitePassword = new ValueChangedListener() {
|
||||
@Override
|
||||
void update() {
|
||||
updateSitePassword();
|
||||
}
|
||||
};
|
||||
private final Preferences preferences = Preferences.get( this );
|
||||
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
||||
private final ImmutableList<MPSiteType> allSiteTypes = ImmutableList.copyOf( MPSiteType.forClass( MPSiteTypeClass.Generated ) );
|
||||
private final ImmutableList<MasterKey.Version> allVersions = ImmutableList.copyOf( MasterKey.Version.values() );
|
||||
|
||||
private ListenableFuture<MasterKey> masterKeyFuture;
|
||||
|
||||
@@ -60,14 +52,14 @@ public class EmergencyActivity extends Activity {
|
||||
@InjectView(R.id.siteNameField)
|
||||
EditText siteNameField;
|
||||
|
||||
@InjectView(R.id.siteTypeField)
|
||||
Spinner siteTypeField;
|
||||
@InjectView(R.id.siteTypeButton)
|
||||
Button siteTypeButton;
|
||||
|
||||
@InjectView(R.id.counterField)
|
||||
EditText counterField;
|
||||
Button siteCounterButton;
|
||||
|
||||
@InjectView(R.id.siteVersionField)
|
||||
Spinner siteVersionField;
|
||||
@InjectView(R.id.siteVersionButton)
|
||||
Button siteVersionButton;
|
||||
|
||||
@InjectView(R.id.sitePasswordField)
|
||||
Button sitePasswordField;
|
||||
@@ -84,8 +76,9 @@ public class EmergencyActivity extends Activity {
|
||||
@InjectView(R.id.maskPasswordField)
|
||||
CheckBox maskPasswordField;
|
||||
|
||||
private int hc_userName;
|
||||
private int hc_masterPassword;
|
||||
private int id_userName;
|
||||
private int id_masterPassword;
|
||||
private int id_version;
|
||||
private String sitePassword;
|
||||
|
||||
public static void start(Context context) {
|
||||
@@ -101,12 +94,58 @@ public class EmergencyActivity extends Activity {
|
||||
setContentView( R.layout.activity_emergency );
|
||||
ButterKnife.inject( this );
|
||||
|
||||
fullNameField.setOnFocusChangeListener( updateMasterKey );
|
||||
masterPasswordField.setOnFocusChangeListener( updateMasterKey );
|
||||
siteNameField.addTextChangedListener( updateSitePassword );
|
||||
siteTypeField.setOnItemSelectedListener( updateSitePassword );
|
||||
counterField.addTextChangedListener( updateSitePassword );
|
||||
siteVersionField.setOnItemSelectedListener( updateMasterKey );
|
||||
fullNameField.setOnFocusChangeListener( new ValueChangedListener() {
|
||||
@Override
|
||||
void update() {
|
||||
updateMasterKey();
|
||||
}
|
||||
} );
|
||||
masterPasswordField.setOnFocusChangeListener( new ValueChangedListener() {
|
||||
@Override
|
||||
void update() {
|
||||
updateMasterKey();
|
||||
}
|
||||
} );
|
||||
siteNameField.addTextChangedListener( new ValueChangedListener() {
|
||||
@Override
|
||||
void update() {
|
||||
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
|
||||
updateSitePassword();
|
||||
}
|
||||
} );
|
||||
siteTypeButton.setOnClickListener( new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
@SuppressWarnings("SuspiciousMethodCalls")
|
||||
MPSiteType siteType =
|
||||
allSiteTypes.get( (allSiteTypes.indexOf( siteTypeButton.getTag() ) + 1) % allSiteTypes.size() );
|
||||
preferences.setDefaultSiteType( siteType );
|
||||
siteTypeButton.setTag( siteType );
|
||||
siteTypeButton.setText( siteType.getShortName() );
|
||||
updateSitePassword();
|
||||
}
|
||||
} );
|
||||
siteCounterButton.setOnClickListener( new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
UnsignedInteger counter =
|
||||
UnsignedInteger.valueOf( siteCounterButton.getText().toString() ).plus( UnsignedInteger.ONE );
|
||||
siteCounterButton.setText( MessageFormat.format( "{0}", counter ) );
|
||||
updateSitePassword();
|
||||
}
|
||||
} );
|
||||
siteVersionButton.setOnClickListener( new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
@SuppressWarnings("SuspiciousMethodCalls")
|
||||
MasterKey.Version siteVersion =
|
||||
allVersions.get( (allVersions.indexOf( siteVersionButton.getTag() ) + 1) % allVersions.size() );
|
||||
preferences.setDefaultVersion( siteVersion );
|
||||
siteVersionButton.setTag( siteVersion );
|
||||
siteVersionButton.setText( siteVersion.name() );
|
||||
updateMasterKey();
|
||||
}
|
||||
} );
|
||||
sitePasswordField.addTextChangedListener( new ValueChangedListener() {
|
||||
@Override
|
||||
void update() {
|
||||
@@ -127,32 +166,26 @@ public class EmergencyActivity extends Activity {
|
||||
sitePasswordField.setTypeface( Res.sourceCodePro_Black );
|
||||
sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
|
||||
|
||||
siteTypeField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MPSiteType.forClass( MPSiteTypeClass.Generated ) ) );
|
||||
siteTypeField.setSelection( MPSiteType.GeneratedLong.ordinal() );
|
||||
|
||||
siteVersionField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MasterKey.Version.values() ) );
|
||||
siteVersionField.setSelection( MasterKey.Version.CURRENT.ordinal() );
|
||||
|
||||
rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
|
||||
getPreferences( MODE_PRIVATE ).edit().putBoolean( "rememberFullName", isChecked ).apply();
|
||||
preferences.setRememberFullName( isChecked );
|
||||
if (isChecked)
|
||||
getPreferences( MODE_PRIVATE ).edit().putString( "fullName", fullNameField.getText().toString() ).apply();
|
||||
preferences.setFullName( fullNameField.getText().toString() );
|
||||
else
|
||||
getPreferences( MODE_PRIVATE ).edit().putString( "fullName", "" ).apply();
|
||||
preferences.setFullName( null );
|
||||
}
|
||||
} );
|
||||
forgetPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
|
||||
getPreferences( MODE_PRIVATE ).edit().putBoolean( "forgetPassword", isChecked ).apply();
|
||||
preferences.setForgetPassword( isChecked );
|
||||
}
|
||||
} );
|
||||
maskPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
|
||||
getPreferences( MODE_PRIVATE ).edit().putBoolean( "maskPassword", isChecked ).apply();
|
||||
preferences.setMaskPassword( isChecked );
|
||||
sitePasswordField.setTransformationMethod( isChecked? new PasswordTransformationMethod(): null );
|
||||
}
|
||||
} );
|
||||
@@ -162,13 +195,24 @@ public class EmergencyActivity extends Activity {
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
fullNameField.setText( getPreferences( MODE_PRIVATE ).getString( "fullName", "" ) );
|
||||
rememberFullNameField.setChecked( isRememberFullNameEnabled() );
|
||||
forgetPasswordField.setChecked( isForgetPasswordEnabled() );
|
||||
maskPasswordField.setChecked( isMaskPasswordEnabled() );
|
||||
sitePasswordField.setTransformationMethod( isMaskPasswordEnabled()? new PasswordTransformationMethod(): null );
|
||||
MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
||||
|
||||
if (TextUtils.isEmpty( masterPasswordField.getText() ))
|
||||
fullNameField.setText( preferences.getFullName() );
|
||||
rememberFullNameField.setChecked( preferences.isRememberFullName() );
|
||||
forgetPasswordField.setChecked( preferences.isForgetPassword() );
|
||||
maskPasswordField.setChecked( preferences.isMaskPassword() );
|
||||
sitePasswordField.setTransformationMethod( preferences.isMaskPassword()? new PasswordTransformationMethod(): null );
|
||||
MPSiteType defaultSiteType = preferences.getDefaultSiteType();
|
||||
siteTypeButton.setTag( defaultSiteType );
|
||||
siteTypeButton.setText( defaultSiteType.getShortName() );
|
||||
MasterKey.Version defaultVersion = preferences.getDefaultVersion();
|
||||
siteVersionButton.setTag( defaultVersion );
|
||||
siteVersionButton.setText( defaultVersion.name() );
|
||||
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
|
||||
|
||||
if (TextUtils.isEmpty( fullNameField.getText() ))
|
||||
fullNameField.requestFocus();
|
||||
else if (TextUtils.isEmpty( masterPasswordField.getText() ))
|
||||
masterPasswordField.requestFocus();
|
||||
else
|
||||
siteNameField.requestFocus();
|
||||
@@ -176,9 +220,9 @@ public class EmergencyActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (isForgetPasswordEnabled()) {
|
||||
if (preferences.isForgetPassword()) {
|
||||
synchronized (this) {
|
||||
hc_userName = hc_masterPassword = 0;
|
||||
id_userName = id_masterPassword = 0;
|
||||
if (masterKeyFuture != null) {
|
||||
masterKeyFuture.cancel( true );
|
||||
masterKeyFuture = null;
|
||||
@@ -195,35 +239,20 @@ public class EmergencyActivity extends Activity {
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
private boolean isRememberFullNameEnabled() {
|
||||
return getPreferences( MODE_PRIVATE ).getBoolean( "rememberFullName", false );
|
||||
}
|
||||
|
||||
private boolean isForgetPasswordEnabled() {
|
||||
return getPreferences( MODE_PRIVATE ).getBoolean( "forgetPassword", false );
|
||||
}
|
||||
|
||||
private boolean isMaskPasswordEnabled() {
|
||||
return getPreferences( MODE_PRIVATE ).getBoolean( "maskPassword", false );
|
||||
}
|
||||
|
||||
private synchronized void updateMasterKey() {
|
||||
final String fullName = fullNameField.getText().toString();
|
||||
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
|
||||
final MasterKey.Version version = (MasterKey.Version) siteVersionField.getSelectedItem();
|
||||
try {
|
||||
if (fullName.hashCode() == hc_userName && Arrays.hashCode( masterPassword ) == hc_masterPassword &&
|
||||
masterKeyFuture != null && masterKeyFuture.get().getAlgorithmVersion() == version)
|
||||
return;
|
||||
}
|
||||
catch (InterruptedException | ExecutionException e) {
|
||||
final MasterKey.Version version = (MasterKey.Version) siteVersionButton.getTag();
|
||||
if (fullName.hashCode() == id_userName && Arrays.hashCode( masterPassword ) == id_masterPassword &&
|
||||
version.ordinal() == id_version && masterKeyFuture != null && !masterKeyFuture.isCancelled())
|
||||
return;
|
||||
}
|
||||
hc_userName = fullName.hashCode();
|
||||
hc_masterPassword = Arrays.hashCode( masterPassword );
|
||||
|
||||
if (isRememberFullNameEnabled())
|
||||
getPreferences( MODE_PRIVATE ).edit().putString( "fullName", fullName ).apply();
|
||||
id_userName = fullName.hashCode();
|
||||
id_masterPassword = Arrays.hashCode( masterPassword );
|
||||
id_version = version.ordinal();
|
||||
|
||||
if (preferences.isRememberFullName())
|
||||
preferences.setFullName( fullName );
|
||||
|
||||
if (masterKeyFuture != null)
|
||||
masterKeyFuture.cancel( true );
|
||||
@@ -243,7 +272,7 @@ public class EmergencyActivity extends Activity {
|
||||
try {
|
||||
return MasterKey.create( version, fullName, masterPassword );
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
catch (Exception e) {
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
logger.err( e, "While generating master key." );
|
||||
@@ -265,8 +294,8 @@ public class EmergencyActivity extends Activity {
|
||||
|
||||
private void updateSitePassword() {
|
||||
final String siteName = siteNameField.getText().toString();
|
||||
final MPSiteType type = (MPSiteType) siteTypeField.getSelectedItem();
|
||||
final UnsignedInteger counter = UnsignedInteger.valueOf( ifNotNullElse( counterField.getText(), "1" ).toString() );
|
||||
final MPSiteType type = (MPSiteType) siteTypeButton.getTag();
|
||||
final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() );
|
||||
|
||||
if (masterKeyFuture == null || siteName.isEmpty() || type == null) {
|
||||
sitePasswordField.setText( "" );
|
||||
@@ -313,6 +342,14 @@ public class EmergencyActivity extends Activity {
|
||||
} );
|
||||
}
|
||||
|
||||
public void integrityTests(View view) {
|
||||
if (masterKeyFuture != null) {
|
||||
masterKeyFuture.cancel( true );
|
||||
masterKeyFuture = null;
|
||||
}
|
||||
TestActivity.startNoSkip( this );
|
||||
}
|
||||
|
||||
public void copySitePassword(View view) {
|
||||
final String currentSitePassword = this.sitePassword;
|
||||
if (TextUtils.isEmpty( currentSitePassword ))
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2016-02-20
|
||||
*/
|
||||
public 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_SITE_TYPE = "siteType";
|
||||
private static final String PREF_ALGORITHM_VERSION = "algorithmVersion";
|
||||
private static Preferences instance;
|
||||
|
||||
private Context context;
|
||||
@Nullable
|
||||
private SharedPreferences prefs;
|
||||
|
||||
public static synchronized Preferences get(final Context context) {
|
||||
if (instance == null)
|
||||
instance = new Preferences( context );
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Preferences(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private SharedPreferences prefs() {
|
||||
if (prefs == null)
|
||||
prefs = (context = context.getApplicationContext()).getSharedPreferences( getClass().getCanonicalName(), Context.MODE_PRIVATE );
|
||||
|
||||
return prefs;
|
||||
}
|
||||
|
||||
public boolean setNativeKDFEnabled(boolean enabled) {
|
||||
if (isAllowNativeKDF() == enabled)
|
||||
return false;
|
||||
|
||||
prefs().edit().putBoolean( PREF_NATIVE_KDF, enabled ).apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAllowNativeKDF() {
|
||||
return prefs().getBoolean( PREF_NATIVE_KDF, MasterKey.isAllowNativeByDefault() );
|
||||
}
|
||||
|
||||
public boolean setTestsPassed(final Set<String> value) {
|
||||
if (Sets.symmetricDifference( getTestsPassed(), value ).isEmpty())
|
||||
return false;
|
||||
|
||||
prefs().edit().putStringSet( PREF_TESTS_PASSED, value ).apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
public Set<String> getTestsPassed() {
|
||||
return prefs().getStringSet( PREF_TESTS_PASSED, ImmutableSet.<String>of() );
|
||||
}
|
||||
|
||||
public boolean setRememberFullName(boolean enabled) {
|
||||
if (isRememberFullName() == enabled)
|
||||
return false;
|
||||
|
||||
prefs().edit().putBoolean( PREF_REMEMBER_FULL_NAME, enabled ).apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isRememberFullName() {
|
||||
return prefs().getBoolean( PREF_REMEMBER_FULL_NAME, false );
|
||||
}
|
||||
|
||||
public boolean setForgetPassword(boolean enabled) {
|
||||
if (isForgetPassword() == enabled)
|
||||
return false;
|
||||
|
||||
prefs().edit().putBoolean( PREF_FORGET_PASSWORD, enabled ).apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isForgetPassword() {
|
||||
return prefs().getBoolean( PREF_FORGET_PASSWORD, false );
|
||||
}
|
||||
|
||||
public boolean setMaskPassword(boolean enabled) {
|
||||
if (isMaskPassword() == enabled)
|
||||
return false;
|
||||
|
||||
prefs().edit().putBoolean( PREF_MASK_PASSWORD, enabled ).apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isMaskPassword() {
|
||||
return prefs().getBoolean( PREF_MASK_PASSWORD, false );
|
||||
}
|
||||
|
||||
public boolean setFullName(@Nullable String value) {
|
||||
if (getFullName().equals( value ))
|
||||
return false;
|
||||
|
||||
prefs().edit().putString( PREF_FULL_NAME, value ).apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getFullName() {
|
||||
return prefs().getString( PREF_FULL_NAME, "" );
|
||||
}
|
||||
|
||||
public boolean setDefaultSiteType(@Nonnull MPSiteType value) {
|
||||
if (getDefaultSiteType().equals( value ))
|
||||
return false;
|
||||
|
||||
prefs().edit().putInt( PREF_SITE_TYPE, value.ordinal() ).apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public MPSiteType getDefaultSiteType() {
|
||||
return MPSiteType.values()[prefs().getInt( PREF_SITE_TYPE, MPSiteType.GeneratedLong.ordinal() )];
|
||||
}
|
||||
|
||||
public boolean setDefaultVersion(@Nonnull MasterKey.Version value) {
|
||||
if (getDefaultVersion().equals( value ))
|
||||
return false;
|
||||
|
||||
prefs().edit().putInt( PREF_ALGORITHM_VERSION, value.ordinal() ).apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public MasterKey.Version getDefaultVersion() {
|
||||
return MasterKey.Version.values()[prefs().getInt( PREF_ALGORITHM_VERSION, MasterKey.Version.CURRENT.ordinal() )];
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,10 @@ 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.view.WindowManager;
|
||||
import android.widget.*;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.InjectView;
|
||||
@@ -13,7 +14,6 @@ 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.Set;
|
||||
import java.util.concurrent.*;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@@ -23,6 +23,7 @@ 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() );
|
||||
|
||||
@@ -38,20 +39,34 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
||||
@InjectView(R.id.actionButton)
|
||||
Button actionButton;
|
||||
|
||||
@InjectView(R.id.nativeKDFField)
|
||||
CheckBox nativeKDFField;
|
||||
|
||||
private MPTestSuite testSuite;
|
||||
private ListenableFuture<Boolean> testFuture;
|
||||
private Runnable action;
|
||||
private ImmutableSet<String> testNames;
|
||||
|
||||
public static void startNoSkip(Context context) {
|
||||
context.startActivity( new Intent( context, TestActivity.class ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate( savedInstanceState );
|
||||
Res.init( getResources() );
|
||||
|
||||
getWindow().setFlags( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE );
|
||||
setContentView( R.layout.activity_test );
|
||||
ButterKnife.inject( this );
|
||||
|
||||
nativeKDFField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
|
||||
preferences.setNativeKDFEnabled( isChecked );
|
||||
MasterKey.setAllowNativeByDefault( isChecked );
|
||||
}
|
||||
} );
|
||||
|
||||
try {
|
||||
setStatus( 0, 0, null );
|
||||
testSuite = new MPTestSuite();
|
||||
@@ -76,63 +91,54 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
|
||||
final Set<String> integrityTestsPassed = getPreferences( MODE_PRIVATE ).getStringSet( "integrityTestsPassed",
|
||||
ImmutableSet.<String>of() );
|
||||
if (!FluentIterable.from( testNames ).anyMatch( new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable final String testName) {
|
||||
return !integrityTestsPassed.contains( testName );
|
||||
}
|
||||
} )) {
|
||||
// None of the tests we need to perform were missing from the tests that have already been passed on this device.
|
||||
finish();
|
||||
EmergencyActivity.start( TestActivity.this );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (testFuture == null) {
|
||||
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() {
|
||||
getPreferences( MODE_PRIVATE ).edit().putStringSet( "integrityTestsPassed", testNames ).apply();
|
||||
finish();
|
||||
EmergencyActivity.start( TestActivity.this );
|
||||
}
|
||||
} );
|
||||
else
|
||||
setStatus( R.string.tests_failed, R.string.tests_btn_failed, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
finish();
|
||||
}
|
||||
} );
|
||||
}
|
||||
nativeKDFField.setChecked( preferences.isAllowNativeKDF() );
|
||||
|
||||
@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() {
|
||||
if (testFuture == null)
|
||||
startTestSuite();
|
||||
}
|
||||
|
||||
private void startTestSuite() {
|
||||
if (testFuture != null)
|
||||
testFuture.cancel( true );
|
||||
|
||||
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();
|
||||
}
|
||||
} );
|
||||
}
|
||||
}, mainExecutor );
|
||||
}
|
||||
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(View v) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password CLI</name>
|
||||
@@ -85,7 +85,7 @@
|
||||
<dependency>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<configuration scan="false">
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>%-8relative %22c{0} [%-5level] %msg%n</Pattern>
|
||||
</layout>
|
||||
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%-8relative %22c{0} [%-5level] %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.lyndir" level="${mp.log.level:-INFO}" />
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="stdout" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password GUI</name>
|
||||
@@ -97,6 +97,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jarsigner-plugin</artifactId>
|
||||
<version>1.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>signing</id>
|
||||
@@ -134,7 +135,7 @@
|
||||
<dependency>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-model</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EXTERNAL DEPENDENCIES -->
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<configuration scan="false">
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>%-8relative %22c{0} [%-5level] %msg%n</Pattern>
|
||||
</layout>
|
||||
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%-8relative %22c{0} [%-5level] %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.lyndir" level="${mp.log.level:-INFO}" />
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="stdout" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password Site Model</name>
|
||||
@@ -23,7 +23,7 @@
|
||||
<dependency>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EXTERNAL DEPENDENCIES -->
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password Test Suite</name>
|
||||
@@ -23,7 +23,7 @@
|
||||
<dependency>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
</dependency>
|
||||
|
||||
<!-- TESTING -->
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<configuration scan="false">
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>%-8relative %22c{0} [%-5level] %msg%n</Pattern>
|
||||
</layout>
|
||||
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%-8relative %22c{0} [%-5level] %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.lyndir.masterpassword" level="${mp.log.level:-TRACE}" />
|
||||
<logger name="com.lyndir" level="${mp.log.level:-INFO}" />
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="stdout" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>2.4-java</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
@@ -58,4 +58,8 @@
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<scm>
|
||||
<tag>2.4-java</tag>
|
||||
</scm>
|
||||
</project>
|
||||
|
||||
@@ -22,6 +22,13 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface MPSiteQuestionEntity(MP)
|
||||
|
||||
- (NSString *)resolveQuestionAnswerUsingKey:(MPKey *)key;
|
||||
- (void)resolveQuestionAnswerUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result;
|
||||
|
||||
@end
|
||||
|
||||
@interface MPSiteEntity(MP)<MPFixable>
|
||||
|
||||
@property(assign) BOOL loginGenerated;
|
||||
@@ -38,8 +45,10 @@
|
||||
- (BOOL)tryMigrateExplicitly:(BOOL)explicit;
|
||||
- (NSString *)resolveLoginUsingKey:(MPKey *)key;
|
||||
- (NSString *)resolvePasswordUsingKey:(MPKey *)key;
|
||||
- (NSString *)resolveSiteAnswerUsingKey:(MPKey *)key;
|
||||
- (void)resolveLoginUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result;
|
||||
- (void)resolvePasswordUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result;
|
||||
- (void)resolveSiteAnswerUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -35,6 +35,20 @@
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPSiteQuestionEntity(MP)
|
||||
|
||||
- (NSString *)resolveQuestionAnswerUsingKey:(MPKey *)key {
|
||||
|
||||
return [self.site.algorithm resolveAnswerForQuestion:self usingKey:key];
|
||||
}
|
||||
|
||||
- (void)resolveQuestionAnswerUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result {
|
||||
|
||||
[self.site.algorithm resolveAnswerForQuestion:self usingKey:key result:result];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPSiteEntity(MP)
|
||||
|
||||
- (MPFixableResult)findAndFixInconsistenciesInContext:(NSManagedObjectContext *)context {
|
||||
@@ -175,6 +189,11 @@
|
||||
return [self.algorithm resolvePasswordForSite:self usingKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)resolveSiteAnswerUsingKey:(MPKey *)key {
|
||||
|
||||
return [self.algorithm resolveAnswerForSite:self usingKey:key];
|
||||
}
|
||||
|
||||
- (void)resolveLoginUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result {
|
||||
|
||||
[self.algorithm resolveLoginForSite:self usingKey:key result:result];
|
||||
@@ -185,6 +204,11 @@
|
||||
[self.algorithm resolvePasswordForSite:self usingKey:key result:result];
|
||||
}
|
||||
|
||||
- (void)resolveSiteAnswerUsingKey:(MPKey *)key result:(void ( ^ )(NSString *))result {
|
||||
|
||||
[self.algorithm resolveAnswerForSite:self usingKey:key result:result];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPGeneratedSiteEntity(MP)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15D21" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="7706"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
|
||||
<capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
@property(nonatomic) NSString *masterPassword;
|
||||
@property(nonatomic) BOOL showVersionContainer;
|
||||
@property(nonatomic) BOOL alternatePressed;
|
||||
@property(nonatomic) BOOL shiftPressed;
|
||||
@property(nonatomic) BOOL locked;
|
||||
@property(nonatomic) BOOL newUser;
|
||||
|
||||
|
||||
@@ -124,6 +124,10 @@
|
||||
|
||||
- (void)flagsChanged:(NSEvent *)theEvent {
|
||||
|
||||
BOOL shiftPressed = (theEvent.modifierFlags & NSShiftKeyMask) != 0;
|
||||
if (shiftPressed != self.shiftPressed)
|
||||
self.shiftPressed = shiftPressed;
|
||||
|
||||
BOOL alternatePressed = (theEvent.modifierFlags & NSAlternateKeyMask) != 0;
|
||||
if (alternatePressed != self.alternatePressed) {
|
||||
self.alternatePressed = alternatePressed;
|
||||
@@ -486,7 +490,7 @@
|
||||
}
|
||||
|
||||
// Performing action while content is available. Copy it.
|
||||
[self copyContent:selectedSite.content];
|
||||
[self copyContent:self.shiftPressed? selectedSite.answer: selectedSite.content];
|
||||
|
||||
[self fadeOut];
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9059" systemVersion="15B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15D21" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9059"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
|
||||
<capability name="box content view" minToolsVersion="7.0"/>
|
||||
<capability name="stacking Non-gravity area distributions on NSStackView" minToolsVersion="7.0" minSystemVersion="10.11"/>
|
||||
</dependencies>
|
||||
@@ -28,10 +28,10 @@
|
||||
<window title="Master Password" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hasShadow="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MPPasswordWindow">
|
||||
<windowCollectionBehavior key="collectionBehavior" moveToActiveSpace="YES" transient="YES" ignoresCycle="YES" fullScreenAuxiliary="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="640" height="560"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="900"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
|
||||
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ" userLabel="Root">
|
||||
<rect key="frame" x="0.0" y="0.0" width="640" height="560"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Bwc-sd-6gm" userLabel="Screen Capture">
|
||||
<rect key="frame" x="-80" y="-80" width="800" height="720"/>
|
||||
@@ -55,19 +55,16 @@
|
||||
</configuration>
|
||||
</ciFilter>
|
||||
</contentFilters>
|
||||
<animations/>
|
||||
<imageCell key="cell" enabled="NO" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="small-screen" id="ArA-2w-I56"/>
|
||||
</imageView>
|
||||
<progressIndicator hidden="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" maxValue="100" displayedWhenStopped="NO" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="oSh-Ec-8Nf" userLabel="Progress Spinner">
|
||||
<rect key="frame" x="312" y="524" width="16" height="16"/>
|
||||
<animations/>
|
||||
</progressIndicator>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="Aue-Zx-6Mf" userLabel="Settings Gear">
|
||||
<rect key="frame" x="588" y="508" width="32" height="32"/>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="icon_gear" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="i8r-9N-vcQ">
|
||||
<rect key="frame" x="585" y="496" width="35" height="44"/>
|
||||
<buttonCell key="cell" type="square" title="⚙" bezelStyle="shadowlessSquare" alignment="center" imageScaling="proportionallyDown" inset="2" id="i8r-9N-vcQ">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<font key="font" size="48" name="AppleSymbols"/>
|
||||
<string key="keyEquivalent">,</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</buttonCell>
|
||||
@@ -76,12 +73,11 @@
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gAU-xs-aae">
|
||||
<rect key="frame" x="595" y="490" width="19" height="14"/>
|
||||
<rect key="frame" x="593" y="478" width="19" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘," id="Xm1-qb-6EP">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -101,7 +97,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" focusRingType="none" alignment="center" usesSingleLineMode="YES" id="NcX-1Z-2OC">
|
||||
<font key="font" metaFont="system" size="36"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -137,7 +132,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" focusRingType="none" alignment="center" placeholderString="" usesSingleLineMode="YES" id="gRw-5C-YUN">
|
||||
<font key="font" metaFont="system" size="36"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -173,7 +167,6 @@
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="R46-fx-n14">
|
||||
<rect key="frame" x="232" y="19" width="177" height="19"/>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="recessed" title="Reset My Master Password" bezelStyle="recessed" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="B7Z-72-fVP" customClass="MPNoStateButtonCell">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
|
||||
<font key="font" metaFont="systemBold" size="12"/>
|
||||
@@ -193,7 +186,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="0.70000000000000007" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Hold alt ⌥ to temporarily reveal what you've typed." id="4Ep-xX-Ky8">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -225,7 +217,6 @@
|
||||
</configuration>
|
||||
</ciFilter>
|
||||
</contentFilters>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="KeljXoleKowi9@" placeholderString="" id="WVV-EE-tkB">
|
||||
<font key="font" size="64" name="SourceCodePro-Regular"/>
|
||||
<color key="textColor" name="keyboardFocusIndicatorColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -240,19 +231,77 @@
|
||||
<binding destination="mcS-ik-b0n" name="value" keyPath="selection.displayedContent" id="Sdg-fb-kQK"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ond-dT-x5d" userLabel="Site Password Tip">
|
||||
<rect key="frame" x="220" y="146" width="160" height="14"/>
|
||||
<searchField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="eBx-2g-chS" userLabel="Site Question">
|
||||
<rect key="frame" x="42" y="33" width="516" height="14"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="512" id="JSe-85-4H0"/>
|
||||
</constraints>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" red="0.0" green="0.0" blue="0.0" alpha="0.80000000000000004" colorSpace="calibratedRGB"/>
|
||||
</shadow>
|
||||
<searchFieldCell key="cell" controlSize="small" selectable="YES" editable="YES" focusRingType="none" alignment="center" placeholderString="Question Keyword" sendsSearchStringImmediately="YES" id="sZN-Vi-v8k">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</searchFieldCell>
|
||||
<connections>
|
||||
<action selector="doSearchSites:" target="-2" id="72O-59-xYV"/>
|
||||
<binding destination="mcS-ik-b0n" name="hidden" keyPath="canRemove" id="Skr-1g-quT">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
<binding destination="mcS-ik-b0n" name="value" keyPath="selection.question" id="3AM-pr-HBA"/>
|
||||
<outlet property="delegate" destination="-2" id="c5n-ve-3Uw"/>
|
||||
</connections>
|
||||
</searchField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cp4-2G-8aG" userLabel="Site Answer">
|
||||
<rect key="frame" x="189" y="12" width="221" height="29"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<contentFilters>
|
||||
<ciFilter name="CIGloom">
|
||||
<configuration>
|
||||
<null key="inputImage"/>
|
||||
<real key="inputIntensity" value="0.80000000000000004"/>
|
||||
<real key="inputRadius" value="8"/>
|
||||
</configuration>
|
||||
</ciFilter>
|
||||
</contentFilters>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="fewc fom pugsuhe xav" placeholderString="" id="oYj-IR-xmw">
|
||||
<font key="font" size="18" name="SourceCodePro-Regular"/>
|
||||
<color key="textColor" name="keyboardFocusIndicatorColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="mcS-ik-b0n" name="hidden" keyPath="canRemove" id="TxZ-TU-RMn">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
<binding destination="mcS-ik-b0n" name="value" keyPath="selection.answer" id="Ba7-t3-euS"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ond-dT-x5d" userLabel="Site Password Tip">
|
||||
<rect key="frame" x="220" y="138" width="160" height="14"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Your password for apple.com:" id="CgJ-XZ-6Hy">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="mcS-ik-b0n" name="hidden" keyPath="canRemove" id="Jvv-jZ-PG1">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
<binding destination="mcS-ik-b0n" name="hidden2" keyPath="selection.content.length" previousBinding="Jvv-jZ-PG1" id="OXN-Zm-1ra">
|
||||
<dictionary key="options">
|
||||
<integer key="NSMultipleValuesPlaceholder" value="-1"/>
|
||||
@@ -262,11 +311,6 @@
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
<binding destination="mcS-ik-b0n" name="hidden" keyPath="canRemove" id="Jvv-jZ-PG1">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ia6-7b-dFr">
|
||||
@@ -275,7 +319,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="No password set. Click "Change Password" on the bottom to set one." id="eDQ-iz-97a">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -312,7 +355,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Master Password generates passwords for your sites (and other things)." id="YyD-hd-wi3">
|
||||
<font key="font" size="16" name="HelveticaNeue"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -341,7 +383,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" id="9c4-NI-NM0">
|
||||
<font key="font" size="12" name="HelveticaNeue"/>
|
||||
<string key="title">— When you create a new account, use the password Master Password gives you for it.
|
||||
@@ -373,16 +414,19 @@
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerY" secondItem="XUV-zU-Y9c" secondAttribute="centerY" id="6Qf-5O-Cvk"/>
|
||||
<constraint firstAttribute="centerX" secondItem="XUV-zU-Y9c" secondAttribute="centerX" id="7sl-qi-HY9"/>
|
||||
<constraint firstItem="cp4-2G-8aG" firstAttribute="centerX" secondItem="XUV-zU-Y9c" secondAttribute="centerX" id="Dx0-IB-hUM"/>
|
||||
<constraint firstItem="Ia6-7b-dFr" firstAttribute="centerY" secondItem="XUV-zU-Y9c" secondAttribute="centerY" id="KqM-uR-Obm"/>
|
||||
<constraint firstItem="Ia6-7b-dFr" firstAttribute="centerX" secondItem="XUV-zU-Y9c" secondAttribute="centerX" id="NFQ-aw-8tm"/>
|
||||
<constraint firstAttribute="centerX" secondItem="sYt-eL-uwt" secondAttribute="centerX" id="OFw-vb-I71"/>
|
||||
<constraint firstItem="XUV-zU-Y9c" firstAttribute="top" secondItem="Ond-dT-x5d" secondAttribute="bottom" constant="8" symbolic="YES" id="UgV-J6-B5T"/>
|
||||
<constraint firstItem="cp4-2G-8aG" firstAttribute="top" secondItem="XUV-zU-Y9c" secondAttribute="bottom" id="T6W-P9-0vj"/>
|
||||
<constraint firstItem="XUV-zU-Y9c" firstAttribute="top" secondItem="Ond-dT-x5d" secondAttribute="bottom" id="UgV-J6-B5T"/>
|
||||
<constraint firstItem="Ond-dT-x5d" firstAttribute="centerX" secondItem="XUV-zU-Y9c" secondAttribute="centerX" id="UhT-LQ-aZ8"/>
|
||||
<constraint firstItem="eBx-2g-chS" firstAttribute="centerX" secondItem="cp4-2G-8aG" secondAttribute="centerX" id="cHz-Q1-8ii"/>
|
||||
<constraint firstItem="sYt-eL-uwt" firstAttribute="top" secondItem="OaQ-of-zmb" secondAttribute="bottom" constant="8" symbolic="YES" id="hjJ-f1-mFv"/>
|
||||
<constraint firstItem="cp4-2G-8aG" firstAttribute="top" secondItem="eBx-2g-chS" secondAttribute="bottom" constant="-8" id="inf-AC-ger"/>
|
||||
<constraint firstItem="sYt-eL-uwt" firstAttribute="centerX" secondItem="OaQ-of-zmb" secondAttribute="centerX" id="mu2-se-Mtn"/>
|
||||
<constraint firstAttribute="centerY" secondItem="sYt-eL-uwt" secondAttribute="centerY" id="zLS-QG-MKS"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
</customView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OnR-s6-d4P" userLabel="Site Name Label">
|
||||
<rect key="frame" x="209" y="310" width="223" height="20"/>
|
||||
@@ -390,7 +434,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" red="0.0" green="0.0" blue="0.0" alpha="0.80000000000000004" colorSpace="calibratedRGB"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Maarten Billemont's password for:" id="1Lb-d0-fQD">
|
||||
<font key="font" size="14" name="HelveticaNeue"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -406,7 +449,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" red="0.0" green="0.0" blue="0.0" alpha="0.80000000000000004" colorSpace="calibratedRGB"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<searchFieldCell key="cell" selectable="YES" editable="YES" focusRingType="none" alignment="center" placeholderString="Site Name" sendsSearchStringImmediately="YES" id="ppl-2c-1E9">
|
||||
<font key="font" size="36" name="HelveticaNeue-Thin"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -424,7 +466,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="0.69999999999999996" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Type the name of your site (eg. apple.com), then hit enter ⏎ to create a password for it." id="QTI-cz-Onx">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -443,14 +484,15 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="rhm-sC-xFS" userLabel="Site Name Tip">
|
||||
<rect key="frame" x="37" y="235" width="566" height="15"/>
|
||||
<rect key="frame" x="150" y="220" width="340" height="30"/>
|
||||
<shadow key="shadow" blurRadius="0.5">
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="0.80000000000000004" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Hit enter ⏎ to copy the password, then paste it using ⌘V. Use the arrows ⇅ to navigate the list or esc ⎋ to exit." id="n3W-XU-dya">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" id="n3W-XU-dya">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<string key="title">Hit enter ⏎ to copy the password, hold shift ⇧ to copy the answer.
|
||||
Use the arrows ⇅ to navigate the list or esc ⎋ to exit.</string>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@@ -468,15 +510,14 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<scrollView focusRingType="none" borderType="none" autohidesScrollers="YES" horizontalLineScroll="35" horizontalPageScroll="10" verticalLineScroll="35" verticalPageScroll="10" hasHorizontalScroller="NO" hasVerticalScroller="NO" horizontalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="Bme-XK-MMc" userLabel="Sites Table">
|
||||
<rect key="frame" x="64" y="80" width="512" height="147"/>
|
||||
<rect key="frame" x="64" y="80" width="512" height="132"/>
|
||||
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="e11-59-xSS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="147"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="132"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="33" rowSizeStyle="automatic" viewBased="YES" floatsGroupRows="NO" id="xvJ-5c-vDp" customClass="MPSitesTableView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="0.0"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="132"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" white="1" alpha="0.0" colorSpace="deviceWhite"/>
|
||||
<color key="gridColor" name="selectedControlColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -504,7 +545,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="0.80000000000000004" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" alignment="center" title="apple.com" id="o0g-Zv-pH4">
|
||||
<font key="font" size="24" name="HelveticaNeue-Thin"/>
|
||||
<color key="textColor" name="alternateSelectedControlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -533,7 +573,6 @@
|
||||
</configuration>
|
||||
</ciFilter>
|
||||
</backgroundFilters>
|
||||
<animations/>
|
||||
<connections>
|
||||
<outlet property="textField" destination="ydd-Rv-tra" id="lMV-D4-Ilq"/>
|
||||
</connections>
|
||||
@@ -549,21 +588,17 @@
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="calibratedRGB"/>
|
||||
</clipView>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="512" id="qfu-pO-SvM"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="8wr-pu-1lc">
|
||||
<rect key="frame" x="-100" y="-100" width="512" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="mcf-ST-XXI">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</scroller>
|
||||
<connections>
|
||||
<binding destination="-2" name="hidden" keyPath="locked" id="FF1-c9-zmm"/>
|
||||
@@ -571,7 +606,6 @@
|
||||
</scrollView>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="brI-fg-Kav">
|
||||
<rect key="frame" x="260" y="45" width="122" height="19"/>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="recessed" title="Change Password" bezelStyle="recessed" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="FQu-fM-NWY" customClass="MPNoStateButtonCell">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
|
||||
<font key="font" metaFont="systemBold" size="12"/>
|
||||
@@ -602,7 +636,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘P" id="MyN-x6-dMk">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -640,7 +673,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Click to set a password:" id="gjc-Fw-xa1">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -678,7 +710,6 @@
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="vES-W5-m4x">
|
||||
<rect key="frame" x="243" y="19" width="155" height="19"/>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="recessed" title="Change Password Type" bezelStyle="recessed" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Fom-sN-EtZ" customClass="MPNoStateButtonCell">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
|
||||
<font key="font" metaFont="systemBold" size="12"/>
|
||||
@@ -700,7 +731,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘T" id="HFM-Bk-akx">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -725,7 +755,6 @@
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="XuF-Sp-6JD">
|
||||
<rect key="frame" x="406" y="19" width="80" height="19"/>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="recessed" title="Delete Site" bezelStyle="recessed" alignment="center" refusesFirstResponder="YES" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="26m-of-YMQ" customClass="MPNoStateButtonCell">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
|
||||
<font key="font" metaFont="systemBold" size="12"/>
|
||||
@@ -747,7 +776,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘D" id="PPC-be-w4E">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -772,7 +800,6 @@
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1Qo-iG-CQt">
|
||||
<rect key="frame" x="126" y="19" width="109" height="19"/>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="recessed" title="Set Login Name" bezelStyle="recessed" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="QFo-9y-aVe" customClass="MPNoStateButtonCell">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
|
||||
<font key="font" metaFont="systemBold" size="12"/>
|
||||
@@ -799,7 +826,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="⌘L" id="fUB-rF-7x8">
|
||||
<font key="font" size="11" name="HelveticaNeue"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -828,7 +854,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Upgrade your site's algorithm version for maximum protection:" id="3ds-qG-YNd">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -856,7 +881,6 @@
|
||||
<subviews>
|
||||
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mcq-qD-yte">
|
||||
<rect key="frame" x="-3" y="-3" width="19" height="27"/>
|
||||
<animations/>
|
||||
<stepperCell key="cell" continuous="YES" alignment="left" minValue="1" maxValue="1000" doubleValue="1" id="73y-03-zHt"/>
|
||||
<connections>
|
||||
<binding destination="mcS-ik-b0n" name="value" keyPath="selection.algorithmVersion" id="GyA-hK-6cD"/>
|
||||
@@ -868,7 +892,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="V1" id="Pjy-Fm-zwB">
|
||||
<font key="font" size="12" name="HelveticaNeue-Medium"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -879,7 +902,6 @@
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<visibilityPriorities>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
@@ -901,7 +923,6 @@
|
||||
<subviews>
|
||||
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="XgA-Vl-CKh" userLabel="Counter Stepper">
|
||||
<rect key="frame" x="-3" y="-3" width="19" height="27"/>
|
||||
<animations/>
|
||||
<stepperCell key="cell" continuous="YES" alignment="left" minValue="1" maxValue="1000" doubleValue="1" id="ikF-n4-xiI"/>
|
||||
<connections>
|
||||
<binding destination="mcS-ik-b0n" name="value" keyPath="selection.counter" id="qmm-6z-boy"/>
|
||||
@@ -913,7 +934,6 @@
|
||||
<size key="offset" width="0.0" height="1"/>
|
||||
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</shadow>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="1" id="dhQ-bJ-rn3">
|
||||
<font key="font" size="12" name="HelveticaNeue-Medium"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -924,7 +944,6 @@
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<visibilityPriorities>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
@@ -934,6 +953,11 @@
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
<connections>
|
||||
<binding destination="mcS-ik-b0n" name="hidden" keyPath="canRemove" id="9vk-TH-Bm2">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
<binding destination="mcS-ik-b0n" name="hidden2" keyPath="selection.generated" previousBinding="9vk-TH-Bm2" id="B6u-H8-b9o">
|
||||
<dictionary key="options">
|
||||
<integer key="NSMultipleValuesPlaceholder" value="-1"/>
|
||||
@@ -943,11 +967,6 @@
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
<binding destination="mcS-ik-b0n" name="hidden" keyPath="canRemove" id="9vk-TH-Bm2">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">NSNegateBoolean</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</stackView>
|
||||
</subviews>
|
||||
@@ -1014,7 +1033,6 @@
|
||||
<constraint firstItem="gAU-xs-aae" firstAttribute="centerX" secondItem="Aue-Zx-6Mf" secondAttribute="centerX" id="yxU-bl-dmQ"/>
|
||||
<constraint firstItem="npC-Kk-gUM" firstAttribute="top" secondItem="CnS-iI-dhr" secondAttribute="bottom" constant="8" symbolic="YES" id="zs0-eA-5MW"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
</view>
|
||||
<point key="canvasLocation" x="-267" y="279"/>
|
||||
</window>
|
||||
@@ -1024,16 +1042,15 @@
|
||||
<binding destination="-2" name="contentArray" keyPath="sites" id="c96-Dv-HK1"/>
|
||||
</connections>
|
||||
</arrayController>
|
||||
<box autoresizesSubviews="NO" misplaced="YES" title="Password Types" borderType="line" titlePosition="noTitle" id="bZe-7q-i6q">
|
||||
<box autoresizesSubviews="NO" title="Password Types" borderType="line" titlePosition="noTitle" id="bZe-7q-i6q">
|
||||
<rect key="frame" x="0.0" y="0.0" width="416" height="250"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<view key="contentView" id="hAc-y9-IMT">
|
||||
<rect key="frame" x="1" y="1" width="414" height="248"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<matrix verticalHuggingPriority="750" misplaced="YES" allowsEmptySelection="NO" autorecalculatesCellSize="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3fr-Fd-pxx">
|
||||
<matrix verticalHuggingPriority="750" allowsEmptySelection="NO" autorecalculatesCellSize="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3fr-Fd-pxx">
|
||||
<rect key="frame" x="18" y="78" width="378" height="158"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
<size key="cellSize" width="179" height="18"/>
|
||||
<size key="intercellSpacing" width="4" height="2"/>
|
||||
@@ -1078,9 +1095,8 @@
|
||||
</column>
|
||||
</cells>
|
||||
</matrix>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kCO-1M-Wz1">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kCO-1M-Wz1">
|
||||
<rect key="frame" x="16" y="14" width="382" height="56"/>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" id="kl0-P1-6ZY">
|
||||
<font key="font" metaFont="toolTip"/>
|
||||
<string key="title">"Personal password" allows you to store your own password. It cannot be regenerated in the event of loss. "Device private password" is similar but will never leave your device: it cannot be synced, backed up or exported.</string>
|
||||
@@ -1089,7 +1105,6 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<animations/>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstItem="kCO-1M-Wz1" firstAttribute="top" secondItem="3fr-Fd-pxx" secondAttribute="bottom" constant="8" symbolic="YES" id="GSx-ci-oqR"/>
|
||||
@@ -1100,13 +1115,12 @@
|
||||
<constraint firstItem="3fr-Fd-pxx" firstAttribute="leading" secondItem="bZe-7q-i6q" secondAttribute="leading" constant="16" id="w0i-lL-lPE"/>
|
||||
<constraint firstItem="kCO-1M-Wz1" firstAttribute="leading" secondItem="bZe-7q-i6q" secondAttribute="leading" constant="16" id="wBb-UE-BfN"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="message" size="11"/>
|
||||
</box>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="icon_gear" width="32" height="32"/>
|
||||
<image name="small-screen" width="25" height="15.5"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
@property (nonatomic) NSString *typeName;
|
||||
@property (nonatomic) NSString *content;
|
||||
@property (nonatomic) NSString *displayedContent;
|
||||
@property (nonatomic) NSString *question;
|
||||
@property (nonatomic) NSString *answer;
|
||||
@property (nonatomic) NSString *loginName;
|
||||
@property (nonatomic) NSNumber *uses;
|
||||
@property (nonatomic) NSUInteger counter;
|
||||
|
||||
@@ -194,13 +194,18 @@
|
||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
[self updateContent:[MPSiteEntity existingObjectWithID:_entityOID inContext:context]];
|
||||
}];
|
||||
|
||||
else
|
||||
PearlNotMainQueue( ^{
|
||||
NSString *password = [self.algorithm generatePasswordForSiteNamed:self.name ofType:self.type withCounter:self.counter
|
||||
usingKey:[MPAppDelegate_Shared get].key];
|
||||
NSString *loginName = [self.algorithm generateLoginForSiteNamed:self.name usingKey:[MPAppDelegate_Shared get].key];
|
||||
[self updatePasswordWithResult:password];
|
||||
[self updateLoginNameWithResult:loginName];
|
||||
[self updatePasswordWithResult:
|
||||
[self.algorithm generatePasswordForSiteNamed:self.name ofType:self.type withCounter:self.counter
|
||||
usingKey:[MPAppDelegate_Shared get].key]];
|
||||
[self updateLoginNameWithResult:
|
||||
[self.algorithm generateLoginForSiteNamed:self.name
|
||||
usingKey:[MPAppDelegate_Shared get].key]];
|
||||
[self updateAnswerWithResult:
|
||||
[self.algorithm generateAnswerForSiteNamed:self.name onQuestion:self.question
|
||||
usingKey:[MPAppDelegate_Shared get].key]];
|
||||
} );
|
||||
}
|
||||
|
||||
@@ -212,6 +217,9 @@
|
||||
[entity resolveLoginUsingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) {
|
||||
[self updateLoginNameWithResult:result];
|
||||
}];
|
||||
[entity resolveSiteAnswerUsingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) {
|
||||
[self updateAnswerWithResult:result];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updatePasswordWithResult:(NSString *)result {
|
||||
@@ -239,4 +247,11 @@
|
||||
} );
|
||||
}
|
||||
|
||||
- (void)updateAnswerWithResult:(NSString *)answer {
|
||||
|
||||
PearlMainQueue( ^{
|
||||
self.answer = answer;
|
||||
} );
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
else if ([cell isKindOfClass:[MPSendAnswersCell class]]) {
|
||||
NSString *body;
|
||||
if (!_multiple) {
|
||||
NSObject *answer = [site.algorithm resolveAnswerForSite:site usingKey:[MPiOSAppDelegate get].key];
|
||||
NSObject *answer = [site resolveSiteAnswerUsingKey:[MPiOSAppDelegate get].key];
|
||||
body = strf( @"Master Password generated the following security answer for your site: %@\n\n"
|
||||
@"%@\n"
|
||||
@"\n\nYou should use this as the answer to each security question the site asks you.\n"
|
||||
@@ -188,7 +188,7 @@
|
||||
NSMutableString *bodyBuilder = [NSMutableString string];
|
||||
[bodyBuilder appendFormat:@"Master Password generated the following security answers for your site: %@\n\n", site.name];
|
||||
for (MPSiteQuestionEntity *question in site.questions) {
|
||||
NSObject *answer = [site.algorithm resolveAnswerForQuestion:question usingKey:[MPiOSAppDelegate get].key];
|
||||
NSObject *answer = [question resolveQuestionAnswerUsingKey:[MPiOSAppDelegate get].key];
|
||||
[bodyBuilder appendFormat:@"For question: '%@', use answer: %@\n", question.keyword, answer];
|
||||
}
|
||||
[bodyBuilder appendFormat:@"\n\nUse the answer for the matching security question.\n"
|
||||
@@ -241,7 +241,7 @@
|
||||
|
||||
self.titleLabel.text = strl( @"Answer for %@:", site.name );
|
||||
self.answerField.text = @"...";
|
||||
[site.algorithm resolveAnswerForSite:site usingKey:[MPiOSAppDelegate get].key result:^(NSString *result) {
|
||||
[site resolveSiteAnswerUsingKey:[MPiOSAppDelegate get].key result:^(NSString *result) {
|
||||
PearlMainQueue( ^{
|
||||
self.answerField.text = result;
|
||||
} );
|
||||
@@ -330,7 +330,7 @@
|
||||
PearlMainQueue( ^{
|
||||
self.answerField.text = @"...";
|
||||
} );
|
||||
[site.algorithm resolveAnswerForQuestion:question usingKey:[MPiOSAppDelegate get].key result:^(NSString *result) {
|
||||
[question resolveQuestionAnswerUsingKey:[MPiOSAppDelegate get].key result:^(NSString *result) {
|
||||
PearlMainQueue( ^{
|
||||
self.questionField.text = keyword;
|
||||
self.answerField.text = result;
|
||||
|
||||
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 585 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 294 KiB After Width: | Height: | Size: 211 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 764 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 400 KiB After Width: | Height: | Size: 277 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 906 B After Width: | Height: | Size: 887 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 965 B |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 254 KiB After Width: | Height: | Size: 211 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 341 KiB After Width: | Height: | Size: 341 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |