diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java
index add7732a..00496abe 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java
@@ -66,6 +66,11 @@ public abstract class MPAlgorithm {
*/
public abstract MPResultType mpw_default_login_type();
+ /**
+ * mpw: defaults: answer result type.
+ */
+ public abstract MPResultType mpw_default_answer_type();
+
/**
* mpw: defaults: initial counter value.
*/
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java
index 1ae201d7..ad4706bd 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java
@@ -256,6 +256,11 @@ public class MPAlgorithmV0 extends MPAlgorithm {
return MPResultType.GeneratedName;
}
+ @Override
+ public MPResultType mpw_default_answer_type() {
+ return MPResultType.GeneratedPhrase;
+ }
+
@Override
public UnsignedInteger mpw_default_counter() {
return UnsignedInteger.ONE;
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileQuestion.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileQuestion.java
new file mode 100644
index 00000000..9aff3cb8
--- /dev/null
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileQuestion.java
@@ -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 .
+//==============================================================================
+
+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 );
+ }
+}
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java
index 7b87881a..db6e8233 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java
@@ -22,6 +22,7 @@ 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;
@@ -36,9 +37,9 @@ public class MPFileSite extends MPSite {
private final MPFileUser user;
private String siteName;
+ private UnsignedInteger siteCounter;
@Nullable
private String siteState;
- private UnsignedInteger siteCounter;
private MPResultType resultType;
private MPAlgorithm algorithm;
@@ -51,6 +52,8 @@ public class MPFileSite extends MPSite {
private int uses;
private ReadableInstant lastUsed;
+ private final Collection questions = new LinkedHashSet<>();
+
public MPFileSite(final MPFileUser user, final String siteName) {
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 url, final int uses, final ReadableInstant lastUsed) {
this.user = user;
+ this.algorithm = algorithm;
+
this.siteName = siteName;
this.siteState = siteState;
- this.siteCounter = ifNotNullElse( siteCounter, user.getAlgorithm().mpw_default_counter() );
- this.resultType = ifNotNullElse( resultType, user.getAlgorithm().mpw_default_password_type() );
- this.algorithm = algorithm;
+ 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;
@@ -116,15 +120,15 @@ public class MPFileSite extends MPSite {
return siteState;
}
- public void setSitePassword(final MPResultType resultType, @Nullable final String result)
+ public void setSitePassword(final MPResultType resultType, @Nullable final String password)
throws MPKeyUnavailableException {
this.resultType = resultType;
- if (result == null)
+ if (password == null)
this.siteState = null;
else
- this.siteState = user.getMasterKey().siteState(
- siteName, siteCounter, MPKeyPurpose.Authentication, null, resultType, result, algorithm );
+ this.siteState = getState(
+ MPKeyPurpose.Authentication, null, siteCounter, resultType, password );
}
@Override
@@ -155,7 +159,6 @@ public class MPFileSite extends MPSite {
@Override
public void setLoginType(@Nullable final MPResultType loginType) {
this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
-
}
@Override
@@ -168,6 +171,11 @@ public class MPFileSite extends MPSite {
this.algorithm = algorithm;
}
+ @Override
+ public Collection extends MPQuestion> getQuestions() {
+ return Collections.unmodifiableCollection( questions );
+ }
+
@Nullable
public String getLoginState() {
return loginState;
@@ -176,9 +184,7 @@ public class MPFileSite extends MPSite {
public void setLoginName(@Nonnull final MPResultType loginType, @Nonnull final String loginName)
throws MPKeyUnavailableException {
this.loginType = loginType;
- this.loginState = user.getMasterKey().siteState(
- siteName, algorithm.mpw_default_counter(), MPKeyPurpose.Identification, null,
- this.loginType, loginName, algorithm );
+ this.loginState = getState( MPKeyPurpose.Identification, null, null, this.loginType, loginName );
}
@Nullable
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java
index 97fbbb48..6aaddfbd 100755
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java
@@ -39,7 +39,7 @@ public class MPFileUser extends MPUser implements Comparable sites = Sets.newHashSet();
+ private final Collection sites = new LinkedHashSet<>();
@Nullable
private byte[] keyID;
@@ -136,7 +136,7 @@ public class MPFileUser extends MPUser implements Comparable getSites() {
+ public Collection getSites() {
return Collections.unmodifiableCollection( sites );
}
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPQuestion.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPQuestion.java
new file mode 100644
index 00000000..13540e8b
--- /dev/null
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPQuestion.java
@@ -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 .
+//==============================================================================
+
+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 );
+ }
+}
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSite.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSite.java
index 0d560d76..9da33720 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSite.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSite.java
@@ -18,10 +18,12 @@
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;
@@ -54,21 +56,40 @@ public abstract class MPSite {
public abstract void setAlgorithm(MPAlgorithm algorithm);
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 {
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)
throws MPKeyUnavailableException {
- return getUser().getMasterKey().siteResult(
- getSiteName(), getAlgorithm().mpw_default_counter(), MPKeyPurpose.Identification, null,
- getLoginType(), loginContent, getAlgorithm() );
+ 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() ));
diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java
index 98683a8b..0f381cee 100644
--- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java
+++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java
@@ -20,11 +20,13 @@ 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.MPSite;
-import com.lyndir.masterpassword.model.MPUser;
+import com.lyndir.masterpassword.model.*;
+import java.util.Collection;
import javax.annotation.Nullable;
@@ -95,6 +97,11 @@ public class IncognitoSite extends MPSite {
this.algorithm = algorithm;
}
+ @Override
+ public Collection getQuestions() {
+ return ImmutableList.of();
+ }
+
@Override
public UnsignedInteger getSiteCounter() {
return siteCounter;
diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java
index bd6c39dd..8ce8d883 100755
--- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java
+++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java
@@ -260,9 +260,7 @@ public abstract class PasswordFrame, S extends MPSite> exten
@Override
public String call()
throws Exception {
- return user.getMasterKey()
- .siteResult( site.getSiteName(), site.getSiteCounter(), MPKeyPurpose.Authentication, null, site.getResultType(),
- null, site.getAlgorithm() );
+ return site.getResult( MPKeyPurpose.Authentication, null, null );
}
} );
Futures.addCallback( passwordFuture, new FutureCallback() {