2
0

Implement security answers & immediate site lookup.

This commit is contained in:
Maarten Billemont
2018-08-07 00:07:16 -04:00
parent 7d1aa9c9f4
commit 10c6d203b8
20 changed files with 276 additions and 91 deletions

View File

@@ -40,6 +40,13 @@ public interface MPQuestion extends Comparable<MPQuestion> {
void setType(MPResultType type);
@Nonnull
default String getAnswer()
throws MPKeyUnavailableException, MPAlgorithmException {
return getAnswer( null );
}
@Nonnull
String getAnswer(@Nullable String state)
throws MPKeyUnavailableException, MPAlgorithmException;

View File

@@ -18,6 +18,7 @@
package com.lyndir.masterpassword.model;
import com.google.common.collect.ImmutableCollection;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.*;
import java.util.Collection;
@@ -57,6 +58,7 @@ public interface MPSite<Q extends MPQuestion> extends Comparable<MPSite<?>> {
void setLoginType(@Nullable MPResultType loginType);
@Nonnull
default String getResult()
throws MPKeyUnavailableException, MPAlgorithmException {
@@ -79,6 +81,16 @@ public interface MPSite<Q extends MPQuestion> extends Comparable<MPSite<?>> {
String getResult(MPKeyPurpose keyPurpose, @Nullable String keyContext, @Nullable String state)
throws MPKeyUnavailableException, MPAlgorithmException;
@Nonnull
String getResult(MPKeyPurpose keyPurpose, @Nullable String keyContext,
@Nullable UnsignedInteger counter, MPResultType type, @Nullable String state)
throws MPKeyUnavailableException, MPAlgorithmException;
@Nonnull
String getState(MPKeyPurpose keyPurpose, @Nullable String keyContext,
@Nullable UnsignedInteger counter, MPResultType type, String state)
throws MPKeyUnavailableException, MPAlgorithmException;
@Nonnull
default String getLogin()
throws MPKeyUnavailableException, MPAlgorithmException {
@@ -94,10 +106,17 @@ public interface MPSite<Q extends MPQuestion> extends Comparable<MPSite<?>> {
@Nonnull
MPUser<?> getUser();
boolean addQuestion(Q question);
@Nonnull
Q addQuestion(String keyword);
@Nonnull
Q addQuestion(Q question);
boolean deleteQuestion(Q question);
@Nonnull
Collection<Q> getQuestions();
@Nonnull
ImmutableCollection<Q> findQuestions(@Nullable String query);
}

View File

@@ -100,6 +100,7 @@ public interface MPUser<S extends MPSite<?>> extends Comparable<MPUser<?>> {
// - Relations
@Nonnull
S addSite(String siteName);
@Nonnull

View File

@@ -22,6 +22,7 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.lyndir.masterpassword.*;
import com.lyndir.masterpassword.model.MPQuestion;
import com.lyndir.masterpassword.model.MPSite;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -33,14 +34,23 @@ import org.jetbrains.annotations.NotNull;
*/
public abstract class MPBasicQuestion extends Changeable implements MPQuestion {
private final MPSite<?> site;
private final String keyword;
private MPResultType type;
protected MPBasicQuestion(final String keyword, final MPResultType type) {
private MPResultType type;
protected MPBasicQuestion(final MPSite<?> site, final String keyword, final MPResultType type) {
this.site = site;
this.keyword = keyword;
this.type = type;
}
@Nonnull
@Override
public MPSite<?> getSite() {
return site;
}
@Nonnull
@Override
public String getKeyword() {
@@ -55,7 +65,7 @@ public abstract class MPBasicQuestion extends Changeable implements MPQuestion {
@Override
public void setType(final MPResultType type) {
if (Objects.equals(this.type, type))
if (this.type == type)
return;
this.type = type;
@@ -70,15 +80,12 @@ public abstract class MPBasicQuestion extends Changeable implements MPQuestion {
return getSite().getResult( MPKeyPurpose.Recovery, getKeyword(), null, getType(), state );
}
@Nonnull
@Override
public abstract MPBasicSite<?, ?> getSite();
@Override
protected void onChanged() {
super.onChanged();
getSite().setChanged();
if (site instanceof Changeable)
((Changeable) site).setChanged();
}
@Override

View File

@@ -21,6 +21,9 @@ 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.base.Strings;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.*;
import com.lyndir.masterpassword.model.*;
@@ -35,9 +38,9 @@ import javax.annotation.Nullable;
public abstract class MPBasicSite<U extends MPUser<?>, Q extends MPQuestion> extends Changeable
implements MPSite<Q> {
private final Collection<Q> questions = new LinkedHashSet<>();
private final U user;
private final String siteName;
private final Collection<Q> questions = new LinkedHashSet<>();
private MPAlgorithm algorithm;
private UnsignedInteger counter;
@@ -104,7 +107,7 @@ public abstract class MPBasicSite<U extends MPUser<?>, Q extends MPQuestion> ext
@Override
public void setResultType(final MPResultType resultType) {
if (Objects.equals( this.resultType, resultType ))
if (this.resultType == resultType)
return;
this.resultType = resultType;
@@ -119,7 +122,7 @@ public abstract class MPBasicSite<U extends MPUser<?>, Q extends MPQuestion> ext
@Override
public void setLoginType(@Nullable final MPResultType loginType) {
if (Objects.equals( this.loginType, loginType ))
if (this.loginType == loginType)
return;
this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
@@ -134,8 +137,10 @@ public abstract class MPBasicSite<U extends MPUser<?>, Q extends MPQuestion> ext
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)
@Nonnull
@Override
public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
@Nullable final UnsignedInteger counter, final MPResultType type, @Nullable final String state)
throws MPKeyUnavailableException, MPAlgorithmException {
return getUser().getMasterKey().siteResult(
@@ -143,8 +148,10 @@ public abstract class MPBasicSite<U extends MPUser<?>, Q extends MPQuestion> ext
keyPurpose, keyContext, type, state );
}
protected String getState(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
@Nullable final UnsignedInteger counter, final MPResultType type, final String state)
@Nonnull
@Override
public String getState(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
@Nullable final UnsignedInteger counter, final MPResultType type, final String state)
throws MPKeyUnavailableException, MPAlgorithmException {
return getUser().getMasterKey().siteState(
@@ -160,13 +167,13 @@ public abstract class MPBasicSite<U extends MPUser<?>, Q extends MPQuestion> ext
return getResult( MPKeyPurpose.Identification, null, null, getLoginType(), state );
}
@Nonnull
@Override
public boolean addQuestion(final Q question) {
if (!questions.add( question ))
return false;
public Q addQuestion(final Q question) {
questions.add( question );
setChanged();
return true;
return question;
}
@Override
@@ -184,6 +191,17 @@ public abstract class MPBasicSite<U extends MPUser<?>, Q extends MPQuestion> ext
return Collections.unmodifiableCollection( questions );
}
@Nonnull
@Override
public ImmutableCollection<Q> findQuestions(@Nullable final String query) {
ImmutableSortedSet.Builder<Q> results = ImmutableSortedSet.naturalOrder();
for (final Q question : getQuestions())
if (Strings.isNullOrEmpty( query ) || question.getKeyword().startsWith( query ))
results.add( question );
return results.build();
}
@Nonnull
@Override
public U getUser() {

View File

@@ -20,6 +20,7 @@ package com.lyndir.masterpassword.model.impl;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableSortedSet;
import com.lyndir.lhunath.opal.system.CodeUtils;
@@ -202,10 +203,9 @@ public abstract class MPBasicUser<S extends MPBasicSite<?, ?>> extends Changeabl
@Override
public ImmutableCollection<S> findSites(@Nullable final String query) {
ImmutableSortedSet.Builder<S> results = ImmutableSortedSet.naturalOrder();
if (query != null)
for (final S site : getSites())
if (site.getSiteName().startsWith( query ))
results.add( site );
for (final S site : getSites())
if (Strings.isNullOrEmpty( query ) || site.getSiteName().startsWith( query ))
results.add( site );
return results.build();
}

View File

@@ -30,16 +30,13 @@ import javax.annotation.Nullable;
*/
public class MPFileQuestion extends MPBasicQuestion {
private final MPFileSite site;
@Nullable
private String answerState;
public MPFileQuestion(final MPFileSite site, final String keyword,
@Nullable final MPResultType type, @Nullable final String answerState) {
super( keyword, ifNotNullElse( type, site.getAlgorithm().mpw_default_answer_type() ) );
super( site, keyword, ifNotNullElse( type, site.getAlgorithm().mpw_default_answer_type() ) );
this.site = site;
this.answerState = answerState;
}
@@ -48,6 +45,8 @@ public class MPFileQuestion extends MPBasicQuestion {
return answerState;
}
@Nonnull
@Override
public String getAnswer()
throws MPKeyUnavailableException, MPAlgorithmException {
return getAnswer( answerState );
@@ -66,9 +65,8 @@ public class MPFileQuestion extends MPBasicQuestion {
setChanged();
}
@Nonnull
@Override
public MPFileSite getSite() {
return site;
public void use() {
if (getSite() instanceof MPFileSite)
((MPFileSite) getSite()).use();
}
}

View File

@@ -145,6 +145,12 @@ public class MPFileSite extends MPBasicSite<MPFileUser, MPFileQuestion> {
setChanged();
}
@Nonnull
@Override
public MPFileQuestion addQuestion(final String keyword) {
return addQuestion( new MPFileQuestion( this, keyword, null, null ) );
}
@Override
public int compareTo(@Nonnull final MPSite<?> o) {
int comparison = (o instanceof MPFileSite)? ((MPFileSite) o).getLastUsed().compareTo( getLastUsed() ): 0;

View File

@@ -207,6 +207,7 @@ public class MPFileUser extends MPBasicUser<MPFileSite> {
super.reset();
}
@Nonnull
@Override
public MPFileSite addSite(final String siteName) {
return addSite( new MPFileSite( this, siteName ) );