diff --git a/core/c/mpw-marshal-util.c b/core/c/mpw-marshal-util.c
index 9bd0e66b..17cba9f1 100644
--- a/core/c/mpw-marshal-util.c
+++ b/core/c/mpw-marshal-util.c
@@ -38,6 +38,7 @@ char *mpw_get_token(const char **in, const char *eol, char *delim) {
time_t mpw_mktime(
const char *time) {
+ // TODO: Support parsing timezone into tm_gmtoff
struct tm tm = { .tm_isdst = -1 };
if (time && sscanf( time, "%4d-%2d-%2dT%2d:%2d:%2dZ",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java
index bf43c6e5..add7732a 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java
@@ -59,7 +59,12 @@ public abstract class MPAlgorithm {
/**
* mpw: defaults: password result type.
*/
- public abstract MPResultType mpw_default_type();
+ public abstract MPResultType mpw_default_password_type();
+
+ /**
+ * mpw: defaults: login result type.
+ */
+ public abstract MPResultType mpw_default_login_type();
/**
* mpw: defaults: initial counter value.
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java
index c0cf5106..1ae201d7 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java
@@ -83,8 +83,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
}
@Override
- public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
- @Nullable final String keyContext) {
+ public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter,
+ final MPKeyPurpose keyPurpose, @Nullable final String keyContext) {
String keyScope = keyPurpose.getScope();
logger.trc( "keyScope: %s", keyScope );
@@ -117,8 +117,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
@Override
public String siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
- final MPKeyPurpose keyPurpose,
- @Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
+ final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
+ final MPResultType resultType, @Nullable final String resultParam) {
switch (resultType.getTypeClass()) {
case Template:
@@ -133,8 +133,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
}
@Override
- public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
- @Nullable final String resultParam) {
+ public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey,
+ final MPResultType resultType, @Nullable final String resultParam) {
int[] _siteKey = new int[siteKey.length];
for (int i = 0; i < siteKey.length; ++i) {
@@ -168,8 +168,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
}
@Override
- public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
- @Nullable final String resultParam) {
+ public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey,
+ final MPResultType resultType, @Nullable final String resultParam) {
Preconditions.checkNotNull( resultParam );
Preconditions.checkArgument( !resultParam.isEmpty() );
@@ -192,8 +192,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
}
@Override
- public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
- @Nullable final String resultParam) {
+ public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey,
+ final MPResultType resultType, @Nullable final String resultParam) {
if (resultType == MPResultType.DeriveKey) {
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
@@ -220,8 +220,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
@Override
public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
- final MPKeyPurpose keyPurpose,
- @Nullable final String keyContext, final MPResultType resultType, final String resultParam) {
+ final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
+ final MPResultType resultType, final String resultParam) {
try {
// Encrypt
@@ -246,111 +246,77 @@ public class MPAlgorithmV0 extends MPAlgorithm {
return MPMasterKey.Version.V0;
}
- /**
- * mpw: defaults: password result type.
- */
@Override
- public MPResultType mpw_default_type() {
+ public MPResultType mpw_default_password_type() {
return MPResultType.GeneratedLong;
}
- /**
- * mpw: defaults: initial counter value.
- */
+ @Override
+ public MPResultType mpw_default_login_type() {
+ return MPResultType.GeneratedName;
+ }
+
@Override
public UnsignedInteger mpw_default_counter() {
return UnsignedInteger.ONE;
}
- /**
- * mpw: validity for the time-based rolling counter.
- */
@Override
@SuppressWarnings("MagicNumber")
public long mpw_otp_window() {
return 5 * 60 /* s */;
}
- /**
- * mpw: Key ID hash.
- */
@Override
public MessageDigests mpw_hash() {
return MessageDigests.SHA256;
}
- /**
- * mpw: Site digest.
- */
@Override
public MessageAuthenticationDigests mpw_digest() {
return MessageAuthenticationDigests.HmacSHA256;
}
- /**
- * mpw: Platform-agnostic byte order.
- */
@Override
public ByteOrder mpw_byteOrder() {
return ByteOrder.BIG_ENDIAN;
}
- /**
- * mpw: Input character encoding.
- */
@Override
public Charset mpw_charset() {
return Charsets.UTF_8;
}
- /**
- * mpw: Master key size (byte).
- */
@Override
@SuppressWarnings("MagicNumber")
public int mpw_dkLen() {
return 64;
}
- /**
- * mpw: Minimum size for derived keys (bit).
- */
@Override
@SuppressWarnings("MagicNumber")
public int mpw_keySize_min() {
return 128;
}
- /**
- * mpw: Maximum size for derived keys (bit).
- */
@Override
@SuppressWarnings("MagicNumber")
public int mpw_keySize_max() {
return 512;
}
- /**
- * scrypt: Parallelization parameter.
- */
@Override
@SuppressWarnings("MagicNumber")
public int scrypt_p() {
return 2;
}
- /**
- * scrypt: Memory cost parameter.
- */
@Override
@SuppressWarnings("MagicNumber")
public int scrypt_r() {
return 8;
}
- /**
- * scrypt: CPU cost parameter.
- */
@Override
@SuppressWarnings("MagicNumber")
public int scrypt_N() {
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPConstant.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPConstant.java
index b4d3cc9b..e0a15cec 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPConstant.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPConstant.java
@@ -42,5 +42,5 @@ public final class MPConstant {
public static final int MS_PER_S = 1000;
- public static final DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis();
+ public static final DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis().withZoneUTC();
}
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPInvalidatedException.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPInvalidatedException.java
deleted file mode 100644
index 53802f37..00000000
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPInvalidatedException.java
+++ /dev/null
@@ -1,25 +0,0 @@
-//==============================================================================
-// This file is part of Master Password.
-// Copyright (c) 2011-2017, Maarten Billemont.
-//
-// Master Password is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Master Password is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You can find a copy of the GNU General Public License in the
-// LICENSE file. Alternatively, see .
-//==============================================================================
-
-package com.lyndir.masterpassword;
-
-/**
- * @author lhunath, 2017-09-21
- */
-public class MPInvalidatedException extends Exception {
-}
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPMasterKey.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPMasterKey.java
index 4a8fd464..f9883326 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPMasterKey.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPMasterKey.java
@@ -56,14 +56,14 @@ public class MPMasterKey {
/**
* Derive the master key for a user based on their name and master password.
*
- * @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
+ * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
*/
private byte[] masterKey(final MPAlgorithm algorithm)
- throws MPInvalidatedException {
+ throws MPKeyUnavailableException {
Preconditions.checkArgument( masterPassword.length > 0 );
if (invalidated)
- throw new MPInvalidatedException();
+ throw new MPKeyUnavailableException();
byte[] key = keyByVersion.get( algorithm.version() );
if (key == null) {
@@ -81,11 +81,11 @@ public class MPMasterKey {
/**
* Derive the master key for a user based on their name and master password.
*
- * @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
+ * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
*/
private byte[] siteKey(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
@Nullable final String keyContext, final MPAlgorithm algorithm)
- throws MPInvalidatedException {
+ throws MPKeyUnavailableException {
Preconditions.checkArgument( !siteName.isEmpty() );
byte[] masterKey = masterKey( algorithm );
@@ -110,12 +110,12 @@ public class MPMasterKey {
* @param resultParam A parameter for the resultType. For stateful result types, the output of
* {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}.
*
- * @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
+ * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
*/
public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
final MPAlgorithm algorithm)
- throws MPInvalidatedException {
+ throws MPKeyUnavailableException {
byte[] masterKey = masterKey( algorithm );
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithm );
@@ -139,12 +139,12 @@ public class MPMasterKey {
* @param resultParam The result token desired from
* {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}.
*
- * @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
+ * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
*/
public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
final MPAlgorithm algorithm)
- throws MPInvalidatedException {
+ throws MPKeyUnavailableException {
Preconditions.checkNotNull( resultParam );
Preconditions.checkArgument( !resultParam.isEmpty() );
@@ -169,10 +169,10 @@ public class MPMasterKey {
/**
* Calculate an identifier for the master key.
*
- * @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
+ * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
*/
public byte[] getKeyID(final MPAlgorithm algorithm)
- throws MPInvalidatedException {
+ throws MPKeyUnavailableException {
return algorithm.toID( masterKey( algorithm ) );
}
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java
index 6e8acab0..7b87881a 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java
@@ -18,10 +18,14 @@
package com.lyndir.masterpassword.model;
+import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
+
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.*;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.joda.time.Instant;
+import org.joda.time.ReadableInstant;
/**
@@ -29,22 +33,23 @@ import org.joda.time.Instant;
*/
public class MPFileSite extends MPSite {
- private final MPFileUser user;
- private String siteName;
+ private final MPFileUser user;
+
+ private String siteName;
@Nullable
- private String siteContent;
- private UnsignedInteger siteCounter;
- private MPResultType resultType;
- private MPAlgorithm algorithm;
+ private String siteState;
+ private UnsignedInteger siteCounter;
+ private MPResultType resultType;
+ private MPAlgorithm algorithm;
@Nullable
- private String loginContent;
+ private String loginState;
private MPResultType loginType;
@Nullable
- private String url;
- private int uses;
- private Instant lastUsed;
+ private String url;
+ private int uses;
+ private ReadableInstant lastUsed;
public MPFileSite(final MPFileUser user, final String siteName) {
this( user, siteName, null, null, user.getAlgorithm() );
@@ -56,45 +61,43 @@ public class MPFileSite extends MPSite {
null, null, null, 0, new Instant() );
}
- protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteContent,
+ protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteState,
@Nullable final UnsignedInteger siteCounter, @Nullable final MPResultType resultType, final MPAlgorithm algorithm,
- @Nullable final String loginContent, @Nullable final MPResultType loginType,
- @Nullable final String url, final int uses, final Instant lastUsed) {
+ @Nullable final String loginState, @Nullable final MPResultType loginType,
+ @Nullable final String url, final int uses, final ReadableInstant lastUsed) {
this.user = user;
this.siteName = siteName;
- this.siteContent = siteContent;
- this.siteCounter = (siteCounter == null)? user.getAlgorithm().mpw_default_counter(): siteCounter;
- this.resultType = (resultType == null)? user.getAlgorithm().mpw_default_type(): resultType;
+ this.siteState = siteState;
+ this.siteCounter = ifNotNullElse( siteCounter, user.getAlgorithm().mpw_default_counter() );
+ this.resultType = ifNotNullElse( resultType, user.getAlgorithm().mpw_default_password_type() );
this.algorithm = algorithm;
- this.loginContent = loginContent;
- this.loginType = (loginType == null)? MPResultType.GeneratedName: loginType;
+ this.loginState = loginState;
+ this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
this.url = url;
this.uses = uses;
this.lastUsed = lastUsed;
}
- public String resultFor(final MPMasterKey masterKey)
- throws MPInvalidatedException {
+ public String getResult()
+ throws MPKeyUnavailableException {
- return resultFor( masterKey, MPKeyPurpose.Authentication, null );
+ return getResult( MPKeyPurpose.Authentication, null );
}
- public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
- throws MPInvalidatedException {
+ public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
+ throws MPKeyUnavailableException {
- return resultFor( masterKey, keyPurpose, keyContext, getSiteContent() );
+ return getResult( keyPurpose, keyContext, siteState );
}
- public String loginFor(final MPMasterKey masterKey)
- throws MPInvalidatedException {
+ public String getLogin()
+ throws MPKeyUnavailableException {
- if (loginType == null)
- loginType = MPResultType.GeneratedName;
-
- return loginFor( masterKey, loginType, loginContent );
+ return getLogin( loginState );
}
- public MPFileUser getUser() {
+ @Override
+ public MPUser> getUser() {
return user;
}
@@ -109,18 +112,18 @@ public class MPFileSite extends MPSite {
}
@Nullable
- public String getSiteContent() {
- return siteContent;
+ public String getSiteState() {
+ return siteState;
}
- public void setSitePassword(final MPMasterKey masterKey, final MPResultType resultType, @Nullable final String result)
- throws MPInvalidatedException {
+ public void setSitePassword(final MPResultType resultType, @Nullable final String result)
+ throws MPKeyUnavailableException {
this.resultType = resultType;
if (result == null)
- this.siteContent = null;
+ this.siteState = null;
else
- this.siteContent = masterKey.siteState(
+ this.siteState = user.getMasterKey().siteState(
siteName, siteCounter, MPKeyPurpose.Authentication, null, resultType, result, algorithm );
}
@@ -144,6 +147,17 @@ public class MPFileSite extends MPSite {
this.resultType = resultType;
}
+ @Override
+ public MPResultType getLoginType() {
+ return loginType;
+ }
+
+ @Override
+ public void setLoginType(@Nullable final MPResultType loginType) {
+ this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
+
+ }
+
@Override
public MPAlgorithm getAlgorithm() {
return algorithm;
@@ -154,25 +168,17 @@ public class MPFileSite extends MPSite {
this.algorithm = algorithm;
}
- public MPResultType getLoginType() {
- return loginType;
- }
-
@Nullable
- public String getLoginContent() {
- return loginContent;
+ public String getLoginState() {
+ return loginState;
}
- public void setLoginName(final MPMasterKey masterKey, @Nullable final MPResultType loginType, @Nullable final String result)
- throws MPInvalidatedException {
+ public void setLoginName(@Nonnull final MPResultType loginType, @Nonnull final String loginName)
+ throws MPKeyUnavailableException {
this.loginType = loginType;
- if (this.loginType != null)
- if (result == null)
- this.loginContent = null;
- else
- this.loginContent = masterKey.siteState(
- siteName, algorithm.mpw_default_counter(), MPKeyPurpose.Identification, null, this.loginType, result,
- algorithm );
+ this.loginState = user.getMasterKey().siteState(
+ siteName, algorithm.mpw_default_counter(), MPKeyPurpose.Identification, null,
+ this.loginType, loginName, algorithm );
}
@Nullable
@@ -188,7 +194,7 @@ public class MPFileSite extends MPSite {
return uses;
}
- public Instant getLastUsed() {
+ public ReadableInstant getLastUsed() {
return lastUsed;
}
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java
index 7f53f98e..099ddf83 100755
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java
@@ -42,9 +42,10 @@ public class MPFileUser extends MPUser implements Comparable sites = Sets.newHashSet();
@Nullable
- private byte[] keyID;
- private MPAlgorithm algorithm;
- private MPMarshalFormat format;
+ private byte[] keyID;
+ private MPAlgorithm algorithm;
+ private MPMarshalFormat format;
+ private MPMarshaller.ContentMode contentMode;
private int avatar;
private MPResultType defaultType;
@@ -55,11 +56,13 @@ public class MPFileUser extends MPUser implements Comparable implements Comparable implements Comparable implements Comparable implements Comparable user.getFormat().ordinal()))
users.put( previousUser.getFullName(), previousUser );
@@ -86,6 +86,9 @@ public class MPFileUserManager extends MPUserManager {
catch (final IOException | MPMarshalException e) {
logger.err( e, "Couldn't read user from: %s", userFile );
}
+ catch (final MPKeyUnavailableException | MPIncorrectMasterPasswordException e) {
+ logger.err( e, "Couldn't authenticate user for: %s", userFile );
+ }
return users.values();
}
@@ -117,7 +120,7 @@ public class MPFileUserManager extends MPUserManager {
* Write the current user state to disk.
*/
public void save(final MPFileUser user, final MPMasterKey masterKey)
- throws MPInvalidatedException {
+ throws MPKeyUnavailableException {
try {
final MPMarshalFormat format = user.getFormat();
new CharSink() {
@@ -126,7 +129,7 @@ public class MPFileUserManager extends MPUserManager {
throws IOException {
return new OutputStreamWriter( new FileOutputStream( getUserFile( user, format ) ), Charsets.UTF_8 );
}
- }.write( format.marshaller().marshall( user, masterKey, MPMarshaller.ContentMode.PROTECTED ) );
+ }.write( format.marshaller().marshall( user ) );
}
catch (final MPMarshalException | IOException e) {
logger.err( e, "Unable to save sites for user: %s", user );
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFlatMarshaller.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFlatMarshaller.java
index 4381ace9..794f6dd3 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFlatMarshaller.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFlatMarshaller.java
@@ -36,11 +36,11 @@ public class MPFlatMarshaller implements MPMarshaller {
@Nonnull
@Override
- public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode)
- throws MPInvalidatedException, MPMarshalException {
+ public String marshall(final MPFileUser user)
+ throws MPKeyUnavailableException, MPMarshalException {
StringBuilder content = new StringBuilder();
content.append( "# Master Password site export\n" );
- content.append( "# " ).append( contentMode.description() ).append( '\n' );
+ content.append( "# " ).append( user.getContentMode().description() ).append( '\n' );
content.append( "# \n" );
content.append( "##\n" );
content.append( "# Format: " ).append( FORMAT ).append( '\n' );
@@ -51,18 +51,18 @@ public class MPFlatMarshaller implements MPMarshaller {
content.append( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' );
content.append( "# Algorithm: " ).append( user.getAlgorithm().version().toInt() ).append( '\n' );
content.append( "# Default Type: " ).append( user.getDefaultType().getType() ).append( '\n' );
- content.append( "# Passwords: " ).append( contentMode.name() ).append( '\n' );
+ content.append( "# Passwords: " ).append( user.getContentMode().name() ).append( '\n' );
content.append( "##\n" );
content.append( "#\n" );
content.append( "# Last Times Password Login\t Site\tSite\n" );
content.append( "# used used type name\t name\tpassword\n" );
for (final MPFileSite site : user.getSites()) {
- String loginName = site.getLoginContent();
- String password = site.getSiteContent();
- if (!contentMode.isRedacted()) {
- loginName = site.loginFor( masterKey );
- password = site.resultFor( masterKey );
+ String loginName = site.getLoginState();
+ String password = site.getSiteState();
+ if (!user.getContentMode().isRedacted()) {
+ loginName = site.getLogin();
+ password = site.getResult();
}
content.append( strf( "%s %8d %8s %25s\t%25s\t%s\n", //
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFlatUnmarshaller.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFlatUnmarshaller.java
index cfc1f599..d0760467 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFlatUnmarshaller.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFlatUnmarshaller.java
@@ -29,6 +29,7 @@ import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import org.joda.time.DateTime;
@@ -46,17 +47,17 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
@Nonnull
@Override
- public MPFileUser unmarshall(@Nonnull final File file)
- throws IOException, MPMarshalException {
+ public MPFileUser unmarshall(@Nonnull final File file, @Nullable final char[] masterPassword)
+ throws IOException, MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException {
try (Reader reader = new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 )) {
- return unmarshall( CharStreams.toString( reader ) );
+ return unmarshall( CharStreams.toString( reader ), masterPassword );
}
}
@Nonnull
@Override
- public MPFileUser unmarshall(@Nonnull final String content)
- throws MPMarshalException {
+ public MPFileUser unmarshall(@Nonnull final String content, @Nullable final char[] masterPassword)
+ throws MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException {
MPFileUser user = null;
byte[] keyID = null;
String fullName = null;
@@ -74,7 +75,8 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
else
// Ends the header.
user = new MPFileUser( fullName, keyID, MPMasterKey.Version.fromInt( mpVersion ).getAlgorithm(),
- avatar, defaultType, new DateTime( 0 ), MPMarshalFormat.Flat );
+ avatar, defaultType, new DateTime( 0 ), MPMarshalFormat.Flat,
+ clearContent? MPMarshaller.ContentMode.VISIBLE : MPMarshaller.ContentMode.PROTECTED );
// Comment.
else if (line.startsWith( "#" )) {
@@ -113,25 +115,31 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
switch (importFormat) {
case 0:
site = new MPFileSite( user, //
- siteMatcher.group( 5 ), siteMatcher.group( 6 ),
+ siteMatcher.group( 5 ), clearContent? null: siteMatcher.group( 6 ),
user.getAlgorithm().mpw_default_counter(),
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
null, null, null, ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
+ if (clearContent)
+ site.setSitePassword( site.getResultType(), siteMatcher.group( 6 ) );
break;
case 1:
site = new MPFileSite( user, //
- siteMatcher.group( 7 ), siteMatcher.group( 8 ),
+ siteMatcher.group( 7 ), clearContent? null: siteMatcher.group( 8 ),
UnsignedInteger.valueOf( colon.matcher( siteMatcher.group( 5 ) ).replaceAll( "" ) ),
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
- siteMatcher.group( 6 ), MPResultType.GeneratedName, null,
+ clearContent? null: siteMatcher.group( 6 ), MPResultType.GeneratedName, null,
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
+ if (clearContent) {
+ site.setSitePassword( site.getResultType(), siteMatcher.group( 8 ) );
+ site.setLoginName( MPResultType.StoredPersonal, siteMatcher.group( 6 ) );
+ }
break;
default:
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONFile.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONFile.java
index aac71e0b..d52ba3f0 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONFile.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONFile.java
@@ -25,8 +25,6 @@ import java.util.LinkedHashMap;
import java.util.Map;
import javax.annotation.Nullable;
import org.joda.time.Instant;
-import org.joda.time.format.DateTimeFormatter;
-import org.joda.time.format.ISODateTimeFormat;
/**
@@ -34,74 +32,57 @@ import org.joda.time.format.ISODateTimeFormat;
*/
public class MPJSONFile {
- private static final DateTimeFormatter dateFormatter = ISODateTimeFormat.dateTimeNoMillis();
-
- Export export;
- User user;
-
- public MPJSONFile(final MPFileUser user, final MPMasterKey masterKey, final MPMarshaller.ContentMode contentMode)
- throws MPInvalidatedException {
- // if (!user.fullName || !strlen( user.fullName )) {
- // *error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
- // return false;
- // }
- // if (!user.masterPassword || !strlen( user.masterPassword )) {
- // *error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Missing master password." };
- // return false;
- // }
- // if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user.algorithm, user.fullName, user.masterPassword )) {
- // *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
- // return false;
- // }
-
+ public MPJSONFile(final MPFileUser user)
+ throws MPKeyUnavailableException {
// Section: "export"
Export fileExport = this.export = new Export();
fileExport.format = 1;
- fileExport.redacted = contentMode.isRedacted();
- fileExport.date = dateFormatter.print( new Instant() );
+ fileExport.redacted = user.getContentMode().isRedacted();
+ fileExport.date = MPConstant.dateTimeFormatter.print( new Instant() );
// Section: "user"
User fileUser = this.user = new User();
fileUser.avatar = user.getAvatar();
- fileUser.fullName = user.getFullName();
+ fileUser.full_name = user.getFullName();
- fileUser.lastUsed = dateFormatter.print( user.getLastUsed() );
- fileUser.keyId = CodeUtils.encodeHex( masterKey.getKeyID( user.getAlgorithm() ) );
+ fileUser.last_used = MPConstant.dateTimeFormatter.print( user.getLastUsed() );
+ fileUser.key_id = CodeUtils.encodeHex( user.getKeyID() );
fileUser.algorithm = user.getAlgorithm().version();
- fileUser.defaultType = user.getDefaultType();
+ fileUser.default_type = user.getDefaultType();
// Section "sites"
- fileUser.sites = new LinkedHashMap<>();
+ sites = new LinkedHashMap<>();
for (final MPFileSite site : user.getSites()) {
Site fileSite;
String content = null, loginContent = null;
- if (!contentMode.isRedacted()) {
+ if (!fileExport.redacted) {
// Clear Text
- content = masterKey.siteResult( site.getSiteName(), site.getSiteCounter(),
- MPKeyPurpose.Authentication, null, site.getResultType(), site.getSiteContent(),
- site.getAlgorithm() );
- loginContent = masterKey.siteResult( site.getSiteName(), site.getAlgorithm().mpw_default_counter(),
- MPKeyPurpose.Identification, null, site.getLoginType(), site.getLoginContent(),
- site.getAlgorithm() );
+ content = site.getResult();
+ loginContent = user.getMasterKey().siteResult(
+ site.getSiteName(), site.getAlgorithm().mpw_default_counter(),
+ MPKeyPurpose.Identification, null, site.getLoginType(), site.getLoginState(), site.getAlgorithm() );
} else {
// Redacted
if (site.getResultType().supportsTypeFeature( MPSiteFeature.ExportContent ))
- content = site.getSiteContent();
+ content = site.getSiteState();
if (site.getLoginType().supportsTypeFeature( MPSiteFeature.ExportContent ))
- loginContent = site.getLoginContent();
+ loginContent = site.getLoginState();
}
- fileUser.sites.put( site.getSiteName(), fileSite = new Site() );
+ sites.put( site.getSiteName(), fileSite = new Site() );
fileSite.type = site.getResultType();
- fileSite.counter = site.getSiteCounter();
+ fileSite.counter = site.getSiteCounter().longValue();
fileSite.algorithm = site.getAlgorithm().version();
fileSite.password = content;
fileSite.login_name = loginContent;
- fileSite.loginType = site.getLoginType();
+ fileSite.login_type = site.getLoginType();
fileSite.uses = site.getUses();
- fileSite.lastUsed = dateFormatter.print( site.getLastUsed() );
+ fileSite.last_used = MPConstant.dateTimeFormatter.print( site.getLastUsed() );
+
+ fileSite._ext_mpw = new Site.Ext();
+ fileSite._ext_mpw.url = site.getUrl();
fileSite.questions = new LinkedHashMap<>();
// for (size_t q = 0; q < site.questions_count; ++q) {
@@ -133,10 +114,44 @@ public class MPJSONFile {
}
}
- public MPFileUser toUser() {
- return new MPFileUser( user.fullName, CodeUtils.decodeHex( user.keyId ), user.algorithm.getAlgorithm(), user.avatar, user.defaultType, dateFormatter.parseDateTime( user.lastUsed ), MPMarshalFormat.JSON );
+ public MPFileUser toUser(@Nullable final char[] masterPassword)
+ throws MPIncorrectMasterPasswordException, MPKeyUnavailableException {
+ MPFileUser user = new MPFileUser(
+ this.user.full_name, CodeUtils.decodeHex( this.user.key_id ), this.user.algorithm.getAlgorithm(),
+ this.user.avatar, this.user.default_type, MPConstant.dateTimeFormatter.parseDateTime( this.user.last_used ),
+ MPMarshalFormat.JSON, export.redacted? MPMarshaller.ContentMode.PROTECTED: MPMarshaller.ContentMode.VISIBLE );
+ if (masterPassword != null)
+ user.authenticate( masterPassword );
+
+ for (final Map.Entry siteEntry : sites.entrySet()) {
+ String siteName = siteEntry.getKey();
+ Site fileSite = siteEntry.getValue();
+ MPFileSite site = new MPFileSite(
+ user, siteName, export.redacted? fileSite.password: null, UnsignedInteger.valueOf( fileSite.counter ),
+ fileSite.type, fileSite.algorithm.getAlgorithm(),
+ export.redacted? fileSite.login_name: null, fileSite.login_type,
+ fileSite._ext_mpw.url, fileSite.uses, MPConstant.dateTimeFormatter.parseDateTime( fileSite.last_used ) );
+
+ if (!export.redacted) {
+ if (fileSite.password != null)
+ site.setSitePassword( fileSite.type, fileSite.password );
+ if (fileSite.login_name != null)
+ site.setLoginName( fileSite.login_type, fileSite.login_name );
+ }
+
+ user.addSite( site );
+ }
+
+ return user;
}
+ // -- Data
+
+ Export export;
+ User user;
+ Map sites;
+
+
public static class Export {
int format;
@@ -147,47 +162,44 @@ public class MPJSONFile {
public static class User {
- String fullName;
-
+ int avatar;
+ String full_name;
+ String last_used;
+ String key_id;
MPMasterKey.Version algorithm;
- boolean redacted;
-
- int avatar;
- MPResultType defaultType;
- String lastUsed;
- String keyId;
-
- Map sites;
+ MPResultType default_type;
}
public static class Site {
+ MPResultType type;
+ long counter;
+ MPMasterKey.Version algorithm;
@Nullable
String password;
@Nullable
String login_name;
- String name;
- String content;
- MPResultType type;
- UnsignedInteger counter;
- MPMasterKey.Version algorithm;
-
- String loginContent;
- MPResultType loginType;
-
- String url;
- int uses;
- String lastUsed;
+ MPResultType login_type;
+ int uses;
+ String last_used;
Map questions;
- }
+
+ Ext _ext_mpw;
- public static class Question {
+ public static class Ext {
- String keyword;
- String content;
- MPResultType type;
+ @Nullable
+ String url;
+ }
+
+
+ public static class Question {
+
+ MPResultType type;
+ String answer;
+ }
}
}
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONMarshaller.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONMarshaller.java
index c1a55f98..f6833e89 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONMarshaller.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONMarshaller.java
@@ -31,14 +31,14 @@ public class MPJSONMarshaller implements MPMarshaller {
private final Gson gson = new GsonBuilder()
.registerTypeAdapter( MPMasterKey.Version.class, new EnumOrdinalAdapter() )
.registerTypeAdapter( MPResultType.class, new MPResultTypeAdapter() )
- .setFieldNamingStrategy( FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES )
+ .setFieldNamingStrategy( FieldNamingPolicy.IDENTITY )
.setPrettyPrinting().create();
@Nonnull
@Override
- public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode)
- throws MPInvalidatedException, MPMarshalException {
+ public String marshall(final MPFileUser user)
+ throws MPKeyUnavailableException, MPMarshalException {
- return gson.toJson( new MPJSONFile( user, masterKey, contentMode ) );
+ return gson.toJson( new MPJSONFile( user ) );
}
}
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONUnmarshaller.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONUnmarshaller.java
index 511774b2..67ed3a0e 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONUnmarshaller.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPJSONUnmarshaller.java
@@ -19,11 +19,11 @@
package com.lyndir.masterpassword.model;
import com.google.gson.*;
-import com.lyndir.masterpassword.MPMasterKey;
-import com.lyndir.masterpassword.MPResultType;
+import com.lyndir.masterpassword.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
/**
@@ -39,19 +39,29 @@ public class MPJSONUnmarshaller implements MPUnmarshaller {
@Nonnull
@Override
- public MPFileUser unmarshall(@Nonnull final File file)
- throws IOException, MPMarshalException {
+ public MPFileUser unmarshall(@Nonnull final File file, @Nullable final char[] masterPassword)
+ throws IOException, MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException {
try (Reader reader = new InputStreamReader( new FileInputStream( file ), StandardCharsets.UTF_8 )) {
- return gson.fromJson( reader, MPJSONFile.class ).toUser();
+ try {
+ return gson.fromJson( reader, MPJSONFile.class ).toUser( masterPassword );
+ }
+ catch (final JsonSyntaxException e) {
+ throw new MPMarshalException( "Couldn't parse JSON in: " + file, e );
+ }
}
}
@Nonnull
@Override
- public MPFileUser unmarshall(@Nonnull final String content)
- throws MPMarshalException {
+ public MPFileUser unmarshall(@Nonnull final String content, @Nullable final char[] masterPassword)
+ throws MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException {
- return gson.fromJson( content, MPJSONFile.class ).toUser();
+ try {
+ return gson.fromJson( content, MPJSONFile.class ).toUser( masterPassword );
+ }
+ catch (final JsonSyntaxException e) {
+ throw new MPMarshalException( "Couldn't parse JSON", e );
+ }
}
}
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPMarshaller.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPMarshaller.java
index f874e7e3..4b954bf8 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPMarshaller.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPMarshaller.java
@@ -18,8 +18,7 @@
package com.lyndir.masterpassword.model;
-import com.lyndir.masterpassword.MPInvalidatedException;
-import com.lyndir.masterpassword.MPMasterKey;
+import com.lyndir.masterpassword.MPKeyUnavailableException;
import javax.annotation.Nonnull;
@@ -29,8 +28,8 @@ import javax.annotation.Nonnull;
public interface MPMarshaller {
@Nonnull
- String marshall(MPFileUser user, MPMasterKey masterKey, ContentMode contentMode)
- throws MPInvalidatedException, MPMarshalException;
+ String marshall(MPFileUser user)
+ throws MPKeyUnavailableException, MPMarshalException;
enum ContentMode {
PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key.", true ),
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSite.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSite.java
index dfb8f909..0d560d76 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSite.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSite.java
@@ -31,6 +31,8 @@ import javax.annotation.Nullable;
*/
public abstract class MPSite {
+ public abstract MPUser> getUser();
+
public abstract String getSiteName();
public abstract void setSiteName(String siteName);
@@ -43,24 +45,28 @@ public abstract class MPSite {
public abstract void setResultType(MPResultType resultType);
+ public abstract MPResultType getLoginType();
+
+ public abstract void setLoginType(@Nullable MPResultType loginType);
+
public abstract MPAlgorithm getAlgorithm();
public abstract void setAlgorithm(MPAlgorithm algorithm);
- public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
+ public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
@Nullable final String siteContent)
- throws MPInvalidatedException {
+ throws MPKeyUnavailableException {
- return masterKey.siteResult(
+ return getUser().getMasterKey().siteResult(
getSiteName(), getSiteCounter(), keyPurpose, keyContext, getResultType(), siteContent, getAlgorithm() );
}
- public String loginFor(final MPMasterKey masterKey, final MPResultType loginType, @Nullable final String loginContent)
- throws MPInvalidatedException {
+ public String getLogin(@Nullable final String loginContent)
+ throws MPKeyUnavailableException {
- return masterKey.siteResult(
- getSiteName(), getAlgorithm().mpw_default_counter(), MPKeyPurpose.Identification, null, loginType, loginContent,
- getAlgorithm() );
+ return getUser().getMasterKey().siteResult(
+ getSiteName(), getAlgorithm().mpw_default_counter(), MPKeyPurpose.Identification, null,
+ getLoginType(), loginContent, getAlgorithm() );
}
@Override
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUnmarshaller.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUnmarshaller.java
index 0be1bbc9..d07555eb 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUnmarshaller.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUnmarshaller.java
@@ -18,9 +18,11 @@
package com.lyndir.masterpassword.model;
+import com.lyndir.masterpassword.MPKeyUnavailableException;
import java.io.File;
import java.io.IOException;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
/**
@@ -29,10 +31,10 @@ import javax.annotation.Nonnull;
public interface MPUnmarshaller {
@Nonnull
- MPFileUser unmarshall(@Nonnull File file)
- throws IOException, MPMarshalException;
+ MPFileUser unmarshall(@Nonnull File file, @Nullable char[] masterPassword)
+ throws IOException, MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException;
@Nonnull
- MPFileUser unmarshall(@Nonnull String content)
- throws MPMarshalException;
+ MPFileUser unmarshall(@Nonnull String content, @Nullable char[] masterPassword)
+ throws MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException;
}
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUser.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUser.java
index 8f79fb21..e5ae697b 100755
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUser.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUser.java
@@ -20,7 +20,6 @@ package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
-import com.google.common.base.Preconditions;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.masterpassword.*;
import java.util.Collection;
@@ -44,12 +43,16 @@ public abstract class MPUser {
}
@Nonnull
- public MPMasterKey getMasterKey() {
- return Preconditions.checkNotNull( key, "User is not authenticated: %s", getFullName() );
+ public MPMasterKey getMasterKey()
+ throws MPKeyUnavailableException {
+ if (key == null)
+ throw new MPKeyUnavailableException();
+
+ return key;
}
public String exportKeyID()
- throws MPInvalidatedException {
+ throws MPKeyUnavailableException {
return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithm() ) );
}
diff --git a/core/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java b/core/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java
index 6995974e..bfbc6840 100644
--- a/core/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java
+++ b/core/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java
@@ -64,7 +64,7 @@ public class MPMasterKeyTest {
masterKey.getKeyID( testCase.getAlgorithm() );
fail( "[testMasterKey] invalidate ineffective: " + testCase );
}
- catch (final MPInvalidatedException ignored) {
+ catch (final MPKeyUnavailableException ignored) {
}
assertNotEquals(
masterPassword,
diff --git a/core/java/tests/src/test/java/com/lyndir/masterpassword/MPModelTest.java b/core/java/tests/src/test/java/com/lyndir/masterpassword/MPModelTest.java
index 75e67807..e0af955a 100644
--- a/core/java/tests/src/test/java/com/lyndir/masterpassword/MPModelTest.java
+++ b/core/java/tests/src/test/java/com/lyndir/masterpassword/MPModelTest.java
@@ -18,8 +18,11 @@
package com.lyndir.masterpassword;
-import com.lyndir.masterpassword.model.MPJSONUnmarshaller;
-import java.io.File;
+import com.google.common.base.Charsets;
+import com.google.common.io.CharStreams;
+import com.lyndir.masterpassword.model.*;
+import java.io.*;
+import org.testng.Assert;
import org.testng.annotations.Test;
@@ -31,7 +34,12 @@ public class MPModelTest {
@Test
public void testMasterKey()
throws Exception {
- System.err.println( new MPJSONUnmarshaller().unmarshall(
- new File( "/Users/lhunath/.mpw.d/Maarten Billemont.mpsites.json" ) ) );
+ File file = new File( "/Users/lhunath/.mpw.d/Maarten Billemont.mpsites.json" );
+ String orig = CharStreams.toString( new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 ) );
+ System.out.println(orig);
+ MPFileUser user = new MPJSONUnmarshaller().unmarshall( file, null );
+ String result = new MPJSONMarshaller().marshall( user );
+ System.out.println(result);
+ Assert.assertEquals( result, orig, "Marshalled sites do not match original sites." );
}
}
diff --git a/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java b/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java
index 10323ac5..a77ff351 100644
--- a/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java
+++ b/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java
@@ -316,7 +316,7 @@ public class EmergencyActivity extends Activity {
}
} );
}
- catch (final MPInvalidatedException ignored) {
+ catch (final MPKeyUnavailableException ignored) {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
}
diff --git a/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java b/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java
index 29e103c6..5cbc7eb2 100644
--- a/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java
+++ b/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java
@@ -148,7 +148,7 @@ public final class Preferences {
@Nonnull
public MPResultType getDefaultResultType() {
- return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, getDefaultVersion().getAlgorithm().mpw_default_type().ordinal() )];
+ return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, getDefaultVersion().getAlgorithm().mpw_default_password_type().ordinal() )];
}
public boolean setDefaultVersion(final MPMasterKey.Version value) {
diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java
index 5151e19c..98683a8b 100644
--- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java
+++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java
@@ -18,10 +18,14 @@
package com.lyndir.masterpassword.gui.model;
+import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
+
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.MPAlgorithm;
import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.model.MPSite;
+import com.lyndir.masterpassword.model.MPUser;
+import javax.annotation.Nullable;
/**
@@ -29,19 +33,28 @@ import com.lyndir.masterpassword.model.MPSite;
*/
public class IncognitoSite extends MPSite {
+ private final IncognitoUser user;
+
private String siteName;
private UnsignedInteger siteCounter;
private MPResultType resultType;
+ private MPResultType loginType;
private MPAlgorithm algorithm;
- public IncognitoSite(final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
+ public IncognitoSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
final MPAlgorithm algorithm) {
+ this.user = user;
this.siteName = siteName;
this.siteCounter = siteCounter;
this.resultType = resultType;
this.algorithm = algorithm;
}
+ @Override
+ public MPUser> getUser() {
+ return user;
+ }
+
@Override
public String getSiteName() {
return siteName;
@@ -62,6 +75,16 @@ public class IncognitoSite extends MPSite {
this.resultType = resultType;
}
+ @Override
+ public MPResultType getLoginType() {
+ return loginType;
+ }
+
+ @Override
+ public void setLoginType(@Nullable final MPResultType loginType) {
+ this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
+ }
+
@Override
public MPAlgorithm getAlgorithm() {
return algorithm;
diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/IncognitoAuthenticationPanel.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/IncognitoAuthenticationPanel.java
index ca3cacdc..bf34b7e0 100644
--- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/IncognitoAuthenticationPanel.java
+++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/IncognitoAuthenticationPanel.java
@@ -86,9 +86,8 @@ public class IncognitoAuthenticationPanel extends AuthenticationPanel( Preconditions.checkNotNull( getSelectedUser() ) ) {
@Override
protected IncognitoSite createSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter,
- final MPResultType resultType,
- final MPAlgorithm algorithm) {
- return new IncognitoSite( siteName, siteCounter, resultType, algorithm );
+ final MPResultType resultType, final MPAlgorithm algorithm) {
+ return new IncognitoSite( user, siteName, siteCounter, resultType, algorithm );
}
};
}
diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java
index a7dd133f..bd6c39dd 100755
--- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java
+++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java
@@ -147,7 +147,7 @@ public abstract class PasswordFrame, S extends MPSite> exten
siteCounterField = Components.spinner( siteCounterModel ) );
sitePanel.add( siteSettings );
resultTypeField.setFont( Res.valueFont().deriveFont( resultTypeField.getFont().getSize2D() ) );
- resultTypeField.setSelectedItem( user.getAlgorithm().mpw_default_type() );
+ resultTypeField.setSelectedItem( user.getAlgorithm().mpw_default_password_type() );
resultTypeField.addItemListener( new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
diff --git a/public/site b/public/site
index e886da7a..54bd876e 160000
--- a/public/site
+++ b/public/site
@@ -1 +1 @@
-Subproject commit e886da7af01747972cde23ff09827b56dbba973c
+Subproject commit 54bd876ed6b8cebba3fdfe8b546d1783894d5401