Initial implementation of questions support.
This commit is contained in:
		@@ -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.
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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 );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<MPFileQuestion> 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
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
 | 
			
		||||
    private static final Logger logger = Logger.get( MPFileUser.class );
 | 
			
		||||
 | 
			
		||||
    private final String                 fullName;
 | 
			
		||||
    private final Collection<MPFileSite> sites = Sets.newHashSet();
 | 
			
		||||
    private final Collection<MPFileSite> sites = new LinkedHashSet<>();
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private byte[]                   keyID;
 | 
			
		||||
@@ -136,7 +136,7 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
 | 
			
		||||
        lastUsed = new Instant();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Iterable<MPFileSite> getSites() {
 | 
			
		||||
    public Collection<MPFileSite> getSites() {
 | 
			
		||||
        return Collections.unmodifiableCollection( sites );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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() ));
 | 
			
		||||
 
 | 
			
		||||
@@ -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<MPQuestion> getQuestions() {
 | 
			
		||||
        return ImmutableList.of();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public UnsignedInteger getSiteCounter() {
 | 
			
		||||
        return siteCounter;
 | 
			
		||||
 
 | 
			
		||||
@@ -260,9 +260,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, 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<String>() {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user