diff --git a/core/c/mpw-types.c b/core/c/mpw-types.c
index 60fb1ca0..ad74b057 100644
--- a/core/c/mpw-types.c
+++ b/core/c/mpw-types.c
@@ -50,14 +50,11 @@ const MPResultType mpw_typeWithName(const char *typeName) {
return MPResultTypeDeriveKey;
}
- // Lower-case and trim optionally leading "Generated" string from typeName to standardize it.
- size_t stdTypeNameOffset = 0;
+ // Lower-case typeName to standardize it.
size_t stdTypeNameSize = strlen( typeName );
- if (strstr( typeName, "Generated" ) == typeName)
- stdTypeNameSize -= (stdTypeNameOffset = strlen( "Generated" ));
char stdTypeName[stdTypeNameSize + 1];
for (size_t c = 0; c < stdTypeNameSize; ++c)
- stdTypeName[c] = (char)tolower( typeName[c + stdTypeNameOffset] );
+ stdTypeName[c] = (char)tolower( typeName[c] );
stdTypeName[stdTypeNameSize] = '\0';
// Find what password type is represented by the type name.
diff --git a/core/java/algorithm/build.gradle b/core/java/algorithm/build.gradle
index c37d3236..d39c8889 100644
--- a/core/java/algorithm/build.gradle
+++ b/core/java/algorithm/build.gradle
@@ -8,6 +8,7 @@ dependencies {
compile (group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.6-p10') {
exclude( module: 'joda-time' )
}
+ compile group: 'com.lyndir.lhunath.opal', name: 'opal-crypto', version: '1.6-p10'
compile group: 'com.lambdaworks', name: 'scrypt', version: '1.4.0'
compile group: 'org.jetbrains', name: 'annotations', version: '13.0'
diff --git a/core/java/algorithm/pom.xml b/core/java/algorithm/pom.xml
index 757fa0d3..3da84269 100644
--- a/core/java/algorithm/pom.xml
+++ b/core/java/algorithm/pom.xml
@@ -31,6 +31,11 @@
+
+ com.lyndir.lhunath.opal
+ opal-crypto
+ 1.6-p9
+
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPConstant.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPConstant.java
index 15cbefbd..1610f496 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPConstant.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPConstant.java
@@ -32,68 +32,16 @@ public final class MPConstant {
/* Environment */
- /**
- * mpw: default user name if one is not provided.
- */
- public static final String env_userName = "MP_USERNAME";
- /**
- * mpw: default site type if one is not provided.
- *
- * @see MPSiteType#forOption(String)
- */
- public static final String env_siteType = "MP_SITETYPE";
- /**
- * mpw: default site counter value if one is not provided.
- */
- public static final String env_siteCounter = "MP_SITECOUNTER";
/**
* mpw: default path to look for run configuration files if the platform default is not desired.
*/
- public static final String env_rcDir = "MP_RCDIR";
+ public static final String env_rcDir = "MPW_RCDIR";
/**
* mpw: permit automatic update checks.
*/
- public static final String env_checkUpdates = "MP_CHECKUPDATES";
+ public static final String env_checkUpdates = "MPW_CHECKUPDATES";
/* Algorithm */
- /**
- * scrypt: CPU cost parameter.
- */
- public static final int scrypt_N = 32768;
- /**
- * scrypt: Memory cost parameter.
- */
- public static final int scrypt_r = 8;
- /**
- * scrypt: Parallelization parameter.
- */
- public static final int scrypt_p = 2;
- /**
- * mpw: Master key size (byte).
- */
- public static final int mpw_dkLen = 64;
- /**
- * mpw: Input character encoding.
- */
- public static final Charset mpw_charset = Charsets.UTF_8;
- /**
- * mpw: Platform-agnostic byte order.
- */
- public static final ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN;
- /**
- * mpw: Site digest.
- */
- public static final MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256;
- /**
- * mpw: Key ID hash.
- */
- public static final MessageDigests mpw_hash = MessageDigests.SHA256;
- /**
- * mpw: validity for the time-based rolling counter.
- */
- public static final int mpw_counter_timeout = 5 * 60 /* s */;
-
-
public static final int MS_PER_S = 1000;
}
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPKeyPurpose.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPKeyPurpose.java
new file mode 100644
index 00000000..db01353c
--- /dev/null
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPKeyPurpose.java
@@ -0,0 +1,90 @@
+//==============================================================================
+// 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;
+
+import com.google.common.collect.ImmutableList;
+import com.lyndir.lhunath.opal.system.logging.Logger;
+import java.util.List;
+import java.util.Locale;
+import javax.annotation.Nullable;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NonNls;
+
+
+/**
+ * @author lhunath, 14-12-02
+ */
+public enum MPKeyPurpose {
+ Password( "authentication", "Generate a key for authentication.", "com.lyndir.masterpassword" ),
+ Login( "identification", "Generate a name for identification.", "com.lyndir.masterpassword.login" ),
+ Answer( "recovery", "Generate an account recovery token.", "com.lyndir.masterpassword.answer" );
+
+ static final Logger logger = Logger.get( MPResultType.class );
+
+ private final String shortName;
+ private final String description;
+ private final String scope;
+
+ MPKeyPurpose(final String shortName, final String description, @NonNls final String scope) {
+ this.shortName = shortName;
+ this.description = description;
+ this.scope = scope;
+ }
+
+ public String getShortName() {
+ return shortName;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getScope() {
+ return scope;
+ }
+
+ /**
+ * @param shortNamePrefix The name for the purpose to look up. It is a case insensitive prefix of the purpose's short name.
+ *
+ * @return The purpose registered with the given name.
+ */
+ @Nullable
+ @Contract("!null -> !null")
+ public static MPKeyPurpose forName(@Nullable final String shortNamePrefix) {
+
+ if (shortNamePrefix == null)
+ return null;
+
+ for (final MPKeyPurpose type : values())
+ if (type.getShortName().toLowerCase( Locale.ROOT ).startsWith( shortNamePrefix.toLowerCase( Locale.ROOT ) ))
+ return type;
+
+ throw logger.bug( "No purpose for name: %s", shortNamePrefix );
+ }
+
+ public static MPKeyPurpose forInt(final int keyPurpose) {
+
+ return values()[keyPurpose];
+ }
+
+ public int toInt() {
+
+ return ordinal();
+ }
+}
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPSiteType.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPResultType.java
similarity index 63%
rename from core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPSiteType.java
rename to core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPResultType.java
index eb90dcf7..4725d90a 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPSiteType.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPResultType.java
@@ -24,7 +24,6 @@ import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.*;
import javax.annotation.Nullable;
import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NonNls;
/**
@@ -32,15 +31,13 @@ import org.jetbrains.annotations.NonNls;
*
* @author lhunath
*/
-public enum MPSiteType {
+public enum MPResultType {
- GeneratedMaximum( "Max", "20 characters, contains symbols.", //
- ImmutableList.of( "x", "max", "maximum" ), // NON-NLS
+ GeneratedMaximum( "Maximum", "20 characters, contains symbols.", //
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ), new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
- MPSiteTypeClass.Generated, 0x0 ),
+ MPResultTypeClass.Generated, 0x0 ),
GeneratedLong( "Long", "Copy-friendly, 14 characters, contains symbols.", //
- ImmutableList.of( "l", "long" ), // NON-NLS
ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ),
new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ),
@@ -52,65 +49,55 @@ public enum MPSiteType {
new MPTemplate( "CvcvCvccnoCvcc" ), new MPTemplate( "CvcvCvccCvccno" ),
new MPTemplate( "CvccnoCvcvCvcc" ), new MPTemplate( "CvccCvcvnoCvcc" ),
new MPTemplate( "CvccCvcvCvccno" ) ), //
- MPSiteTypeClass.Generated, 0x1 ),
+ MPResultTypeClass.Generated, 0x1 ),
GeneratedMedium( "Medium", "Copy-friendly, 8 characters, contains symbols.", //
- ImmutableList.of( "m", "med", "medium" ), // NON-NLS
ImmutableList.of( new MPTemplate( "CvcnoCvc" ), new MPTemplate( "CvcCvcno" ) ), //
- MPSiteTypeClass.Generated, 0x2 ),
+ MPResultTypeClass.Generated, 0x2 ),
GeneratedBasic( "Basic", "8 characters, no symbols.", //
- ImmutableList.of( "b", "basic" ), // NON-NLS
ImmutableList.of( new MPTemplate( "aaanaaan" ), new MPTemplate( "aannaaan" ), new MPTemplate( "aaannaaa" ) ), //
- MPSiteTypeClass.Generated, 0x3 ),
+ MPResultTypeClass.Generated, 0x3 ),
GeneratedShort( "Short", "Copy-friendly, 4 characters, no symbols.", //
- ImmutableList.of( "s", "short" ), // NON-NLS
ImmutableList.of( new MPTemplate( "Cvcn" ) ), //
- MPSiteTypeClass.Generated, 0x4 ),
+ MPResultTypeClass.Generated, 0x4 ),
GeneratedPIN( "PIN", "4 numbers.", //
- ImmutableList.of( "i", "pin" ), // NON-NLS
ImmutableList.of( new MPTemplate( "nnnn" ) ), //
- MPSiteTypeClass.Generated, 0x5 ),
+ MPResultTypeClass.Generated, 0x5 ),
GeneratedName( "Name", "9 letter name.", //
- ImmutableList.of( "n", "name" ), // NON-NLS
ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), //
- MPSiteTypeClass.Generated, 0xE ),
+ MPResultTypeClass.Generated, 0xE ),
GeneratedPhrase( "Phrase", "20 character sentence.", //
- ImmutableList.of( "p", "phrase" ), // NON-NLS
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ), new MPTemplate( "cvc cvccvcvcv cvcv" ),
new MPTemplate( "cv cvccv cvc cvcvccv" ) ), //
- MPSiteTypeClass.Generated, 0xF ),
+ MPResultTypeClass.Generated, 0xF ),
StoredPersonal( "Personal", "AES-encrypted, exportable.", //
- ImmutableList.of( "personal" ), // NON-NLS
ImmutableList.of(), //
- MPSiteTypeClass.Stored, 0x0, MPSiteFeature.ExportContent ),
+ MPResultTypeClass.Stored, 0x0, MPSiteFeature.ExportContent ),
StoredDevicePrivate( "Device", "AES-encrypted, not exported.", //
- ImmutableList.of( "device" ), // NON-NLS
ImmutableList.of(), //
- MPSiteTypeClass.Stored, 0x1, MPSiteFeature.DevicePrivate );
+ MPResultTypeClass.Stored, 0x1, MPSiteFeature.DevicePrivate );
- static final Logger logger = Logger.get( MPSiteType.class );
+ static final Logger logger = Logger.get( MPResultType.class );
private final String shortName;
private final String description;
- private final List options;
private final List templates;
- private final MPSiteTypeClass typeClass;
+ private final MPResultTypeClass typeClass;
private final int typeIndex;
private final Set typeFeatures;
- MPSiteType(final String shortName, final String description, final List options, final List templates,
- final MPSiteTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
+ MPResultType(final String shortName, final String description, final List templates,
+ final MPResultTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
this.shortName = shortName;
this.description = description;
- this.options = options;
this.templates = templates;
this.typeClass = typeClass;
this.typeIndex = typeIndex;
@@ -131,11 +118,7 @@ public enum MPSiteType {
return description;
}
- public List getOptions() {
- return options;
- }
-
- public MPSiteTypeClass getTypeClass() {
+ public MPResultTypeClass getTypeClass() {
return typeClass;
}
@@ -154,35 +137,22 @@ public enum MPSiteType {
}
/**
- * @param option The option to select a type with. It is matched case insensitively.
- *
- * @return The type registered for the given option.
- */
- public static MPSiteType forOption(final String option) {
-
- for (final MPSiteType type : values())
- if (type.getOptions().contains( option.toLowerCase( Locale.ROOT ) ))
- return type;
-
- throw logger.bug( "No type for option: %s", option );
- }
-
- /**
- * @param name The name fromInt the type to look up. It is matched case insensitively.
+ * @param shortNamePrefix The name for the type to look up. It is a case insensitive prefix of the type's short name.
*
* @return The type registered with the given name.
*/
+ @Nullable
@Contract("!null -> !null")
- public static MPSiteType forName(@Nullable final String name) {
+ public static MPResultType forName(@Nullable final String shortNamePrefix) {
- if (name == null)
+ if (shortNamePrefix == null)
return null;
- for (final MPSiteType type : values())
- if (type.name().equalsIgnoreCase( name ))
+ for (final MPResultType type : values())
+ if (type.getShortName().toLowerCase( Locale.ROOT ).startsWith( shortNamePrefix.toLowerCase( Locale.ROOT ) ))
return type;
- throw logger.bug( "No type for name: %s", name );
+ throw logger.bug( "No type for name: %s", shortNamePrefix );
}
/**
@@ -190,10 +160,10 @@ public enum MPSiteType {
*
* @return All types that support the given class.
*/
- public static ImmutableList forClass(final MPSiteTypeClass typeClass) {
+ public static ImmutableList forClass(final MPResultTypeClass typeClass) {
- ImmutableList.Builder types = ImmutableList.builder();
- for (final MPSiteType type : values())
+ ImmutableList.Builder types = ImmutableList.builder();
+ for (final MPResultType type : values())
if (type.getTypeClass() == typeClass)
types.add( type );
@@ -205,11 +175,11 @@ public enum MPSiteType {
*
* @return The type registered with the given type.
*/
- public static MPSiteType forType(final int type) {
+ public static MPResultType forType(final int type) {
- for (final MPSiteType siteType : values())
- if (siteType.getType() == type)
- return siteType;
+ for (final MPResultType resultType : values())
+ if (resultType.getType() == type)
+ return resultType;
throw logger.bug( "No type: %s", type );
}
@@ -219,17 +189,27 @@ public enum MPSiteType {
*
* @return All types that support the given mask.
*/
- public static ImmutableList forMask(final int mask) {
+ public static ImmutableList forMask(final int mask) {
- int typeMask = mask & ~0xF;
- ImmutableList.Builder types = ImmutableList.builder();
- for (final MPSiteType siteType : values())
- if (((siteType.getType() & ~0xF) & typeMask) != 0)
- types.add( siteType );
+ int typeMask = mask & ~0xF;
+ ImmutableList.Builder types = ImmutableList.builder();
+ for (final MPResultType resultType : values())
+ if (((resultType.getType() & ~0xF) & typeMask) != 0)
+ types.add( resultType );
return types.build();
}
+ public static MPResultType forInt(final int resultType) {
+
+ return values()[resultType];
+ }
+
+ public int toInt() {
+
+ return ordinal();
+ }
+
public MPTemplate getTemplateAtRollingIndex(final int templateIndex) {
return templates.get( templateIndex % templates.size() );
}
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPSiteTypeClass.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPResultTypeClass.java
similarity index 94%
rename from core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPSiteTypeClass.java
rename to core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPResultTypeClass.java
index e4ab3748..aed71f05 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPSiteTypeClass.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPResultTypeClass.java
@@ -23,13 +23,13 @@ package com.lyndir.masterpassword;
*
* @author lhunath
*/
-public enum MPSiteTypeClass {
+public enum MPResultTypeClass {
Generated( 1 << 4 ),
Stored( 1 << 5 );
private final int mask;
- MPSiteTypeClass(final int mask) {
+ MPResultTypeClass(final int mask) {
this.mask = mask;
}
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPSiteVariant.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPSiteVariant.java
deleted file mode 100644
index 3c6256ba..00000000
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPSiteVariant.java
+++ /dev/null
@@ -1,103 +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 .
-//==============================================================================
-
-package com.lyndir.masterpassword;
-
-import com.google.common.collect.ImmutableList;
-import com.lyndir.lhunath.opal.system.logging.Logger;
-import java.util.List;
-import java.util.Locale;
-import javax.annotation.Nullable;
-import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NonNls;
-
-
-/**
- * @author lhunath, 14-12-02
- */
-public enum MPSiteVariant {
- Password( "Generate a key for authentication.", "Doesn't currently use a context.", //
- ImmutableList.of( "p", "password" ), "com.lyndir.masterpassword" ), // NON-NLS
- Login( "Generate a name for identification.", "Doesn't currently use a context.", //
- ImmutableList.of( "l", "login" ), "com.lyndir.masterpassword.login" ), // NON-NLS
- Answer( "Generate an answer to a security question.", "Empty for a universal site answer or\nthe most significant word(s) of the question.", //
- ImmutableList.of( "a", "answer" ), "com.lyndir.masterpassword.answer" ); // NON-NLS
-
- static final Logger logger = Logger.get( MPSiteType.class );
-
- private final String description;
- private final String contextDescription;
- private final List options;
- private final String scope;
-
- MPSiteVariant(final String description, final String contextDescription, final List options, @NonNls final String scope) {
- this.contextDescription = contextDescription;
-
- this.options = options;
- this.description = description;
- this.scope = scope;
- }
-
- public String getDescription() {
- return description;
- }
-
- public String getContextDescription() {
- return contextDescription;
- }
-
- public List getOptions() {
- return options;
- }
-
- public String getScope() {
- return scope;
- }
-
- /**
- * @param option The option to select a variant with. It is matched case insensitively.
- *
- * @return The variant registered for the given option.
- */
- public static MPSiteVariant forOption(final String option) {
-
- for (final MPSiteVariant variant : values())
- if (variant.getOptions().contains( option.toLowerCase( Locale.ROOT ) ))
- return variant;
-
- throw logger.bug( "No variant for option: %s", option );
- }
- /**
- * @param name The name fromInt the variant to look up. It is matched case insensitively.
- *
- * @return The variant registered with the given name.
- */
- @Contract("!null -> !null")
- public static MPSiteVariant forName(@Nullable final String name) {
-
- if (name == null)
- return null;
-
- for (final MPSiteVariant type : values())
- if (type.name().equalsIgnoreCase( name ))
- return type;
-
- throw logger.bug( "No variant for name: %s", name );
- }
-
-}
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKey.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKey.java
index d8135da7..af9775b3 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKey.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKey.java
@@ -86,16 +86,61 @@ public abstract class MasterKey {
allowNativeByDefault = allowNative;
}
- protected MasterKey(@Nonnull final String fullName) {
+ protected MasterKey(final String fullName) {
+ Preconditions.checkArgument( !fullName.isEmpty() );
this.fullName = fullName;
logger.trc( "fullName: %s", fullName );
}
+ /**
+ * Derive the master key for a user based on their name and master password.
+ *
+ * @param masterPassword The user's master password.
+ */
@Nullable
@SuppressWarnings("MethodCanBeVariableArityMethod")
protected abstract byte[] deriveKey(char[] masterPassword);
+ /**
+ * Derive the site key for a user's site from the given master key and site parameters.
+ *
+ * @param siteName A site identifier.
+ * @param siteCounter The result identifier.
+ * @param keyPurpose The intended purpose for this site key.
+ * @param keyContext A site-scoped key modifier.
+ */
+ protected abstract byte[] siteKey(String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
+ @Nullable String keyContext);
+
+ /**
+ * Generate a site result token.
+ *
+ * @param siteName A site identifier.
+ * @param siteCounter The result identifier.
+ * @param keyPurpose The intended purpose for this site result.
+ * @param keyContext A site-scoped result modifier.
+ * @param resultType The type of result to generate.
+ * @param resultParam A parameter for the resultType. For stateful result types, the output of
+ * {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String)}.
+ */
+ public abstract String siteResult(String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
+ @Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
+
+ /**
+ * Encrypt a stateful site token for persistence.
+ *
+ * @param siteName A site identifier.
+ * @param siteCounter The result identifier.
+ * @param keyPurpose The intended purpose for the site token.
+ * @param keyContext A site-scoped key modifier.
+ * @param resultType The type of result token to encrypt.
+ * @param resultParam The result token desired from
+ * {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String)}.
+ */
+ public abstract String siteState(String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
+ @Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
+
public abstract Version getAlgorithmVersion();
@Nonnull
@@ -125,9 +170,6 @@ public abstract class MasterKey {
return idForBytes( getKey() );
}
- public abstract String encode(@Nonnull String siteName, MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
- MPSiteVariant siteVariant, @Nullable String siteContext);
-
public boolean isValid() {
return masterKey != null;
}
@@ -150,17 +192,17 @@ public abstract class MasterKey {
masterKey = deriveKey( masterPassword );
if (masterKey == null)
- logger.dbg( "masterKey calculation failed after %.2fs.", (double)(System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
+ logger.dbg( "masterKey calculation failed after %.2fs.", (double) (System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
else
logger.trc( "masterKey ID: %s (derived in %.2fs)", CodeUtils.encodeHex( idForBytes( masterKey ) ),
- (double)(System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
+ (double) (System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
return this;
}
protected abstract byte[] bytesForInt(int number);
- protected abstract byte[] bytesForInt(@Nonnull UnsignedInteger number);
+ protected abstract byte[] bytesForInt(UnsignedInteger number);
protected abstract byte[] idForBytes(byte[] bytes);
@@ -168,19 +210,19 @@ public abstract class MasterKey {
/**
* bugs:
* - does math with chars whose signedness was platform-dependent.
- * - miscounted the byte-length fromInt multi-byte site names.
- * - miscounted the byte-length fromInt multi-byte full names.
+ * - miscounted the byte-length for multi-byte site names.
+ * - miscounted the byte-length for multi-byte full names.
*/
V0,
/**
* bugs:
- * - miscounted the byte-length fromInt multi-byte site names.
- * - miscounted the byte-length fromInt multi-byte full names.
+ * - miscounted the byte-length for multi-byte site names.
+ * - miscounted the byte-length for multi-byte full names.
*/
V1,
/**
* bugs:
- * - miscounted the byte-length fromInt multi-byte full names.
+ * - miscounted the byte-length for multi-byte full names.
*/
V2,
/**
@@ -200,20 +242,5 @@ public abstract class MasterKey {
return ordinal();
}
-
- public String toBundleVersion() {
- switch (this) {
- case V0:
- return "1.0";
- case V1:
- return "2.0";
- case V2:
- return "2.1";
- case V3:
- return "2.2";
- }
-
- throw new UnsupportedOperationException( strf( "Unsupported version: %s", this ) );
- }
}
}
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV0.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV0.java
index 18b08891..e3dce3ab 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV0.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV0.java
@@ -18,30 +18,68 @@
package com.lyndir.masterpassword;
-import com.google.common.base.Preconditions;
+import com.google.common.base.*;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lambdaworks.crypto.SCrypt;
+import com.lyndir.lhunath.opal.crypto.CryptUtils;
import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.nio.*;
+import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.util.Arrays;
-import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.crypto.IllegalBlockSizeException;
/**
* bugs:
- * - V2: miscounted the byte-length fromInt multi-byte full names.
- * - V1: miscounted the byte-length fromInt multi-byte site names.
+ * - V2: miscounted the byte-length for multi-byte full names.
+ * - V1: miscounted the byte-length for multi-byte site names.
* - V0: does math with chars whose signedness was platform-dependent.
*
* @author lhunath, 2014-08-30
*/
public class MasterKeyV0 extends MasterKey {
- private static final int MP_intLen = 32;
+ /**
+ * mpw: validity for the time-based rolling counter.
+ */
+ protected static final int mpw_otp_window = 5 * 60 /* s */;
+ /**
+ * mpw: Key ID hash.
+ */
+ protected static final MessageDigests mpw_hash = MessageDigests.SHA256;
+ /**
+ * mpw: Site digest.
+ */
+ protected static final MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256;
+ /**
+ * mpw: Platform-agnostic byte order.
+ */
+ protected static final ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN;
+ /**
+ * mpw: Input character encoding.
+ */
+ protected static final Charset mpw_charset = Charsets.UTF_8;
+ /**
+ * mpw: Master key size (byte).
+ */
+ protected static final int mpw_dkLen = 64;
+ /**
+ * scrypt: Parallelization parameter.
+ */
+ protected static final int scrypt_p = 2;
+ /**
+ * scrypt: Memory cost parameter.
+ */
+ protected static final int scrypt_r = 8;
+ /**
+ * scrypt: CPU cost parameter.
+ */
+ protected static final int scrypt_N = 32768;
+ private static final int MP_intLen = 32;
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV0.class );
@@ -59,112 +97,171 @@ public class MasterKeyV0 extends MasterKey {
@Nullable
@Override
protected byte[] deriveKey(final char[] masterPassword) {
+ Preconditions.checkArgument( masterPassword.length > 0 );
+
String fullName = getFullName();
- byte[] fullNameBytes = fullName.getBytes( MPConstant.mpw_charset );
+ byte[] fullNameBytes = fullName.getBytes( mpw_charset );
byte[] fullNameLengthBytes = bytesForInt( fullName.length() );
+ ByteBuffer mpBytesBuf = mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
- String mpKeyScope = MPSiteVariant.Password.getScope();
- byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MPConstant.mpw_charset ), fullNameLengthBytes, fullNameBytes );
- logger.trc( "key scope: %s", mpKeyScope );
- logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
+ logger.trc( "-- mpw_masterKey (algorithm: %u)", getAlgorithmVersion().toInt() );
+ logger.trc( "fullName: %s", fullName );
+ logger.trc( "masterPassword.id: %s", (Object) idForBytes( mpBytesBuf.array() ) );
- ByteBuffer mpBytesBuf = MPConstant.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
+ String keyScope = MPKeyPurpose.Password.getScope();
+ logger.trc( "keyScope: %s", keyScope );
+
+ // Calculate the master key salt.
+ logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
+ keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
+ byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( mpw_charset ), fullNameLengthBytes, fullNameBytes );
+ logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
+
+ // Calculate the master key.
+ logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )",
+ scrypt_N, scrypt_r, scrypt_p );
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
+ byte[] masterKey = scrypt( masterKeySalt, mpBytes ); // TODO: Why not mpBytesBuf.array()?
+ Arrays.fill( masterKeySalt, (byte) 0 );
+ Arrays.fill( mpBytes, (byte) 0 );
+ logger.trc( " => masterKey.id: %s", (masterKey == null)? null: (Object) idForBytes( masterKey ) );
- return scrypt( masterKeySalt, mpBytes );
+ return masterKey;
}
@Nullable
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
try {
if (isAllowNative())
- return SCrypt.scrypt( mpBytes, masterKeySalt, MPConstant.scrypt_N, MPConstant.scrypt_r, MPConstant.scrypt_p, MPConstant.mpw_dkLen );
+ return SCrypt.scrypt( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
else
- return SCrypt.scryptJ( mpBytes, masterKeySalt, MPConstant.scrypt_N, MPConstant.scrypt_r, MPConstant.scrypt_p, MPConstant.mpw_dkLen );
+ return SCrypt.scryptJ( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
}
catch (final GeneralSecurityException e) {
logger.bug( e );
return null;
}
- finally {
- Arrays.fill( mpBytes, (byte) 0 );
- }
}
@Override
- public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
- final MPSiteVariant siteVariant, @Nullable final String siteContext) {
- Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
+ protected byte[] siteKey(final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
+ @Nullable final String keyContext) {
Preconditions.checkArgument( !siteName.isEmpty() );
+ logger.trc( "-- mpw_siteKey (algorithm: %u)", getAlgorithmVersion().toInt() );
logger.trc( "siteName: %s", siteName );
- logger.trc( "siteCounter: %d", siteCounter.longValue() );
- logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
- logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
+ logger.trc( "siteCounter: %d", siteCounter );
+ logger.trc( "keyPurpose: %d (%s)", keyPurpose.toInt(), keyPurpose.getShortName() );
+ logger.trc( "keyContext: %s", keyContext );
+ String keyScope = keyPurpose.getScope();
+ logger.trc( "keyScope: %s", keyScope );
+
+ // OTP counter value.
if (siteCounter.longValue() == 0)
- siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
+ siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (mpw_otp_window * 1000)) * mpw_otp_window );
- String siteScope = siteVariant.getScope();
- byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
+ // Calculate the site seed.
+ byte[] siteNameBytes = siteName.getBytes( mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter );
- byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
- byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
- logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "": siteContext );
- logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
- siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
- (siteContextBytes == null)? "(null)": siteContext );
+ byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( mpw_charset );
+ byte[] keyContextLengthBytes = (keyContextBytes == null)? null: bytesForInt( keyContextBytes.length );
+ logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
+ keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
+ (keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
- byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
- if (siteContextBytes != null)
- sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
- logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
+ byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
+ if (keyContextBytes != null)
+ sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
+ logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
- byte[] sitePasswordSeedBytes = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
- int[] sitePasswordSeed = new int[sitePasswordSeedBytes.length];
- for (int i = 0; i < sitePasswordSeedBytes.length; ++i) {
+ byte[] masterKey = getKey();
+ logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", (Object) idForBytes( masterKey ) );
+ byte[] sitePasswordSeedBytes = mpw_digest.of( masterKey, sitePasswordInfo );
+ logger.trc( " => siteKey.id: %s", (Object) idForBytes( sitePasswordSeedBytes ) );
+
+ return sitePasswordSeedBytes;
+ }
+
+ @Override
+ public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
+ @Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
+
+ byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext );
+ int[] sitePasswordSeed = new int[siteKey.length];
+ for (int i = 0; i < siteKey.length; ++i) {
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( ByteOrder.BIG_ENDIAN );
- Arrays.fill( buf.array(), (byte) ((sitePasswordSeedBytes[i] > 0)? 0x00: 0xFF) );
+ Arrays.fill( buf.array(), (byte) ((siteKey[i] > 0)? 0x00: 0xFF) );
buf.position( 2 );
- buf.put( sitePasswordSeedBytes[i] ).rewind();
+ buf.put( siteKey[i] ).rewind();
sitePasswordSeed[i] = buf.getInt() & 0xFFFF;
}
- logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
+ logger.trc( "-- mpw_siteResult (algorithm: %u)", getAlgorithmVersion().toInt() );
+ logger.trc( "resultType: %d (%s)", resultType.toInt(), resultType.getShortName() );
+ logger.trc( "resultParam: %s", resultParam );
+
+ // Determine the template.
Preconditions.checkState( sitePasswordSeed.length > 0 );
int templateIndex = sitePasswordSeed[0];
- MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
- logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
+ MPTemplate template = resultType.getTemplateAtRollingIndex( templateIndex );
+ logger.trc( "template: %u => %s", templateIndex, template.getTemplateString() );
+ // Encode the password from the seed using the template.
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = sitePasswordSeed[i + 1];
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
- logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
- sitePasswordSeed[i + 1], passwordCharacter );
+ logger.trc( " - class: %c, index: %5u (0x%02hX) => character: %c",
+ characterClass.getIdentifier(), characterIndex, sitePasswordSeed[i + 1], passwordCharacter );
password.append( passwordCharacter );
}
+ logger.trc( " => password: %s", password );
return password.toString();
}
@Override
- protected byte[] bytesForInt(final int number) {
- return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MPConstant.mpw_byteOrder ).putInt( number ).array();
+ public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
+ @Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
+
+ Preconditions.checkNotNull( resultParam );
+ Preconditions.checkArgument( !resultParam.isEmpty() );
+
+ try {
+ // Encrypt
+ ByteBuffer plainText = mpw_charset.encode( CharBuffer.wrap( resultParam ) );
+ byte[] cipherBuf = CryptUtils.encrypt( plainText.array(), getKey(), true );
+ logger.trc( "cipherBuf: %zu bytes = %s", cipherBuf.length, CodeUtils.encodeHex( cipherBuf ) );
+
+ // Base64-encode
+ String cipherText = Verify.verifyNotNull( CryptUtils.encodeBase64( cipherBuf ) );
+ logger.trc( "b64 encoded -> cipherText: %s", cipherText );
+
+ return cipherText;
+ }
+ catch (final IllegalBlockSizeException e) {
+ throw logger.bug( e );
+ }
}
@Override
- protected byte[] bytesForInt(@Nonnull final UnsignedInteger number) {
- return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MPConstant.mpw_byteOrder ).putInt( number.intValue() ).array();
+ protected byte[] bytesForInt(final int number) {
+ return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( mpw_byteOrder ).putInt( number ).array();
+ }
+
+ @Override
+ protected byte[] bytesForInt(final UnsignedInteger number) {
+ return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( mpw_byteOrder ).putInt( number.intValue() ).array();
}
@Override
protected byte[] idForBytes(final byte[] bytes) {
- return MPConstant.mpw_hash.of( bytes );
+ return mpw_hash.of( bytes );
}
}
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV1.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV1.java
index 47d1a17d..3dcfad27 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV1.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV1.java
@@ -23,14 +23,13 @@ import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
-import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* bugs:
- * - V2: miscounted the byte-length fromInt multi-byte full names.
- * - V1: miscounted the byte-length fromInt multi-byte site names.
+ * - V2: miscounted the byte-length for multi-byte full names.
+ * - V1: miscounted the byte-length for multi-byte site names.
*
* @author lhunath, 2014-08-30
*/
@@ -50,53 +49,33 @@ public class MasterKeyV1 extends MasterKeyV0 {
}
@Override
- public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
- final MPSiteVariant siteVariant, @Nullable final String siteContext) {
- Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
- Preconditions.checkArgument( !siteName.isEmpty() );
+ public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
+ @Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
- logger.trc( "siteName: %s", siteName );
- logger.trc( "siteCounter: %d", siteCounter.longValue() );
- logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
- logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
+ byte[] sitePasswordSeed = siteKey( siteName, siteCounter, keyPurpose, keyContext );
- if (siteCounter.longValue() == 0)
- siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
-
- String siteScope = siteVariant.getScope();
- byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
- byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
- byte[] siteCounterBytes = bytesForInt( siteCounter );
- byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
- byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
- logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "": siteContext );
- logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
- siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
- (siteContextBytes == null)? "(null)": siteContext );
-
- byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
- if (siteContextBytes != null)
- sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
- logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
-
- byte[] sitePasswordSeed = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
- logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) );
+ logger.trc( "-- mpw_siteResult (algorithm: %u)", getAlgorithmVersion().toInt() );
+ logger.trc( "resultType: %d (%s)", resultType.toInt(), resultType.getShortName() );
+ logger.trc( "resultParam: %s", resultParam );
+ // Determine the template.
Preconditions.checkState( sitePasswordSeed.length > 0 );
int templateIndex = sitePasswordSeed[0] & 0xFF; // Mask the integer's sign.
- MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
- logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
+ MPTemplate template = resultType.getTemplateAtRollingIndex( templateIndex );
+ logger.trc( "template: %u => %s", templateIndex, template.getTemplateString() );
+ // Encode the password from the seed using the template.
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = sitePasswordSeed[i + 1] & 0xFF; // Mask the integer's sign.
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
- logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
- sitePasswordSeed[i + 1], passwordCharacter );
+ logger.trc( " - class: %c, index: %3u (0x%02hhX) => character: %c",
+ characterClass.getIdentifier(), characterIndex, sitePasswordSeed[i + 1], passwordCharacter );
password.append( passwordCharacter );
}
+ logger.trc( " => password: %s", password );
return password.toString();
}
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV2.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV2.java
index e5472414..9ad93303 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV2.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV2.java
@@ -23,13 +23,12 @@ import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
-import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* bugs:
- * - V2: miscounted the byte-length fromInt multi-byte full names.
+ * - V2: miscounted the byte-length for multi-byte full names.
*
* @author lhunath, 2014-08-30
*/
@@ -49,54 +48,43 @@ public class MasterKeyV2 extends MasterKeyV1 {
}
@Override
- public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
- final MPSiteVariant siteVariant, @Nullable final String siteContext) {
- Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
+ protected byte[] siteKey(final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
+ @Nullable final String keyContext) {
Preconditions.checkArgument( !siteName.isEmpty() );
+ logger.trc( "-- mpw_siteKey (algorithm: %u)", getAlgorithmVersion().toInt() );
logger.trc( "siteName: %s", siteName );
- logger.trc( "siteCounter: %d", siteCounter.longValue() );
- logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
- logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
+ logger.trc( "siteCounter: %d", siteCounter );
+ logger.trc( "keyPurpose: %d (%s)", keyPurpose.toInt(), keyPurpose.getShortName() );
+ logger.trc( "keyContext: %s", keyContext );
+ String keyScope = keyPurpose.getScope();
+ logger.trc( "keyScope: %s", keyScope );
+
+ // OTP counter value.
if (siteCounter.longValue() == 0)
- siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
+ siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MasterKeyV0.mpw_otp_window * 1000)) * MasterKeyV0.mpw_otp_window );
- String siteScope = siteVariant.getScope();
- byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
+ // Calculate the site seed.
+ byte[] siteNameBytes = siteName.getBytes( MasterKeyV0.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
byte[] siteCounterBytes = bytesForInt( siteCounter );
- byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
- byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
- logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "": siteContext );
- logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
- siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
- (siteContextBytes == null)? "(null)": siteContext );
+ byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( MasterKeyV0.mpw_charset );
+ byte[] keyContextLengthBytes = (keyContextBytes == null)? null: bytesForInt( keyContextBytes.length );
+ logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
+ keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
+ (keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
- byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
- if (siteContextBytes != null)
- sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
- logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
+ byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( MasterKeyV0.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
+ if (keyContextBytes != null)
+ sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
+ logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
- byte[] sitePasswordSeed = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
- logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) );
+ byte[] masterKey = getKey();
+ logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", (Object) idForBytes( masterKey ) );
+ byte[] sitePasswordSeedBytes = MasterKeyV0.mpw_digest.of( masterKey, sitePasswordInfo );
+ logger.trc( " => siteKey.id: %s", (Object) idForBytes( sitePasswordSeedBytes ) );
- Preconditions.checkState( sitePasswordSeed.length > 0 );
- int templateIndex = sitePasswordSeed[0] & 0xFF; // Mask the integer's sign.
- MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
- logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
-
- StringBuilder password = new StringBuilder( template.length() );
- for (int i = 0; i < template.length(); ++i) {
- int characterIndex = sitePasswordSeed[i + 1] & 0xFF; // Mask the integer's sign.
- MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
- char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
- logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
- sitePasswordSeed[i + 1], passwordCharacter );
-
- password.append( passwordCharacter );
- }
-
- return password.toString();
+ return sitePasswordSeedBytes;
}
}
diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV3.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV3.java
index 041af542..5baacbb5 100644
--- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV3.java
+++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MasterKeyV3.java
@@ -18,6 +18,7 @@
package com.lyndir.masterpassword;
+import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
@@ -51,19 +52,37 @@ public class MasterKeyV3 extends MasterKeyV2 {
@Nullable
@Override
protected byte[] deriveKey(final char[] masterPassword) {
- byte[] fullNameBytes = getFullName().getBytes( MPConstant.mpw_charset );
+ Preconditions.checkArgument( masterPassword.length > 0 );
+
+ String fullName = getFullName();
+ byte[] fullNameBytes = fullName.getBytes( MasterKeyV0.mpw_charset );
byte[] fullNameLengthBytes = bytesForInt( fullNameBytes.length );
+ ByteBuffer mpBytesBuf = MasterKeyV0.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
- String mpKeyScope = MPSiteVariant.Password.getScope();
- byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MPConstant.mpw_charset ), fullNameLengthBytes, fullNameBytes );
- logger.trc( "key scope: %s", mpKeyScope );
- logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
+ logger.trc( "-- mpw_masterKey (algorithm: %u)", getAlgorithmVersion().toInt() );
+ logger.trc( "fullName: %s", fullName );
+ logger.trc( "masterPassword.id: %s", (Object) idForBytes( mpBytesBuf.array() ) );
- ByteBuffer mpBytesBuf = MPConstant.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
+ String keyScope = MPKeyPurpose.Password.getScope();
+ logger.trc( "keyScope: %s", keyScope );
+
+ // Calculate the master key salt.
+ logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
+ keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
+ byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( MasterKeyV0.mpw_charset ), fullNameLengthBytes, fullNameBytes );
+ logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
+
+ // Calculate the master key.
+ logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )",
+ MasterKeyV0.scrypt_N, MasterKeyV0.scrypt_r, MasterKeyV0.scrypt_p );
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
+ byte[] masterKey = scrypt( masterKeySalt, mpBytes ); // TODO: Why not mpBytesBuf.array()?
+ Arrays.fill( masterKeySalt, (byte) 0 );
+ Arrays.fill( mpBytes, (byte) 0 );
+ logger.trc( " => masterKey.id: %s", (masterKey == null)? null: (Object) idForBytes( masterKey ) );
- return scrypt( masterKeySalt, mpBytes );
+ return masterKey;
}
}
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 e23a03fe..872f5bc9 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
@@ -14,50 +14,50 @@ import org.joda.time.Instant;
*/
public class MPSite {
- public static final MPSiteType DEFAULT_TYPE = MPSiteType.GeneratedLong;
+ public static final MPResultType DEFAULT_TYPE = MPResultType.GeneratedLong;
public static final UnsignedInteger DEFAULT_COUNTER = UnsignedInteger.valueOf( 1 );
private final MPUser user;
private MasterKey.Version algorithmVersion;
private Instant lastUsed;
private String siteName;
- private MPSiteType siteType;
+ private MPResultType resultType;
private UnsignedInteger siteCounter;
private int uses;
private String loginName;
public MPSite(final MPUser user, final String siteName) {
- this( user, siteName, DEFAULT_TYPE, DEFAULT_COUNTER );
+ this( user, siteName, DEFAULT_COUNTER, DEFAULT_TYPE );
}
- public MPSite(final MPUser user, final String siteName, final MPSiteType siteType, final UnsignedInteger siteCounter) {
+ public MPSite(final MPUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType) {
this.user = user;
this.algorithmVersion = MasterKey.Version.CURRENT;
this.lastUsed = new Instant();
this.siteName = siteName;
- this.siteType = siteType;
+ this.resultType = resultType;
this.siteCounter = siteCounter;
}
protected MPSite(final MPUser user, final MasterKey.Version algorithmVersion, final Instant lastUsed, final String siteName,
- final MPSiteType siteType, final UnsignedInteger siteCounter, final int uses, @Nullable final String loginName,
+ final MPResultType resultType, final UnsignedInteger siteCounter, final int uses, @Nullable final String loginName,
@Nullable final String importContent) {
this.user = user;
this.algorithmVersion = algorithmVersion;
this.lastUsed = lastUsed;
this.siteName = siteName;
- this.siteType = siteType;
+ this.resultType = resultType;
this.siteCounter = siteCounter;
this.uses = uses;
this.loginName = loginName;
}
public String resultFor(final MasterKey masterKey) {
- return resultFor( masterKey, MPSiteVariant.Password, null );
+ return resultFor( masterKey, MPKeyPurpose.Password, null );
}
- public String resultFor(final MasterKey masterKey, final MPSiteVariant variant, @Nullable final String context) {
- return masterKey.encode( siteName, siteType, siteCounter, variant, context );
+ public String resultFor(final MasterKey masterKey, final MPKeyPurpose purpose, @Nullable final String context) {
+ return masterKey.siteResult( siteName, siteCounter, purpose, context, resultType, null );
}
public MPUser getUser() {
@@ -94,12 +94,12 @@ public class MPSite {
this.siteName = siteName;
}
- public MPSiteType getSiteType() {
- return siteType;
+ public MPResultType getResultType() {
+ return resultType;
}
- public void setSiteType(final MPSiteType siteType) {
- this.siteType = siteType;
+ public void setResultType(final MPResultType resultType) {
+ this.resultType = resultType;
}
public UnsignedInteger getSiteCounter() {
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSiteMarshaller.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSiteMarshaller.java
index 6c109004..5210c91d 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSiteMarshaller.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSiteMarshaller.java
@@ -64,7 +64,7 @@ public class MPSiteMarshaller {
header.append( "# Full Name: " ).append( user.getFullName() ).append( '\n' );
header.append( "# Avatar: " ).append( user.getAvatar() ).append( '\n' );
header.append( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' );
- header.append( "# Version: " ).append( MasterKey.Version.CURRENT.toBundleVersion() ).append( '\n' );
+// header.append( "# Version: " ).append( MasterKey.Version.CURRENT.toBundleVersion() ).append( '\n' );
header.append( "# Algorithm: " ).append( MasterKey.Version.CURRENT.toInt() ).append( '\n' );
header.append( "# Default Type: " ).append( user.getDefaultType().getType() ).append( '\n' );
header.append( "# Passwords: " ).append( this.contentMode.name() ).append( '\n' );
@@ -82,7 +82,7 @@ public class MPSiteMarshaller {
rfc3339.print( site.getLastUsed() ), // lastUsed
site.getUses(), // uses
strf( "%d:%d:%d", //
- site.getSiteType().getType(), // type
+ site.getResultType().getType(), // type
site.getAlgorithmVersion().toInt(), // algorithm
site.getSiteCounter().intValue() ), // counter
ifNotNullElse( site.getLoginName(), "" ), // loginName
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSiteUnmarshaller.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSiteUnmarshaller.java
index c0dbc4bc..69a8f928 100644
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSiteUnmarshaller.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPSiteUnmarshaller.java
@@ -11,7 +11,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.lhunath.opal.system.util.NNOperation;
-import com.lyndir.masterpassword.MPSiteType;
+import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.MasterKey;
import java.io.*;
import java.util.List;
@@ -54,13 +54,13 @@ public class MPSiteUnmarshaller {
@Nonnull
public static MPSiteUnmarshaller unmarshall(@Nonnull final List lines) {
- byte[] keyID = null;
- String fullName = null;
- int mpVersion = 0, importFormat = 0, avatar = 0;
- boolean clearContent = false, headerStarted = false;
- MPSiteType defaultType = MPSiteType.GeneratedLong;
- MPSiteUnmarshaller marshaller = null;
- final ImmutableList.Builder sites = ImmutableList.builder();
+ byte[] keyID = null;
+ String fullName = null;
+ int mpVersion = 0, importFormat = 0, avatar = 0;
+ boolean clearContent = false, headerStarted = false;
+ MPResultType defaultType = MPResultType.GeneratedLong;
+ MPSiteUnmarshaller marshaller = null;
+ final ImmutableList.Builder sites = ImmutableList.builder();
for (final String line : lines)
// Header delimitor.
@@ -92,7 +92,7 @@ public class MPSiteUnmarshaller {
else if ("Passwords".equalsIgnoreCase( name ))
clearContent = "visible".equalsIgnoreCase( value );
else if ("Default Type".equalsIgnoreCase( name ))
- defaultType = MPSiteType.forType( ConversionUtils.toIntegerNN( value ) );
+ defaultType = MPResultType.forType( ConversionUtils.toIntegerNN( value ) );
}
}
}
@@ -110,7 +110,7 @@ public class MPSiteUnmarshaller {
}
protected MPSiteUnmarshaller(final int importFormat, final int mpVersion, final String fullName, final byte[] keyID, final int avatar,
- final MPSiteType defaultType, final boolean clearContent) {
+ final MPResultType defaultType, final boolean clearContent) {
this.importFormat = importFormat;
this.mpVersion = mpVersion;
this.clearContent = clearContent;
@@ -131,7 +131,7 @@ public class MPSiteUnmarshaller {
MasterKey.Version.fromInt( ConversionUtils.toIntegerNN( siteMatcher.group( 4 ).replace( ":", "" ) ) ), //
rfc3339.parseDateTime( siteMatcher.group( 1 ) ).toInstant(), //
siteMatcher.group( 5 ), //
- MPSiteType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ), MPSite.DEFAULT_COUNTER, //
+ MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ), MPSite.DEFAULT_COUNTER, //
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ), //
null, //
siteMatcher.group( 6 ) );
@@ -142,7 +142,7 @@ public class MPSiteUnmarshaller {
MasterKey.Version.fromInt( ConversionUtils.toIntegerNN( siteMatcher.group( 4 ).replace( ":", "" ) ) ), //
rfc3339.parseDateTime( siteMatcher.group( 1 ) ).toInstant(), //
siteMatcher.group( 7 ), //
- MPSiteType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
+ MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
UnsignedInteger.valueOf( siteMatcher.group( 5 ).replace( ":", "" ) ), //
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ), //
siteMatcher.group( 6 ), //
diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUser.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUser.java
index e75806e2..ef08c212 100755
--- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUser.java
+++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPUser.java
@@ -5,7 +5,7 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.lyndir.lhunath.opal.system.CodeUtils;
-import com.lyndir.masterpassword.MPSiteType;
+import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.MasterKey;
import java.util.*;
import javax.annotation.Nonnull;
@@ -25,7 +25,7 @@ public class MPUser implements Comparable {
private byte[] keyID;
private final MasterKey.Version algorithmVersion;
private int avatar;
- private MPSiteType defaultType;
+ private MPResultType defaultType;
private ReadableInstant lastUsed;
public MPUser(final String fullName) {
@@ -33,11 +33,11 @@ public class MPUser implements Comparable {
}
public MPUser(final String fullName, @Nullable final byte[] keyID) {
- this( fullName, keyID, MasterKey.Version.CURRENT, 0, MPSiteType.GeneratedLong, new DateTime() );
+ this( fullName, keyID, MasterKey.Version.CURRENT, 0, MPResultType.GeneratedLong, new DateTime() );
}
public MPUser(final String fullName, @Nullable final byte[] keyID, final MasterKey.Version algorithmVersion, final int avatar,
- final MPSiteType defaultType, final ReadableInstant lastUsed) {
+ final MPResultType defaultType, final ReadableInstant lastUsed) {
this.fullName = fullName;
this.keyID = (keyID == null)? null: keyID.clone();
this.algorithmVersion = algorithmVersion;
@@ -107,11 +107,11 @@ public class MPUser implements Comparable {
this.avatar = avatar;
}
- public MPSiteType getDefaultType() {
+ public MPResultType getDefaultType() {
return defaultType;
}
- public void setDefaultType(final MPSiteType defaultType) {
+ public void setDefaultType(final MPResultType defaultType) {
this.defaultType = defaultType;
}
diff --git a/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTestSuite.java b/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTestSuite.java
index 8eaa6fea..4af802d0 100644
--- a/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTestSuite.java
+++ b/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTestSuite.java
@@ -99,12 +99,12 @@ public class MPTestSuite implements Callable {
currentCase.siteName = text;
if ("siteCounter".equals( qName ))
currentCase.siteCounter = text.isEmpty()? null: UnsignedInteger.valueOf( text );
- if ("siteType".equals( qName ))
- currentCase.siteType = text;
- if ("siteVariant".equals( qName ))
- currentCase.siteVariant = text;
- if ("siteContext".equals( qName ))
- currentCase.siteContext = text;
+ if ("resultType".equals( qName ))
+ currentCase.resultType = text;
+ if ("keyPurpose".equals( qName ))
+ currentCase.keyPurpose = text;
+ if ("keyContext".equals( qName ))
+ currentCase.keyContext = text;
if ("result".equals( qName ))
currentCase.result = text;
}
@@ -173,8 +173,9 @@ public class MPTestSuite implements Callable {
@Override
public Boolean apply(@Nonnull final MPTests.Case testCase) {
MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() );
- String sitePassword = masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(),
- testCase.getSiteVariant(), testCase.getSiteContext() );
+ String sitePassword = masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
+ testCase.getKeyContext(), testCase.getResultType(),
+ null );
return testCase.getResult().equals( sitePassword );
}
diff --git a/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java b/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java
index c7ba7fe2..1c79c157 100644
--- a/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java
+++ b/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java
@@ -66,18 +66,18 @@ public class MPTests {
public static class Case {
- String identifier;
- String parent;
- Integer algorithm;
- String fullName;
- String masterPassword;
- String keyID;
- String siteName;
+ String identifier;
+ String parent;
+ Integer algorithm;
+ String fullName;
+ String masterPassword;
+ String keyID;
+ String siteName;
UnsignedInteger siteCounter;
- String siteType;
- String siteVariant;
- String siteContext;
- String result;
+ String resultType;
+ String keyPurpose;
+ String keyContext;
+ String result;
private transient Case parentCase;
@@ -130,25 +130,25 @@ public class MPTests {
return checkNotNull( parentCase.siteCounter );
}
} );
- siteType = ifNotNullElse( siteType, new NNSupplier() {
+ resultType = ifNotNullElse( resultType, new NNSupplier() {
@Nonnull
@Override
public String get() {
- return checkNotNull( parentCase.siteType );
+ return checkNotNull( parentCase.resultType );
}
} );
- siteVariant = ifNotNullElse( siteVariant, new NNSupplier() {
+ keyPurpose = ifNotNullElse( keyPurpose, new NNSupplier() {
@Nonnull
@Override
public String get() {
- return checkNotNull( parentCase.siteVariant );
+ return checkNotNull( parentCase.keyPurpose );
}
} );
- siteContext = ifNotNullElse( siteContext, new NNSupplier() {
+ keyContext = ifNotNullElse( keyContext, new NNSupplier() {
@Nonnull
@Override
public String get() {
- return (parentCase == null)? "": checkNotNull( parentCase.siteContext );
+ return (parentCase == null)? "": checkNotNull( parentCase.keyContext );
}
} );
result = ifNotNullElse( result, new NNSupplier() {
@@ -200,18 +200,18 @@ public class MPTests {
}
@Nonnull
- public MPSiteType getSiteType() {
- return MPSiteType.forName( checkNotNull( siteType ) );
+ public MPResultType getResultType() {
+ return MPResultType.forName( checkNotNull( resultType ) );
}
@Nonnull
- public MPSiteVariant getSiteVariant() {
- return MPSiteVariant.forName( checkNotNull( siteVariant ) );
+ public MPKeyPurpose getKeyPurpose() {
+ return MPKeyPurpose.forName( checkNotNull( keyPurpose ) );
}
@Nonnull
- public String getSiteContext() {
- return checkNotNull( siteContext );
+ public String getKeyContext() {
+ return checkNotNull( keyContext );
}
@Nonnull
diff --git a/core/java/tests/src/main/resources/mpw_tests.xml b/core/java/tests/src/main/resources/mpw_tests.xml
index 36465d8b..01f56a9a 100644
--- a/core/java/tests/src/main/resources/mpw_tests.xml
+++ b/core/java/tests/src/main/resources/mpw_tests.xml
@@ -7,7 +7,7 @@
98EEF4D1DF46D849574A82A03C3177056B15DFFCA29BB3899DE4628453675302masterpasswordapp.com1
- GeneratedLong
+ LongAuthentication
@@ -33,12 +33,12 @@
Identification
- GeneratedName
+ NamewohzaqageRecovery
- GeneratedPhrase
+ Phrasexin diyjiqoja hubu
@@ -46,31 +46,31 @@
xogx tem cegyiva jab
- GeneratedMaximum
+ MaximumW6@692^B1#&@gVdSdLZ@
- GeneratedMedium
+ MediumJej2$Quv
- GeneratedBasic
+ BasicWAo2xIg6
- GeneratedShort
+ ShortJej2
- GeneratedPIN
+ PIN7662
- GeneratedName
+ Namejejraquvo
- GeneratedPhrase
+ Phrasejejr quv cabsibu tam
@@ -99,12 +99,12 @@
Identification
- GeneratedName
+ NamewohzaqageRecovery
- GeneratedPhrase
+ Phrasexin diyjiqoja hubu
@@ -112,31 +112,31 @@
xogx tem cegyiva jab
- GeneratedMaximum
+ MaximumW6@692^B1#&@gVdSdLZ@
- GeneratedMedium
+ MediumJej2$Quv
- GeneratedBasic
+ BasicWAo2xIg6
- GeneratedShort
+ ShortJej2
- GeneratedPIN
+ PIN7662
- GeneratedName
+ Namejejraquvo
- GeneratedPhrase
+ Phrasejejr quv cabsibu tam
@@ -165,12 +165,12 @@
Identification
- GeneratedName
+ NamewohzaqageRecovery
- GeneratedPhrase
+ Phrasexin diyjiqoja hubu
@@ -178,31 +178,31 @@
xogx tem cegyiva jab
- GeneratedMaximum
+ MaximumW6@692^B1#&@gVdSdLZ@
- GeneratedMedium
+ MediumJej2$Quv
- GeneratedBasic
+ BasicWAo2xIg6
- GeneratedShort
+ ShortJej2
- GeneratedPIN
+ PIN7662
- GeneratedName
+ Namejejraquvo
- GeneratedPhrase
+ Phrasejejr quv cabsibu tam
@@ -231,12 +231,12 @@
Identification
- GeneratedName
+ NamelozwajaveRecovery
- GeneratedPhrase
+ Phrasemiy lirfijoja dubu
@@ -244,31 +244,31 @@
movm bex gevrica jaf
- GeneratedMaximum
+ Maximumw1!3bA3icmRAc)SS@lwl
- GeneratedMedium
+ MediumFej7]Jug
- GeneratedBasic
+ BasicwvH7irC1
- GeneratedShort
+ ShortFej7
- GeneratedPIN
+ PIN2117
- GeneratedName
+ Namefejrajugo
- GeneratedPhrase
+ Phrasefejr jug gabsibu bax
diff --git a/core/java/tests/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java b/core/java/tests/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java
index 803c6a00..82144f3c 100644
--- a/core/java/tests/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java
+++ b/core/java/tests/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java
@@ -55,8 +55,9 @@ public class MasterKeyTest {
MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() );
assertEquals(
- masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(),
- testCase.getSiteVariant(), testCase.getSiteContext() ),
+ masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
+ testCase.getKeyContext(), testCase.getResultType(),
+ null ),
testCase.getResult(), "[testEncode] Failed test case: " + testCase );
return true;
@@ -101,8 +102,9 @@ public class MasterKeyTest {
MasterKey masterKey = MasterKey.create( defaultCase.getFullName(), defaultCase.getMasterPassword() );
masterKey.invalidate();
- masterKey.encode( defaultCase.getSiteName(), defaultCase.getSiteType(), defaultCase.getSiteCounter(),
- defaultCase.getSiteVariant(), defaultCase.getSiteContext() );
+ masterKey.siteResult( defaultCase.getSiteName(), defaultCase.getSiteCounter(), defaultCase.getKeyPurpose(),
+ defaultCase.getKeyContext(), defaultCase.getResultType(),
+ null );
fail( "[testInvalidate] Master key should have been invalidated, but was still usable." );
}
diff --git a/gradle/pom.xml b/gradle/pom.xml
index a4bbcf3e..d9abad1e 100644
--- a/gradle/pom.xml
+++ b/gradle/pom.xml
@@ -22,7 +22,6 @@
masterpassword-testsmasterpassword-algorithmmasterpassword-model
- masterpassword-climasterpassword-gui
diff --git a/gradle/settings.gradle b/gradle/settings.gradle
index 151e9057..a56506d2 100644
--- a/gradle/settings.gradle
+++ b/gradle/settings.gradle
@@ -9,9 +9,6 @@ project(':masterpassword-model').projectDir = new File( '../core/java/model' )
include 'masterpassword-tests'
project(':masterpassword-tests').projectDir = new File( '../core/java/tests' )
-include 'masterpassword-cli'
-project(':masterpassword-cli').projectDir = new File( '../platform-independent/cli-java' )
-
include 'masterpassword-gui'
project(':masterpassword-gui').projectDir = new File( '../platform-independent/gui-java' )
diff --git a/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java b/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java
index 88ae8672..9011ffb5 100644
--- a/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java
+++ b/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java
@@ -52,10 +52,10 @@ public class EmergencyActivity extends Activity {
private static final int PASSWORD_NOTIFICATION = 0;
public static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S;
- private final Preferences preferences = Preferences.get( this );
- private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
- private final ImmutableList allSiteTypes = ImmutableList.copyOf( MPSiteType.forClass( MPSiteTypeClass.Generated ) );
- private final ImmutableList allVersions = ImmutableList.copyOf( MasterKey.Version.values() );
+ private final Preferences preferences = Preferences.get( this );
+ private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
+ private final ImmutableList allResultTypes = ImmutableList.copyOf( MPResultType.forClass( MPResultTypeClass.Generated ) );
+ private final ImmutableList allVersions = ImmutableList.copyOf( MasterKey.Version.values() );
private ListenableFuture masterKeyFuture;
@@ -71,8 +71,8 @@ public class EmergencyActivity extends Activity {
@BindView(R.id.siteNameField)
EditText siteNameField;
- @BindView(R.id.siteTypeButton)
- Button siteTypeButton;
+ @BindView(R.id.resultTypeButton)
+ Button resultTypeButton;
@BindView(R.id.counterField)
Button siteCounterButton;
@@ -131,15 +131,15 @@ public class EmergencyActivity extends Activity {
updateSitePassword();
}
} );
- siteTypeButton.setOnClickListener( new View.OnClickListener() {
+ resultTypeButton.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(final View v) {
@SuppressWarnings("SuspiciousMethodCalls")
- MPSiteType siteType =
- allSiteTypes.get( (allSiteTypes.indexOf( siteTypeButton.getTag() ) + 1) % allSiteTypes.size() );
- preferences.setDefaultSiteType( siteType );
- siteTypeButton.setTag( siteType );
- siteTypeButton.setText( siteType.getShortName() );
+ MPResultType resultType =
+ allResultTypes.get( (allResultTypes.indexOf( resultTypeButton.getTag() ) + 1) % allResultTypes.size() );
+ preferences.setDefaultResultType( resultType );
+ resultTypeButton.setTag( resultType );
+ resultTypeButton.setText( resultType.getShortName() );
updateSitePassword();
}
} );
@@ -220,9 +220,9 @@ public class EmergencyActivity extends Activity {
forgetPasswordField.setChecked( preferences.isForgetPassword() );
maskPasswordField.setChecked( preferences.isMaskPassword() );
sitePasswordField.setTransformationMethod( preferences.isMaskPassword()? new PasswordTransformationMethod(): null );
- MPSiteType defaultSiteType = preferences.getDefaultSiteType();
- siteTypeButton.setTag( defaultSiteType );
- siteTypeButton.setText( defaultSiteType.getShortName() );
+ MPResultType defaultResultType = preferences.getDefaultResultType();
+ resultTypeButton.setTag( defaultResultType );
+ resultTypeButton.setText( defaultResultType.getShortName() );
MasterKey.Version defaultVersion = preferences.getDefaultVersion();
siteVersionButton.setTag( defaultVersion );
siteVersionButton.setText( defaultVersion.name() );
@@ -313,9 +313,9 @@ public class EmergencyActivity extends Activity {
}
private void updateSitePassword() {
- final String siteName = siteNameField.getText().toString();
- final MPSiteType type = (MPSiteType) siteTypeButton.getTag();
- final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() );
+ final String siteName = siteNameField.getText().toString();
+ final MPResultType type = (MPResultType) resultTypeButton.getTag();
+ final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() );
if ((masterKeyFuture == null) || siteName.isEmpty() || (type == null)) {
sitePasswordField.setText( "" );
@@ -332,7 +332,7 @@ public class EmergencyActivity extends Activity {
@Override
public void run() {
try {
- sitePassword = masterKeyFuture.get().encode( siteName, type, counter, MPSiteVariant.Password, null );
+ sitePassword = masterKeyFuture.get().siteResult( siteName, counter, MPKeyPurpose.Password, null, type, null );
runOnUiThread( new Runnable() {
@Override
diff --git a/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java b/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java
index 23e5b2e4..3d4d047a 100644
--- a/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java
+++ b/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java
@@ -38,7 +38,7 @@ public final class Preferences {
private static final String PREF_FORGET_PASSWORD = "forgetPassword";
private static final String PREF_MASK_PASSWORD = "maskPassword";
private static final String PREF_FULL_NAME = "fullName";
- private static final String PREF_SITE_TYPE = "siteType";
+ private static final String PREF_RESULT_TYPE = "resultType";
private static final String PREF_ALGORITHM_VERSION = "algorithmVersion";
private static Preferences instance;
@@ -138,20 +138,20 @@ public final class Preferences {
return prefs().getString( PREF_FULL_NAME, "" );
}
- public boolean setDefaultSiteType(@Nonnull final MPSiteType value) {
- if (getDefaultSiteType() == value)
+ public boolean setDefaultResultType(final MPResultType value) {
+ if (getDefaultResultType() == value)
return false;
- prefs().edit().putInt( PREF_SITE_TYPE, value.ordinal() ).apply();
+ prefs().edit().putInt( PREF_RESULT_TYPE, value.ordinal() ).apply();
return true;
}
@Nonnull
- public MPSiteType getDefaultSiteType() {
- return MPSiteType.values()[prefs().getInt( PREF_SITE_TYPE, MPSiteType.GeneratedLong.ordinal() )];
+ public MPResultType getDefaultResultType() {
+ return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, MPResultType.GeneratedLong.ordinal() )];
}
- public boolean setDefaultVersion(@Nonnull final MasterKey.Version value) {
+ public boolean setDefaultVersion(final MasterKey.Version value) {
if (getDefaultVersion() == value)
return false;
diff --git a/platform-android/src/main/res/layout/activity_emergency.xml b/platform-android/src/main/res/layout/activity_emergency.xml
index d2312d33..2c0fb79b 100644
--- a/platform-android/src/main/res/layout/activity_emergency.xml
+++ b/platform-android/src/main/res/layout/activity_emergency.xml
@@ -105,7 +105,7 @@
android:id="@id/sitePasswordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:nextFocusForward="@+id/siteTypeButton"
+ android:nextFocusForward="@+id/resultTypeButton"
android:gravity="center"
android:background="@android:color/transparent"
android:textColor="#FFFFFF"
@@ -157,7 +157,7 @@
android:gravity="center">
+ android:text="@string/resultType_hint" />
diff --git a/platform-android/src/main/res/values/strings.xml b/platform-android/src/main/res/values/strings.xml
index efc25fd9..bdcde8e1 100644
--- a/platform-android/src/main/res/values/strings.xml
+++ b/platform-android/src/main/res/values/strings.xml
@@ -8,7 +8,7 @@
Your master passwordeg. google.comTap to copy
- Type
+ TypeCounterAlgorithm
diff --git a/platform-darwin/Resources/Data/ciphers.plist b/platform-darwin/Resources/Data/ciphers.plist
deleted file mode 100644
index 3a64450c..00000000
--- a/platform-darwin/Resources/Data/ciphers.plist
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
- MPGeneratedSiteEntity
-
- Login Name
-
- cvccvcvcv
-
- Phrase
-
- cvcc cvc cvccvcv cvc
- cvc cvccvcvcv cvcv
- cv cvccv cvc cvcvccv
-
- Maximum Security Password
-
- anoxxxxxxxxxxxxxxxxx
- axxxxxxxxxxxxxxxxxno
-
- Long Password
-
- CvcvnoCvcvCvcv
- CvcvCvcvnoCvcv
- CvcvCvcvCvcvno
- CvccnoCvcvCvcv
- CvccCvcvnoCvcv
- CvccCvcvCvcvno
- CvcvnoCvccCvcv
- CvcvCvccnoCvcv
- CvcvCvccCvcvno
- CvcvnoCvcvCvcc
- CvcvCvcvnoCvcc
- CvcvCvcvCvccno
- CvccnoCvccCvcv
- CvccCvccnoCvcv
- CvccCvccCvcvno
- CvcvnoCvccCvcc
- CvcvCvccnoCvcc
- CvcvCvccCvccno
- CvccnoCvcvCvcc
- CvccCvcvnoCvcc
- CvccCvcvCvccno
-
- Medium Password
-
- CvcnoCvc
- CvcCvcno
-
- Basic Password
-
- aaanaaan
- aannaaan
- aaannaaa
-
- Short Password
-
- Cvcn
-
- PIN
-
- nnnn
-
-
- MPCharacterClasses
-
- V
- AEIOU
- C
- BCDFGHJKLMNPQRSTVWXYZ
- v
- aeiou
- c
- bcdfghjklmnpqrstvwxyz
- A
- AEIOUBCDFGHJKLMNPQRSTVWXYZ
- a
- AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz
- n
- 0123456789
- o
- @&%?,=[]_:-+*$#!'^~;()/.
- x
- AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()
-
-
-
-
-
diff --git a/platform-independent/cli-java/build.gradle b/platform-independent/cli-java/build.gradle
deleted file mode 100644
index 41a2f099..00000000
--- a/platform-independent/cli-java/build.gradle
+++ /dev/null
@@ -1,14 +0,0 @@
-plugins {
- id 'java'
- id 'application'
- id 'com.github.johnrengelman.shadow' version '1.2.4'
-}
-
-description = 'Master Password CLI'
-mainClassName = 'com.lyndir.masterpassword.CLI'
-
-dependencies {
- compile project(':masterpassword-algorithm')
-
- compile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2'
-}
diff --git a/platform-independent/cli-java/pom.xml b/platform-independent/cli-java/pom.xml
deleted file mode 100644
index 69df3bf0..00000000
--- a/platform-independent/cli-java/pom.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
- 4.0.0
-
-
-
- com.lyndir.masterpassword
- masterpassword
- GIT-SNAPSHOT
-
-
- Master Password CLI
- A CLI interface to the Master Password algorithm
-
- masterpassword-cli
- jar
-
-
-
-
-
- src/main/scripts
- true
- ${project.build.directory}
-
-
-
-
- org.apache.maven.plugins
- maven-antrun-plugin
- 1.7
-
-
- prepare-package
- prepare-package
-
-
-
-
-
-
- run
-
-
-
-
-
- org.apache.maven.plugins
- maven-shade-plugin
- 2.2
-
-
- package
-
- shade
-
-
-
-
- com.lyndir.masterpassword.CLI
-
-
-
-
- *:*
-
- META-INF/*.SF
- META-INF/*.DSA
- META-INF/*.RSA
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- com.lyndir.masterpassword
- masterpassword-algorithm
- GIT-SNAPSHOT
-
-
-
- ch.qos.logback
- logback-classic
-
-
-
-
-
diff --git a/platform-independent/cli-java/src/main/java/com/lyndir/masterpassword/CLI.java b/platform-independent/cli-java/src/main/java/com/lyndir/masterpassword/CLI.java
deleted file mode 100644
index 7b05872e..00000000
--- a/platform-independent/cli-java/src/main/java/com/lyndir/masterpassword/CLI.java
+++ /dev/null
@@ -1,189 +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 .
-//==============================================================================
-
-package com.lyndir.masterpassword;
-
-import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
-import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Joiner;
-import com.google.common.collect.Maps;
-import com.google.common.io.LineReader;
-import com.google.common.primitives.UnsignedInteger;
-import com.lyndir.lhunath.opal.system.util.ConversionUtils;
-import com.lyndir.lhunath.opal.system.util.StringUtils;
-import java.io.*;
-import java.util.Arrays;
-import java.util.Map;
-
-
-/**
- *
Jun 10, 2008
- *
- * @author mbillemo
- */
-@SuppressWarnings({ "UseOfSystemOutOrSystemErr", "HardCodedStringLiteral" })
-public final class CLI {
-
- public static void main(final String... args)
- throws IOException {
-
- // Read information from the environment.
- char[] masterPassword;
- String siteName = null, context = null;
- String userName = System.getenv( MPConstant.env_userName );
- String siteTypeName = ifNotNullElse( System.getenv( MPConstant.env_siteType ), "" );
- MPSiteType siteType = siteTypeName.isEmpty()? MPSiteType.GeneratedLong: MPSiteType.forOption( siteTypeName );
- MPSiteVariant variant = MPSiteVariant.Password;
- String siteCounterName = ifNotNullElse( System.getenv( MPConstant.env_siteCounter ), "" );
- UnsignedInteger siteCounter = siteCounterName.isEmpty()? UnsignedInteger.valueOf( 1 ): UnsignedInteger.valueOf( siteCounterName );
-
- // Parse information from option arguments.
- boolean userNameArg = false, typeArg = false, counterArg = false, variantArg = false, contextArg = false;
- for (final String arg : Arrays.asList( args ))
- // Full Name
- if ("-u".equals( arg ) || "--username".equals( arg ))
- userNameArg = true;
- else if (userNameArg) {
- userName = arg;
- userNameArg = false;
- }
-
- // Type
- else if ("-t".equals( arg ) || "--type".equals( arg ))
- typeArg = true;
- else if (typeArg) {
- siteType = MPSiteType.forOption( arg );
- typeArg = false;
- }
-
- // Counter
- else if ("-c".equals( arg ) || "--counter".equals( arg ))
- counterArg = true;
- else if (counterArg) {
- siteCounter = UnsignedInteger.valueOf( arg );
- counterArg = false;
- }
-
- // Variant
- else if ("-v".equals( arg ) || "--variant".equals( arg ))
- variantArg = true;
- else if (variantArg) {
- variant = MPSiteVariant.forOption( arg );
- variantArg = false;
- }
-
- // Context
- else if ("-C".equals( arg ) || "--context".equals( arg ))
- contextArg = true;
- else if (contextArg) {
- context = arg;
- contextArg = false;
- }
-
- // Help
- else if ("-h".equals( arg ) || "--help".equals( arg )) {
- System.out.println();
- System.out.format( "Usage: mpw [-u name] [-t type] [-c counter] site%n%n" );
- System.out.format( " -u name Specify the full name of the user.%n" );
- System.out.format( " Defaults to %s in env.%n%n", MPConstant.env_userName );
- System.out.format( " -t type Specify the password's template.%n" );
- System.out.format( " Defaults to %s in env or 'long' for password, 'name' for login.%n", MPConstant.env_siteType );
-
- int optionsLength = 0;
- Map typeMap = Maps.newLinkedHashMap();
- for (final MPSiteType elementType : MPSiteType.values()) {
- String options = Joiner.on( ", " ).join( elementType.getOptions() );
- typeMap.put( options, elementType );
- optionsLength = Math.max( optionsLength, options.length() );
- }
- for (final Map.Entry entry : typeMap.entrySet()) {
- String infoString = strf( " -v %" + optionsLength + "s | ", entry.getKey() );
- String infoNewline = strf( "%n%s | ", StringUtils.repeat( " ", infoString.length() - 3 ) );
- infoString += entry.getValue().getDescription().replaceAll( strf( "%n" ), infoNewline );
- System.out.println( infoString );
- }
- System.out.println();
-
- System.out.format( " -c counter The value of the counter.%n" );
- System.out.format( " Defaults to %s in env or '1'.%n%n", MPConstant.env_siteCounter );
- System.out.format( " -v variant The kind of content to generate.%n" );
- System.out.format( " Defaults to 'password'.%n" );
-
- optionsLength = 0;
- Map variantMap = Maps.newLinkedHashMap();
- for (final MPSiteVariant elementVariant : MPSiteVariant.values()) {
- String options = Joiner.on( ", " ).join( elementVariant.getOptions() );
- variantMap.put( options, elementVariant );
- optionsLength = Math.max( optionsLength, options.length() );
- }
- for (final Map.Entry entry : variantMap.entrySet()) {
- String infoString = strf( " -v %" + optionsLength + "s | ", entry.getKey() );
- String infoNewline = strf( "%n%s | ", StringUtils.repeat( " ", infoString.length() - 3 ) );
- infoString += entry.getValue().getDescription().replaceAll( strf( "%n" ), infoNewline );
- System.out.println( infoString );
- }
- System.out.println();
-
- System.out.format( " -C context A variant-specific context.%n" );
- System.out.format( " Defaults to empty.%n" );
- for (final Map.Entry entry : variantMap.entrySet()) {
- String infoString = strf( " -v %" + optionsLength + "s | ", entry.getKey() );
- String infoNewline = strf( "%n%s | ", StringUtils.repeat( " ", infoString.length() - 3 ) );
- infoString += entry.getValue().getContextDescription().replaceAll( strf( "%n" ), infoNewline );
- System.out.println( infoString );
- }
- System.out.println();
-
- System.out.format( " ENVIRONMENT%n%n" );
- System.out.format( " MP_USERNAME | The full name of the user.%n" );
- System.out.format( " MP_SITETYPE | The default password template.%n" );
- System.out.format( " MP_SITECOUNTER | The default counter value.%n%n" );
- return;
- } else
- siteName = arg;
-
- // Read missing information from the console.
- Console console = System.console();
- try (InputStreamReader inReader = new InputStreamReader( System.in, Charsets.UTF_8 )) {
- LineReader lineReader = new LineReader( inReader );
-
- if (siteName == null) {
- System.err.format( "Site name: " );
- siteName = lineReader.readLine();
- }
-
- if (userName == null) {
- System.err.format( "User's name: " );
- userName = lineReader.readLine();
- }
-
- if (console != null)
- masterPassword = console.readPassword( "%s's master password: ", userName );
-
- else {
- System.err.format( "%s's master password: ", userName );
- masterPassword = lineReader.readLine().toCharArray();
- }
- }
-
- // Encode and write out the site password.
- System.out.println( MasterKey.create( userName, masterPassword ).encode( siteName, siteType, siteCounter, variant, context ) );
- }
-}
diff --git a/platform-independent/cli-java/src/main/java/com/lyndir/masterpassword/package-info.java b/platform-independent/cli-java/src/main/java/com/lyndir/masterpassword/package-info.java
deleted file mode 100644
index 927ee095..00000000
--- a/platform-independent/cli-java/src/main/java/com/lyndir/masterpassword/package-info.java
+++ /dev/null
@@ -1,28 +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 .
-//==============================================================================
-
-/**
- *
- * @author lhunath, 15-02-04
- */
-
-
-@ParametersAreNonnullByDefault
-package com.lyndir.masterpassword;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/platform-independent/cli-java/src/main/resources/logback.xml b/platform-independent/cli-java/src/main/resources/logback.xml
deleted file mode 100644
index 42815ef6..00000000
--- a/platform-independent/cli-java/src/main/resources/logback.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
- %-8relative %22c{0} [%-5level] %msg%n
-
-
-
-
-
-
-
-
-
-
diff --git a/platform-independent/cli-java/src/main/scripts/bashlib b/platform-independent/cli-java/src/main/scripts/bashlib
deleted file mode 100755
index ff367e7d..00000000
--- a/platform-independent/cli-java/src/main/scripts/bashlib
+++ /dev/null
@@ -1,1958 +0,0 @@
-#! /usr/bin/env bash
-# ___________________________________________________________________________ #
-# #
-# BashLIB -- A library for Bash scripting convenience. #
-# #
-# #
-# Licensed under the Apache License, Version 2.0 (the "License"); #
-# you may not use this file except in compliance with the License. #
-# You may obtain a copy of the License at #
-# #
-# http://www.apache.org/licenses/LICENSE-2.0 #
-# #
-# Unless required by applicable law or agreed to in writing, software #
-# distributed under the License is distributed on an "AS IS" BASIS, #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and #
-# limitations under the License. #
-# ___________________________________________________________________________ #
-# #
-# #
-# Copyright 2007-2013, lhunath #
-# * http://www.lhunath.com #
-# * Maarten Billemont #
-# #
-
-
-
-# ______________________________________________________________________
-# | |
-# | .:: TABLE OF CONTENTS ::. |
-# |______________________________________________________________________|
-#
-# chr decimal
-# Outputs the character that has the given decimal ASCII value.
-#
-# ord character
-# Outputs the decimal ASCII value of the given character.
-#
-# hex character
-# Outputs the hexadecimal ASCII value of the given character.
-#
-# unhex character
-# Outputs the character that has the given decimal ASCII value.
-#
-# max numbers...
-# Outputs the highest of the given numbers.
-#
-# min numbers...
-# Outputs the lowest of the given numbers.
-#
-# totime "YYYY-MM-DD HH:MM:SS.mmm"...
-# Outputs the number of milliseconds in the given date string(s).
-#
-# exists application
-# Succeeds if the application is in PATH and is executable.
-#
-# eol message
-# Return termination punctuation for a message, if necessary.
-#
-# hr pattern [length]
-# Outputs a horizontal ruler of the given length in characters or the terminal column length otherwise.
-#
-# cloc
-# Outputs the current cursor location as two space-separated numbers: row column.
-#
-# readwhile command [args]
-# Outputs the characters typed by the user into the terminal's input buffer while running the given command.
-#
-# pushqueue element ...
-# Pushes the given arguments as elements onto the queue.
-#
-# popqueue
-# Pops one element off the queue.
-#
-# log [format] [arguments...]
-# Log an event at a certain importance level. The event is expressed as a printf(1) format argument.
-#
-# emit [options] message... [-- [command args...]]
-# Display a message with contextual coloring.
-#
-# spinner [-code|message... [-- style color textstyle textcolor]]
-# Displays a spinner on the screen that waits until a certain time.
-#
-# report [-code] [-e] failure-message [success-message]
-# This is a convenience function for replacement of spinner -code.
-#
-# ask [-c optionchars|-d default] [-s|-S maskchar] message...
-# Ask a question and read the user's reply to it. Then output the result on stdout.
-#
-# trim lines ...
-# Trim the whitespace off of the beginning and end of the given lines.
-#
-# reverse [-0|-d delimitor] [elements ...] [<<< elements]
-# Reverse the order of the given elements.
-#
-# order [-0|-d char] [-[cC] isAscending|-n] [-t number] [elements ...] [<<< elements]
-# Orders the elements in ascending order.
-#
-# mutex file
-# Open a mutual exclusion lock on the file, unless another process already owns one.
-#
-# pushjob [poolsize] command
-# Start an asynchronous command within a pool, waiting for space in the pool if it is full.
-#
-# fsleep time
-# Wait for the given (fractional) amount of seconds.
-#
-# getArgs [options] optstring [args...]
-# Retrieve all options present in the given arguments.
-#
-# showHelp name description author [option description]...
-# Generate a prettily formatted usage description of the application.
-#
-# shquote [-e] [argument...]
-# Shell-quote the arguments to make them safe for injection into bash code.
-#
-# requote [string]
-# Escape the argument string to make it safe for injection into a regex.
-#
-# shorten [-p pwd] path [suffix]...
-# Shorten an absolute path for pretty printing.
-#
-# up .../path|num
-# Walk the current working directory up towards root num times or until path is found.
-#
-# buildarray name terms... -- elements...
-# Create an array by adding all the terms to it for each element, replacing {} terms by the element.
-#
-# inArray element array
-# Checks whether a certain element is in the given array.
-#
-# xpathNodes query [files...]
-# Outputs every xpath node that matches the query on a separate line.
-#
-# hideDebug [on|off]
-# Toggle Bash's debugging mode off temporarily.
-#
-# stackTrace
-# Output the current script's function execution stack.
-#
-_tocHash=71e13f42e1ea82c1c7019b27a3bc71f3
-
-
-# ______________________________________________________________________
-# | |
-# | .:: GLOBAL CONFIGURATION ::. |
-# |______________________________________________________________________|
-
-# Unset all exported functions. Exported functions are evil.
-while read _ _ func; do
- command unset -f "$func"
-done < <(command declare -Fx)
-
-{
-shopt -s extglob
-shopt -s globstar
-} 2>/dev/null ||:
-
-# Generate Table Of Contents
-genToc() {
- local line= comments=() usage= whatis= lineno=0 out= outhash= outline=
- while read -r line; do
- (( ++lineno ))
-
- [[ $line = '#'* ]] && comments+=("$line") && continue
- [[ $line = +([[:alnum:]])'() {' ]] && IFS='()' read func _ <<< "$line" && [[ $func != $FUNCNAME ]] && {
- usage=${comments[3]##'#'+( )}
- whatis=${comments[5]##'#'+( )}
- [[ $usage = $func* && $whatis = *. ]] || err "Malformed docs for %s (line %d)." "$func" "$lineno"
-
- printf -v outline '# %s\n# %s\n#\n' "$usage" "$whatis"
- out+=$outline
- }
- comments=()
- done < ~/.bin/bashlib
-
- outhash=$(openssl md5 <<< "$out")
- if [[ $_tocHash = $outhash ]]; then
- inf 'Table of contents up-to-date.'
- else
- printf '%s' "$out"
- printf '_tocHash=%q' "$outhash"
- wrn 'Table of contents outdated.'
- fi
-}
-
-
-
-# ______________________________________________________________________
-# | |
-# | .:: GLOBAL DECLARATIONS ::. |
-# |______________________________________________________________________|
-
-# Variables for global internal operation.
-bobber=( '.' 'o' 'O' 'o' )
-spinner=( '-' \\ '|' '/' )
-crosser=( '+' 'x' '+' 'x' )
-runner=( '> >' \
- '>> ' \
- ' >>' )
-
-# Variables for terminal requests.
-[[ -t 2 ]] && {
- alt=$( tput smcup || tput ti ) # Start alt display
- ealt=$( tput rmcup || tput te ) # End alt display
- hide=$( tput civis || tput vi ) # Hide cursor
- show=$( tput cnorm || tput ve ) # Show cursor
- save=$( tput sc ) # Save cursor
- load=$( tput rc ) # Load cursor
- dim=$( tput dim || tput mh ) # Start dim
- bold=$( tput bold || tput md ) # Start bold
- stout=$( tput smso || tput so ) # Start stand-out
- estout=$( tput rmso || tput se ) # End stand-out
- under=$( tput smul || tput us ) # Start underline
- eunder=$( tput rmul || tput ue ) # End underline
- reset=$( tput sgr0 || tput me ) # Reset cursor
- blink=$( tput blink || tput mb ) # Start blinking
- italic=$( tput sitm || tput ZH ) # Start italic
- eitalic=$( tput ritm || tput ZR ) # End italic
-[[ $TERM != *-m ]] && {
- red=$( tput setaf 1|| tput AF 1 )
- green=$( tput setaf 2|| tput AF 2 )
- yellow=$( tput setaf 3|| tput AF 3 )
- blue=$( tput setaf 4|| tput AF 4 )
- magenta=$( tput setaf 5|| tput AF 5 )
- cyan=$( tput setaf 6|| tput AF 6 )
-}
- black=$( tput setaf 0|| tput AF 0 )
- white=$( tput setaf 7|| tput AF 7 )
- default=$( tput op )
- eed=$( tput ed || tput cd ) # Erase to end of display
- eel=$( tput el || tput ce ) # Erase to end of line
- ebl=$( tput el1 || tput cb ) # Erase to beginning of line
- ewl=$eel$ebl # Erase whole line
- draw=$( tput -S <<< ' enacs
- smacs
- acsc
- rmacs' || { \
- tput eA; tput as;
- tput ac; tput ae; } ) # Drawing characters
- back=$'\b'
-} 2>/dev/null ||:
-
-
-
-
-
-# ______________________________________________________________________
-# | |
-# | .:: FUNCTION DECLARATIONS ::. |
-# |______________________________________________________________________|
-
-
-
-# ______________________________________________________________________
-# |__ Chr _______________________________________________________________|
-#
-# chr decimal
-#
-# Outputs the character that has the given decimal ASCII value.
-#
-chr() {
- printf \\"$(printf '%03o' "$1")"
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Ord _______________________________________________________________|
-#
-# ord character
-#
-# Outputs the decimal ASCII value of the given character.
-#
-ord() {
- printf %d "'$1"
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Hex _______________________________________________________________|
-#
-# hex character
-#
-# Outputs the hexadecimal ASCII value of the given character.
-#
-hex() {
- printf '%x' "'$1"
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Unhex _______________________________________________________________|
-#
-# unhex character
-#
-# Outputs the character that has the given decimal ASCII value.
-#
-unhex() {
- printf \\x"$1"
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ max _______________________________________________________________|
-#
-# max numbers...
-#
-# Outputs the highest of the given numbers.
-#
-max() {
- local max=$1 n
- for n
- do (( n > max )) && max=$n; done
- printf %d "$max"
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ min _______________________________________________________________|
-#
-# min numbers...
-#
-# Outputs the lowest of the given numbers.
-#
-min() {
- local min=$1 n
- for n
- do (( n < min )) && min=$n; done
- printf %d "$min"
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ totime ____________________________________________________________|
-#
-# totime "YYYY-MM-DD HH:MM:SS.mmm"...
-#
-# Outputs the number of milliseconds in the given date string(s).
-#
-# When multiple date string arguments are given, multiple time strings are output, one per line.
-#
-# The fields should be in the above defined order. The delimitor between the fields may be any one of [ -:.].
-# If a date string does not follow the defined format, the result is undefined.
-#
-# Note that this function uses a very simplistic conversion formula which does not take any special calendar
-# convenions into account. It assumes there are 12 months in evert year, 31 days in every month, 24 hours
-# in every day, 60 minutes in every hour, 60 seconds in every minute and 1000 milliseconds in every second.
-#
-totime() {
- local arg time year month day hour minute second milli
- for arg; do
- IFS=' -:.' read year month day hour minute second milli <<< "$arg" &&
- (( time = (((((((((((10#$year * 12) + 10#$month) * 31) + 10#$day) * 24) + 10#$hour) * 60) + 10#$minute) * 60) + 10#$second) * 1000) + 10#$milli )) &&
- printf '%d\n' "$time"
- done
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Exists ____________________________________________________________|
-#
-# exists application
-#
-# Succeeds if the application is in PATH and is executable.
-#
-exists() {
- [[ -x $(type -P "$1" 2>/dev/null) ]]
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Eol _______________________________________________________________|
-#
-# eol message
-#
-# Return termination punctuation for a message, if necessary.
-#
-eol() {
- : #[[ $1 && $1 != *[\!\?.,:\;\|] ]] && printf .. ||:
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Hr _______________________________________________________________|
-#
-# hr pattern [length]
-#
-# Outputs a horizontal ruler of the given length in characters or the terminal column length otherwise.
-# The ruler is a repetition of the given pattern string.
-#
-hr() {
- local pattern=${1:--} length=${2:-$COLUMNS} ruler=
- (( length )) || length=$(tput cols)
-
- while (( ${#ruler} < length )); do
- ruler+=${pattern:0:length-${#ruler}}
- done
-
- printf %s "$ruler"
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ CLoc ______________________________________________________________|
-#
-# cloc
-#
-# Outputs the current cursor location as two space-separated numbers: row column.
-#
-cloc() {
- local old=$(stty -g)
- trap 'stty "$old"' RETURN
- stty raw
-
- # If the tty has input waiting then we can't read back its response. We'd only break and pollute the tty input buffer.
- read -t 0 < /dev/tty 2>/dev/null && return 1
-
- printf '\e[6n' > /dev/tty
- IFS='[;' read -dR _ row col < /dev/tty
- printf '%d %d' "$row" "$col"
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ readwhile ______________________________________________________________|
-#
-# readwhile command [args]
-#
-# Outputs the characters typed by the user into the terminal's input buffer while running the given command.
-#
-readwhile() {
- local old=$(stty -g) in result REPLY
- trap 'stty "$old"' RETURN
- stty raw
-
- "$@"
- result=$?
-
- while read -t 0; do
- IFS= read -rd '' -n1 && in+=$REPLY
- done
- printf %s "$in"
-
- return $result
-} # _____________________________________________________________________
-
-
-
-# ___________________________________________________________________________
-# |__ pushqueue ______________________________________________________________|
-#
-# pushqueue element ...
-#
-# Pushes the given arguments as elements onto the queue.
-#
-pushqueue() {
- [[ $_queue ]] || {
- coproc _queue {
- while IFS= read -r -d ''; do
- printf '%s\0' "$REPLY"
- done
- }
- }
-
- printf '%s\0' "$@" >&"${_queue[1]}"
-} # _____________________________________________________________________
-
-
-
-# __________________________________________________________________________
-# |__ popqueue ______________________________________________________________|
-#
-# popqueue
-#
-# Pops one element off the queue.
-# If no elements are available on the queue, this command fails with exit code 1.
-#
-popqueue() {
- local REPLY
- [[ $_queue ]] && read -t0 <&"${_queue[0]}" || return
- IFS= read -r -d '' <&"${_queue[0]}"
- printf %s "$REPLY"
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Latest ____________________________________________________________|
-#
-# latest [file...]
-#
-# Output the argument that represents the file with the latest modification time.
-#
-latest() (
- shopt -s nullglob
- local file latest=$1
- for file; do
- [[ $file -nt $latest ]] && latest=$file
- done
- printf '%s\n' "$latest"
-) # _____________________________________________________________________
-
-
-
-# _______________________________________________________________________
-# |__ Iterate ____________________________________________________________|
-#
-# iterate [command]
-#
-# All arguments to iterate make up a single command that will be executed.
-#
-# Any of the arguments may be of the format {x..y[..z]} which causes the command
-# to be executed in a loop, each iteration substituting the argument for the
-# current step the loop has reached from x to y. We step from x to y by
-# walking from x's position in the ASCII character table to y's with a step of z
-# or 1 if z is not specified.
-#
-iterate() (
- set -x
- local command=( "$@" ) iterationCommand=() loop= a= arg= current=() step=() target=()
- for a in "${!command[@]}"; do
- arg=${command[a]}
- if [[ $arg = '{'*'}' ]]; then
- loop=${arg#'{'} loop=${loop%'}'}
- step[a]=${loop#*..*..} current[a]=${loop%%..*} target[a]=${loop#*..} target[a]=${target[a]%.."${step[a]}"}
- [[ ! ${step[a]} || ${step[a]} = $loop ]] && step[a]=1
- fi
- done
- if (( ${#current[@]} )); then
- for loop in "${!current[@]}"; do
- while true; do
- iterationCommand=()
-
- for a in "${!command[@]}"; do
- (( a == loop )) \
- && iterationCommand+=( "${current[a]}" ) \
- || iterationCommand+=( "${command[a]}" )
- done
-
- iterate "${iterationCommand[@]}"
-
- [[ ${current[loop]} = ${target[loop]} ]] && break
- current[loop]="$(chr "$(( $(ord "${current[loop]}") + ${step[loop]} ))")"
- done
- done
- else
- "${command[@]}"
- fi
-) # _____________________________________________________________________
-
-# ______________________________________________________________________
-# |__ Logging ___________________________________________________________|
-#
-# log [format] [arguments...]
-#
-# Log an event at a certain importance level. The event is expressed as a printf(1) format argument.
-# The current exit code remains unaffected by the execution of this function.
-#
-# Instead of 'log', you can use a level as command name, to log at that level. Using log, messages are
-# logged at level inf. The supported levels are: trc, dbg, inf, wrn, err, ftl.
-#
-# If you prefix the command name with a p, the log message is shown as a spinner and waits for the next
-# closing statement. Eg.
-#
-# pinf 'Converting image'
-# convert image.png image.jpg
-# fnip
-#
-# The closing statement (here fnip) is the reverse of the opening statement and exits with the exit code
-# of the last command. If the last command failed, it shows the exit code in the spinner before it is stopped.
-# The closing statement also takes a format and arguments, which are displayed in the spinner.
-#
-log() {
- local exitcode=$? level=${level:-inf} supported=0 end=$'\n' type=msg conMsg= logMsg= format= colorFormat= date= info= arg= args=() colorArgs=() ruler=
-
- # Handle options.
- local OPTIND=1
- while getopts :puPr arg; do
- case $arg in
- p)
- end='.. '
- type=startProgress ;;
- u)
- end='.. '
- type=updateProgress ;;
- P)
- type=stopProgress ;;
- r)
- ruler='____' ;;
- esac
- done
- shift "$((OPTIND-1))"
- format=$1 args=( "${@:2}" )
- (( ! ${#args[@]} )) && [[ $format ]] && { args=("$format") format=%s; local bold=; }
-
- # Level-specific settings.
- case $level in
- TRC) (( supported = _logVerbosity >= 4 ))
- logLevelColor=$_logTrcColor ;;
- DBG) (( supported = _logVerbosity >= 3 ))
- logLevelColor=$_logDbgColor ;;
- INF) (( supported = _logVerbosity >= 2 ))
- logLevelColor=$_logInfColor ;;
- WRN) (( supported = _logVerbosity >= 1 ))
- logLevelColor=$_logWrnColor ;;
- ERR) (( supported = _logVerbosity >= 0 ))
- logLevelColor=$_logErrColor ;;
- FTL) (( supported = 1 ))
- logLevelColor=$_logFtlColor ;;
- *)
- log FTL "Log level %s does not exist" "$level"
- exit 1 ;;
- esac
- (( ! supported )) && return "$exitcode"
- local logColor=${logColor:-$logLevelColor}
-
- # Generate the log message.
- date=$(date +"${_logDate:-%H:%M}")
- case $type in
- msg|startProgress)
- printf -v logMsg "[%s %-3s] $format$end" "$date" "$level" "${args[@]}"
- if (( _logColor )); then
- colorFormat=$(sed -e "s/$(requote "$reset")/$reset$logColor/g" -e "s/%[^a-z]*[a-z]/$reset$bold$logColor&$reset$logColor/g" <<< "$format")
- colorArgs=("${args[@]//$reset/$reset$bold$logColor}")
- printf -v conMsg "$reset[%s $logLevelColor%-3s$reset] $logColor$colorFormat$reset$black\$$reset$end$save" "$date" "$level" "${colorArgs[@]}"
- else
- conMsg=$logMsg
- fi
- ;;
-
- updateProgress)
- printf -v logMsg printf " [$format]" "${args[@]}"
- if (( _logColor )); then
- colorFormat=$(sed -e "s/$(requote "$reset")/$reset$logColor/g" -e "s/%[^a-z]*[a-z]/$reset$bold$logColor&$reset$logColor/g" <<< "$format")
- colorArgs=("${args[@]//$reset/$reset$bold$logColor}")
- printf -v conMsg "$load$eel$blue$bold[$reset$logColor$colorFormat$reset$blue$bold]$reset$end" "${colorArgs[@]}"
- else
- conMsg=$logMsg
- fi
- ;;
-
- stopProgress)
- case $exitcode in
- 0) printf -v logMsg "done${format:+ ($format)}.\n" "${args[@]}"
- if (( _logColor )); then
- colorFormat=$(sed -e "s/$(requote "$reset")/$reset$logColor/g" -e "s/%[^a-z]*[a-z]/$reset$bold$logColor&$reset$logColor/g" <<< "$format")
- colorArgs=("${args[@]//$reset/$reset$bold$logColor}")
- printf -v conMsg "$load$eel$green${bold}done${colorFormat:+ ($reset$logColor$colorFormat$reset$green$bold)}$reset.\n" "${colorArgs[@]}"
- else
- conMsg=$logMsg
- fi
- ;;
-
- *) info=${format:+$(printf ": $format" "${args[@]}")}
- printf -v logMsg "error(%d%s).\n" "$exitcode" "$info"
- if (( _logColor )); then
- printf -v conMsg "${eel}${red}error${reset}(${bold}${red}%d${reset}%s).\n" "$exitcode" "$info"
- else
- conMsg=$logMsg
- fi
- ;;
- esac
- ;;
- esac
-
- # Create the log file.
- if [[ $_logFile && ! -e $_logFile ]]; then
- [[ $_logFile = */* ]] || $_logFile=./$logFile
- mkdir -p "${_logFile%/*}" && touch "$_logFile"
- fi
-
- # Stop the spinner.
- if [[ $type = stopProgress && $_logSpinner ]]; then
- kill "$_logSpinner"
- wait "$_logSpinner" 2>/dev/null
- unset _logSpinner
- fi
-
- # Output the ruler.
- if [[ $ruler ]]; then
- printf >&2 '%s\n' "$(hr "$ruler")"
- [[ -w $_logFile ]] \
- && printf >> "$_logFile" '%s' "$ruler"
- fi
-
- # Output the log message.
- printf >&2 '%s' "$conMsg"
- [[ -w $_logFile ]] \
- && printf >> "$_logFile" '%s' "$logMsg"
-
- # Start the spinner.
- if [[ $type = startProgress && ! $_logSpinner ]]; then
- {
- set +m
- trap 'touch exit; printf %s "$show"' EXIT
- echo "$BASHPID" > start
- printf %s "$hide"
- while printf "$eel$blue$bold[$reset%s$reset$blue$bold]$reset\b\b\b" "${spinner[s++ % ${#spinner[@]}]}" && sleep .1
- do :; done
- } & _logSpinner=$!
- fi 2>/dev/null
-
- return $exitcode
-}
-trc() { level=TRC log "$@"; }
-dbg() { level=DBG log "$@"; }
-inf() { level=INF log "$@"; }
-wrn() { level=WRN log "$@"; }
-err() { level=ERR log "$@"; }
-ftl() { level=FTL log "$@"; }
-plog() { log -p "$@"; }
-ulog() { log -u "$@"; }
-golp() { log -P "$@"; }
-ptrc() { level=TRC plog "$@"; }
-pdbg() { level=DBG plog "$@"; }
-pinf() { level=INF plog "$@"; }
-pwrn() { level=WRN plog "$@"; }
-perr() { level=ERR plog "$@"; }
-pftl() { level=FTL plog "$@"; }
-utrc() { level=TRC ulog "$@"; }
-udbg() { level=DBG ulog "$@"; }
-uinf() { level=INF ulog "$@"; }
-uwrn() { level=WRN ulog "$@"; }
-uerr() { level=ERR ulog "$@"; }
-uftl() { level=FTL ulog "$@"; }
-gtrc() { level=trc golp "$@"; }
-gbdp() { level=DBG golp "$@"; }
-fnip() { level=INF golp "$@"; }
-nrwp() { level=WRN golp "$@"; }
-rrep() { level=ERR golp "$@"; }
-ltfp() { level=FTL golp "$@"; }
-_logColor=${_logColor:-$([[ -t 2 ]] && echo 1)} _logVerbosity=2
-_logTrcColor=$grey _logDbgColor=$blue _logInfColor=$white _logWrnColor=$yellow _logErrColor=$red _logFtlColor=$bold$red
-# _______________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Emit ______________________________________________________________|
-#
-# emit [options] message... [-- [command args...]]
-#
-# Display a message with contextual coloring.
-#
-# DEPRECATED: Use inf and variants instead.
-#
-# When a command is provided, a spinner will be activated in front of the
-# message for as long as the command runs. When the command ends, its
-# exit status will result in a message 'done' or 'failed' to be displayed.
-#
-# It is possible to only specify -- as final argument. This will prepare
-# a spinner for you with the given message but leave it up to you to
-# notify the spinner that it needs to stop. See the documentation for
-# 'spinner' to learn how to do this.
-#
-# -n Do not end the line with a newline.
-# -b Activate bright (bold) mode.
-# -d Activate half-bright (dim) mode.
-# -g Display in green.
-# -y Display in yellow.
-# -r Display in red.
-# -w Display in the default color.
-#
-# -[code] A proxy-call to 'spinner -[code]'.
-#
-# Non-captialized versions of these options affect the * or the spinner
-# in front of the message. Capitalized options affect the message text
-# displayed.
-#
-emit() {
-
- # Proxy call to spinner.
- [[ $# -eq 1 && $1 = -+([0-9]) ]] \
- && { spinner $1; return; }
-
- # Initialize the vars.
- local arg
- local style=
- local color=
- local textstyle=
- local textcolor=
- local noeol=0
- local cmd=0
-
- # Parse the options.
- spinArgs=()
- for arg in $(getArgs odbwgyrDBWGYRn "$@"); do
- case ${arg%% } in
- d) style=$dim ;;
- b) style=$bold ;;
- w) color=$white ;;
- g) color=$green ;;
- y) color=$yellow ;;
- r) color=$red ;;
- D) textstyle=$dim ;;
- B) textstyle=$bold ;;
- W) textcolor=$white ;;
- G) textcolor=$green ;;
- Y) textcolor=$yellow ;;
- R) textcolor=$red ;;
- n) noeol=1
- spinArgs+=(-n) ;;
- o) spinArgs+=("-$arg") ;;
- esac
- done
- shift $(getArgs -c odbwgyrDBWGYRn "$@")
- while [[ $1 = +* ]]; do
- spinArgs+=("-${1#+}")
- shift
- done
-
- # Defaults.
- color=${color:-$textcolor}
- color=${color:-$green}
- [[ $color = $textcolor && -z $style ]] && style=$bold
-
- # Get the text message.
- local text= origtext=
- for arg; do [[ $arg = -- ]] && break; origtext+="$arg "; done
- origtext=${origtext%% }
- (( noeol )) && text=$origtext || text=$origtext$reset$(eol "$origtext")$'\n'
-
-
- # Trim off everything up to --
- while [[ $# -gt 1 && $1 != -- ]]; do shift; done
- [[ $1 = -- ]] && { shift; cmd=1; }
-
- # Figure out what FD to use for our messages.
- [[ -t 1 ]]; local fd=$(( $? + 1 ))
-
- # Display the message or spinner.
- if (( cmd )); then
- # Don't let this Bash handle SIGINT.
- #trap : INT
-
- # Create the spinner in the background.
- spinPipe=${TMPDIR:-/tmp}/bashlib.$$
- { touch "$spinPipe" && rm -f "$spinPipe" && mkfifo "$spinPipe"; } 2>/dev/null \
- || unset spinPipe
- { spinner "${spinArgs[@]}" "$origtext" -- "$style" "$color" "$textstyle" "$textcolor" < "${spinPipe:-/dev/null}" & } 2>/dev/null
- [[ $spinPipe ]] && echo > "$spinPipe"
- spinPid=$!
-
- # Execute the command for the spinner if one is given.
- #fsleep 1 # Let the spinner initialize itself properly first. # Can probably remove this now that we echo > spinPipe?
- if (( $# == 1 )); then command=$1
- elif (( $# > 1 )); then command=$(printf '%q ' "$@")
- else return 0; fi
-
- eval "$command" >/dev/null \
- && spinner -0 \
- || spinner -1
- else
- # Make reset codes restore the initial font.
- local font=$reset$textstyle$textcolor
- text=$font${text//$reset/$font}
-
- printf "\r$reset $style$color* %s$reset" "$text" >&$fd
- fi
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Spinner ___________________________________________________________|
-#
-# spinner [-code|message... [-- style color textstyle textcolor]]
-#
-# DEPRECATED: Use pinf and variants instead.
-#
-# Displays a spinner on the screen that waits until a certain time.
-# Best used through its interface provided by 'emit'.
-#
-# style A terminal control string that defines the style of the spinner.
-# color A terminal control string that defines the color of the spinner.
-# textstyle A terminal control string that defines the style of the message.
-# textcolor A terminal control string that defines the color of the message.
-#
-# -[code] Shut down a previously activated spinner with the given exit
-# code. If the exit code is 0, a green message 'done' will be
-# displayed. Otherwise a red message 'failed' will appear.
-# The function will return with this exit code as result.
-#
-# You can manually specify a previously started spinner by putting its PID in
-# the 'spinPid' variable. If this variable is not defined, the PID of the most
-# recently backgrounded process is used. The 'spinPid' variable is unset upon
-# each call to 'spinner' and reset to the PID of the spinner if one is created.
-#
-spinner() {
-
- # Check usage.
- (( ! $# )) || getArgs -q :h "$@" && {
- emit -y 'Please specify a message as argument or a status option.'
- return 1
- }
-
- # Initialize spinner vars.
- # Make sure monitor mode is off or we won't be able to trap INT properly.
- local monitor=0; [[ $- = *m* ]] && monitor=1
- local done=
-
- # Place the trap for interrupt signals.
- trap 'done="${red}failed"' USR2
- trap 'done="${green}done"' USR1
-
- # Initialize the vars.
- local pid=${spinPid:-$!}
- local graphics=( "${bobber[@]}" )
- local style=$bold
- local color=$green
- local textstyle=
- local textcolor=
- local output=
- local noeol=
- unset spinPid
-
- # Any remaining options are the exit status of an existing spinner or spinner type.
- while [[ $1 = -* ]]; do
- arg=${1#-}
- shift
-
- # Stop parsing when arg is --
- [[ $arg = - ]] && break
-
- # Process arg: Either a spinner type or result code.
- if [[ $arg = *[^0-9]* ]]; then
- case $arg in
- b) graphics=( "${bobber[@]}" ) ;;
- c) graphics=( "${crosser[@]}" ) ;;
- r) graphics=( "${runner[@]}" ) ;;
- s) graphics=( "${spinner[@]}" ) ;;
- o) output=1 ;;
- n) noeol=1 ;;
- esac
- elif [[ $pid ]]; then
- [[ $arg = 0 ]] \
- && kill -USR1 $pid 2>/dev/null \
- || kill -USR2 $pid 2>/dev/null
-
- trap - INT
- wait $pid 2>/dev/null
-
- return $arg
- fi
- done
-
- # Read arguments.
- local text= origtext=
- for arg; do [[ $arg = -- ]] && break; origtext+="$arg "; done
- origtext=${origtext% }
- local styles=$*; [[ $styles = *' -- '* ]] || styles=
- read -a styles <<< "${styles##* -- }"
- [[ ${styles[0]} ]] && style=${styles[0]}
- [[ ${styles[1]} ]] && color=${styles[1]}
- [[ ${styles[2]} ]] && textstyle=${styles[2]}
- [[ ${styles[3]} ]] && textcolor=${styles[3]}
-
- # Figure out what FD to use for our messages.
- [[ -t 1 ]]; local fd=$(( $? + 1 ))
-
- # Make reset codes restore the initial font.
- local font=$reset$textstyle$textcolor
- origtext=$font${origtext//$reset/$font}
- (( noeol )) && text=$origtext || text=$origtext$reset$(eol "$origtext")
-
- # Spinner initial status.
- printf "\r$save$eel$reset $style$color* %s$reset" "$text" >&$fd
- (( output )) && printf "\n" >&$fd
-
- # Render the spinner.
- set +m
- local i=0
- while [[ ! $done ]]; do
- IFS= read -r -d '' newtext || true
- newtext=${newtext%%$'\n'}; newtext=${newtext##*$'\n'}
- if [[ $newtext = +* ]]; then
- newtext="$origtext [${newtext#+}]"
- fi
- if [[ $newtext ]]; then
- newtext="$font${newtext//$reset/$font}"
- (( noeol )) && text=$newtext || text=$newtext$reset$(eol "$newtext")
- fi
-
- if (( output ))
- then printf "\r" >&$fd
- else printf "$load$eel" >&$fd
- fi
-
- if (( output ))
- then printf "$reset $style$color$blue%s %s$reset" \
- "${graphics[i++ % 4]}" "$text" >&$fd
- else printf "$reset $style$color%s %s$reset" \
- "${graphics[i++ % 4]}" "$text" >&$fd
- fi
-
- fsleep .25 # Four iterations make one second.
-
- # Cancel when calling script disappears.
- kill -0 $$ >/dev/null || done="${red}aborted"
- done
-
- # Get rid of the spinner traps.
- trap - USR1 USR2; (( monitor )) && set -m
-
- # Spinner final status.
- if (( output ))
- then text=; printf "\r" >&$fd
- else printf "$load" >&$fd
- fi
-
- printf "$eel$reset $style$color* %s${text:+ }$bold%s$font.$reset\n" \
- "$text" "$done" >&$fd
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ report ___________________________________________________________|
-#
-# report [-code] [-e] failure-message [success-message]
-#
-# This is a convenience function for replacement of spinner -code.
-#
-# DEPRECATED: Use fnip and variants instead.
-#
-# It checks either the exit code of the previously completed command or
-# the code provided as option to determine whether to display the success
-# or failure message. It calls spinner -code to complete an actively
-# emitted message if there is one. The success message is optional.
-#
-# -[code] The exit code to use.
-# -e Exit the script on failure.
-#
-report() {
-
- # Exit Status of previous command.
- local code=$?
-
- # Parse the options.
- while [[ $1 = -* && $2 ]]; do
- arg=${1#-}
- shift
-
- # Stop parsing when arg is --
- [[ $arg = - ]] && break
-
- # Process arg: Either a spinner type or result code.
- if [[ $arg = *[^0-9]* ]]; then
- case $arg in
- esac
- else code=$arg
- fi
- done
-
- # Initialize the vars.
- local failure=$1
- local success=$2
-
- # Check usage.
- (( ! $# )) || getArgs -q :h "$@" && {
- emit -y 'Please specify at least a failure message as argument.'
- return 1
- }
-
- # Proxy call to spinner.
- (( spinPid )) \
- && { spinner -$code; }
-
- # Success or failure message.
- if (( ! code ))
- then [[ $success ]] && emit " $success"
- else [[ $failure ]] && emit -R " $failure"
- fi
-
- # Pass on exit code.
- return $code
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Ask _______________________________________________________________|
-#
-# ask [-c optionchars|-d default] [-s|-S maskchar] message...
-#
-# Ask a question and read the user's reply to it. Then output the result on stdout.
-#
-# When in normal mode, a single line is read. If the line is empty and
-# -d was specified, the default argument is output instead of an empty line.
-# The exit code is always 0.
-#
-# When in option mode (-c), the user is shown the option characters with
-# which he can reply and a single character is read.
-# If the reply is empty (user hits enter) and any of the optionchars are
-# upper-case, the upper-case option (= the default option) character will
-# be output instead of an empty line.
-# If the reply character is not amoungst the provided options the default
-# option is again output instead if present. If no default was given, an
-# exit code of 2 is returned.
-# You may mark an optionchar as 'valid' by appending a '!' to it. As a
-# result, an exit code of 0 will only be returned if this valid option
-# is replied. If not, an exit code of 1 will be returned.
-#
-ask() {
-
- # Check usage.
- (( ! $# )) || getArgs -q :h "$@" && {
- emit -y 'Please specify a question as argument.'
- return 1
- }
-
- # Initialize the vars.
- local opt arg
- local option=
- local options=
- local default=
- local silent=
- local valid=
- local muteChar=
- local message=
-
- # Parse the options.
- local OPTIND=1
- while getopts :sS:c:d: opt; do
- case $opt in
- s) silent=1 ;;
- S) silent=1 muteChar=$OPTARG ;;
- c) while read -n1 arg; do
- case $arg in
- [[:upper:]]) default=$arg ;;
- !) valid=${options: -1}; continue ;;
- esac
-
- options+=$arg
- done <<< "$OPTARG" ;;
- d) default=$OPTARG option=$default ;;
- esac
- done
-
- # Trim off the options.
- shift $((OPTIND-1))
-
- # Figure out what FD to use for our messages.
- [[ -t 1 ]] && local fd=1 || local fd=2
-
- # Ask the question.
- message=$1; shift; printf -v message "$message" "$@"
- emit -yn "$message${option:+ [$option]}${options:+ [$options]} "
-
- # Read the reply.
- exec 8<&0; [[ -t 8 ]] || exec 8&$fd
- done
- REPLY=$reply
- else
- read -u8 -e ${options:+-n1} ${silent:+-s}
- fi
- [[ $options && $REPLY ]] || (( silent )) && printf '\n' >&$fd
-
- # Evaluate the reply.
- while true; do
- if [[ $REPLY && ( ! $options || $options = *$REPLY* ) ]]; then
- if [[ $valid ]]
- then [[ $REPLY = $valid ]]
- else printf "%s" "$REPLY"
- fi
-
- return
- fi
-
- [[ -z $default || $REPLY = $default ]] \
- && return 2
-
- REPLY=$default
- done
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Trim ______________________________________________________________|
-#
-# trim lines ...
-#
-# Trim the whitespace off of the beginning and end of the given lines.
-# Each argument is considdered one line; is treated and printed out.
-#
-# When no arguments are given, lines will be read from standard input.
-#
-trim() {
-
- # Initialize the vars.
- local lines
- local line
- local oIFS
-
- # Get the lines.
- lines=( "$@" )
- if (( ! ${#lines[@]} )); then
- oIFS=$IFS; IFS=$'\n'
- lines=( $(cat) )
- IFS=$oIFS
- fi
-
- # Trim the lines
- for line in "${lines[@]}"; do
- line=${line##*([[:space:]])}; line=${line%%*([[:space:]])}
- printf "%s" "$line"
- done
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Reverse ___________________________________________________________|
-#
-# reverse [-0|-d delimitor] [elements ...] [<<< elements]
-#
-# Reverse the order of the given elements.
-# Elements are read from command arguments or standard input if no element
-# arguments are given.
-# They are reversed and output on standard output.
-#
-# If the -0 option is given, input and output are delimited by NUL bytes.
-# If the -d option is given, input and output are delimited by the
-# character argument.
-# Otherwise, they are delimited by newlines.
-#
-reverse() {
-
- # Initialize the vars.
- local elements=() delimitor=$'\n' i
-
- # Parse the options.
- local OPTIND=1
- while getopts :0d: opt; do
- case $opt in
- 0) delimitor=$'\0' ;;
- d) delimitor=$OPTARG ;;
- esac
- done
- shift "$((OPTIND-1))"
-
- # Get the elements.
- if (( $# )); then
- elements=( "$@" )
- else
- while IFS= read -r -d "$delimitor"; do
- elements+=("$REPLY")
- done
- fi
-
- # Iterate in reverse order.
- for (( i=${#elements[@]} - 1; i >=0; --i )); do
- printf "%s${delimitor:-'\0'}" "${elements[i]}"
- done
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Order _____________________________________________________________|
-#
-# order [-0|-d char] [-[cC] isAscending|-n] [-t number] [-a array|elements ...] [<<< elements]
-#
-# Orders the elements in ascending order.
-# Elements are read from command arguments or standard input if no element
-# arguments are given.
-# The result is output on standard output.
-#
-# By default, the elements will be ordered using lexicographic comparison.
-# If the -n option is given, the elements will be considered integer numbers.
-# If the -c option is given, the command name following it will be used
-# as a comparator.
-# If the -C option is given, the bash code following it will be used
-# as a comparator.
-# If the -t option is given, only the first number results are returned.
-# If the -a option is given, the elements in array are ordered instead and
-# array is mutated to contain the result.
-# If number is 0, all results are returned.
-#
-# If given, isAscending comparator command will be executed for each element
-# comparison and will be passed two element arguments. The command should
-# succeed if the first argument is less than the second argument for the
-# purpose of this sort.
-#
-# If the -0 option is given, input and output are delimited by NUL bytes.
-# If the -d option is given, input and output are delimited by the
-# character argument.
-# Otherwise, they are delimited by newlines.
-#
-# The ordering is implemented by an insertion sort algorithm.
-#
-order() {
-
- # Initialize the vars.
- local elements=() element delimitor=$'\n' i isAscending=_order_string_ascends top=0 array= arrayElements=
-
- # Parse the options.
- local OPTIND=1
- while getopts :0nd:c:C:t:a: opt; do
- case $opt in
- 0) delimitor=$'\0' ;;
- d) delimitor=$OPTARG ;;
- n) comparator=_order_number_ascends ;;
- c) isAscending=$OPTARG ;;
- C) isAscending=_order_cmd_ascends _order_cmd=$OPTARG ;;
- t) top=$OPTARG ;;
- a) array=$OPTARG arrayElements=$array[@] ;;
- esac
- done
- shift "$((OPTIND-1))"
-
- # Get the elements.
- if [[ $array ]]; then
- elements=( "${!arrayElements}" )
- elif (( $# )); then
- elements=( "$@" )
- else
- while IFS= read -r -d "$delimitor"; do
- elements+=("$REPLY")
- done
- fi
-
- # Iterate in reverse order.
- for (( i = 2; i < ${#elements[@]}; ++i )); do
- for (( j = i; j > 1; --j )); do
- element=${elements[j]}
- if "$isAscending" "$element" "${elements[j-1]}"; then
- elements[j]=${elements[j-1]}
- elements[j-1]=$element
- fi
- done
- done
-
- (( top )) || top=${#elements[@]}
- if [[ $array ]]; then
- declare -ga "$array=($(printf '%q ' "${elements[@]:0:top}"))"
- else
- printf "%s${delimitor:-\0}" "${elements[@]:0:top}"
- fi
-} # _____________________________________________________________________
-_order_string_ascends() { [[ $1 < $2 ]]; }
-_order_number_ascends() { (( $1 < $2 )); }
-_order_mtime_ascends() { [[ $1 -ot $2 ]]; }
-_order_cmd_ascends() { bash -c "$_order_cmd" -- "$@"; }
-
-
-# ______________________________________________________________________
-# |__ Mutex _____________________________________________________________|
-#
-# mutex file
-#
-# Open a mutual exclusion lock on the file, unless another process already owns one.
-#
-# If the file is already locked by another process, the operation fails.
-# This function defines a lock on a file as having a file descriptor open to the file.
-# This function uses FD 9 to open a lock on the file. To release the lock, close FD 9:
-# exec 9>&-
-#
-mutex() {
- local lockfile=${1:-${BASH_SOURCE[-1]}} pid pids
- [[ -e $lockfile ]] || err "No such file: $lockfile" || return
-
- exec 9>> "$lockfile" && [[ $({ fuser -f "$lockfile"; } 2>&- 9>&-) == $$ ]]
-}
-
-
-# ______________________________________________________________________
-# |__ PushJob ___________________________________________________________|
-#
-# pushjob [poolsize] command
-#
-# Start an asynchronous command within a pool, waiting for space in the pool if it is full.
-#
-# The pool is pruned automatically as running jobs complete. This function
-# allows you to easily run asynchronous commands within a pool of N,
-# automatically starting the next command as soon as there's space.
-#
-pushjob() {
- local size=$1; shift 1
-
- # Wait for space in the pool.
- until (( ${#jobpool[@]} < size )); do
- sleep 1 & pushjobsleep=$!
- wait "$pushjobsleep"
- done 2>/dev/null
-
- # Register prunejobs and start the pushed job.
- trap _prunejobs SIGCHLD
- set -m
- "$@" & jobpool[$!]=
-}
-_prunejobs() {
- # Prune all pool jobs that are no longer running.
- for pid in "${!jobpool[@]}"; do
- kill -0 "$pid" 2>/dev/null || unset "jobpool[$pid]"
- done
-
- # Unregister SIGCHLD if our pool is empty.
- (( ${#jobpool[@]} )) || trap - SIGCHLD
-
- # Wake up pushjob.
- kill "$pushjobsleep" 2>/dev/null
-}
-
-
-
-
-# ______________________________________________________________________
-# |__ FSleep _____________________________________________________________|
-#
-# fsleep time
-#
-# Wait for the given (fractional) amount of seconds.
-#
-# This implementation solves the problem portably, assuming that either
-# bash 4.x or a fractional sleep(1) is available.
-#
-fsleep() {
-
- local fifo=${TMPDIR:-/tmp}/.fsleep.$$
- trap 'rm -f "$fifo"' RETURN
- mkfifo "$fifo" && { read -t "$1" <> "$fifo" 2>/dev/null || sleep "$1"; }
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ GetArgs ___________________________________________________________|
-#
-# getArgs [options] optstring [args...]
-#
-# Retrieve all options present in the given arguments.
-#
-# This is a wrapper for getopts(P) which will safely work inside functions.
-# It manages OPTIND for you and returns a list of options found in the
-# provided arguments.
-#
-# optstring This is a string of characters in which each character
-# represents an option to look for in the arguments.
-# See getopts(P) for a description of the optstring syntax.
-#
-# args This is a list of arguments in which to look for options.
-# Most commonly, you will use "$@" to supply these arguments.
-#
-# -c Instead of output the arguments, output OPTARGS.
-# -q Be quiet. No arguments are displayed. Only the exit code is set.
-# -n Use newlines as a separator between the options that were found.
-# -0 Use NULL-bytes as a separator between the options that were found.
-#
-# If any given arguments are found, an exit code of 0 is returned. If none
-# are found, an exit code of 1 is returned.
-#
-# After the operation, OPTARGS is set the the index of the last argument
-# that has been parsed by getArgs. Ready for you to use shift $OPTARGS.
-#
-getArgs() {
-
- # Check usage.
- (( ! $# )) && {
- emit -y 'Please provide the arguments to search for in' \
- 'getopts(P) format followed by the positional parameters.'
- return 1
- }
-
- # Initialize the defaults.
- local arg
- local found=0
- local quiet=0
- local count=0
- local delimitor=' '
-
- # Parse the options.
- while [[ $1 = -* ]]; do
- case $1 in
- -q) quiet=1 ;;
- -c) count=1 ;;
- -n) delimitor=$'\n' ;;
- -0) delimitor=$'\0' ;;
- esac
- shift
- done
-
- # Get the optstring.
- local optstring=$1; shift
-
- # Enumerate the arguments.
- local OPTIND=1
- while getopts "$optstring" arg; do
- [[ $arg != '?' ]] && found=1
-
- (( quiet + count )) || \
- printf "%s${OPTARG:+ }%s%s" "$arg" "$OPTARG" "$delimitor"
- done
- OPTARGS=$(( OPTIND - 1 ))
-
- # Any arguments found?
- (( count )) && printf "%s" "$OPTARGS"
- return $(( ! found ))
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ ShowHelp __________________________________________________________|
-#
-# showHelp name description author [option description]...
-#
-# Generate a prettily formatted usage description of the application.
-#
-# name Provide the name of the application.
-#
-# description Provide a detailed description of the application's
-# purpose and usage.
-#
-# option An option the application can take as argument.
-#
-# description A description of the effect of the preceding option.
-#
-showHelp() {
-
- # Check usage.
- (( $# < 3 )) || getArgs -q :h "$@" && {
- emit -y 'Please provide the name, description, author and options' \
- 'of the application.'
- return 1
- }
-
- # Parse the options.
- local appName=$1; shift
- local appDesc=${1//+([[:space:]])/ }; shift
- local appAuthor=$1; shift
- local cols=$(tput cols)
- (( cols = ${cols:-80} - 10 ))
-
- # Figure out what FD to use for our messages.
- [[ -t 1 ]]; local fd=$(( $? + 1 ))
-
- # Print out the help header.
- printf "$reset$bold\n" >&$fd
- printf "\t\t%s\n" "$appName" >&$fd
- printf "$reset\n" >&$fd
- printf "%s\n" "$appDesc" | fmt -w "$cols" | sed $'s/^/\t/' >&$fd
- printf "\t $reset$bold~ $reset$bold%s\n" "$appAuthor" >&$fd
- printf "$reset\n" >&$fd
-
- # Print out the application options and columnize them.
- while (( $# )); do
- local optName=$1; shift
- local optDesc=$1; shift
- printf " %s\t" "$optName"
- printf "%s\n" "${optDesc//+( )/ }" | fmt -w "$cols" | sed $'1!s/^/ \t/'
- printf "\n"
- done | column -t -s $'\t' \
- | sed "s/^\( [^ ]*\)/$bold$green\1$reset/" >&$fd
- printf "\n" >&$fd
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Quote _____________________________________________________________|
-#
-# shquote [-e] [argument...]
-#
-# Shell-quote the arguments to make them safe for injection into bash code.
-#
-# The result is bash code that represents a series of words, where each
-# word is a literal string argument. By default, quoting happens using
-# single-quotes.
-#
-# -e Use backslashes rather than single quotes.
-# -d Use double-quotes rather than single quotes (does NOT disable expansions!).
-#
-shquote() {
-
- # Initialize the defaults.
- local arg escape=0 sq="'\\''" dq='\"' quotedArgs=() type=single
-
- # Parse the options.
- while [[ $1 = -* ]]; do
- case $1 in
- -e) type=escape ;;
- -d) type=double ;;
- --) shift; break ;;
- esac
- shift
- done
-
- # Print out each argument, quoting it properly.
- for arg; do
- case "$type" in
- escape)
- quotedArgs+=("$(printf "%q" "$arg")") ;;
- single)
- arg=${arg//"'"/$sq}
- quotedArgs+=("$(printf "'%s'" "$arg")") ;;
- double)
- arg=${arg//'"'/$dq}
- quotedArgs+=("$(printf '"%s"' "$arg")") ;;
- esac
- done
-
- printf '%s\n' "$(IFS=' '; echo "${quotedArgs[*]}")"
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ ReQuote __________________________________________________________|
-#
-# requote [string]
-#
-# Escape the argument string to make it safe for injection into a regex.
-#
-# The result is a regular expression that matches the literal argument
-# string.
-#
-requote() {
-
- # Initialize the defaults.
- local char
-
- printf '%s' "$1" | while IFS= read -r -d '' -n1 char; do
- printf '[%s]' "$char"
- done
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Shorten ___________________________________________________________|
-#
-# shorten [-p pwd] path [suffix]...
-#
-# Shorten an absolute path for pretty printing.
-# Paths are shortened by replacing the homedir by ~, making it relative and
-# cutting off given suffixes from the end.
-#
-# -p Use the given pathname as the base for relative filenames instead of PWD.
-# path The path string to shorten.
-# suffix Suffix strings that must be cut off from the end.
-# Only the first suffix string matched will be cut off.
-#
-shorten() {
-
- # Check usage.
- (( $# < 1 )) || getArgs -q :h "$@" && {
- emit -y 'Please provide the path to shorten.'
- return 1
- }
-
- # Parse the options.
- local suffix path pwd=$PWD
- [[ $1 = -p ]] && { pwd=$2; shift 2; }
- path=$1; shift
-
- # Make path absolute.
- [[ $path = /* ]] || path=$PWD/$path
-
- # If the path denotes something that exists; it's easy.
- if [[ -d $path ]]
- then path=$(cd "$path"; printf "%s" "$PWD")
- elif [[ -d ${path%/*} ]]
- then path=$(cd "${path%/*}"; printf "%s" "$PWD/${path##*/}")
-
- # If not, we'll try readlink -m.
- elif readlink -m / >/dev/null 2>&1; then
- path=$(readlink -m "$path")
-
- # If we don't have that - unleash the sed(1) madness.
- else
- local oldpath=/
- while [[ $oldpath != $path ]]; do
- oldpath=$path
- path=$(sed -e 's,///*,/,g' -e 's,\(^\|/\)\./,\1,g' -e 's,\(^\|/\)[^/]*/\.\.\($\|/\),\1,g' <<< "$path")
- done
- fi
-
- # Replace special paths.
- path=${path/#$HOME/'~'}
- path=${path#$pwd/}
-
- # Cut off suffix.
- for suffix; do
- [[ $path = *$suffix ]] && {
- path=${path%$suffix}
- break
- }
- done
-
- printf "%s" "$path"
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ Up ________________________________________________________________|
-#
-# up .../path|num
-#
-# Walk the current working directory up towards root num times or until path is found.
-#
-# Returns 0 if the destination was reached or 1 if we hit root.
-#
-# Prints PWD on stdout on success.
-#
-up() {
- local up=0
- until [[ $PWD = / ]]; do
- cd ../
-
- if [[ $1 = .../* ]]; then
- [[ -e ${1#.../} ]] && pwd && return
- elif (( ++up == $1 )); then
- pwd && return
- fi
- done
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ BuildArray ________________________________________________________|
-#
-# buildarray name terms... -- elements...
-#
-# Create an array by adding all the terms to it for each element, replacing {} terms by the element.
-#
-# name The name of the array to put the result into.
-# terms The values to add to the array for each of the elements. A {} term is replaced by the current element.
-# elements The elements to iterate the terms for.
-#
-buildarray() {
- local target=$1 term terms=() element value
- shift
-
- while [[ $1 != -- ]]; do
- terms+=("$1")
- shift
- done
- shift
-
- for element; do
- for term in "${terms[@]}"; do
- [[ $term = {} ]] && value="$element" || value="$term"
- declare -ag "$target+=($(printf '%q' "$value"))"
- done
- done
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ InArray ___________________________________________________________|
-#
-# inArray element array
-#
-# Checks whether a certain element is in the given array.
-#
-# element The element to search the array for.
-# array This is a list of elements to search through.
-#
-inArray() {
-
- # Check usage.
- (( $# < 1 )) || getArgs -q :h "$@" && {
- emit -y 'Please provide the element to search for and the array' \
- 'to search through.'
- return 1
- }
-
- # Parse the options.
- local element
- local search=$1; shift
-
- # Perform the search.
- for element
- do [[ $element = $search ]] && return 0; done
- return 1
-} # _____________________________________________________________________
-
-
-
-# ______________________________________________________________________
-# |__ HideDebug _________________________________________________________|
-#
-# hideDebug [on|off]
-#
-# Toggle Bash's debugging mode off temporarily.
-# To hide Bash's debugging output for a function, you should have
-# hideDebug on
-# as its first line, and
-# hideDebug off
-# as its last.
-#
-hideDebug() {
-
- if [[ $1 = on ]]; then
- : -- HIDING DEBUG OUTPUT ..
- [[ $- != *x* ]]; bashlib_debugWasOn=$?
- set +x
- elif [[ $1 = off ]]; then
- : -- SHOWING DEBUG OUTPUT ..
- (( bashlib_debugWasOn )) && \
- set -x
- fi
-}
-
-
-
-# ______________________________________________________________________
-# |__ anfunc ____________________________________________________________|
-#
-# anfunc [on|off]
-#
-# Turn on or off support for annonymous functions.
-#
-# WARNING: This is a hack. It turns on extdebug and causes any argument
-# that matches (){code} to be replaced by a function name that if invoked
-# runs code.
-#
-# eg.
-# confirm '(){ rm "$1" }' *.txt
-# # In this example, confirm() could be a function that asks confirmation
-# # for each argument past the first and runs the anfunc in the first
-# # argument on each confirmed argument.
-#
-# Don't use this. It is an academic experiment and has bugs.
-#
-# Bugs:
-# - commands lose their exit code.
-# To inhibit the real command from running, we use extdebug and
-# a DEBUG trap that returns non-0. As a result, the actual return
-# code is lost.
-#
-anfunc() {
- case "$1" in
- on)
- shopt -s extdebug
- trap _anfunc_trap DEBUG
- ;;
- off)
- trap - DEBUG
- shopt -u extdebug
- ;;
- esac
-}
-_anfunc_trap() {
- local f w
-
- # Perform the command parsing and handling up to its word splitting.
- # This includes command substitution, quote handling, pathname expansion, etc.
- declare -a words="($BASH_COMMAND)"
-
- # Iterate the words to run in the final stage, and handle anfunc matches.
- for ((w=0; w<${#words[@]}; ++w)); do
- [[ ${words[w]} = '(){'*'}' ]] &&
- # Declare a new function for this anfunc.
- eval "_f$((++f))${words[w]}" &&
- # Replace the word by the new function's name.
- words[w]="_f$f"
- done
-
- # Run the command.
- eval "$(printf '%q ' "${words[@]}")"
-
- # Clean up the anfuncs.
- for ((; f>0; --f)); do
- unset -f "_f$f"
- done
-
- # Inhibit the real command's execution.
- return 1
-}
-
-
-
-# ______________________________________________________________________
-# |__ StackTrace ________________________________________________________|
-#
-# stackTrace
-#
-# Output the current script's function execution stack.
-#
-stackTrace() {
-
- # Some general debug information.
- printf "\t$bold%s$reset v$bold%s$reset" "$BASH" "$BASH_VERSION\n"
- printf " Was running: $bold%s %s$reset" "$BASH_COMMAND" "$*\n"
- printf "\n"
- printf " [Shell : $bold%15s$reset] [Subshells : $bold%5s$reset]\n" "$SHLVL" "$BASH_SUBSHELL"
- printf " [Locale : $bold%15s$reset] [Runtime : $bold%5s$reset]\n" "$LC_ALL" "${SECONDS}s"
- printf "\n"
-
- # Search through the map.
- local arg=0
- for i in ${!FUNCNAME[@]}; do
- #if (( i )); then
-
- # Print this execution stack's location.
- printf "$reset $bold-$reset $green"
- [[ ${BASH_SOURCE[i+1]} ]] \
- && printf "%s$reset:$green$bold%s" "${BASH_SOURCE[i+1]}" "${BASH_LINENO[i]}" \
- || printf "${bold}Prompt"
-
- # Print this execution stack's function and positional parameters.
- printf "$reset :\t$bold%s(" "${FUNCNAME[i]}"
- [[ ${BASH_ARGC[i]} ]] && \
- for (( j = 0; j < ${BASH_ARGC[i]}; j++ )); do
- (( j )) && printf ', '
- printf "%s" "${BASH_ARGV[arg]}"
- let arg++
- done
-
- # Print the end of this execution stack's line.
- printf ")$reset\n"
- #fi
- done
- printf "\n"
-
-} # _____________________________________________________________________
-
-
-
-
-
-# ______________________________________________________________________
-# | |
-# | .:: ENTRY POINT ::. |
-# |______________________________________________________________________|
-
-# Make sure this file is sourced and not executed.
-( return 2>/dev/null ) || {
- emit -R "You should source this file, not execute it."
- exit 1
-}
-
-:
-: .:: END SOURCING ::.
-: ______________________________________________________________________
-:
diff --git a/platform-independent/cli-java/src/main/scripts/install b/platform-independent/cli-java/src/main/scripts/install
deleted file mode 100755
index 8b4f8f61..00000000
--- a/platform-independent/cli-java/src/main/scripts/install
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env bash
-#
-# Install the Master Password CLI tool.
-set -e
-cd "${BASH_SOURCE%/*}"
-source bashlib
-
-inf "This will install the mpw tool."
-
-# Try to guess then ask for the bin dir to install to.
-IFS=: read -a paths <<< "$PATH"
-if inArray ~/bin "${paths[@]}"; then
- bindir=~/bin
-elif inArray ~/.bin "${paths[@]}"; then
- bindir=~/.bin
-elif inArray /usr/local/bin "${paths[@]}"; then
- bindir=/usr/local/bin
-else
- bindir=~/bin
-fi
-bindir=$(ask -d "$bindir" "What bin directory should I install to?")
-[[ -d "$bindir" ]] || mkdir "$bindir" || ftl 'Cannot create missing bin directory: %s' "$bindir" || exit
-[[ -w "$bindir" ]] || ftl 'Cannot write to bin directory: %s' "$bindir" || exit
-
-# Try to guess then ask for the share dir to install to.
-sharedir=$(cd -P "$bindir/.."; [[ $bindir = */.bin ]] && printf '%s/.share' "$PWD" || printf '%s/share' "$PWD")
-sharedir=$(ask -d "$sharedir" "What share directory should I install to?")
-[[ -d "$sharedir" ]] || mkdir "$sharedir" || ftl 'Cannot create missing share directory: %s' "$sharedir" || exit
-[[ -w "$sharedir" ]] || ftl 'Cannot write to share directory: %s' "$sharedir" || exit
-
-# Install Master Password.
-sharepath=$sharedir/masterpassword
-mkdir -p "$sharepath"
-cp -a "masterpassword-cli-"*".jar" bashlib mpw "$sharepath"
-ex -c "%s~%SHAREPATH%~$sharepath~g|x" "$sharepath/mpw"
-ln -sf "$sharepath/mpw" "$bindir/mpw"
-chmod +x "$sharepath/mpw"
-[[ ! -e "$bindir/bashlib" ]] && ln -s "$sharepath/bashlib" "$bindir/bashlib" ||:
-
-# Convenience bash function.
-inf "Installation successful!"
-echo
-inf "To improve usability, you can install an mpw function in your bash shell."
-inf "This function adds the following features:"
-inf " - Ask the Master Password once, remember in the shell."
-inf " - Automatically put the password in the clipboard (some platforms)."
-echo
-inf "To do this you need the following function in ~/.bashrc:\n%s" "$(> ~/.bashrc
- inf "Done! Don't forget to run '%s' to apply the changes!" "source ~/.bashrc"
-fi
-echo
-inf "To begin using Master Password, type: mpw [site name]"
diff --git a/platform-independent/cli-java/src/main/scripts/mpw b/platform-independent/cli-java/src/main/scripts/mpw
deleted file mode 100755
index beb231b8..00000000
--- a/platform-independent/cli-java/src/main/scripts/mpw
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-
-# Uncomment this to set your user name. Master Password will no longer ask you for a user name.
-# export MP_USERNAME="Robert Lee Mitchell"
-# Uncomment this to hardcode your master password. Make sure this file's permissions are tight. Master Password will not ask you for your master password anymore. This is probably not a good idea.
-# export MP_PASSWORD="banana colored duckling"
-
-cd "%SHAREPATH%"
-exec java -jar masterpassword-cli-GIT-SNAPSHOT.jar "$@"
diff --git a/platform-independent/cli-java/src/main/scripts/mpw.bashrc b/platform-independent/cli-java/src/main/scripts/mpw.bashrc
deleted file mode 100644
index 6f790542..00000000
--- a/platform-independent/cli-java/src/main/scripts/mpw.bashrc
+++ /dev/null
@@ -1,15 +0,0 @@
-source bashlib
-mpw() {
- _nocopy() { echo >&2 "$(cat)"; }
- _copy() { "$(type -P pbcopy || type -P xclip || echo _nocopy)"; }
-
- # Empty the clipboard
- :| _copy 2>/dev/null
-
- # Ask for the user's name and password if not yet known.
- MP_USERNAME=${MP_USERNAME:-$(ask -s 'Your Full Name:')}
- MP_PASSWORD=${MP_PASSWORD:-$(ask -s 'Master Password:')}
-
- # Start Master Password and copy the output.
- printf %s "$(MP_USERNAME=$MP_USERNAME MP_PASSWORD=$MP_PASSWORD command mpw "$@")" | _copy
-}
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 95356782..2c6d798a 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
@@ -1,7 +1,7 @@
package com.lyndir.masterpassword.gui.model;
import com.google.common.primitives.UnsignedInteger;
-import com.lyndir.masterpassword.MPSiteType;
+import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.MasterKey;
@@ -11,15 +11,15 @@ import com.lyndir.masterpassword.MasterKey;
public class IncognitoSite extends Site {
private String siteName;
- private MPSiteType siteType;
private UnsignedInteger siteCounter;
+ private MPResultType resultType;
private MasterKey.Version algorithmVersion;
- public IncognitoSite(final String siteName, final MPSiteType siteType, final UnsignedInteger siteCounter,
+ public IncognitoSite(final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
final MasterKey.Version algorithmVersion) {
this.siteName = siteName;
- this.siteType = siteType;
this.siteCounter = siteCounter;
+ this.resultType = resultType;
this.algorithmVersion = algorithmVersion;
}
@@ -34,13 +34,13 @@ public class IncognitoSite extends Site {
}
@Override
- public MPSiteType getSiteType() {
- return siteType;
+ public MPResultType getResultType() {
+ return resultType;
}
@Override
- public void setSiteType(final MPSiteType siteType) {
- this.siteType = siteType;
+ public void setResultType(final MPResultType resultType) {
+ this.resultType = resultType;
}
@Override
diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/ModelSite.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/ModelSite.java
index be41ce12..c4552fec 100755
--- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/ModelSite.java
+++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/ModelSite.java
@@ -1,7 +1,7 @@
package com.lyndir.masterpassword.gui.model;
import com.google.common.primitives.UnsignedInteger;
-import com.lyndir.masterpassword.MPSiteType;
+import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.MasterKey;
import com.lyndir.masterpassword.model.*;
@@ -33,14 +33,14 @@ public class ModelSite extends Site {
}
@Override
- public MPSiteType getSiteType() {
- return model.getSiteType();
+ public MPResultType getResultType() {
+ return model.getResultType();
}
@Override
- public void setSiteType(final MPSiteType siteType) {
- if (siteType != getSiteType()) {
- model.setSiteType( siteType );
+ public void setResultType(final MPResultType resultType) {
+ if (resultType != getResultType()) {
+ model.setResultType( resultType );
MPUserFileManager.get().save();
}
}
diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/ModelUser.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/ModelUser.java
index a1716348..42d31fd4 100755
--- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/ModelUser.java
+++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/ModelUser.java
@@ -79,7 +79,7 @@ public class ModelUser extends User {
@Override
public void addSite(final Site site) {
- model.addSite( new MPSite( model, site.getSiteName(), site.getSiteType(), site.getSiteCounter() ) );
+ model.addSite( new MPSite( model, site.getSiteName(), site.getSiteCounter(), site.getResultType() ) );
model.updateLastUsed();
MPUserFileManager.get().save();
}
diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/Site.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/Site.java
index 62f0dea6..0f48a07f 100644
--- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/Site.java
+++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/Site.java
@@ -3,7 +3,7 @@ package com.lyndir.masterpassword.gui.model;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.google.common.primitives.UnsignedInteger;
-import com.lyndir.masterpassword.MPSiteType;
+import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.MasterKey;
@@ -16,9 +16,9 @@ public abstract class Site {
public abstract void setSiteName(String siteName);
- public abstract MPSiteType getSiteType();
+ public abstract MPResultType getResultType();
- public abstract void setSiteType(MPSiteType siteType);
+ public abstract void setResultType(MPResultType resultType);
public abstract MasterKey.Version getAlgorithmVersion();
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 38343d1a..cff64d63 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
@@ -32,10 +32,10 @@ public class PasswordFrame extends JFrame implements DocumentListener {
private final Components.GradientPanel root;
private final JTextField siteNameField;
private final JButton siteActionButton;
- private final JComboBox siteTypeField;
private final JComboBox siteVersionField;
private final JSpinner siteCounterField;
private final UnsignedIntegerModel siteCounterModel;
+ private final JComboBox resultTypeField;
private final JPasswordField passwordField;
private final JLabel tipLabel;
private final JCheckBox maskPasswordField;
@@ -118,17 +118,17 @@ public class PasswordFrame extends JFrame implements DocumentListener {
// Site Type & Counter
siteCounterModel = new UnsignedIntegerModel( UnsignedInteger.ONE, UnsignedInteger.ONE );
- MPSiteType[] types = Iterables.toArray( MPSiteType.forClass( MPSiteTypeClass.Generated ), MPSiteType.class );
+ MPResultType[] types = Iterables.toArray( MPResultType.forClass( MPResultTypeClass.Generated ), MPResultType.class );
JComponent siteSettings = Components.boxLayout( BoxLayout.LINE_AXIS, //
- siteTypeField = Components.comboBox( types ), //
+ resultTypeField = Components.comboBox( types ), //
Components.stud(), //
siteVersionField = Components.comboBox( MasterKey.Version.values() ), //
Components.stud(), //
siteCounterField = Components.spinner( siteCounterModel ) );
sitePanel.add( siteSettings );
- siteTypeField.setFont( Res.valueFont().deriveFont( 12f ) );
- siteTypeField.setSelectedItem( MPSiteType.GeneratedLong );
- siteTypeField.addItemListener( new ItemListener() {
+ resultTypeField.setFont( Res.valueFont().deriveFont( 12f ) );
+ resultTypeField.setSelectedItem( MPResultType.GeneratedLong );
+ resultTypeField.addItemListener( new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
updatePassword( true );
@@ -215,7 +215,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
return Futures.immediateCancelledFuture();
}
- MPSiteType siteType = siteTypeField.getModel().getElementAt( siteTypeField.getSelectedIndex() );
+ MPResultType resultType = resultTypeField.getModel().getElementAt( resultTypeField.getSelectedIndex() );
MasterKey.Version siteVersion = siteVersionField.getItemAt( siteVersionField.getSelectedIndex() );
UnsignedInteger siteCounter = siteCounterModel.getNumber();
@@ -228,9 +228,9 @@ public class PasswordFrame extends JFrame implements DocumentListener {
}
} );
final Site site = ifNotNullElse( Iterables.getFirst( siteResults, null ),
- new IncognitoSite( siteNameQuery, siteType, siteCounter, siteVersion ) );
+ new IncognitoSite( siteNameQuery, siteCounter, resultType, siteVersion ) );
if ((currentSite != null) && currentSite.getSiteName().equals( site.getSiteName() )) {
- site.setSiteType( siteType );
+ site.setResultType( resultType );
site.setAlgorithmVersion( siteVersion );
site.setSiteCounter( siteCounter );
}
@@ -240,7 +240,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
public String call()
throws Exception {
return user.getKey( site.getAlgorithmVersion() )
- .encode( site.getSiteName(), site.getSiteType(), site.getSiteCounter(), MPSiteVariant.Password, null );
+ .siteResult( site.getSiteName(), site.getSiteCounter(), MPKeyPurpose.Password, null, site.getResultType(), null );
}
} );
Futures.addCallback( passwordFuture, new FutureCallback() {
@@ -256,7 +256,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
siteActionButton.setText( "Delete Site" );
else
siteActionButton.setText( "Add Site" );
- siteTypeField.setSelectedItem( currentSite.getSiteType() );
+ resultTypeField.setSelectedItem( currentSite.getResultType() );
siteVersionField.setSelectedItem( currentSite.getAlgorithmVersion() );
siteCounterField.setValue( currentSite.getSiteCounter() );
siteNameField.setText( currentSite.getSiteName() );