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'
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' )
}
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 'com.fasterxml.jackson.core:jackson-annotations:2.9.5'

View File

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

View File

@ -247,7 +247,7 @@ public class MPAlgorithmV0 extends MPAlgorithm {
}
@Override
public MPResultType mpw_default_password_type() {
public MPResultType mpw_default_result_type() {
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;
/**
* @author lhunath, 14-12-17
*/
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() );
this.user = user;
}
public MPFileUser getUser() {
public MPUser<?> getUser() {
return user;
}
}

View File

@ -18,24 +18,35 @@
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;
/**
* @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)
throws MPKeyUnavailableException {
@Nonnull
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;
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 java.util.Collection;
import java.util.Objects;
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,
@Nullable final String state)
throws MPKeyUnavailableException {
void setLoginType(@Nullable MPResultType loginType);
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,
@Nullable final UnsignedInteger siteCounter, final MPResultType type,
@Nullable final String state)
throws MPKeyUnavailableException {
String getLogin(@Nullable String state)
throws MPKeyUnavailableException;
return getUser().getMasterKey().siteResult(
getSiteName(), ifNotNullElse( siteCounter, getAlgorithm().mpw_default_counter() ), keyPurpose, keyContext,
type, state, getAlgorithm() );
}
// - Relations
protected String getState(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
@Nullable final UnsignedInteger siteCounter, final MPResultType type,
@Nullable final String state)
throws MPKeyUnavailableException {
MPUser<? extends MPSite> getUser();
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() );
}
Collection<? extends MPQuestion> getQuestions();
}

View File

@ -21,35 +21,41 @@ package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import java.util.Objects;
import org.jetbrains.annotations.NotNull;
/**
* @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;
}
public MPFileSite getSite() {
public MPSite getSite() {
return site;
}
@Override
public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPSiteResult) && Objects.equals( site, ((MPSiteResult) obj).site ));
public int hashCode() {
return Objects.hashCode( getSite() );
}
@Override
public int hashCode() {
return Objects.hashCode( site );
public boolean equals(final Object obj) {
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
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;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.masterpassword.*;
import java.util.Collection;
import java.util.Objects;
import javax.annotation.Nonnull;
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
protected MPMasterKey key;
byte[] getKeyID();
public abstract String getFullName();
@Nullable
String exportKeyID();
public boolean isMasterKeyAvailable() {
return key != null;
}
@Nonnull
public MPMasterKey getMasterKey()
throws MPKeyUnavailableException {
if (key == null)
throw new MPKeyUnavailableException();
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)
/**
* 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.
*
* @param masterPassword The password to authenticate with.
*
* @throws MPIncorrectMasterPasswordException If authentication fails due to the given master password not matching the user's keyID.
*/
void authenticate(char[] masterPassword)
throws MPIncorrectMasterPasswordException;
@Override
public int hashCode() {
return Objects.hashCode( getFullName() );
}
/**
* 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 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
public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPUser) && Objects.equals( getFullName(), ((MPUser<?>) obj).getFullName() ));
}
boolean isMasterKeyAvailable();
@Override
public String toString() {
return strf( "{%s: %s}", getClass().getSimpleName(), getFullName() );
}
@Nonnull
MPMasterKey getMasterKey()
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;
import com.google.common.collect.*;
import com.lyndir.masterpassword.model.impl.MPFileUser;
import java.util.Map;
import java.util.SortedSet;
@ -26,28 +27,28 @@ import java.util.SortedSet;
/**
* @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) {
for (final MPFileUser user : users)
protected MPUserManager(final Iterable<U> users) {
for (final U user : users)
usersByName.put( user.getFullName(), user );
}
public SortedSet<MPFileUser> getUsers() {
public SortedSet<U> getUsers() {
return FluentIterable.from( usersByName.values() ).toSortedSet( Ordering.natural() );
}
public MPFileUser getUserNamed(final String fullName) {
public U getUserNamed(final String fullName) {
return usersByName.get( fullName );
}
public void addUser(final MPFileUser user) {
public void addUser(final U user) {
usersByName.put( user.getFullName(), user );
}
public void deleteUser(final MPFileUser user) {
public void deleteUser(final U user) {
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/>.
//==============================================================================
package com.lyndir.masterpassword.model;
package com.lyndir.masterpassword.model.impl;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
import com.lyndir.masterpassword.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* @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
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.keyword = keyword;
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()
throws MPKeyUnavailableException {
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/>.
//==============================================================================
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.masterpassword.*;
import java.util.*;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import com.lyndir.masterpassword.model.MPUser;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.joda.time.Instant;
@ -33,21 +32,16 @@ import org.joda.time.ReadableInstant;
* @author lhunath, 14-12-07
*/
@SuppressWarnings("ComparableImplementedButEqualsNotOverridden")
public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileUser> {
public class MPFileUser extends MPBasicUser<MPFileSite> {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPFileUser.class );
private final String fullName;
private final Collection<MPFileSite> sites = new LinkedHashSet<>();
@Nullable
private byte[] keyID;
private MPAlgorithm algorithm;
private MPMarshalFormat format;
private MPMarshaller.ContentMode contentMode;
private int avatar;
private MPResultType defaultType;
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) {
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 );
}
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm, final int avatar,
final MPResultType defaultType, final ReadableInstant lastUsed,
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 MPMarshaller.ContentMode contentMode) {
this.fullName = fullName;
super( avatar, fullName, algorithm );
this.keyID = (keyID == null)? null: keyID.clone();
this.algorithm = algorithm;
this.avatar = avatar;
this.defaultType = defaultType;
this.lastUsed = lastUsed;
this.format = format;
this.contentMode = contentMode;
}
@Override
public String getFullName() {
return fullName;
}
@Nullable
@Override
public byte[] getKeyID() {
return (keyID == null)? null: keyID.clone();
}
@Override
public MPAlgorithm getAlgorithm() {
return algorithm;
public void setAlgorithm(final MPAlgorithm 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) {
this.algorithm = algorithm;
super.setAlgorithm( algorithm );
}
public MPMarshalFormat getFormat() {
@ -111,15 +108,6 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
this.contentMode = contentMode;
}
@Override
public int getAvatar() {
return avatar;
}
public void setAvatar(final int avatar) {
this.avatar = avatar;
}
public MPResultType getDefaultType() {
return defaultType;
}
@ -136,30 +124,6 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
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) {
this.json = json;
}
@ -169,33 +133,13 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
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
public MPMasterKey authenticate(final char[] masterPassword)
throws MPIncorrectMasterPasswordException {
try {
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 );
public void authenticate(final MPMasterKey masterKey)
throws MPIncorrectMasterPasswordException, MPKeyUnavailableException {
super.authenticate( masterKey );
return key;
}
catch (final MPKeyUnavailableException e) {
throw logger.bug( e );
}
if (keyID == null)
keyID = masterKey.getKeyID( getAlgorithm() );
}
void save()
@ -204,11 +148,11 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
}
@Override
public int compareTo(final MPFileUser o) {
int comparison = getLastUsed().compareTo( o.getLastUsed() );
if (comparison == 0)
comparison = getFullName().compareTo( o.getFullName() );
public int compareTo(final MPUser<?> o) {
int comparison = (o instanceof MPFileUser)? getLastUsed().compareTo( ((MPFileUser) o).getLastUsed() ): 0;
if (comparison != 0)
return comparison;
return super.compareTo( o );
}
}

View File

@ -16,7 +16,7 @@
// 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.*;
@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.io.CharSink;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.masterpassword.*;
import com.lyndir.masterpassword.model.*;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
@ -37,7 +38,7 @@ import javax.annotation.Nonnull;
* @author lhunath, 14-12-07
*/
@SuppressWarnings("CallToSystemGetenv")
public class MPFileUserManager extends MPUserManager {
public class MPFileUserManager extends MPUserManager<MPFileUser> {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPFileUserManager.class );
@ -137,7 +138,7 @@ public class MPFileUserManager extends MPUserManager {
}
@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() );
}

View File

@ -16,7 +16,7 @@
// 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.StringUtils.*;
@ -59,7 +59,7 @@ public class MPFlatMarshaller implements MPMarshaller {
for (final MPFileSite site : user.getSites()) {
String loginName = site.getLoginState();
String password = site.getSiteState();
String password = site.getResultState();
if (!user.getContentMode().isRedacted()) {
loginName = site.getLogin();
password = site.getResult();
@ -71,9 +71,9 @@ public class MPFlatMarshaller implements MPMarshaller {
strf( "%d:%d:%d", //
site.getResultType().getType(), // type
site.getAlgorithm().version().toInt(), // algorithm
site.getSiteCounter().intValue() ), // counter
site.getCounter().intValue() ), // counter
ifNotNullElse( loginName, "" ), // loginName
site.getSiteName(), // siteName
site.getName(), // siteName
ifNotNullElse( password, "" ) // password
) );
}

View File

@ -16,7 +16,7 @@
// 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.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.util.ConversionUtils;
import com.lyndir.masterpassword.*;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -115,11 +116,11 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
switch (importFormat) {
case 0:
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(),
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
clearContent? null: siteMatcher.group( 6 ),
null, null, null, ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
if (clearContent)
@ -128,12 +129,12 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
case 1:
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( "" ) ),
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
clearContent? null: siteMatcher.group( 6 ), MPResultType.GeneratedName, null,
clearContent? null: siteMatcher.group( 8 ),
MPResultType.GeneratedName, clearContent? null: siteMatcher.group( 6 ), null,
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
if (clearContent) {

View File

@ -16,7 +16,7 @@
// 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.JsonAnySetter;

View File

@ -16,20 +16,16 @@
// 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 com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.core.*;
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.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.masterpassword.*;
import java.io.IOException;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import java.util.*;
import javax.annotation.Nullable;
import org.joda.time.Instant;
@ -62,7 +58,7 @@ public class MPJSONFile extends MPJSONAnyObject {
user.avatar = modelUser.getAvatar();
user.full_name = modelUser.getFullName();
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.default_type = modelUser.getDefaultType();
@ -75,21 +71,21 @@ public class MPJSONFile extends MPJSONAnyObject {
// Clear Text
content = modelSite.getResult();
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() );
} else {
// Redacted
if (modelSite.getResultType().supportsTypeFeature( MPSiteFeature.ExportContent ))
content = modelSite.getSiteState();
content = modelSite.getResultState();
if (modelSite.getLoginType().supportsTypeFeature( MPSiteFeature.ExportContent ))
loginContent = modelSite.getLoginState();
}
Site site = sites.get( modelSite.getSiteName() );
Site site = sites.get( modelSite.getName() );
if (site == null)
sites.put( modelSite.getSiteName(), site = new Site() );
sites.put( modelSite.getName(), site = new Site() );
site.type = modelSite.getResultType();
site.counter = modelSite.getSiteCounter().longValue();
site.counter = modelSite.getCounter().longValue();
site.algorithm = modelSite.getAlgorithm().version();
site.password = content;
site.login_name = loginContent;
@ -140,7 +136,7 @@ public class MPJSONFile extends MPJSONAnyObject {
MPAlgorithm algorithm = ifNotNullElse( user.algorithm, MPMasterKey.Version.CURRENT ).getAlgorithm();
MPFileUser model = new MPFileUser(
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(),
MPMarshalFormat.JSON, export.redacted? MPMarshaller.ContentMode.PROTECTED: MPMarshaller.ContentMode.VISIBLE );
model.setJSON( this );
@ -151,9 +147,9 @@ public class MPJSONFile extends MPJSONAnyObject {
String siteName = siteEntry.getKey();
Site fileSite = siteEntry.getValue();
MPFileSite site = new MPFileSite(
model, siteName, export.redacted? fileSite.password: null, UnsignedInteger.valueOf( fileSite.counter ),
fileSite.type, fileSite.algorithm.getAlgorithm(),
export.redacted? fileSite.login_name: null, fileSite.login_type,
model, siteName, fileSite.algorithm.getAlgorithm(), UnsignedInteger.valueOf( fileSite.counter ), fileSite.type,
export.redacted? fileSite.password: null,
fileSite.login_type, export.redacted? fileSite.login_name: null,
(fileSite._ext_mpw != null)? fileSite._ext_mpw.url: null, fileSite.uses,
(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/>.
//==============================================================================
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.lyndir.masterpassword.MPKeyUnavailableException;

View File

@ -16,13 +16,14 @@
// 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.databind.JsonMappingException;
import com.lyndir.masterpassword.MPKeyUnavailableException;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import java.io.File;
import java.io.IOException;
import javax.annotation.Nonnull;

View File

@ -16,7 +16,7 @@
// 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

View File

@ -16,7 +16,7 @@
// 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

View File

@ -16,7 +16,7 @@
// 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 javax.annotation.Nonnull;

View File

@ -16,9 +16,10 @@
// 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.model.MPIncorrectMasterPasswordException;
import java.io.File;
import java.io.IOException;
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
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) {

View File

@ -18,97 +18,32 @@
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.primitives.UnsignedInteger;
import com.lyndir.masterpassword.MPAlgorithm;
import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.model.*;
import com.lyndir.masterpassword.model.impl.MPBasicSite;
import java.util.Collection;
import javax.annotation.Nullable;
/**
* @author lhunath, 14-12-16
*/
public class IncognitoSite extends MPSite {
public class IncognitoSite extends MPBasicSite {
private final IncognitoUser user;
private String siteName;
private UnsignedInteger siteCounter;
private MPResultType resultType;
private MPResultType loginType;
private MPAlgorithm algorithm;
public IncognitoSite(final IncognitoUser user, final String siteName) {
super( siteName, user.getAlgorithm() );
public IncognitoSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
final MPAlgorithm algorithm) {
this.user = user;
this.siteName = siteName;
this.siteCounter = siteCounter;
this.resultType = resultType;
this.algorithm = algorithm;
}
@Override
public MPUser<?> getUser() {
public MPUser<? extends MPSite> getUser() {
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
public Collection<MPQuestion> getQuestions() {
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;
import com.google.common.collect.ImmutableList;
import com.lyndir.masterpassword.MPAlgorithm;
import com.lyndir.masterpassword.MPMasterKey;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import com.lyndir.masterpassword.model.MPUser;
import java.util.Collection;
import javax.annotation.Nonnull;
import com.lyndir.masterpassword.model.impl.MPBasicUser;
import javax.annotation.Nullable;
/**
* @author lhunath, 2014-06-08
*/
public class IncognitoUser extends MPUser<IncognitoSite> {
private final String fullName;
public class IncognitoUser extends MPBasicUser<IncognitoSite> {
public IncognitoUser(final String fullName) {
this.fullName = fullName;
super(fullName, MPMasterKey.Version.CURRENT.getAlgorithm());
}
@Nullable
@Override
public String getFullName() {
return fullName;
}
@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 );
public byte[] getKeyID() {
return null;
}
}

View File

@ -29,6 +29,8 @@ import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.gui.Res;
import com.lyndir.masterpassword.gui.util.Components;
import com.lyndir.masterpassword.model.*;
import com.lyndir.masterpassword.model.impl.*;
import com.lyndir.masterpassword.model.impl.MPFileSite;
import java.awt.*;
import java.awt.event.*;
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,
final MPResultType resultType,
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.UnsignedIntegerModel;
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.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
@ -45,7 +48,7 @@ import javax.swing.event.*;
/**
* @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")
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 ) );
sitePanel.add( siteSettings );
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() {
@Override
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>() {
@Override
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 ),
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.setAlgorithm( siteAlgorithm );
site.setSiteCounter( siteCounter );
site.setCounter( siteCounter );
}
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" );
resultTypeField.setSelectedItem( currentSite.getResultType() );
siteVersionField.setSelectedItem( currentSite.getAlgorithm() );
siteCounterField.setValue( currentSite.getSiteCounter() );
siteNameField.setText( currentSite.getSiteName() );
siteCounterField.setValue( currentSite.getCounter() );
siteNameField.setText( currentSite.getName() );
if (siteNameField.getText().startsWith( siteNameQuery ))
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.gui.Res;
import com.lyndir.masterpassword.gui.util.Components;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import com.lyndir.masterpassword.model.MPUser;
import com.lyndir.masterpassword.model.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.Future;
@ -49,7 +48,7 @@ public class UnlockFrame extends JFrame {
private Future<?> identiconFuture;
private boolean incognito;
@Nullable
private MPUser<?> user;
private MPUser<? extends MPSite> user;
public UnlockFrame(final SignInCallback signInCallback) {
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;
checkSignIn();
}