2
0

Initial implementation of questions support.

This commit is contained in:
Maarten Billemont 2018-05-14 12:24:15 -04:00
parent 38a357cb28
commit 8d7c351912
9 changed files with 191 additions and 24 deletions

View File

@ -66,6 +66,11 @@ public abstract class MPAlgorithm {
*/ */
public abstract MPResultType mpw_default_login_type(); public abstract MPResultType mpw_default_login_type();
/**
* mpw: defaults: answer result type.
*/
public abstract MPResultType mpw_default_answer_type();
/** /**
* mpw: defaults: initial counter value. * mpw: defaults: initial counter value.
*/ */

View File

@ -256,6 +256,11 @@ public class MPAlgorithmV0 extends MPAlgorithm {
return MPResultType.GeneratedName; return MPResultType.GeneratedName;
} }
@Override
public MPResultType mpw_default_answer_type() {
return MPResultType.GeneratedPhrase;
}
@Override @Override
public UnsignedInteger mpw_default_counter() { public UnsignedInteger mpw_default_counter() {
return UnsignedInteger.ONE; return UnsignedInteger.ONE;

View File

@ -0,0 +1,84 @@
//==============================================================================
// 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.ifNotNullElse;
import com.lyndir.masterpassword.*;
import javax.annotation.Nullable;
/**
* @author lhunath, 2018-05-14
*/
public class MPFileQuestion extends MPQuestion {
private final MPSite 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) {
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 );
}
}

View File

@ -22,6 +22,7 @@ import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.*;
import java.util.*;
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;
@ -36,9 +37,9 @@ public class MPFileSite extends MPSite {
private final MPFileUser user; private final MPFileUser user;
private String siteName; private String siteName;
private UnsignedInteger siteCounter;
@Nullable @Nullable
private String siteState; private String siteState;
private UnsignedInteger siteCounter;
private MPResultType resultType; private MPResultType resultType;
private MPAlgorithm algorithm; private MPAlgorithm algorithm;
@ -51,6 +52,8 @@ public class MPFileSite extends MPSite {
private int uses; private int uses;
private ReadableInstant lastUsed; private ReadableInstant lastUsed;
private final Collection<MPFileQuestion> questions = new LinkedHashSet<>();
public MPFileSite(final MPFileUser user, final String siteName) { public MPFileSite(final MPFileUser user, final String siteName) {
this( user, siteName, null, null, user.getAlgorithm() ); this( user, siteName, null, null, user.getAlgorithm() );
} }
@ -66,11 +69,12 @@ public class MPFileSite extends MPSite {
@Nullable final String loginState, @Nullable final MPResultType loginType, @Nullable final String loginState, @Nullable final MPResultType loginType,
@Nullable final String url, final int uses, final ReadableInstant lastUsed) { @Nullable final String url, final int uses, final ReadableInstant lastUsed) {
this.user = user; this.user = user;
this.algorithm = algorithm;
this.siteName = siteName; this.siteName = siteName;
this.siteState = siteState; this.siteState = siteState;
this.siteCounter = ifNotNullElse( siteCounter, user.getAlgorithm().mpw_default_counter() ); this.siteCounter = ifNotNullElse( siteCounter, getAlgorithm().mpw_default_counter() );
this.resultType = ifNotNullElse( resultType, user.getAlgorithm().mpw_default_password_type() ); this.resultType = ifNotNullElse( resultType, getAlgorithm().mpw_default_password_type() );
this.algorithm = algorithm;
this.loginState = loginState; this.loginState = loginState;
this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() ); this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
this.url = url; this.url = url;
@ -116,15 +120,15 @@ public class MPFileSite extends MPSite {
return siteState; return siteState;
} }
public void setSitePassword(final MPResultType resultType, @Nullable final String result) public void setSitePassword(final MPResultType resultType, @Nullable final String password)
throws MPKeyUnavailableException { throws MPKeyUnavailableException {
this.resultType = resultType; this.resultType = resultType;
if (result == null) if (password == null)
this.siteState = null; this.siteState = null;
else else
this.siteState = user.getMasterKey().siteState( this.siteState = getState(
siteName, siteCounter, MPKeyPurpose.Authentication, null, resultType, result, algorithm ); MPKeyPurpose.Authentication, null, siteCounter, resultType, password );
} }
@Override @Override
@ -155,7 +159,6 @@ public class MPFileSite extends MPSite {
@Override @Override
public void setLoginType(@Nullable final MPResultType loginType) { public void setLoginType(@Nullable final MPResultType loginType) {
this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() ); this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
} }
@Override @Override
@ -168,6 +171,11 @@ public class MPFileSite extends MPSite {
this.algorithm = algorithm; this.algorithm = algorithm;
} }
@Override
public Collection<? extends MPQuestion> getQuestions() {
return Collections.unmodifiableCollection( questions );
}
@Nullable @Nullable
public String getLoginState() { public String getLoginState() {
return loginState; return loginState;
@ -176,9 +184,7 @@ public class MPFileSite extends MPSite {
public void setLoginName(@Nonnull final MPResultType loginType, @Nonnull final String loginName) public void setLoginName(@Nonnull final MPResultType loginType, @Nonnull final String loginName)
throws MPKeyUnavailableException { throws MPKeyUnavailableException {
this.loginType = loginType; this.loginType = loginType;
this.loginState = user.getMasterKey().siteState( this.loginState = getState( MPKeyPurpose.Identification, null, null, this.loginType, loginName );
siteName, algorithm.mpw_default_counter(), MPKeyPurpose.Identification, null,
this.loginType, loginName, algorithm );
} }
@Nullable @Nullable

View File

@ -39,7 +39,7 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
private static final Logger logger = Logger.get( MPFileUser.class ); private static final Logger logger = Logger.get( MPFileUser.class );
private final String fullName; private final String fullName;
private final Collection<MPFileSite> sites = Sets.newHashSet(); private final Collection<MPFileSite> sites = new LinkedHashSet<>();
@Nullable @Nullable
private byte[] keyID; private byte[] keyID;
@ -136,7 +136,7 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
lastUsed = new Instant(); lastUsed = new Instant();
} }
public Iterable<MPFileSite> getSites() { public Collection<MPFileSite> getSites() {
return Collections.unmodifiableCollection( sites ); return Collections.unmodifiableCollection( sites );
} }

View File

@ -0,0 +1,41 @@
//==============================================================================
// 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 com.lyndir.masterpassword.*;
import javax.annotation.Nullable;
/**
* @author lhunath, 2018-05-14
*/
public abstract class MPQuestion {
public abstract MPSite getSite();
public abstract String getKeyword();
public abstract MPResultType getType();
public String getAnswer(@Nullable final String state)
throws MPKeyUnavailableException {
return getSite().getResult( MPKeyPurpose.Recovery, getKeyword(), null, getType(), state );
}
}

View File

@ -18,10 +18,12 @@
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 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.Objects; import java.util.Objects;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -54,21 +56,40 @@ public abstract class MPSite {
public abstract void setAlgorithm(MPAlgorithm algorithm); public abstract void setAlgorithm(MPAlgorithm algorithm);
public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext, public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
@Nullable final String siteContent) @Nullable final String state)
throws MPKeyUnavailableException {
return getResult( keyPurpose, keyContext, getSiteCounter(), getResultType(), state );
}
protected String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
@Nullable final UnsignedInteger siteCounter, final MPResultType type,
@Nullable final String state)
throws MPKeyUnavailableException { throws MPKeyUnavailableException {
return getUser().getMasterKey().siteResult( return getUser().getMasterKey().siteResult(
getSiteName(), getSiteCounter(), keyPurpose, keyContext, getResultType(), siteContent, getAlgorithm() ); getSiteName(), ifNotNullElse( siteCounter, getAlgorithm().mpw_default_counter() ), keyPurpose, keyContext,
type, state, getAlgorithm() );
}
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) public String getLogin(@Nullable final String loginContent)
throws MPKeyUnavailableException { throws MPKeyUnavailableException {
return getUser().getMasterKey().siteResult( return getResult( MPKeyPurpose.Identification, null,null, getLoginType(), loginContent );
getSiteName(), getAlgorithm().mpw_default_counter(), MPKeyPurpose.Identification, null,
getLoginType(), loginContent, getAlgorithm() );
} }
public abstract Collection<? extends MPQuestion> getQuestions();
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPSite) && Objects.equals( getSiteName(), ((MPSite) obj).getSiteName() )); return (this == obj) || ((obj instanceof MPSite) && Objects.equals( getSiteName(), ((MPSite) obj).getSiteName() ));

View File

@ -20,11 +20,13 @@ package com.lyndir.masterpassword.gui.model;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse; 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.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.MPAlgorithm; import com.lyndir.masterpassword.MPAlgorithm;
import com.lyndir.masterpassword.MPResultType; import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.model.MPSite; import com.lyndir.masterpassword.model.*;
import com.lyndir.masterpassword.model.MPUser; import java.util.Collection;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -95,6 +97,11 @@ public class IncognitoSite extends MPSite {
this.algorithm = algorithm; this.algorithm = algorithm;
} }
@Override
public Collection<MPQuestion> getQuestions() {
return ImmutableList.of();
}
@Override @Override
public UnsignedInteger getSiteCounter() { public UnsignedInteger getSiteCounter() {
return siteCounter; return siteCounter;

View File

@ -260,9 +260,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
@Override @Override
public String call() public String call()
throws Exception { throws Exception {
return user.getMasterKey() return site.getResult( MPKeyPurpose.Authentication, null, null );
.siteResult( site.getSiteName(), site.getSiteCounter(), MPKeyPurpose.Authentication, null, site.getResultType(),
null, site.getAlgorithm() );
} }
} ); } );
Futures.addCallback( passwordFuture, new FutureCallback<String>() { Futures.addCallback( passwordFuture, new FutureCallback<String>() {