2
0

Refactor masterpassword-model

This commit is contained in:
Maarten Billemont 2018-05-15 13:53:27 -04:00
parent 8d7c351912
commit bda1ac3bd4
34 changed files with 878 additions and 650 deletions

View File

@ -5,10 +5,10 @@ plugins {
description = 'Master Password Algorithm Implementation' description = 'Master Password Algorithm Implementation'
dependencies { dependencies {
compile( group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.6-p11' ) { compile( group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: 'GIT-SNAPSHOT' ) {
exclude( module: 'joda-time' ) exclude( module: 'joda-time' )
} }
compile group: 'com.lyndir.lhunath.opal', name: 'opal-crypto', version: '1.6-p11' compile group: 'com.lyndir.lhunath.opal', name: 'opal-crypto', version: 'GIT-SNAPSHOT'
compile group: 'com.lambdaworks', name: 'scrypt', version: '1.4.0' compile group: 'com.lambdaworks', name: 'scrypt', version: '1.4.0'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.9.5' compile 'com.fasterxml.jackson.core:jackson-annotations:2.9.5'

View File

@ -59,7 +59,7 @@ public abstract class MPAlgorithm {
/** /**
* mpw: defaults: password result type. * mpw: defaults: password result type.
*/ */
public abstract MPResultType mpw_default_password_type(); public abstract MPResultType mpw_default_result_type();
/** /**
* mpw: defaults: login result type. * mpw: defaults: login result type.

View File

@ -247,7 +247,7 @@ public class MPAlgorithmV0 extends MPAlgorithm {
} }
@Override @Override
public MPResultType mpw_default_password_type() { public MPResultType mpw_default_result_type() {
return MPResultType.GeneratedLong; return MPResultType.GeneratedLong;
} }

View File

@ -1,212 +0,0 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.*;
import java.util.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.joda.time.Instant;
import org.joda.time.ReadableInstant;
/**
* @author lhunath, 14-12-05
*/
public class MPFileSite extends MPSite {
private final MPFileUser user;
private String siteName;
private UnsignedInteger siteCounter;
@Nullable
private String siteState;
private MPResultType resultType;
private MPAlgorithm algorithm;
@Nullable
private String loginState;
private MPResultType loginType;
@Nullable
private String url;
private int uses;
private ReadableInstant lastUsed;
private final Collection<MPFileQuestion> questions = new LinkedHashSet<>();
public MPFileSite(final MPFileUser user, final String siteName) {
this( user, siteName, null, null, user.getAlgorithm() );
}
public MPFileSite(final MPFileUser user, final String siteName, @Nullable final UnsignedInteger siteCounter,
@Nullable final MPResultType resultType, final MPAlgorithm algorithm) {
this( user, siteName, null, siteCounter, resultType, algorithm,
null, null, null, 0, new Instant() );
}
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 loginState, @Nullable final MPResultType loginType,
@Nullable final String url, final int uses, final ReadableInstant lastUsed) {
this.user = user;
this.algorithm = algorithm;
this.siteName = siteName;
this.siteState = siteState;
this.siteCounter = ifNotNullElse( siteCounter, getAlgorithm().mpw_default_counter() );
this.resultType = ifNotNullElse( resultType, getAlgorithm().mpw_default_password_type() );
this.loginState = loginState;
this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
this.url = url;
this.uses = uses;
this.lastUsed = lastUsed;
}
public String getResult()
throws MPKeyUnavailableException {
return getResult( MPKeyPurpose.Authentication, null );
}
public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
throws MPKeyUnavailableException {
return getResult( keyPurpose, keyContext, siteState );
}
public String getLogin()
throws MPKeyUnavailableException {
return getLogin( loginState );
}
@Override
public MPUser<?> getUser() {
return user;
}
@Override
public String getSiteName() {
return siteName;
}
@Override
public void setSiteName(final String siteName) {
this.siteName = siteName;
}
@Nullable
public String getSiteState() {
return siteState;
}
public void setSitePassword(final MPResultType resultType, @Nullable final String password)
throws MPKeyUnavailableException {
this.resultType = resultType;
if (password == null)
this.siteState = null;
else
this.siteState = getState(
MPKeyPurpose.Authentication, null, siteCounter, resultType, password );
}
@Override
public UnsignedInteger getSiteCounter() {
return siteCounter;
}
@Override
public void setSiteCounter(final UnsignedInteger siteCounter) {
this.siteCounter = siteCounter;
}
@Override
public MPResultType getResultType() {
return resultType;
}
@Override
public void setResultType(final MPResultType resultType) {
this.resultType = resultType;
}
@Override
public 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;
}
@Override
public void setAlgorithm(final MPAlgorithm algorithm) {
this.algorithm = algorithm;
}
@Override
public Collection<? extends MPQuestion> getQuestions() {
return Collections.unmodifiableCollection( questions );
}
@Nullable
public String getLoginState() {
return loginState;
}
public void setLoginName(@Nonnull final MPResultType loginType, @Nonnull final String loginName)
throws MPKeyUnavailableException {
this.loginType = loginType;
this.loginState = getState( MPKeyPurpose.Identification, null, null, this.loginType, loginName );
}
@Nullable
public String getUrl() {
return url;
}
public void setUrl(@Nullable final String url) {
this.url = url;
}
public int getUses() {
return uses;
}
public ReadableInstant getLastUsed() {
return lastUsed;
}
public void use() {
uses++;
lastUsed = new Instant();
user.use();
}
}

View File

@ -18,20 +18,21 @@
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model;
/** /**
* @author lhunath, 14-12-17 * @author lhunath, 14-12-17
*/ */
public class MPIncorrectMasterPasswordException extends Exception { public class MPIncorrectMasterPasswordException extends Exception {
private final MPFileUser user; private final MPUser<?> user;
public MPIncorrectMasterPasswordException(final MPFileUser user) { public MPIncorrectMasterPasswordException(final MPUser<?> user) {
super( "Incorrect master password for user: " + user.getFullName() ); super( "Incorrect master password for user: " + user.getFullName() );
this.user = user; this.user = user;
} }
public MPFileUser getUser() { public MPUser<?> getUser() {
return user; return user;
} }
} }

View File

@ -18,24 +18,35 @@
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.MPKeyUnavailableException;
import com.lyndir.masterpassword.MPResultType;
import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
/** /**
* @author lhunath, 2018-05-14 * @author lhunath, 2018-05-15
*/ */
public abstract class MPQuestion { public interface MPQuestion extends Comparable<MPQuestion> {
public abstract MPSite getSite(); // -- Meta
public abstract String getKeyword(); @Nonnull
String getKeyword();
public abstract MPResultType getType(); // -- Algorithm
public String getAnswer(@Nullable final String state) @Nonnull
throws MPKeyUnavailableException { MPResultType getType();
return getSite().getResult( MPKeyPurpose.Recovery, getKeyword(), null, getType(), state ); void setType(MPResultType type);
}
@Nonnull
String getAnswer(@Nullable String state)
throws MPKeyUnavailableException;
// -- Relationship
@Nonnull
MPSite getSite();
} }

View File

@ -18,90 +18,50 @@
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.*;
import java.util.Collection; import java.util.Collection;
import java.util.Objects;
import javax.annotation.Nullable; import javax.annotation.Nullable;
/** /**
* @author lhunath, 14-12-16 * @author lhunath, 2018-05-14
*/ */
public abstract class MPSite { public interface MPSite extends Comparable<MPSite> {
public abstract MPUser<?> getUser(); // - Meta
public abstract String getSiteName(); String getName();
public abstract void setSiteName(String siteName); void setName(String name);
public abstract UnsignedInteger getSiteCounter(); // - Algorithm
public abstract void setSiteCounter(UnsignedInteger siteCounter); MPAlgorithm getAlgorithm();
public abstract MPResultType getResultType(); void setAlgorithm(MPAlgorithm algorithm);
public abstract void setResultType(MPResultType resultType); UnsignedInteger getCounter();
public abstract MPResultType getLoginType(); void setCounter(UnsignedInteger counter);
public abstract void setLoginType(@Nullable MPResultType loginType); MPResultType getResultType();
public abstract MPAlgorithm getAlgorithm(); void setResultType(MPResultType resultType);
public abstract void setAlgorithm(MPAlgorithm algorithm); MPResultType getLoginType();
public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext, void setLoginType(@Nullable MPResultType loginType);
@Nullable final String state)
throws MPKeyUnavailableException {
return getResult( keyPurpose, keyContext, getSiteCounter(), getResultType(), state ); String getResult(MPKeyPurpose keyPurpose, @Nullable String keyContext, @Nullable String state)
} throws MPKeyUnavailableException;
protected String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext, String getLogin(@Nullable String state)
@Nullable final UnsignedInteger siteCounter, final MPResultType type, throws MPKeyUnavailableException;
@Nullable final String state)
throws MPKeyUnavailableException { // - Relations
return getUser().getMasterKey().siteResult( MPUser<? extends MPSite> getUser();
getSiteName(), ifNotNullElse( siteCounter, getAlgorithm().mpw_default_counter() ), keyPurpose, keyContext,
type, state, getAlgorithm() ); Collection<? extends MPQuestion> getQuestions();
}
protected String getState(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
@Nullable final UnsignedInteger siteCounter, final MPResultType type,
@Nullable final String state)
throws MPKeyUnavailableException {
return getUser().getMasterKey().siteState(
getSiteName(), ifNotNullElse( siteCounter, getAlgorithm().mpw_default_counter() ), keyPurpose, keyContext,
type, state, getAlgorithm() );
}
public String getLogin(@Nullable final String loginContent)
throws MPKeyUnavailableException {
return getResult( MPKeyPurpose.Identification, null,null, getLoginType(), loginContent );
}
public abstract Collection<? extends MPQuestion> getQuestions();
@Override
public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPSite) && Objects.equals( getSiteName(), ((MPSite) obj).getSiteName() ));
}
@Override
public int hashCode() {
return Objects.hashCode( getSiteName() );
}
@Override
public String toString() {
return strf( "{%s: %s}", getClass().getSimpleName(), getSiteName() );
}
} }

View File

@ -21,35 +21,41 @@ package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*; import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import java.util.Objects; import java.util.Objects;
import org.jetbrains.annotations.NotNull;
/** /**
* @author lhunath, 14-12-07 * @author lhunath, 14-12-07
*/ */
public class MPSiteResult { public class MPSiteResult implements Comparable<MPSiteResult> {
private final MPFileSite site; private final MPSite site;
public MPSiteResult(final MPFileSite site) { public MPSiteResult(final MPSite site) {
this.site = site; this.site = site;
} }
public MPFileSite getSite() { public MPSite getSite() {
return site; return site;
} }
@Override @Override
public boolean equals(final Object obj) { public int hashCode() {
return (this == obj) || ((obj instanceof MPSiteResult) && Objects.equals( site, ((MPSiteResult) obj).site )); return Objects.hashCode( getSite() );
} }
@Override @Override
public int hashCode() { public boolean equals(final Object obj) {
return Objects.hashCode( site ); return (this == obj) || ((obj instanceof MPSiteResult) && Objects.equals( getSite(), ((MPSiteResult) obj).getSite() ));
}
@Override
public int compareTo(@NotNull final MPSiteResult o) {
return getSite().compareTo( o.getSite() );
} }
@Override @Override
public String toString() { public String toString() {
return strf( "{MPSiteResult: %s}", site ); return strf( "{%s: %s}", getClass().getSimpleName(), getSite() );
} }
} }

View File

@ -18,72 +18,78 @@
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.*;
import java.util.Collection; import java.util.Collection;
import java.util.Objects;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
/** /**
* @author lhunath, 2014-06-08 * @author lhunath, 2018-05-14
*/ */
public abstract class MPUser<S extends MPSite> { public interface MPUser<S extends MPSite> extends Comparable<MPUser<?>> {
// - Meta
int getAvatar();
void setAvatar(int avatar);
@Nonnull
String getFullName();
// - Algorithm
@Nonnull
MPAlgorithm getAlgorithm();
void setAlgorithm(MPAlgorithm algorithm);
@Nullable @Nullable
protected MPMasterKey key; byte[] getKeyID();
public abstract String getFullName(); @Nullable
String exportKeyID();
public boolean isMasterKeyAvailable() { /**
return key != null; * Performs an authentication attempt against the keyID for this user.
} *
* Note: If a keyID is not set, authentication will always succeed and the keyID will be set to match the given master password.
@Nonnull *
public MPMasterKey getMasterKey() * @param masterPassword The password to authenticate with.
throws MPKeyUnavailableException { *
if (key == null) * @throws MPIncorrectMasterPasswordException If authentication fails due to the given master password not matching the user's keyID.
throw new MPKeyUnavailableException(); */
void authenticate(char[] masterPassword)
return key;
}
public String exportKeyID()
throws MPKeyUnavailableException {
return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithm() ) );
}
public abstract MPAlgorithm getAlgorithm();
public int getAvatar() {
return 0;
}
public abstract void addSite(S site);
public abstract void deleteSite(S site);
public abstract Collection<S> findSites(String query);
@Nonnull
public abstract MPMasterKey authenticate(char[] masterPassword)
throws MPIncorrectMasterPasswordException; throws MPIncorrectMasterPasswordException;
@Override /**
public int hashCode() { * Performs an authentication attempt against the keyID for this user.
return Objects.hashCode( getFullName() ); *
} * Note: If a keyID is not set, authentication will always succeed and the keyID will be set to match the given key.
*
* @param masterKey The master key to authenticate with.
*
* @throws MPIncorrectMasterPasswordException If authentication fails due to the given master password not matching the user's keyID.
*/
void authenticate(MPMasterKey masterKey)
throws MPIncorrectMasterPasswordException, MPKeyUnavailableException;
@Override boolean isMasterKeyAvailable();
public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPUser) && Objects.equals( getFullName(), ((MPUser<?>) obj).getFullName() ));
}
@Override @Nonnull
public String toString() { MPMasterKey getMasterKey()
return strf( "{%s: %s}", getClass().getSimpleName(), getFullName() ); throws MPKeyUnavailableException;
}
// - Relations
void addSite(S site);
void deleteSite(S site);
@Nonnull
Collection<S> getSites();
@Nonnull
Collection<S> findSites(String query);
} }

View File

@ -19,6 +19,7 @@
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model;
import com.google.common.collect.*; import com.google.common.collect.*;
import com.lyndir.masterpassword.model.impl.MPFileUser;
import java.util.Map; import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
@ -26,28 +27,28 @@ import java.util.SortedSet;
/** /**
* @author lhunath, 14-12-05 * @author lhunath, 14-12-05
*/ */
public abstract class MPUserManager { public abstract class MPUserManager<U extends MPUser<?>> {
private final Map<String, MPFileUser> usersByName = Maps.newHashMap(); private final Map<String, U> usersByName = Maps.newHashMap();
protected MPUserManager(final Iterable<MPFileUser> users) { protected MPUserManager(final Iterable<U> users) {
for (final MPFileUser user : users) for (final U user : users)
usersByName.put( user.getFullName(), user ); usersByName.put( user.getFullName(), user );
} }
public SortedSet<MPFileUser> getUsers() { public SortedSet<U> getUsers() {
return FluentIterable.from( usersByName.values() ).toSortedSet( Ordering.natural() ); return FluentIterable.from( usersByName.values() ).toSortedSet( Ordering.natural() );
} }
public MPFileUser getUserNamed(final String fullName) { public U getUserNamed(final String fullName) {
return usersByName.get( fullName ); return usersByName.get( fullName );
} }
public void addUser(final MPFileUser user) { public void addUser(final U user) {
usersByName.put( user.getFullName(), user ); usersByName.put( user.getFullName(), user );
} }
public void deleteUser(final MPFileUser user) { public void deleteUser(final U user) {
usersByName.remove( user.getFullName() ); usersByName.remove( user.getFullName() );
} }
} }

View File

@ -0,0 +1,93 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword.model.impl;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.lyndir.masterpassword.*;
import com.lyndir.masterpassword.model.MPQuestion;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
/**
* @author lhunath, 2018-05-14
*/
public abstract class MPBasicQuestion implements MPQuestion {
private final String keyword;
private MPResultType type;
protected MPBasicQuestion(final String keyword, final MPResultType type) {
this.keyword = keyword;
this.type = type;
}
@Nonnull
@Override
public String getKeyword() {
return keyword;
}
@Nonnull
@Override
public MPResultType getType() {
return type;
}
@Override
public void setType(final MPResultType type) {
this.type = type;
}
@Nonnull
@Override
public String getAnswer(@Nullable final String state)
throws MPKeyUnavailableException {
return getSite().getResult( MPKeyPurpose.Recovery, getKeyword(), null, getType(), state );
}
@Nonnull
@Override
public abstract MPBasicSite getSite();
@Override
public int hashCode() {
return Objects.hashCode( getKeyword() );
}
@Override
public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPQuestion) && Objects.equals( getKeyword(), ((MPQuestion) obj).getKeyword() ));
}
@Override
public int compareTo(@NotNull final MPQuestion o) {
return getKeyword().compareTo( o.getKeyword() );
}
@Override
public String toString() {
return strf( "{%s: %s}", getClass().getSimpleName(), getKeyword() );
}
}

View File

@ -0,0 +1,165 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword.model.impl;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.*;
import com.lyndir.masterpassword.model.MPQuestion;
import com.lyndir.masterpassword.model.MPSite;
import java.util.*;
import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
/**
* @author lhunath, 14-12-16
*/
public abstract class MPBasicSite implements MPSite {
private String name;
private MPAlgorithm algorithm;
private UnsignedInteger counter;
private MPResultType resultType;
private MPResultType loginType;
private final Collection<MPFileQuestion> questions = new LinkedHashSet<>();
protected MPBasicSite(final String name, final MPAlgorithm algorithm) {
this( name, algorithm, null, null, null );
}
protected MPBasicSite(final String name, final MPAlgorithm algorithm, @Nullable final UnsignedInteger counter,
@Nullable final MPResultType resultType, @Nullable final MPResultType loginType) {
this.name = name;
this.algorithm = algorithm;
this.counter = (counter == null)? algorithm.mpw_default_counter(): counter;
this.resultType = (resultType == null)? algorithm.mpw_default_result_type(): resultType;
this.loginType = (loginType == null)? algorithm.mpw_default_login_type(): loginType;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(final String name) {
this.name = name;
}
@Override
public MPAlgorithm getAlgorithm() {
return algorithm;
}
@Override
public void setAlgorithm(final MPAlgorithm algorithm) {
this.algorithm = algorithm;
}
@Override
public UnsignedInteger getCounter() {
return counter;
}
@Override
public void setCounter(final UnsignedInteger counter) {
this.counter = counter;
}
@Override
public MPResultType getResultType() {
return resultType;
}
@Override
public void setResultType(final MPResultType 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
public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext, @Nullable final String state)
throws MPKeyUnavailableException {
return getResult( keyPurpose, keyContext, getCounter(), getResultType(), state );
}
protected String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
@Nullable final UnsignedInteger counter, final MPResultType type, @Nullable final String state)
throws MPKeyUnavailableException {
return getUser().getMasterKey().siteResult(
getName(), ifNotNullElse( counter, getAlgorithm().mpw_default_counter() ), keyPurpose, keyContext,
type, state, getAlgorithm() );
}
protected String getState(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
@Nullable final UnsignedInteger counter, final MPResultType type, @Nullable final String state)
throws MPKeyUnavailableException {
return getUser().getMasterKey().siteState(
getName(), ifNotNullElse( counter, getAlgorithm().mpw_default_counter() ), keyPurpose, keyContext,
type, state, getAlgorithm() );
}
@Override
public String getLogin(@Nullable final String state)
throws MPKeyUnavailableException {
return getResult( MPKeyPurpose.Identification, null, null, getLoginType(), state );
}
@Override
public Collection<? extends MPQuestion> getQuestions() {
return Collections.unmodifiableCollection( questions );
}
@Override
public int hashCode() {
return Objects.hashCode( getName() );
}
@Override
public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPSite) && Objects.equals( getName(), ((MPSite) obj).getName() ));
}
@Override
public int compareTo(@NotNull final MPSite o) {
return getName().compareTo( o.getName() );
}
@Override
public String toString() {
return strf( "{%s: %s}", getClass().getSimpleName(), getName() );
}
}

View File

@ -0,0 +1,186 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword.model.impl;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.collect.ImmutableList;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.masterpassword.*;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import com.lyndir.masterpassword.model.MPUser;
import java.util.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* @author lhunath, 2014-06-08
*/
public abstract class MPBasicUser<S extends MPBasicSite> implements MPUser<S> {
private int avatar;
private final String fullName;
private MPAlgorithm algorithm;
@Nullable
protected MPMasterKey masterKey;
private final Collection<S> sites = new LinkedHashSet<>();
protected MPBasicUser(final String fullName, final MPAlgorithm algorithm) {
this( 0, fullName, algorithm );
}
protected MPBasicUser(final int avatar, final String fullName, final MPAlgorithm algorithm) {
this.avatar = avatar;
this.fullName = fullName;
this.algorithm = algorithm;
}
@Override
public int getAvatar() {
return avatar;
}
@Override
public void setAvatar(final int avatar) {
this.avatar = avatar;
}
@Nonnull
@Override
public String getFullName() {
return fullName;
}
@Nonnull
@Override
public MPAlgorithm getAlgorithm() {
return algorithm;
}
@Override
public void setAlgorithm(final MPAlgorithm algorithm) {
this.algorithm = algorithm;
}
@Nullable
@Override
public byte[] getKeyID() {
try {
return getMasterKey().getKeyID( getAlgorithm() );
}
catch (final MPKeyUnavailableException ignore) {
return null;
}
}
@Nullable
@Override
public String exportKeyID() {
return CodeUtils.encodeHex( getKeyID() );
}
@Override
public void authenticate(final char[] masterPassword)
throws MPIncorrectMasterPasswordException {
try {
authenticate( new MPMasterKey( getFullName(), masterPassword ) );
}
catch (final MPKeyUnavailableException e) {
throw new IllegalStateException( e );
}
}
@Override
public void authenticate(final MPMasterKey masterKey)
throws MPIncorrectMasterPasswordException, MPKeyUnavailableException {
if (!masterKey.getFullName().equals( getFullName() ))
throw new IllegalArgumentException(
"Master key (for " + masterKey.getFullName() + ") is not for this user (" + getFullName() + ")." );
byte[] keyID = getKeyID();
if ((keyID != null) && !Arrays.equals( masterKey.getKeyID( getAlgorithm() ), keyID ))
throw new MPIncorrectMasterPasswordException( this );
this.masterKey = masterKey;
}
@Override
public boolean isMasterKeyAvailable() {
return masterKey != null;
}
@Nonnull
@Override
public MPMasterKey getMasterKey()
throws MPKeyUnavailableException {
if (masterKey == null)
throw new MPKeyUnavailableException();
return masterKey;
}
@Override
public void addSite(final S site) {
sites.add( site );
}
@Override
public void deleteSite(final S site) {
sites.remove( site );
}
@Nonnull
@Override
public Collection<S> getSites() {
return Collections.unmodifiableCollection( sites );
}
@Nonnull
@Override
public Collection<S> findSites(final String query) {
ImmutableList.Builder<S> results = ImmutableList.builder();
for (final S site : getSites())
if (site.getName().startsWith( query ))
results.add( site );
return results.build();
}
@Override
public int hashCode() {
return Objects.hashCode( getFullName() );
}
@Override
public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPUser) && Objects.equals( getFullName(), ((MPUser<?>) obj).getFullName() ));
}
@Override
public int compareTo(final MPUser<?> o) {
return getFullName().compareTo( o.getFullName() );
}
@Override
public String toString() {
return strf( "{%s: %s}", getClass().getSimpleName(), getFullName() );
}
}

View File

@ -16,69 +16,52 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
/** /**
* @author lhunath, 2018-05-14 * @author lhunath, 2018-05-14
*/ */
public class MPFileQuestion extends MPQuestion { public class MPFileQuestion extends MPBasicQuestion {
private final MPSite site; private final MPFileSite site;
private String keyword;
@Nullable @Nullable
private String state; private String state;
private MPResultType type;
public MPFileQuestion(final MPSite site, final String keyword, @Nullable final String state, @Nullable final MPResultType type) { public MPFileQuestion(final MPFileSite site, final String keyword,
@Nullable final MPResultType type, @Nullable final String state) {
super( keyword, ifNotNullElse( type, site.getAlgorithm().mpw_default_answer_type() ) );
this.site = site; this.site = site;
this.keyword = keyword;
this.state = state; this.state = state;
this.type = ifNotNullElse( type, site.getAlgorithm().mpw_default_answer_type() );
}
@Override
public MPSite getSite() {
return site;
}
@Override
public String getKeyword() {
return keyword;
}
public void setKeyword(final String keyword) {
this.keyword = keyword;
}
public void setAnswer(final MPResultType type, @Nullable final String answer)
throws MPKeyUnavailableException {
this.type = type;
if (answer == null)
this.state = null;
else
this.state = getSite().getState(
MPKeyPurpose.Recovery, getKeyword(), null, type, answer );
}
@Override
public MPResultType getType() {
return type;
}
public void setType(final MPResultType type) {
this.type = type;
} }
public String getAnswer() public String getAnswer()
throws MPKeyUnavailableException { throws MPKeyUnavailableException {
return getAnswer( state ); return getAnswer( state );
} }
public void setAnswer(final MPResultType type, @Nullable final String answer)
throws MPKeyUnavailableException {
setType( type );
if (answer == null)
this.state = null;
else
this.state = getSite().getState(
MPKeyPurpose.Recovery, getKeyword(), null, getType(), answer );
}
@Nonnull
@Override
public MPFileSite getSite() {
return site;
}
} }

View File

@ -0,0 +1,150 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword.model.impl;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.*;
import com.lyndir.masterpassword.model.MPUser;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.joda.time.Instant;
import org.joda.time.ReadableInstant;
/**
* @author lhunath, 14-12-05
*/
public class MPFileSite extends MPBasicSite {
private final MPFileUser user;
@Nullable
private String url;
private int uses;
private ReadableInstant lastUsed;
@Nullable
private String resultState;
@Nullable
private String loginState;
public MPFileSite(final MPFileUser user, final String name) {
this( user, name, null, null, null );
}
public MPFileSite(final MPFileUser user, final String name,
@Nullable final MPAlgorithm algorithm, @Nullable final UnsignedInteger counter,
@Nullable final MPResultType resultType) {
this( user, name, algorithm, counter, resultType, null,
null, null, null, 0, new Instant() );
}
protected MPFileSite(final MPFileUser user, final String name,
@Nullable final MPAlgorithm algorithm, @Nullable final UnsignedInteger counter,
@Nullable final MPResultType resultType, @Nullable final String resultState,
@Nullable final MPResultType loginType, @Nullable final String loginState,
@Nullable final String url, final int uses, final ReadableInstant lastUsed) {
super( name, (algorithm == null)? user.getAlgorithm(): algorithm, counter, resultType, loginType );
this.user = user;
this.resultState = resultState;
this.loginState = loginState;
this.url = url;
this.uses = uses;
this.lastUsed = lastUsed;
}
@Nullable
public String getUrl() {
return url;
}
public void setUrl(@Nullable final String url) {
this.url = url;
}
public int getUses() {
return uses;
}
public ReadableInstant getLastUsed() {
return lastUsed;
}
public void use() {
uses++;
lastUsed = new Instant();
user.use();
}
public String getResult()
throws MPKeyUnavailableException {
return getResult( MPKeyPurpose.Authentication, null );
}
public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
throws MPKeyUnavailableException {
return getResult( keyPurpose, keyContext, getResultState() );
}
public String getLogin()
throws MPKeyUnavailableException {
return getLogin( getLoginState() );
}
@Nullable
public String getResultState() {
return resultState;
}
public void setSitePassword(final MPResultType resultType, @Nullable final String password)
throws MPKeyUnavailableException {
setResultType( resultType );
if (password == null)
this.resultState = null;
else
this.resultState = getState(
MPKeyPurpose.Authentication, null, getCounter(), getResultType(), password );
}
@Nullable
public String getLoginState() {
return loginState;
}
public void setLoginName(@Nonnull final MPResultType loginType, @Nullable final String loginName)
throws MPKeyUnavailableException {
setLoginType( loginType );
if (loginName == null)
this.loginState = null;
else
this.loginState = getState(
MPKeyPurpose.Identification, null, null, getLoginType(), loginName );
}
@Override
public MPUser<? extends com.lyndir.masterpassword.model.MPSite> getUser() {
return user;
}
}

View File

@ -16,13 +16,12 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.*;
import java.util.*; import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import com.lyndir.masterpassword.model.MPUser;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.joda.time.Instant; import org.joda.time.Instant;
@ -33,21 +32,16 @@ import org.joda.time.ReadableInstant;
* @author lhunath, 14-12-07 * @author lhunath, 14-12-07
*/ */
@SuppressWarnings("ComparableImplementedButEqualsNotOverridden") @SuppressWarnings("ComparableImplementedButEqualsNotOverridden")
public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileUser> { public class MPFileUser extends MPBasicUser<MPFileSite> {
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPFileUser.class ); private static final Logger logger = Logger.get( MPFileUser.class );
private final String fullName;
private final Collection<MPFileSite> sites = new LinkedHashSet<>();
@Nullable @Nullable
private byte[] keyID; private byte[] keyID;
private MPAlgorithm algorithm;
private MPMarshalFormat format; private MPMarshalFormat format;
private MPMarshaller.ContentMode contentMode; private MPMarshaller.ContentMode contentMode;
private int avatar;
private MPResultType defaultType; private MPResultType defaultType;
private ReadableInstant lastUsed; private ReadableInstant lastUsed;
@ -59,40 +53,43 @@ 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_password_type(), new Instant(), this( fullName, keyID, algorithm, 0, algorithm.mpw_default_result_type(), new Instant(),
MPMarshalFormat.DEFAULT, MPMarshaller.ContentMode.PROTECTED ); 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 MPResultType defaultType, final ReadableInstant lastUsed, final int avatar, final MPResultType defaultType, final ReadableInstant lastUsed,
final MPMarshalFormat format, final MPMarshaller.ContentMode contentMode) { final MPMarshalFormat format, final MPMarshaller.ContentMode contentMode) {
this.fullName = fullName; super( avatar, fullName, algorithm );
this.keyID = (keyID == null)? null: keyID.clone(); this.keyID = (keyID == null)? null: keyID.clone();
this.algorithm = algorithm;
this.avatar = avatar;
this.defaultType = defaultType; this.defaultType = defaultType;
this.lastUsed = lastUsed; this.lastUsed = lastUsed;
this.format = format; this.format = format;
this.contentMode = contentMode; this.contentMode = contentMode;
} }
@Override
public String getFullName() {
return fullName;
}
@Nullable @Nullable
@Override
public byte[] getKeyID() { public byte[] getKeyID() {
return (keyID == null)? null: keyID.clone(); return (keyID == null)? null: keyID.clone();
} }
@Override @Override
public MPAlgorithm getAlgorithm() { public void setAlgorithm(final MPAlgorithm algorithm) {
return algorithm; if (!algorithm.equals( getAlgorithm() ) && (keyID != null)) {
if (masterKey == null)
throw new IllegalStateException( "Cannot update algorithm when keyID is set but masterKey is unavailable." );
try {
keyID = masterKey.getKeyID( algorithm );
}
catch (final MPKeyUnavailableException e) {
throw new IllegalStateException( "Cannot update algorithm when keyID is set but masterKey is unavailable.", e );
}
} }
public void setAlgorithm(final MPAlgorithm algorithm) { super.setAlgorithm( algorithm );
this.algorithm = algorithm;
} }
public MPMarshalFormat getFormat() { public MPMarshalFormat getFormat() {
@ -111,15 +108,6 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
this.contentMode = contentMode; this.contentMode = contentMode;
} }
@Override
public int getAvatar() {
return avatar;
}
public void setAvatar(final int avatar) {
this.avatar = avatar;
}
public MPResultType getDefaultType() { public MPResultType getDefaultType() {
return defaultType; return defaultType;
} }
@ -136,30 +124,6 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
lastUsed = new Instant(); lastUsed = new Instant();
} }
public Collection<MPFileSite> getSites() {
return Collections.unmodifiableCollection( sites );
}
@Override
public void addSite(final MPFileSite site) {
sites.add( site );
}
@Override
public void deleteSite(final MPFileSite site) {
sites.remove( site );
}
@Override
public Collection<MPFileSite> findSites(final String query) {
ImmutableList.Builder<MPFileSite> results = ImmutableList.builder();
for (final MPFileSite site : getSites())
if (site.getSiteName().startsWith( query ))
results.add( site );
return results.build();
}
public void setJSON(final MPJSONFile json) { public void setJSON(final MPJSONFile json) {
this.json = json; this.json = json;
} }
@ -169,33 +133,13 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
return (json == null)? json = new MPJSONFile(): json; return (json == null)? json = new MPJSONFile(): json;
} }
/**
* Performs an authentication attempt against the keyID for this user.
*
* Note: If this user doesn't have a keyID set yet, authentication will always succeed and the key ID will be set as a result.
*
* @param masterPassword The password to authenticate with.
*
* @return The master key for the user if authentication was successful.
*
* @throws MPIncorrectMasterPasswordException If authentication fails due to the given master password not matching the user's keyID.
*/
@Nonnull
@Override @Override
public MPMasterKey authenticate(final char[] masterPassword) public void authenticate(final MPMasterKey masterKey)
throws MPIncorrectMasterPasswordException { throws MPIncorrectMasterPasswordException, MPKeyUnavailableException {
try { super.authenticate( masterKey );
key = new MPMasterKey( getFullName(), masterPassword );
if ((keyID == null) || (keyID.length == 0))
keyID = key.getKeyID( algorithm );
else if (!Arrays.equals( key.getKeyID( algorithm ), keyID ))
throw new MPIncorrectMasterPasswordException( this );
return key; if (keyID == null)
} keyID = masterKey.getKeyID( getAlgorithm() );
catch (final MPKeyUnavailableException e) {
throw logger.bug( e );
}
} }
void save() void save()
@ -204,11 +148,11 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
} }
@Override @Override
public int compareTo(final MPFileUser o) { public int compareTo(final MPUser<?> o) {
int comparison = getLastUsed().compareTo( o.getLastUsed() ); int comparison = (o instanceof MPFileUser)? getLastUsed().compareTo( ((MPFileUser) o).getLastUsed() ): 0;
if (comparison == 0) if (comparison != 0)
comparison = getFullName().compareTo( o.getFullName() );
return comparison; return comparison;
return super.compareTo( o );
} }
} }

View File

@ -16,7 +16,7 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.io.CharSink; import com.google.common.io.CharSink;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.*;
import com.lyndir.masterpassword.model.*;
import java.io.*; import java.io.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -37,7 +38,7 @@ import javax.annotation.Nonnull;
* @author lhunath, 14-12-07 * @author lhunath, 14-12-07
*/ */
@SuppressWarnings("CallToSystemGetenv") @SuppressWarnings("CallToSystemGetenv")
public class MPFileUserManager extends MPUserManager { public class MPFileUserManager extends MPUserManager<MPFileUser> {
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPFileUserManager.class ); private static final Logger logger = Logger.get( MPFileUserManager.class );
@ -137,7 +138,7 @@ public class MPFileUserManager extends MPUserManager {
} }
@Nonnull @Nonnull
private File getUserFile(final MPFileUser user, final MPMarshalFormat format) { private File getUserFile(final MPUser<?> user, final MPMarshalFormat format) {
return new File( path, user.getFullName() + format.fileSuffix() ); return new File( path, user.getFullName() + format.fileSuffix() );
} }

View File

@ -16,7 +16,7 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*; import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
@ -59,7 +59,7 @@ public class MPFlatMarshaller implements MPMarshaller {
for (final MPFileSite site : user.getSites()) { for (final MPFileSite site : user.getSites()) {
String loginName = site.getLoginState(); String loginName = site.getLoginState();
String password = site.getSiteState(); String password = site.getResultState();
if (!user.getContentMode().isRedacted()) { if (!user.getContentMode().isRedacted()) {
loginName = site.getLogin(); loginName = site.getLogin();
password = site.getResult(); password = site.getResult();
@ -71,9 +71,9 @@ public class MPFlatMarshaller implements MPMarshaller {
strf( "%d:%d:%d", // strf( "%d:%d:%d", //
site.getResultType().getType(), // type site.getResultType().getType(), // type
site.getAlgorithm().version().toInt(), // algorithm site.getAlgorithm().version().toInt(), // algorithm
site.getSiteCounter().intValue() ), // counter site.getCounter().intValue() ), // counter
ifNotNullElse( loginName, "" ), // loginName ifNotNullElse( loginName, "" ), // loginName
site.getSiteName(), // siteName site.getName(), // siteName
ifNotNullElse( password, "" ) // password ifNotNullElse( password, "" ) // password
) ); ) );
} }

View File

@ -16,7 +16,7 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
import com.google.common.base.*; import com.google.common.base.*;
import com.google.common.io.CharStreams; import com.google.common.io.CharStreams;
@ -25,6 +25,7 @@ import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.ConversionUtils; import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.*;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import java.io.*; import java.io.*;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -115,11 +116,11 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
switch (importFormat) { switch (importFormat) {
case 0: case 0:
site = new MPFileSite( user, // site = new MPFileSite( user, //
siteMatcher.group( 5 ), clearContent? null: siteMatcher.group( 6 ), siteMatcher.group( 5 ), MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
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( clearContent? null: siteMatcher.group( 6 ),
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) if (clearContent)
@ -128,12 +129,12 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
case 1: case 1:
site = new MPFileSite( user, // site = new MPFileSite( user, //
siteMatcher.group( 7 ), clearContent? null: siteMatcher.group( 8 ), siteMatcher.group( 7 ), MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
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( clearContent? null: siteMatcher.group( 8 ),
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(), MPResultType.GeneratedName, clearContent? null: siteMatcher.group( 6 ), 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) { if (clearContent) {

View File

@ -16,7 +16,7 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonAnySetter;

View File

@ -16,20 +16,16 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.CodeUtils; import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.*;
import java.io.IOException; import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import java.util.*; import java.util.*;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.joda.time.Instant; import org.joda.time.Instant;
@ -62,7 +58,7 @@ public class MPJSONFile extends MPJSONAnyObject {
user.avatar = modelUser.getAvatar(); user.avatar = modelUser.getAvatar();
user.full_name = modelUser.getFullName(); user.full_name = modelUser.getFullName();
user.last_used = MPConstant.dateTimeFormatter.print( modelUser.getLastUsed() ); user.last_used = MPConstant.dateTimeFormatter.print( modelUser.getLastUsed() );
user.key_id = CodeUtils.encodeHex( modelUser.getKeyID() ); user.key_id = modelUser.exportKeyID();
user.algorithm = modelUser.getAlgorithm().version(); user.algorithm = modelUser.getAlgorithm().version();
user.default_type = modelUser.getDefaultType(); user.default_type = modelUser.getDefaultType();
@ -75,21 +71,21 @@ public class MPJSONFile extends MPJSONAnyObject {
// Clear Text // Clear Text
content = modelSite.getResult(); content = modelSite.getResult();
loginContent = modelUser.getMasterKey().siteResult( loginContent = modelUser.getMasterKey().siteResult(
modelSite.getSiteName(), modelSite.getAlgorithm().mpw_default_counter(), modelSite.getName(), modelSite.getAlgorithm().mpw_default_counter(),
MPKeyPurpose.Identification, null, modelSite.getLoginType(), modelSite.getLoginState(), modelSite.getAlgorithm() ); MPKeyPurpose.Identification, null, modelSite.getLoginType(), modelSite.getLoginState(), modelSite.getAlgorithm() );
} else { } else {
// Redacted // Redacted
if (modelSite.getResultType().supportsTypeFeature( MPSiteFeature.ExportContent )) if (modelSite.getResultType().supportsTypeFeature( MPSiteFeature.ExportContent ))
content = modelSite.getSiteState(); content = modelSite.getResultState();
if (modelSite.getLoginType().supportsTypeFeature( MPSiteFeature.ExportContent )) if (modelSite.getLoginType().supportsTypeFeature( MPSiteFeature.ExportContent ))
loginContent = modelSite.getLoginState(); loginContent = modelSite.getLoginState();
} }
Site site = sites.get( modelSite.getSiteName() ); Site site = sites.get( modelSite.getName() );
if (site == null) if (site == null)
sites.put( modelSite.getSiteName(), site = new Site() ); sites.put( modelSite.getName(), site = new Site() );
site.type = modelSite.getResultType(); site.type = modelSite.getResultType();
site.counter = modelSite.getSiteCounter().longValue(); site.counter = modelSite.getCounter().longValue();
site.algorithm = modelSite.getAlgorithm().version(); site.algorithm = modelSite.getAlgorithm().version();
site.password = content; site.password = content;
site.login_name = loginContent; site.login_name = loginContent;
@ -140,7 +136,7 @@ public class MPJSONFile extends MPJSONAnyObject {
MPAlgorithm algorithm = ifNotNullElse( user.algorithm, MPMasterKey.Version.CURRENT ).getAlgorithm(); MPAlgorithm algorithm = ifNotNullElse( user.algorithm, MPMasterKey.Version.CURRENT ).getAlgorithm();
MPFileUser model = new MPFileUser( MPFileUser model = new MPFileUser(
user.full_name, CodeUtils.decodeHex( user.key_id ), algorithm, user.avatar, user.full_name, CodeUtils.decodeHex( user.key_id ), algorithm, user.avatar,
(user.default_type != null)? user.default_type: algorithm.mpw_default_password_type(), (user.default_type != null)? user.default_type: algorithm.mpw_default_result_type(),
(user.last_used != null)? MPConstant.dateTimeFormatter.parseDateTime( user.last_used ): new Instant(), (user.last_used != null)? MPConstant.dateTimeFormatter.parseDateTime( user.last_used ): new Instant(),
MPMarshalFormat.JSON, export.redacted? MPMarshaller.ContentMode.PROTECTED: MPMarshaller.ContentMode.VISIBLE ); MPMarshalFormat.JSON, export.redacted? MPMarshaller.ContentMode.PROTECTED: MPMarshaller.ContentMode.VISIBLE );
model.setJSON( this ); model.setJSON( this );
@ -151,9 +147,9 @@ public class MPJSONFile extends MPJSONAnyObject {
String siteName = siteEntry.getKey(); String siteName = siteEntry.getKey();
Site fileSite = siteEntry.getValue(); Site fileSite = siteEntry.getValue();
MPFileSite site = new MPFileSite( MPFileSite site = new MPFileSite(
model, siteName, export.redacted? fileSite.password: null, UnsignedInteger.valueOf( fileSite.counter ), model, siteName, fileSite.algorithm.getAlgorithm(), UnsignedInteger.valueOf( fileSite.counter ), fileSite.type,
fileSite.type, fileSite.algorithm.getAlgorithm(), export.redacted? fileSite.password: null,
export.redacted? fileSite.login_name: null, fileSite.login_type, fileSite.login_type, export.redacted? fileSite.login_name: null,
(fileSite._ext_mpw != null)? fileSite._ext_mpw.url: null, fileSite.uses, (fileSite._ext_mpw != null)? fileSite._ext_mpw.url: null, fileSite.uses,
(fileSite.last_used != null)? MPConstant.dateTimeFormatter.parseDateTime( fileSite.last_used ): new Instant() ); (fileSite.last_used != null)? MPConstant.dateTimeFormatter.parseDateTime( fileSite.last_used ): new Instant() );

View File

@ -16,9 +16,9 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
import static com.lyndir.masterpassword.model.MPJSONFile.objectMapper; import static com.lyndir.masterpassword.model.impl.MPJSONFile.objectMapper;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.lyndir.masterpassword.MPKeyUnavailableException; import com.lyndir.masterpassword.MPKeyUnavailableException;

View File

@ -16,13 +16,14 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
import static com.lyndir.masterpassword.model.MPJSONFile.objectMapper; import static com.lyndir.masterpassword.model.impl.MPJSONFile.objectMapper;
import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonMappingException;
import com.lyndir.masterpassword.MPKeyUnavailableException; import com.lyndir.masterpassword.MPKeyUnavailableException;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;

View File

@ -16,7 +16,7 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
/** /**
* @author lhunath, 2018-04-26 * @author lhunath, 2018-04-26

View File

@ -16,7 +16,7 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
/** /**
* @author lhunath, 2017-09-20 * @author lhunath, 2017-09-20

View File

@ -16,7 +16,7 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
import com.lyndir.masterpassword.MPKeyUnavailableException; import com.lyndir.masterpassword.MPKeyUnavailableException;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;

View File

@ -16,9 +16,10 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model.impl;
import com.lyndir.masterpassword.MPKeyUnavailableException; import com.lyndir.masterpassword.MPKeyUnavailableException;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;

View File

@ -0,0 +1,25 @@
//==============================================================================
// 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/>.
//==============================================================================
/**
* @author lhunath, 2018-05-14
*/
@ParametersAreNonnullByDefault
package com.lyndir.masterpassword.model.impl;
import javax.annotation.ParametersAreNonnullByDefault;

View File

@ -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_password_type().ordinal() )]; return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, getDefaultVersion().getAlgorithm().mpw_default_result_type().ordinal() )];
} }
public boolean setDefaultVersion(final MPMasterKey.Version value) { public boolean setDefaultVersion(final MPMasterKey.Version value) {

View File

@ -18,97 +18,32 @@
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.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.MPAlgorithm;
import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.model.*; import com.lyndir.masterpassword.model.*;
import com.lyndir.masterpassword.model.impl.MPBasicSite;
import java.util.Collection; import java.util.Collection;
import javax.annotation.Nullable;
/** /**
* @author lhunath, 14-12-16 * @author lhunath, 14-12-16
*/ */
public class IncognitoSite extends MPSite { public class IncognitoSite extends MPBasicSite {
private final IncognitoUser user; private final IncognitoUser user;
private String siteName; public IncognitoSite(final IncognitoUser user, final String siteName) {
private UnsignedInteger siteCounter; super( siteName, user.getAlgorithm() );
private MPResultType resultType;
private MPResultType loginType;
private MPAlgorithm algorithm;
public IncognitoSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
final MPAlgorithm algorithm) {
this.user = user; this.user = user;
this.siteName = siteName;
this.siteCounter = siteCounter;
this.resultType = resultType;
this.algorithm = algorithm;
} }
@Override @Override
public MPUser<?> getUser() { public MPUser<? extends MPSite> getUser() {
return user; return user;
} }
@Override
public String getSiteName() {
return siteName;
}
@Override
public void setSiteName(final String siteName) {
this.siteName = siteName;
}
@Override
public MPResultType getResultType() {
return resultType;
}
@Override
public void setResultType(final MPResultType 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
public MPAlgorithm getAlgorithm() {
return algorithm;
}
@Override
public void setAlgorithm(final MPAlgorithm algorithm) {
this.algorithm = algorithm;
}
@Override @Override
public Collection<MPQuestion> getQuestions() { public Collection<MPQuestion> getQuestions() {
return ImmutableList.of(); return ImmutableList.of();
} }
@Override
public UnsignedInteger getSiteCounter() {
return siteCounter;
}
@Override
public void setSiteCounter(final UnsignedInteger siteCounter) {
this.siteCounter = siteCounter;
}
} }

View File

@ -18,53 +18,23 @@
package com.lyndir.masterpassword.gui.model; package com.lyndir.masterpassword.gui.model;
import com.google.common.collect.ImmutableList;
import com.lyndir.masterpassword.MPAlgorithm;
import com.lyndir.masterpassword.MPMasterKey; import com.lyndir.masterpassword.MPMasterKey;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException; import com.lyndir.masterpassword.model.impl.MPBasicUser;
import com.lyndir.masterpassword.model.MPUser; import javax.annotation.Nullable;
import java.util.Collection;
import javax.annotation.Nonnull;
/** /**
* @author lhunath, 2014-06-08 * @author lhunath, 2014-06-08
*/ */
public class IncognitoUser extends MPUser<IncognitoSite> { public class IncognitoUser extends MPBasicUser<IncognitoSite> {
private final String fullName;
public IncognitoUser(final String fullName) { public IncognitoUser(final String fullName) {
this.fullName = fullName; super(fullName, MPMasterKey.Version.CURRENT.getAlgorithm());
} }
@Nullable
@Override @Override
public String getFullName() { public byte[] getKeyID() {
return fullName; return null;
}
@Override
public MPAlgorithm getAlgorithm() {
return MPMasterKey.Version.CURRENT.getAlgorithm();
}
@Override
public void addSite(final IncognitoSite site) {
}
@Override
public void deleteSite(final IncognitoSite site) {
}
@Override
public Collection<IncognitoSite> findSites(final String query) {
return ImmutableList.of();
}
@Nonnull
@Override
public MPMasterKey authenticate(final char[] masterPassword)
throws MPIncorrectMasterPasswordException {
return key = new MPMasterKey( getFullName(), masterPassword );
} }
} }

View File

@ -29,6 +29,8 @@ import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.gui.Res; import com.lyndir.masterpassword.gui.Res;
import com.lyndir.masterpassword.gui.util.Components; import com.lyndir.masterpassword.gui.util.Components;
import com.lyndir.masterpassword.model.*; import com.lyndir.masterpassword.model.*;
import com.lyndir.masterpassword.model.impl.*;
import com.lyndir.masterpassword.model.impl.MPFileSite;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -214,7 +216,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel<MPFileUser> im
protected MPFileSite createSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter, protected MPFileSite createSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter,
final MPResultType resultType, final MPResultType resultType,
final MPAlgorithm algorithm) { final MPAlgorithm algorithm) {
return new MPFileSite( user, siteName, siteCounter, resultType, algorithm ); return new MPFileSite( user, siteName, algorithm, siteCounter, resultType );
} }
}; };
} }

View File

@ -31,6 +31,9 @@ import com.lyndir.masterpassword.gui.Res;
import com.lyndir.masterpassword.gui.util.Components; import com.lyndir.masterpassword.gui.util.Components;
import com.lyndir.masterpassword.gui.util.UnsignedIntegerModel; import com.lyndir.masterpassword.gui.util.UnsignedIntegerModel;
import com.lyndir.masterpassword.model.*; import com.lyndir.masterpassword.model.*;
import com.lyndir.masterpassword.model.impl.MPBasicSite;
import com.lyndir.masterpassword.model.impl.MPFileSite;
import com.lyndir.masterpassword.model.impl.MPFileUser;
import java.awt.*; import java.awt.*;
import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable; import java.awt.datatransfer.Transferable;
@ -45,7 +48,7 @@ import javax.swing.event.*;
/** /**
* @author lhunath, 2014-06-08 * @author lhunath, 2014-06-08
*/ */
public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> extends JFrame implements DocumentListener { public abstract class PasswordFrame<U extends MPUser<S>, S extends MPBasicSite> extends JFrame implements DocumentListener {
@SuppressWarnings("FieldCanBeLocal") @SuppressWarnings("FieldCanBeLocal")
private final Components.GradientPanel root; private final Components.GradientPanel root;
@ -147,7 +150,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_password_type() ); resultTypeField.setSelectedItem( user.getAlgorithm().mpw_default_result_type() );
resultTypeField.addItemListener( new ItemListener() { resultTypeField.addItemListener( new ItemListener() {
@Override @Override
public void itemStateChanged(final ItemEvent e) { public void itemStateChanged(final ItemEvent e) {
@ -245,15 +248,15 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
siteResults = FluentIterable.from( siteResults ).filter( new Predicate<S>() { siteResults = FluentIterable.from( siteResults ).filter( new Predicate<S>() {
@Override @Override
public boolean apply(@Nullable final S siteResult) { public boolean apply(@Nullable final S siteResult) {
return (siteResult != null) && siteNameQuery.equals( siteResult.getSiteName() ); return (siteResult != null) && siteNameQuery.equals( siteResult.getName() );
} }
} ); } );
final S site = ifNotNullElse( Iterables.getFirst( siteResults, null ), final S site = ifNotNullElse( Iterables.getFirst( siteResults, null ),
createSite( user, siteNameQuery, siteCounter, resultType, siteAlgorithm ) ); createSite( user, siteNameQuery, siteCounter, resultType, siteAlgorithm ) );
if ((currentSite != null) && currentSite.getSiteName().equals( site.getSiteName() )) { if ((currentSite != null) && currentSite.getName().equals( site.getName() )) {
site.setResultType( resultType ); site.setResultType( resultType );
site.setAlgorithm( siteAlgorithm ); site.setAlgorithm( siteAlgorithm );
site.setSiteCounter( siteCounter ); site.setCounter( siteCounter );
} }
ListenableFuture<String> passwordFuture = Res.execute( this, new Callable<String>() { ListenableFuture<String> passwordFuture = Res.execute( this, new Callable<String>() {
@ -278,8 +281,8 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
siteActionButton.setText( "Add Site" ); siteActionButton.setText( "Add Site" );
resultTypeField.setSelectedItem( currentSite.getResultType() ); resultTypeField.setSelectedItem( currentSite.getResultType() );
siteVersionField.setSelectedItem( currentSite.getAlgorithm() ); siteVersionField.setSelectedItem( currentSite.getAlgorithm() );
siteCounterField.setValue( currentSite.getSiteCounter() ); siteCounterField.setValue( currentSite.getCounter() );
siteNameField.setText( currentSite.getSiteName() ); siteNameField.setText( currentSite.getName() );
if (siteNameField.getText().startsWith( siteNameQuery )) if (siteNameField.getText().startsWith( siteNameQuery ))
siteNameField.select( siteNameQuery.length(), siteNameField.getText().length() ); siteNameField.select( siteNameQuery.length(), siteNameField.getText().length() );

View File

@ -24,8 +24,7 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.lyndir.masterpassword.MPIdenticon; import com.lyndir.masterpassword.MPIdenticon;
import com.lyndir.masterpassword.gui.Res; import com.lyndir.masterpassword.gui.Res;
import com.lyndir.masterpassword.gui.util.Components; import com.lyndir.masterpassword.gui.util.Components;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException; import com.lyndir.masterpassword.model.*;
import com.lyndir.masterpassword.model.MPUser;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -49,7 +48,7 @@ public class UnlockFrame extends JFrame {
private Future<?> identiconFuture; private Future<?> identiconFuture;
private boolean incognito; private boolean incognito;
@Nullable @Nullable
private MPUser<?> user; private MPUser<? extends MPSite> user;
public UnlockFrame(final SignInCallback signInCallback) { public UnlockFrame(final SignInCallback signInCallback) {
super( "Unlock Master Password" ); super( "Unlock Master Password" );
@ -158,7 +157,7 @@ public class UnlockFrame extends JFrame {
} ); } );
} }
void updateUser(@Nullable final MPUser<?> user) { void updateUser(@Nullable final MPUser<? extends MPSite> user) {
this.user = user; this.user = user;
checkSignIn(); checkSignIn();
} }