Initial Java JSON serialization/deserialization.
This commit is contained in:
parent
1cb720da32
commit
f0d523fb35
@ -38,6 +38,7 @@ char *mpw_get_token(const char **in, const char *eol, char *delim) {
|
|||||||
time_t mpw_mktime(
|
time_t mpw_mktime(
|
||||||
const char *time) {
|
const char *time) {
|
||||||
|
|
||||||
|
// TODO: Support parsing timezone into tm_gmtoff
|
||||||
struct tm tm = { .tm_isdst = -1 };
|
struct tm tm = { .tm_isdst = -1 };
|
||||||
if (time && sscanf( time, "%4d-%2d-%2dT%2d:%2d:%2dZ",
|
if (time && sscanf( time, "%4d-%2d-%2dT%2d:%2d:%2dZ",
|
||||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
||||||
|
@ -59,7 +59,12 @@ public abstract class MPAlgorithm {
|
|||||||
/**
|
/**
|
||||||
* mpw: defaults: password result type.
|
* 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.
|
* mpw: defaults: initial counter value.
|
||||||
|
@ -83,8 +83,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter,
|
||||||
@Nullable final String keyContext) {
|
final MPKeyPurpose keyPurpose, @Nullable final String keyContext) {
|
||||||
|
|
||||||
String keyScope = keyPurpose.getScope();
|
String keyScope = keyPurpose.getScope();
|
||||||
logger.trc( "keyScope: %s", keyScope );
|
logger.trc( "keyScope: %s", keyScope );
|
||||||
@ -117,8 +117,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
|
public String siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
|
||||||
final MPKeyPurpose keyPurpose,
|
final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
|
||||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
|
final MPResultType resultType, @Nullable final String resultParam) {
|
||||||
|
|
||||||
switch (resultType.getTypeClass()) {
|
switch (resultType.getTypeClass()) {
|
||||||
case Template:
|
case Template:
|
||||||
@ -133,8 +133,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey,
|
||||||
@Nullable final String resultParam) {
|
final MPResultType resultType, @Nullable final String resultParam) {
|
||||||
|
|
||||||
int[] _siteKey = new int[siteKey.length];
|
int[] _siteKey = new int[siteKey.length];
|
||||||
for (int i = 0; i < siteKey.length; ++i) {
|
for (int i = 0; i < siteKey.length; ++i) {
|
||||||
@ -168,8 +168,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey,
|
||||||
@Nullable final String resultParam) {
|
final MPResultType resultType, @Nullable final String resultParam) {
|
||||||
|
|
||||||
Preconditions.checkNotNull( resultParam );
|
Preconditions.checkNotNull( resultParam );
|
||||||
Preconditions.checkArgument( !resultParam.isEmpty() );
|
Preconditions.checkArgument( !resultParam.isEmpty() );
|
||||||
@ -192,8 +192,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey,
|
||||||
@Nullable final String resultParam) {
|
final MPResultType resultType, @Nullable final String resultParam) {
|
||||||
|
|
||||||
if (resultType == MPResultType.DeriveKey) {
|
if (resultType == MPResultType.DeriveKey) {
|
||||||
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
|
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
|
||||||
@ -220,8 +220,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
|
public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
|
||||||
final MPKeyPurpose keyPurpose,
|
final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
|
||||||
@Nullable final String keyContext, final MPResultType resultType, final String resultParam) {
|
final MPResultType resultType, final String resultParam) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Encrypt
|
// Encrypt
|
||||||
@ -246,111 +246,77 @@ public class MPAlgorithmV0 extends MPAlgorithm {
|
|||||||
return MPMasterKey.Version.V0;
|
return MPMasterKey.Version.V0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: defaults: password result type.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MPResultType mpw_default_type() {
|
public MPResultType mpw_default_password_type() {
|
||||||
return MPResultType.GeneratedLong;
|
return MPResultType.GeneratedLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* mpw: defaults: initial counter value.
|
public MPResultType mpw_default_login_type() {
|
||||||
*/
|
return MPResultType.GeneratedName;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UnsignedInteger mpw_default_counter() {
|
public UnsignedInteger mpw_default_counter() {
|
||||||
return UnsignedInteger.ONE;
|
return UnsignedInteger.ONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: validity for the time-based rolling counter.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("MagicNumber")
|
@SuppressWarnings("MagicNumber")
|
||||||
public long mpw_otp_window() {
|
public long mpw_otp_window() {
|
||||||
return 5 * 60 /* s */;
|
return 5 * 60 /* s */;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Key ID hash.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MessageDigests mpw_hash() {
|
public MessageDigests mpw_hash() {
|
||||||
return MessageDigests.SHA256;
|
return MessageDigests.SHA256;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Site digest.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MessageAuthenticationDigests mpw_digest() {
|
public MessageAuthenticationDigests mpw_digest() {
|
||||||
return MessageAuthenticationDigests.HmacSHA256;
|
return MessageAuthenticationDigests.HmacSHA256;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Platform-agnostic byte order.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public ByteOrder mpw_byteOrder() {
|
public ByteOrder mpw_byteOrder() {
|
||||||
return ByteOrder.BIG_ENDIAN;
|
return ByteOrder.BIG_ENDIAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Input character encoding.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Charset mpw_charset() {
|
public Charset mpw_charset() {
|
||||||
return Charsets.UTF_8;
|
return Charsets.UTF_8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Master key size (byte).
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("MagicNumber")
|
@SuppressWarnings("MagicNumber")
|
||||||
public int mpw_dkLen() {
|
public int mpw_dkLen() {
|
||||||
return 64;
|
return 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Minimum size for derived keys (bit).
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("MagicNumber")
|
@SuppressWarnings("MagicNumber")
|
||||||
public int mpw_keySize_min() {
|
public int mpw_keySize_min() {
|
||||||
return 128;
|
return 128;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: Maximum size for derived keys (bit).
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("MagicNumber")
|
@SuppressWarnings("MagicNumber")
|
||||||
public int mpw_keySize_max() {
|
public int mpw_keySize_max() {
|
||||||
return 512;
|
return 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* scrypt: Parallelization parameter.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("MagicNumber")
|
@SuppressWarnings("MagicNumber")
|
||||||
public int scrypt_p() {
|
public int scrypt_p() {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* scrypt: Memory cost parameter.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("MagicNumber")
|
@SuppressWarnings("MagicNumber")
|
||||||
public int scrypt_r() {
|
public int scrypt_r() {
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* scrypt: CPU cost parameter.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("MagicNumber")
|
@SuppressWarnings("MagicNumber")
|
||||||
public int scrypt_N() {
|
public int scrypt_N() {
|
||||||
|
@ -42,5 +42,5 @@ public final class MPConstant {
|
|||||||
|
|
||||||
public static final int MS_PER_S = 1000;
|
public static final int MS_PER_S = 1000;
|
||||||
|
|
||||||
public static final DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis();
|
public static final DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis().withZoneUTC();
|
||||||
}
|
}
|
||||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
package com.lyndir.masterpassword;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author lhunath, 2017-09-21
|
|
||||||
*/
|
|
||||||
public class MPInvalidatedException extends Exception {
|
|
||||||
}
|
|
@ -56,14 +56,14 @@ public class MPMasterKey {
|
|||||||
/**
|
/**
|
||||||
* Derive the master key for a user based on their name and master password.
|
* 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)
|
private byte[] masterKey(final MPAlgorithm algorithm)
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
Preconditions.checkArgument( masterPassword.length > 0 );
|
Preconditions.checkArgument( masterPassword.length > 0 );
|
||||||
|
|
||||||
if (invalidated)
|
if (invalidated)
|
||||||
throw new MPInvalidatedException();
|
throw new MPKeyUnavailableException();
|
||||||
|
|
||||||
byte[] key = keyByVersion.get( algorithm.version() );
|
byte[] key = keyByVersion.get( algorithm.version() );
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
@ -81,11 +81,11 @@ public class MPMasterKey {
|
|||||||
/**
|
/**
|
||||||
* Derive the master key for a user based on their name and master password.
|
* 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,
|
private byte[] siteKey(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||||
@Nullable final String keyContext, final MPAlgorithm algorithm)
|
@Nullable final String keyContext, final MPAlgorithm algorithm)
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
Preconditions.checkArgument( !siteName.isEmpty() );
|
Preconditions.checkArgument( !siteName.isEmpty() );
|
||||||
|
|
||||||
byte[] masterKey = masterKey( algorithm );
|
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
|
* @param resultParam A parameter for the resultType. For stateful result types, the output of
|
||||||
* {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}.
|
* {@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,
|
public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
||||||
final MPAlgorithm algorithm)
|
final MPAlgorithm algorithm)
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
|
|
||||||
byte[] masterKey = masterKey( algorithm );
|
byte[] masterKey = masterKey( algorithm );
|
||||||
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithm );
|
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithm );
|
||||||
@ -139,12 +139,12 @@ public class MPMasterKey {
|
|||||||
* @param resultParam The result token desired from
|
* @param resultParam The result token desired from
|
||||||
* {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}.
|
* {@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,
|
public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
||||||
final MPAlgorithm algorithm)
|
final MPAlgorithm algorithm)
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
|
|
||||||
Preconditions.checkNotNull( resultParam );
|
Preconditions.checkNotNull( resultParam );
|
||||||
Preconditions.checkArgument( !resultParam.isEmpty() );
|
Preconditions.checkArgument( !resultParam.isEmpty() );
|
||||||
@ -169,10 +169,10 @@ public class MPMasterKey {
|
|||||||
/**
|
/**
|
||||||
* Calculate an identifier for the master key.
|
* 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)
|
public byte[] getKeyID(final MPAlgorithm algorithm)
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
|
|
||||||
return algorithm.toID( masterKey( algorithm ) );
|
return algorithm.toID( masterKey( algorithm ) );
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,14 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword.model;
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
|
||||||
|
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
import com.lyndir.masterpassword.*;
|
import com.lyndir.masterpassword.*;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import org.joda.time.Instant;
|
import org.joda.time.Instant;
|
||||||
|
import org.joda.time.ReadableInstant;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,21 +34,22 @@ import org.joda.time.Instant;
|
|||||||
public class MPFileSite extends MPSite {
|
public class MPFileSite extends MPSite {
|
||||||
|
|
||||||
private final MPFileUser user;
|
private final MPFileUser user;
|
||||||
|
|
||||||
private String siteName;
|
private String siteName;
|
||||||
@Nullable
|
@Nullable
|
||||||
private String siteContent;
|
private String siteState;
|
||||||
private UnsignedInteger siteCounter;
|
private UnsignedInteger siteCounter;
|
||||||
private MPResultType resultType;
|
private MPResultType resultType;
|
||||||
private MPAlgorithm algorithm;
|
private MPAlgorithm algorithm;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private String loginContent;
|
private String loginState;
|
||||||
private MPResultType loginType;
|
private MPResultType loginType;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private String url;
|
private String url;
|
||||||
private int uses;
|
private int uses;
|
||||||
private Instant lastUsed;
|
private ReadableInstant lastUsed;
|
||||||
|
|
||||||
public MPFileSite(final MPFileUser user, final String siteName) {
|
public MPFileSite(final MPFileUser user, final String siteName) {
|
||||||
this( user, siteName, null, null, user.getAlgorithm() );
|
this( user, siteName, null, null, user.getAlgorithm() );
|
||||||
@ -56,45 +61,43 @@ public class MPFileSite extends MPSite {
|
|||||||
null, null, null, 0, new Instant() );
|
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 UnsignedInteger siteCounter, @Nullable final MPResultType resultType, final MPAlgorithm algorithm,
|
||||||
@Nullable final String loginContent, @Nullable final MPResultType loginType,
|
@Nullable final String loginState, @Nullable final MPResultType loginType,
|
||||||
@Nullable final String url, final int uses, final Instant lastUsed) {
|
@Nullable final String url, final int uses, final ReadableInstant lastUsed) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.siteName = siteName;
|
this.siteName = siteName;
|
||||||
this.siteContent = siteContent;
|
this.siteState = siteState;
|
||||||
this.siteCounter = (siteCounter == null)? user.getAlgorithm().mpw_default_counter(): siteCounter;
|
this.siteCounter = ifNotNullElse( siteCounter, user.getAlgorithm().mpw_default_counter() );
|
||||||
this.resultType = (resultType == null)? user.getAlgorithm().mpw_default_type(): resultType;
|
this.resultType = ifNotNullElse( resultType, user.getAlgorithm().mpw_default_password_type() );
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
this.loginContent = loginContent;
|
this.loginState = loginState;
|
||||||
this.loginType = (loginType == null)? MPResultType.GeneratedName: loginType;
|
this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.uses = uses;
|
this.uses = uses;
|
||||||
this.lastUsed = lastUsed;
|
this.lastUsed = lastUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String resultFor(final MPMasterKey masterKey)
|
public String getResult()
|
||||||
throws MPInvalidatedException {
|
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)
|
public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
|
|
||||||
return resultFor( masterKey, keyPurpose, keyContext, getSiteContent() );
|
return getResult( keyPurpose, keyContext, siteState );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String loginFor(final MPMasterKey masterKey)
|
public String getLogin()
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
|
|
||||||
if (loginType == null)
|
return getLogin( loginState );
|
||||||
loginType = MPResultType.GeneratedName;
|
|
||||||
|
|
||||||
return loginFor( masterKey, loginType, loginContent );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPFileUser getUser() {
|
@Override
|
||||||
|
public MPUser<?> getUser() {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,18 +112,18 @@ public class MPFileSite extends MPSite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getSiteContent() {
|
public String getSiteState() {
|
||||||
return siteContent;
|
return siteState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSitePassword(final MPMasterKey masterKey, final MPResultType resultType, @Nullable final String result)
|
public void setSitePassword(final MPResultType resultType, @Nullable final String result)
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
this.resultType = resultType;
|
this.resultType = resultType;
|
||||||
|
|
||||||
if (result == null)
|
if (result == null)
|
||||||
this.siteContent = null;
|
this.siteState = null;
|
||||||
else
|
else
|
||||||
this.siteContent = masterKey.siteState(
|
this.siteState = user.getMasterKey().siteState(
|
||||||
siteName, siteCounter, MPKeyPurpose.Authentication, null, resultType, result, algorithm );
|
siteName, siteCounter, MPKeyPurpose.Authentication, null, resultType, result, algorithm );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,6 +147,17 @@ public class MPFileSite extends MPSite {
|
|||||||
this.resultType = resultType;
|
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
|
@Override
|
||||||
public MPAlgorithm getAlgorithm() {
|
public MPAlgorithm getAlgorithm() {
|
||||||
return algorithm;
|
return algorithm;
|
||||||
@ -154,25 +168,17 @@ public class MPFileSite extends MPSite {
|
|||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPResultType getLoginType() {
|
|
||||||
return loginType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getLoginContent() {
|
public String getLoginState() {
|
||||||
return loginContent;
|
return loginState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLoginName(final MPMasterKey masterKey, @Nullable final MPResultType loginType, @Nullable final String result)
|
public void setLoginName(@Nonnull final MPResultType loginType, @Nonnull final String loginName)
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
this.loginType = loginType;
|
this.loginType = loginType;
|
||||||
if (this.loginType != null)
|
this.loginState = user.getMasterKey().siteState(
|
||||||
if (result == null)
|
siteName, algorithm.mpw_default_counter(), MPKeyPurpose.Identification, null,
|
||||||
this.loginContent = null;
|
this.loginType, loginName, algorithm );
|
||||||
else
|
|
||||||
this.loginContent = masterKey.siteState(
|
|
||||||
siteName, algorithm.mpw_default_counter(), MPKeyPurpose.Identification, null, this.loginType, result,
|
|
||||||
algorithm );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -188,7 +194,7 @@ public class MPFileSite extends MPSite {
|
|||||||
return uses;
|
return uses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instant getLastUsed() {
|
public ReadableInstant getLastUsed() {
|
||||||
return lastUsed;
|
return lastUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
private byte[] keyID;
|
private byte[] keyID;
|
||||||
private MPAlgorithm algorithm;
|
private MPAlgorithm algorithm;
|
||||||
private MPMarshalFormat format;
|
private MPMarshalFormat format;
|
||||||
|
private MPMarshaller.ContentMode contentMode;
|
||||||
|
|
||||||
private int avatar;
|
private int avatar;
|
||||||
private MPResultType defaultType;
|
private MPResultType defaultType;
|
||||||
@ -55,11 +56,13 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm) {
|
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm) {
|
||||||
this( fullName, keyID, algorithm, 0, algorithm.mpw_default_type(), new Instant(), MPMarshalFormat.DEFAULT );
|
this( fullName, keyID, algorithm, 0, algorithm.mpw_default_password_type(), new Instant(),
|
||||||
|
MPMarshalFormat.DEFAULT, MPMarshaller.ContentMode.PROTECTED );
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm, final int avatar,
|
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm, final int avatar,
|
||||||
final MPResultType defaultType, final ReadableInstant lastUsed, final MPMarshalFormat format) {
|
final MPResultType defaultType, final ReadableInstant lastUsed,
|
||||||
|
final MPMarshalFormat format, final MPMarshaller.ContentMode contentMode) {
|
||||||
this.fullName = fullName;
|
this.fullName = fullName;
|
||||||
this.keyID = (keyID == null)? null: keyID.clone();
|
this.keyID = (keyID == null)? null: keyID.clone();
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
@ -67,6 +70,7 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
this.defaultType = defaultType;
|
this.defaultType = defaultType;
|
||||||
this.lastUsed = lastUsed;
|
this.lastUsed = lastUsed;
|
||||||
this.format = format;
|
this.format = format;
|
||||||
|
this.contentMode = contentMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -74,6 +78,11 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
return fullName;
|
return fullName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public byte[] getKeyID() {
|
||||||
|
return (keyID == null)? null: keyID.clone();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MPAlgorithm getAlgorithm() {
|
public MPAlgorithm getAlgorithm() {
|
||||||
return algorithm;
|
return algorithm;
|
||||||
@ -91,6 +100,14 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
this.format = format;
|
this.format = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MPMarshaller.ContentMode getContentMode() {
|
||||||
|
return contentMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentMode(final MPMarshaller.ContentMode contentMode) {
|
||||||
|
this.contentMode = contentMode;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getAvatar() {
|
public int getAvatar() {
|
||||||
return avatar;
|
return avatar;
|
||||||
@ -164,13 +181,13 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
catch (final MPInvalidatedException e) {
|
catch (final MPKeyUnavailableException e) {
|
||||||
throw logger.bug( e );
|
throw logger.bug( e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void save()
|
void save()
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
MPFileUserManager.get().save( this, getMasterKey() );
|
MPFileUserManager.get().save( this, getMasterKey() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ public class MPFileUserManager extends MPUserManager {
|
|||||||
for (final MPMarshalFormat format : MPMarshalFormat.values())
|
for (final MPMarshalFormat format : MPMarshalFormat.values())
|
||||||
if (userFile.getName().endsWith( format.fileSuffix() ))
|
if (userFile.getName().endsWith( format.fileSuffix() ))
|
||||||
try {
|
try {
|
||||||
MPFileUser user = format.unmarshaller().unmarshall( userFile );
|
MPFileUser user = format.unmarshaller().unmarshall( userFile, null );
|
||||||
MPFileUser previousUser = users.put( user.getFullName(), user );
|
MPFileUser previousUser = users.put( user.getFullName(), user );
|
||||||
if ((previousUser != null) && (previousUser.getFormat().ordinal() > user.getFormat().ordinal()))
|
if ((previousUser != null) && (previousUser.getFormat().ordinal() > user.getFormat().ordinal()))
|
||||||
users.put( previousUser.getFullName(), previousUser );
|
users.put( previousUser.getFullName(), previousUser );
|
||||||
@ -86,6 +86,9 @@ public class MPFileUserManager extends MPUserManager {
|
|||||||
catch (final IOException | MPMarshalException e) {
|
catch (final IOException | MPMarshalException e) {
|
||||||
logger.err( e, "Couldn't read user from: %s", userFile );
|
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();
|
return users.values();
|
||||||
}
|
}
|
||||||
@ -117,7 +120,7 @@ public class MPFileUserManager extends MPUserManager {
|
|||||||
* Write the current user state to disk.
|
* Write the current user state to disk.
|
||||||
*/
|
*/
|
||||||
public void save(final MPFileUser user, final MPMasterKey masterKey)
|
public void save(final MPFileUser user, final MPMasterKey masterKey)
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
try {
|
try {
|
||||||
final MPMarshalFormat format = user.getFormat();
|
final MPMarshalFormat format = user.getFormat();
|
||||||
new CharSink() {
|
new CharSink() {
|
||||||
@ -126,7 +129,7 @@ public class MPFileUserManager extends MPUserManager {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
return new OutputStreamWriter( new FileOutputStream( getUserFile( user, format ) ), Charsets.UTF_8 );
|
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) {
|
catch (final MPMarshalException | IOException e) {
|
||||||
logger.err( e, "Unable to save sites for user: %s", user );
|
logger.err( e, "Unable to save sites for user: %s", user );
|
||||||
|
@ -36,11 +36,11 @@ public class MPFlatMarshaller implements MPMarshaller {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode)
|
public String marshall(final MPFileUser user)
|
||||||
throws MPInvalidatedException, MPMarshalException {
|
throws MPKeyUnavailableException, MPMarshalException {
|
||||||
StringBuilder content = new StringBuilder();
|
StringBuilder content = new StringBuilder();
|
||||||
content.append( "# Master Password site export\n" );
|
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( "##\n" );
|
content.append( "##\n" );
|
||||||
content.append( "# Format: " ).append( FORMAT ).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( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' );
|
||||||
content.append( "# Algorithm: " ).append( user.getAlgorithm().version().toInt() ).append( '\n' );
|
content.append( "# Algorithm: " ).append( user.getAlgorithm().version().toInt() ).append( '\n' );
|
||||||
content.append( "# Default Type: " ).append( user.getDefaultType().getType() ).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( "#\n" );
|
content.append( "#\n" );
|
||||||
content.append( "# Last Times Password Login\t Site\tSite\n" );
|
content.append( "# Last Times Password Login\t Site\tSite\n" );
|
||||||
content.append( "# used used type name\t name\tpassword\n" );
|
content.append( "# used used type name\t name\tpassword\n" );
|
||||||
|
|
||||||
for (final MPFileSite site : user.getSites()) {
|
for (final MPFileSite site : user.getSites()) {
|
||||||
String loginName = site.getLoginContent();
|
String loginName = site.getLoginState();
|
||||||
String password = site.getSiteContent();
|
String password = site.getSiteState();
|
||||||
if (!contentMode.isRedacted()) {
|
if (!user.getContentMode().isRedacted()) {
|
||||||
loginName = site.loginFor( masterKey );
|
loginName = site.getLogin();
|
||||||
password = site.resultFor( masterKey );
|
password = site.getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
content.append( strf( "%s %8d %8s %25s\t%25s\t%s\n", //
|
content.append( strf( "%s %8d %8s %25s\t%25s\t%s\n", //
|
||||||
|
@ -29,6 +29,7 @@ import java.io.*;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
|
|
||||||
@ -46,17 +47,17 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public MPFileUser unmarshall(@Nonnull final File file)
|
public MPFileUser unmarshall(@Nonnull final File file, @Nullable final char[] masterPassword)
|
||||||
throws IOException, MPMarshalException {
|
throws IOException, MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException {
|
||||||
try (Reader reader = new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 )) {
|
try (Reader reader = new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 )) {
|
||||||
return unmarshall( CharStreams.toString( reader ) );
|
return unmarshall( CharStreams.toString( reader ), masterPassword );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public MPFileUser unmarshall(@Nonnull final String content)
|
public MPFileUser unmarshall(@Nonnull final String content, @Nullable final char[] masterPassword)
|
||||||
throws MPMarshalException {
|
throws MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException {
|
||||||
MPFileUser user = null;
|
MPFileUser user = null;
|
||||||
byte[] keyID = null;
|
byte[] keyID = null;
|
||||||
String fullName = null;
|
String fullName = null;
|
||||||
@ -74,7 +75,8 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
|
|||||||
else
|
else
|
||||||
// Ends the header.
|
// Ends the header.
|
||||||
user = new MPFileUser( fullName, keyID, MPMasterKey.Version.fromInt( mpVersion ).getAlgorithm(),
|
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.
|
// Comment.
|
||||||
else if (line.startsWith( "#" )) {
|
else if (line.startsWith( "#" )) {
|
||||||
@ -113,25 +115,31 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
|
|||||||
switch (importFormat) {
|
switch (importFormat) {
|
||||||
case 0:
|
case 0:
|
||||||
site = new MPFileSite( user, //
|
site = new MPFileSite( user, //
|
||||||
siteMatcher.group( 5 ), siteMatcher.group( 6 ),
|
siteMatcher.group( 5 ), clearContent? null: siteMatcher.group( 6 ),
|
||||||
user.getAlgorithm().mpw_default_counter(),
|
user.getAlgorithm().mpw_default_counter(),
|
||||||
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
|
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
|
||||||
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
|
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
|
||||||
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
|
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
|
||||||
null, null, null, ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
|
null, null, null, ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
|
||||||
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
|
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
|
||||||
|
if (clearContent)
|
||||||
|
site.setSitePassword( site.getResultType(), siteMatcher.group( 6 ) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
site = new MPFileSite( user, //
|
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( "" ) ),
|
UnsignedInteger.valueOf( colon.matcher( siteMatcher.group( 5 ) ).replaceAll( "" ) ),
|
||||||
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
|
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
|
||||||
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
|
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
|
||||||
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
|
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 ) ),
|
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
|
||||||
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
|
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
|
||||||
|
if (clearContent) {
|
||||||
|
site.setSitePassword( site.getResultType(), siteMatcher.group( 8 ) );
|
||||||
|
site.setLoginName( MPResultType.StoredPersonal, siteMatcher.group( 6 ) );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -25,8 +25,6 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import org.joda.time.Instant;
|
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 {
|
public class MPJSONFile {
|
||||||
|
|
||||||
private static final DateTimeFormatter dateFormatter = ISODateTimeFormat.dateTimeNoMillis();
|
public MPJSONFile(final MPFileUser user)
|
||||||
|
throws MPKeyUnavailableException {
|
||||||
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;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Section: "export"
|
// Section: "export"
|
||||||
Export fileExport = this.export = new Export();
|
Export fileExport = this.export = new Export();
|
||||||
fileExport.format = 1;
|
fileExport.format = 1;
|
||||||
fileExport.redacted = contentMode.isRedacted();
|
fileExport.redacted = user.getContentMode().isRedacted();
|
||||||
fileExport.date = dateFormatter.print( new Instant() );
|
fileExport.date = MPConstant.dateTimeFormatter.print( new Instant() );
|
||||||
|
|
||||||
// Section: "user"
|
// Section: "user"
|
||||||
User fileUser = this.user = new User();
|
User fileUser = this.user = new User();
|
||||||
fileUser.avatar = user.getAvatar();
|
fileUser.avatar = user.getAvatar();
|
||||||
fileUser.fullName = user.getFullName();
|
fileUser.full_name = user.getFullName();
|
||||||
|
|
||||||
fileUser.lastUsed = dateFormatter.print( user.getLastUsed() );
|
fileUser.last_used = MPConstant.dateTimeFormatter.print( user.getLastUsed() );
|
||||||
fileUser.keyId = CodeUtils.encodeHex( masterKey.getKeyID( user.getAlgorithm() ) );
|
fileUser.key_id = CodeUtils.encodeHex( user.getKeyID() );
|
||||||
|
|
||||||
fileUser.algorithm = user.getAlgorithm().version();
|
fileUser.algorithm = user.getAlgorithm().version();
|
||||||
fileUser.defaultType = user.getDefaultType();
|
fileUser.default_type = user.getDefaultType();
|
||||||
|
|
||||||
// Section "sites"
|
// Section "sites"
|
||||||
fileUser.sites = new LinkedHashMap<>();
|
sites = new LinkedHashMap<>();
|
||||||
for (final MPFileSite site : user.getSites()) {
|
for (final MPFileSite site : user.getSites()) {
|
||||||
Site fileSite;
|
Site fileSite;
|
||||||
String content = null, loginContent = null;
|
String content = null, loginContent = null;
|
||||||
if (!contentMode.isRedacted()) {
|
if (!fileExport.redacted) {
|
||||||
// Clear Text
|
// Clear Text
|
||||||
content = masterKey.siteResult( site.getSiteName(), site.getSiteCounter(),
|
content = site.getResult();
|
||||||
MPKeyPurpose.Authentication, null, site.getResultType(), site.getSiteContent(),
|
loginContent = user.getMasterKey().siteResult(
|
||||||
site.getAlgorithm() );
|
site.getSiteName(), site.getAlgorithm().mpw_default_counter(),
|
||||||
loginContent = masterKey.siteResult( site.getSiteName(), site.getAlgorithm().mpw_default_counter(),
|
MPKeyPurpose.Identification, null, site.getLoginType(), site.getLoginState(), site.getAlgorithm() );
|
||||||
MPKeyPurpose.Identification, null, site.getLoginType(), site.getLoginContent(),
|
|
||||||
site.getAlgorithm() );
|
|
||||||
} else {
|
} else {
|
||||||
// Redacted
|
// Redacted
|
||||||
if (site.getResultType().supportsTypeFeature( MPSiteFeature.ExportContent ))
|
if (site.getResultType().supportsTypeFeature( MPSiteFeature.ExportContent ))
|
||||||
content = site.getSiteContent();
|
content = site.getSiteState();
|
||||||
if (site.getLoginType().supportsTypeFeature( MPSiteFeature.ExportContent ))
|
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.type = site.getResultType();
|
||||||
fileSite.counter = site.getSiteCounter();
|
fileSite.counter = site.getSiteCounter().longValue();
|
||||||
fileSite.algorithm = site.getAlgorithm().version();
|
fileSite.algorithm = site.getAlgorithm().version();
|
||||||
fileSite.password = content;
|
fileSite.password = content;
|
||||||
fileSite.login_name = loginContent;
|
fileSite.login_name = loginContent;
|
||||||
fileSite.loginType = site.getLoginType();
|
fileSite.login_type = site.getLoginType();
|
||||||
|
|
||||||
fileSite.uses = site.getUses();
|
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<>();
|
fileSite.questions = new LinkedHashMap<>();
|
||||||
// for (size_t q = 0; q < site.questions_count; ++q) {
|
// for (size_t q = 0; q < site.questions_count; ++q) {
|
||||||
@ -133,10 +114,44 @@ public class MPJSONFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPFileUser toUser() {
|
public MPFileUser toUser(@Nullable final char[] masterPassword)
|
||||||
return new MPFileUser( user.fullName, CodeUtils.decodeHex( user.keyId ), user.algorithm.getAlgorithm(), user.avatar, user.defaultType, dateFormatter.parseDateTime( user.lastUsed ), MPMarshalFormat.JSON );
|
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<String, Site> 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<String, Site> sites;
|
||||||
|
|
||||||
|
|
||||||
public static class Export {
|
public static class Export {
|
||||||
|
|
||||||
int format;
|
int format;
|
||||||
@ -147,47 +162,44 @@ public class MPJSONFile {
|
|||||||
|
|
||||||
public static class User {
|
public static class User {
|
||||||
|
|
||||||
String fullName;
|
|
||||||
|
|
||||||
MPMasterKey.Version algorithm;
|
|
||||||
boolean redacted;
|
|
||||||
|
|
||||||
int avatar;
|
int avatar;
|
||||||
MPResultType defaultType;
|
String full_name;
|
||||||
String lastUsed;
|
String last_used;
|
||||||
String keyId;
|
String key_id;
|
||||||
|
MPMasterKey.Version algorithm;
|
||||||
Map<String, Site> sites;
|
MPResultType default_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class Site {
|
public static class Site {
|
||||||
|
|
||||||
|
MPResultType type;
|
||||||
|
long counter;
|
||||||
|
MPMasterKey.Version algorithm;
|
||||||
@Nullable
|
@Nullable
|
||||||
String password;
|
String password;
|
||||||
@Nullable
|
@Nullable
|
||||||
String login_name;
|
String login_name;
|
||||||
String name;
|
MPResultType login_type;
|
||||||
String content;
|
|
||||||
MPResultType type;
|
|
||||||
UnsignedInteger counter;
|
|
||||||
MPMasterKey.Version algorithm;
|
|
||||||
|
|
||||||
String loginContent;
|
|
||||||
MPResultType loginType;
|
|
||||||
|
|
||||||
String url;
|
|
||||||
int uses;
|
int uses;
|
||||||
String lastUsed;
|
String last_used;
|
||||||
|
|
||||||
Map<String, Question> questions;
|
Map<String, Question> questions;
|
||||||
|
|
||||||
|
Ext _ext_mpw;
|
||||||
|
|
||||||
|
|
||||||
|
public static class Ext {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
String url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class Question {
|
public static class Question {
|
||||||
|
|
||||||
String keyword;
|
|
||||||
String content;
|
|
||||||
MPResultType type;
|
MPResultType type;
|
||||||
|
String answer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,14 +31,14 @@ public class MPJSONMarshaller implements MPMarshaller {
|
|||||||
private final Gson gson = new GsonBuilder()
|
private final Gson gson = new GsonBuilder()
|
||||||
.registerTypeAdapter( MPMasterKey.Version.class, new EnumOrdinalAdapter() )
|
.registerTypeAdapter( MPMasterKey.Version.class, new EnumOrdinalAdapter() )
|
||||||
.registerTypeAdapter( MPResultType.class, new MPResultTypeAdapter() )
|
.registerTypeAdapter( MPResultType.class, new MPResultTypeAdapter() )
|
||||||
.setFieldNamingStrategy( FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES )
|
.setFieldNamingStrategy( FieldNamingPolicy.IDENTITY )
|
||||||
.setPrettyPrinting().create();
|
.setPrettyPrinting().create();
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode)
|
public String marshall(final MPFileUser user)
|
||||||
throws MPInvalidatedException, MPMarshalException {
|
throws MPKeyUnavailableException, MPMarshalException {
|
||||||
|
|
||||||
return gson.toJson( new MPJSONFile( user, masterKey, contentMode ) );
|
return gson.toJson( new MPJSONFile( user ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,11 @@
|
|||||||
package com.lyndir.masterpassword.model;
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
import com.lyndir.masterpassword.MPMasterKey;
|
import com.lyndir.masterpassword.*;
|
||||||
import com.lyndir.masterpassword.MPResultType;
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,19 +39,29 @@ public class MPJSONUnmarshaller implements MPUnmarshaller {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public MPFileUser unmarshall(@Nonnull final File file)
|
public MPFileUser unmarshall(@Nonnull final File file, @Nullable final char[] masterPassword)
|
||||||
throws IOException, MPMarshalException {
|
throws IOException, MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException {
|
||||||
|
|
||||||
try (Reader reader = new InputStreamReader( new FileInputStream( file ), StandardCharsets.UTF_8 )) {
|
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
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public MPFileUser unmarshall(@Nonnull final String content)
|
public MPFileUser unmarshall(@Nonnull final String content, @Nullable final char[] masterPassword)
|
||||||
throws MPMarshalException {
|
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 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,7 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword.model;
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
import com.lyndir.masterpassword.MPInvalidatedException;
|
import com.lyndir.masterpassword.MPKeyUnavailableException;
|
||||||
import com.lyndir.masterpassword.MPMasterKey;
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
|
||||||
@ -29,8 +28,8 @@ import javax.annotation.Nonnull;
|
|||||||
public interface MPMarshaller {
|
public interface MPMarshaller {
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
String marshall(MPFileUser user, MPMasterKey masterKey, ContentMode contentMode)
|
String marshall(MPFileUser user)
|
||||||
throws MPInvalidatedException, MPMarshalException;
|
throws MPKeyUnavailableException, MPMarshalException;
|
||||||
|
|
||||||
enum ContentMode {
|
enum ContentMode {
|
||||||
PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key.", true ),
|
PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key.", true ),
|
||||||
|
@ -31,6 +31,8 @@ import javax.annotation.Nullable;
|
|||||||
*/
|
*/
|
||||||
public abstract class MPSite {
|
public abstract class MPSite {
|
||||||
|
|
||||||
|
public abstract MPUser<?> getUser();
|
||||||
|
|
||||||
public abstract String getSiteName();
|
public abstract String getSiteName();
|
||||||
|
|
||||||
public abstract void setSiteName(String siteName);
|
public abstract void setSiteName(String siteName);
|
||||||
@ -43,24 +45,28 @@ public abstract class MPSite {
|
|||||||
|
|
||||||
public abstract void setResultType(MPResultType resultType);
|
public abstract void setResultType(MPResultType resultType);
|
||||||
|
|
||||||
|
public abstract MPResultType getLoginType();
|
||||||
|
|
||||||
|
public abstract void setLoginType(@Nullable MPResultType loginType);
|
||||||
|
|
||||||
public abstract MPAlgorithm getAlgorithm();
|
public abstract MPAlgorithm getAlgorithm();
|
||||||
|
|
||||||
public abstract void setAlgorithm(MPAlgorithm algorithm);
|
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)
|
@Nullable final String siteContent)
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
|
|
||||||
return masterKey.siteResult(
|
return getUser().getMasterKey().siteResult(
|
||||||
getSiteName(), getSiteCounter(), keyPurpose, keyContext, getResultType(), siteContent, getAlgorithm() );
|
getSiteName(), getSiteCounter(), keyPurpose, keyContext, getResultType(), siteContent, getAlgorithm() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String loginFor(final MPMasterKey masterKey, final MPResultType loginType, @Nullable final String loginContent)
|
public String getLogin(@Nullable final String loginContent)
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
|
|
||||||
return masterKey.siteResult(
|
return getUser().getMasterKey().siteResult(
|
||||||
getSiteName(), getAlgorithm().mpw_default_counter(), MPKeyPurpose.Identification, null, loginType, loginContent,
|
getSiteName(), getAlgorithm().mpw_default_counter(), MPKeyPurpose.Identification, null,
|
||||||
getAlgorithm() );
|
getLoginType(), loginContent, getAlgorithm() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword.model;
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import com.lyndir.masterpassword.MPKeyUnavailableException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,10 +31,10 @@ import javax.annotation.Nonnull;
|
|||||||
public interface MPUnmarshaller {
|
public interface MPUnmarshaller {
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
MPFileUser unmarshall(@Nonnull File file)
|
MPFileUser unmarshall(@Nonnull File file, @Nullable char[] masterPassword)
|
||||||
throws IOException, MPMarshalException;
|
throws IOException, MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException;
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
MPFileUser unmarshall(@Nonnull String content)
|
MPFileUser unmarshall(@Nonnull String content, @Nullable char[] masterPassword)
|
||||||
throws MPMarshalException;
|
throws MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ package com.lyndir.masterpassword.model;
|
|||||||
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
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.lhunath.opal.system.CodeUtils;
|
||||||
import com.lyndir.masterpassword.*;
|
import com.lyndir.masterpassword.*;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -44,12 +43,16 @@ public abstract class MPUser<S extends MPSite> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public MPMasterKey getMasterKey() {
|
public MPMasterKey getMasterKey()
|
||||||
return Preconditions.checkNotNull( key, "User is not authenticated: %s", getFullName() );
|
throws MPKeyUnavailableException {
|
||||||
|
if (key == null)
|
||||||
|
throw new MPKeyUnavailableException();
|
||||||
|
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String exportKeyID()
|
public String exportKeyID()
|
||||||
throws MPInvalidatedException {
|
throws MPKeyUnavailableException {
|
||||||
return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithm() ) );
|
return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithm() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ public class MPMasterKeyTest {
|
|||||||
masterKey.getKeyID( testCase.getAlgorithm() );
|
masterKey.getKeyID( testCase.getAlgorithm() );
|
||||||
fail( "[testMasterKey] invalidate ineffective: " + testCase );
|
fail( "[testMasterKey] invalidate ineffective: " + testCase );
|
||||||
}
|
}
|
||||||
catch (final MPInvalidatedException ignored) {
|
catch (final MPKeyUnavailableException ignored) {
|
||||||
}
|
}
|
||||||
assertNotEquals(
|
assertNotEquals(
|
||||||
masterPassword,
|
masterPassword,
|
||||||
|
@ -18,8 +18,11 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword;
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
import com.lyndir.masterpassword.model.MPJSONUnmarshaller;
|
import com.google.common.base.Charsets;
|
||||||
import java.io.File;
|
import com.google.common.io.CharStreams;
|
||||||
|
import com.lyndir.masterpassword.model.*;
|
||||||
|
import java.io.*;
|
||||||
|
import org.testng.Assert;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
|
||||||
@ -31,7 +34,12 @@ public class MPModelTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testMasterKey()
|
public void testMasterKey()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
System.err.println( new MPJSONUnmarshaller().unmarshall(
|
File file = new File( "/Users/lhunath/.mpw.d/Maarten Billemont.mpsites.json" );
|
||||||
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." );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,7 +316,7 @@ public class EmergencyActivity extends Activity {
|
|||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
catch (final MPInvalidatedException ignored) {
|
catch (final MPKeyUnavailableException ignored) {
|
||||||
sitePasswordField.setText( "" );
|
sitePasswordField.setText( "" );
|
||||||
progressView.setVisibility( View.INVISIBLE );
|
progressView.setVisibility( View.INVISIBLE );
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ public final class Preferences {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public MPResultType getDefaultResultType() {
|
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) {
|
public boolean setDefaultVersion(final MPMasterKey.Version value) {
|
||||||
|
@ -18,10 +18,14 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword.gui.model;
|
package com.lyndir.masterpassword.gui.model;
|
||||||
|
|
||||||
|
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
|
||||||
|
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
import com.lyndir.masterpassword.MPAlgorithm;
|
import com.lyndir.masterpassword.MPAlgorithm;
|
||||||
import com.lyndir.masterpassword.MPResultType;
|
import com.lyndir.masterpassword.MPResultType;
|
||||||
import com.lyndir.masterpassword.model.MPSite;
|
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 {
|
public class IncognitoSite extends MPSite {
|
||||||
|
|
||||||
|
private final IncognitoUser user;
|
||||||
|
|
||||||
private String siteName;
|
private String siteName;
|
||||||
private UnsignedInteger siteCounter;
|
private UnsignedInteger siteCounter;
|
||||||
private MPResultType resultType;
|
private MPResultType resultType;
|
||||||
|
private MPResultType loginType;
|
||||||
private MPAlgorithm algorithm;
|
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) {
|
final MPAlgorithm algorithm) {
|
||||||
|
this.user = user;
|
||||||
this.siteName = siteName;
|
this.siteName = siteName;
|
||||||
this.siteCounter = siteCounter;
|
this.siteCounter = siteCounter;
|
||||||
this.resultType = resultType;
|
this.resultType = resultType;
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPUser<?> getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSiteName() {
|
public String getSiteName() {
|
||||||
return siteName;
|
return siteName;
|
||||||
@ -62,6 +75,16 @@ public class IncognitoSite extends MPSite {
|
|||||||
this.resultType = resultType;
|
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
|
@Override
|
||||||
public MPAlgorithm getAlgorithm() {
|
public MPAlgorithm getAlgorithm() {
|
||||||
return algorithm;
|
return algorithm;
|
||||||
|
@ -86,9 +86,8 @@ public class IncognitoAuthenticationPanel extends AuthenticationPanel<IncognitoU
|
|||||||
return new PasswordFrame<IncognitoUser, IncognitoSite>( Preconditions.checkNotNull( getSelectedUser() ) ) {
|
return new PasswordFrame<IncognitoUser, IncognitoSite>( Preconditions.checkNotNull( getSelectedUser() ) ) {
|
||||||
@Override
|
@Override
|
||||||
protected IncognitoSite createSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter,
|
protected IncognitoSite createSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter,
|
||||||
final MPResultType resultType,
|
final MPResultType resultType, final MPAlgorithm algorithm) {
|
||||||
final MPAlgorithm algorithm) {
|
return new IncognitoSite( user, siteName, siteCounter, resultType, algorithm );
|
||||||
return new IncognitoSite( siteName, siteCounter, resultType, algorithm );
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
siteCounterField = Components.spinner( siteCounterModel ) );
|
siteCounterField = Components.spinner( siteCounterModel ) );
|
||||||
sitePanel.add( siteSettings );
|
sitePanel.add( siteSettings );
|
||||||
resultTypeField.setFont( Res.valueFont().deriveFont( resultTypeField.getFont().getSize2D() ) );
|
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() {
|
resultTypeField.addItemListener( new ItemListener() {
|
||||||
@Override
|
@Override
|
||||||
public void itemStateChanged(final ItemEvent e) {
|
public void itemStateChanged(final ItemEvent e) {
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit e886da7af01747972cde23ff09827b56dbba973c
|
Subproject commit 54bd876ed6b8cebba3fdfe8b546d1783894d5401
|
Loading…
Reference in New Issue
Block a user