WIP - JSON mpsites serialization.
This commit is contained in:
parent
cb74b1f3fc
commit
1031414ba2
@ -174,6 +174,11 @@ public enum MPResultType {
|
|||||||
return typeFeatures;
|
return typeFeatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean supportsTypeFeature(final MPSiteFeature feature) {
|
||||||
|
|
||||||
|
return typeFeatures.contains( feature );
|
||||||
|
}
|
||||||
|
|
||||||
public int getType() {
|
public int getType() {
|
||||||
int mask = typeIndex | typeClass.getMask();
|
int mask = typeIndex | typeClass.getMask();
|
||||||
for (final MPSiteFeature typeFeature : typeFeatures)
|
for (final MPSiteFeature typeFeature : typeFeatures)
|
||||||
|
@ -9,6 +9,7 @@ dependencies {
|
|||||||
compile project( ':masterpassword-algorithm' )
|
compile project( ':masterpassword-algorithm' )
|
||||||
|
|
||||||
compile group: 'joda-time', name: 'joda-time', version: '2.4'
|
compile group: 'joda-time', name: 'joda-time', version: '2.4'
|
||||||
|
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.2'
|
||||||
compileOnly group: 'com.google.auto.value', name: 'auto-value', version: '1.2'
|
compileOnly group: 'com.google.auto.value', name: 'auto-value', version: '1.2'
|
||||||
apt group: 'com.google.auto.value', name: 'auto-value', version: '1.2'
|
apt group: 'com.google.auto.value', name: 'auto-value', version: '1.2'
|
||||||
|
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 2018-04-27
|
||||||
|
*/
|
||||||
|
public class EnumOrdinalAdapter implements JsonSerializer<Enum<?>>, JsonDeserializer<Enum<?>> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Enum<?> deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
|
||||||
|
throws JsonParseException {
|
||||||
|
Enum<?>[] enumConstants = ((Class<Enum<?>>) typeOfT).getEnumConstants();
|
||||||
|
if (enumConstants == null)
|
||||||
|
throw new JsonParseException( "Not an enum: " + typeOfT );
|
||||||
|
|
||||||
|
try {
|
||||||
|
int ordinal = json.getAsInt();
|
||||||
|
if ((ordinal < 0) || (ordinal >= enumConstants.length))
|
||||||
|
throw new JsonParseException( "No ordinal " + ordinal + " in enum: " + typeOfT );
|
||||||
|
|
||||||
|
return enumConstants[ordinal];
|
||||||
|
} catch (final ClassCastException | IllegalStateException e) {
|
||||||
|
throw new JsonParseException( "Not an ordinal value: " + json, e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(final Enum<?> src, final Type typeOfSrc, final JsonSerializationContext context) {
|
||||||
|
return new JsonPrimitive( src.ordinal() );
|
||||||
|
}
|
||||||
|
}
|
@ -39,7 +39,6 @@ public class MPFileSite extends MPSite {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private String loginContent;
|
private String loginContent;
|
||||||
@Nullable
|
|
||||||
private MPResultType loginType;
|
private MPResultType loginType;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -48,35 +47,27 @@ public class MPFileSite extends MPSite {
|
|||||||
private Instant lastUsed;
|
private Instant lastUsed;
|
||||||
|
|
||||||
public MPFileSite(final MPFileUser user, final String siteName) {
|
public MPFileSite(final MPFileUser user, final String siteName) {
|
||||||
this( user, siteName,
|
this( user, siteName, null, null, user.getAlgorithm() );
|
||||||
user.getAlgorithm().mpw_default_counter(),
|
|
||||||
user.getAlgorithm().mpw_default_type(),
|
|
||||||
user.getAlgorithm() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPFileSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
|
public MPFileSite(final MPFileUser user, final String siteName, @Nullable final UnsignedInteger siteCounter,
|
||||||
final MPAlgorithm algorithm) {
|
@Nullable final MPResultType resultType, final MPAlgorithm algorithm) {
|
||||||
this.user = user;
|
this( user, siteName, null, siteCounter, resultType, algorithm,
|
||||||
this.siteName = siteName;
|
null, null, null, 0, new Instant() );
|
||||||
this.siteCounter = siteCounter;
|
|
||||||
this.resultType = resultType;
|
|
||||||
this.algorithm = algorithm;
|
|
||||||
this.lastUsed = new Instant();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteContent,
|
protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteContent,
|
||||||
final UnsignedInteger siteCounter,
|
@Nullable final UnsignedInteger siteCounter, @Nullable final MPResultType resultType, final MPAlgorithm algorithm,
|
||||||
final MPResultType resultType, final MPAlgorithm algorithm,
|
|
||||||
@Nullable final String loginContent, @Nullable final MPResultType loginType,
|
@Nullable final String loginContent, @Nullable final MPResultType loginType,
|
||||||
@Nullable final String url, final int uses, final Instant lastUsed) {
|
@Nullable final String url, final int uses, final Instant lastUsed) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.siteName = siteName;
|
this.siteName = siteName;
|
||||||
this.siteContent = siteContent;
|
this.siteContent = siteContent;
|
||||||
this.siteCounter = siteCounter;
|
this.siteCounter = (siteCounter == null)? user.getAlgorithm().mpw_default_counter(): siteCounter;
|
||||||
this.resultType = resultType;
|
this.resultType = (resultType == null)? user.getAlgorithm().mpw_default_type(): resultType;
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
this.loginContent = loginContent;
|
this.loginContent = loginContent;
|
||||||
this.loginType = loginType;
|
this.loginType = (loginType == null)? MPResultType.GeneratedName: loginType;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.uses = uses;
|
this.uses = uses;
|
||||||
this.lastUsed = lastUsed;
|
this.lastUsed = lastUsed;
|
||||||
@ -163,7 +154,6 @@ public class MPFileSite extends MPSite {
|
|||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public MPResultType getLoginType() {
|
public MPResultType getLoginType() {
|
||||||
return loginType;
|
return loginType;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ public class MPFileUserManager extends MPUserManager {
|
|||||||
super.deleteUser( user );
|
super.deleteUser( user );
|
||||||
|
|
||||||
// Remove deleted users.
|
// Remove deleted users.
|
||||||
File userFile = getUserFile( user );
|
File userFile = getUserFile( user, user.getFormat() );
|
||||||
if (userFile.exists() && !userFile.delete())
|
if (userFile.exists() && !userFile.delete())
|
||||||
logger.err( "Couldn't delete file: %s", userFile );
|
logger.err( "Couldn't delete file: %s", userFile );
|
||||||
}
|
}
|
||||||
@ -119,13 +119,14 @@ public class MPFileUserManager extends MPUserManager {
|
|||||||
public void save(final MPFileUser user, final MPMasterKey masterKey)
|
public void save(final MPFileUser user, final MPMasterKey masterKey)
|
||||||
throws MPInvalidatedException {
|
throws MPInvalidatedException {
|
||||||
try {
|
try {
|
||||||
|
final MPMarshalFormat format = user.getFormat();
|
||||||
new CharSink() {
|
new CharSink() {
|
||||||
@Override
|
@Override
|
||||||
public Writer openStream()
|
public Writer openStream()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return new OutputStreamWriter( new FileOutputStream( getUserFile( user ) ), Charsets.UTF_8 );
|
return new OutputStreamWriter( new FileOutputStream( getUserFile( user, format ) ), Charsets.UTF_8 );
|
||||||
}
|
}
|
||||||
}.write( user.getFormat().marshaller().marshall( user, masterKey, MPMarshaller.ContentMode.PROTECTED ) );
|
}.write( format.marshaller().marshall( user, masterKey, MPMarshaller.ContentMode.PROTECTED ) );
|
||||||
}
|
}
|
||||||
catch (final MPMarshalException | IOException e) {
|
catch (final MPMarshalException | IOException e) {
|
||||||
logger.err( e, "Unable to save sites for user: %s", user );
|
logger.err( e, "Unable to save sites for user: %s", user );
|
||||||
@ -133,8 +134,8 @@ public class MPFileUserManager extends MPUserManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private File getUserFile(final MPFileUser user) {
|
private File getUserFile(final MPFileUser user, final MPMarshalFormat format) {
|
||||||
return new File( path, user.getFullName() + ".mpsites" );
|
return new File( path, user.getFullName() + format.fileSuffix() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,193 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
|
import com.lyndir.masterpassword.*;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.joda.time.Instant;
|
||||||
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
|
import org.joda.time.format.ISODateTimeFormat;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 2018-04-27
|
||||||
|
*/
|
||||||
|
public class MPJSONFile {
|
||||||
|
|
||||||
|
private static final DateTimeFormatter dateFormatter = ISODateTimeFormat.dateTimeNoMillis();
|
||||||
|
|
||||||
|
Export export;
|
||||||
|
User user;
|
||||||
|
|
||||||
|
public MPJSONFile(final MPFileUser user, final MPMasterKey masterKey, final MPMarshaller.ContentMode contentMode)
|
||||||
|
throws MPInvalidatedException {
|
||||||
|
// if (!user.fullName || !strlen( user.fullName )) {
|
||||||
|
// *error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// if (!user.masterPassword || !strlen( user.masterPassword )) {
|
||||||
|
// *error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Missing master password." };
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user.algorithm, user.fullName, user.masterPassword )) {
|
||||||
|
// *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Section: "export"
|
||||||
|
Export fileExport = this.export = new Export();
|
||||||
|
fileExport.format = 1;
|
||||||
|
fileExport.redacted = contentMode.isRedacted();
|
||||||
|
fileExport.date = dateFormatter.print( new Instant() );
|
||||||
|
|
||||||
|
// Section: "user"
|
||||||
|
User fileUser = this.user = new User();
|
||||||
|
fileUser.avatar = user.getAvatar();
|
||||||
|
fileUser.fullName = user.getFullName();
|
||||||
|
|
||||||
|
fileUser.lastUsed = dateFormatter.print( user.getLastUsed() );
|
||||||
|
fileUser.keyId = CodeUtils.encodeHex( masterKey.getKeyID( user.getAlgorithm() ) );
|
||||||
|
|
||||||
|
fileUser.algorithm = user.getAlgorithm().version();
|
||||||
|
fileUser.defaultType = user.getDefaultType();
|
||||||
|
|
||||||
|
// Section "sites"
|
||||||
|
fileUser.sites = new LinkedHashMap<>();
|
||||||
|
for (final MPFileSite site : user.getSites()) {
|
||||||
|
Site fileSite;
|
||||||
|
String content = null, loginContent = null;
|
||||||
|
if (!contentMode.isRedacted()) {
|
||||||
|
// Clear Text
|
||||||
|
content = masterKey.siteResult( site.getSiteName(), site.getSiteCounter(),
|
||||||
|
MPKeyPurpose.Authentication, null, site.getResultType(), site.getSiteContent(),
|
||||||
|
site.getAlgorithm() );
|
||||||
|
loginContent = masterKey.siteResult( site.getSiteName(), site.getAlgorithm().mpw_default_counter(),
|
||||||
|
MPKeyPurpose.Identification, null, site.getLoginType(), site.getLoginContent(),
|
||||||
|
site.getAlgorithm() );
|
||||||
|
} else {
|
||||||
|
// Redacted
|
||||||
|
if (site.getResultType().supportsTypeFeature( MPSiteFeature.ExportContent ))
|
||||||
|
content = site.getSiteContent();
|
||||||
|
if (site.getLoginType().supportsTypeFeature( MPSiteFeature.ExportContent ))
|
||||||
|
loginContent = site.getLoginContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
fileUser.sites.put( site.getSiteName(), fileSite = new Site() );
|
||||||
|
fileSite.type = site.getResultType();
|
||||||
|
fileSite.counter = site.getSiteCounter();
|
||||||
|
fileSite.algorithm = site.getAlgorithm().version();
|
||||||
|
fileSite.password = content;
|
||||||
|
fileSite.login_name = loginContent;
|
||||||
|
fileSite.loginType = site.getLoginType();
|
||||||
|
|
||||||
|
fileSite.uses = site.getUses();
|
||||||
|
fileSite.lastUsed = dateFormatter.print( site.getLastUsed() );
|
||||||
|
|
||||||
|
fileSite.questions = new LinkedHashMap<>();
|
||||||
|
// for (size_t q = 0; q < site.questions_count; ++q) {
|
||||||
|
// MPMarshalledQuestion *question = &site.questions[q];
|
||||||
|
// if (!question.keyword)
|
||||||
|
// continue;
|
||||||
|
//
|
||||||
|
// json_object *json_site_question = json_object_new_object();
|
||||||
|
// json_object_object_add( json_site_questions, question.keyword, json_site_question );
|
||||||
|
// json_object_object_add( json_site_question, "type = question.type;
|
||||||
|
//
|
||||||
|
// if (!user.redacted) {
|
||||||
|
// // Clear Text
|
||||||
|
// const char *answerContent = mpw_siteResult( masterKey, site.name, MPCounterValueInitial,
|
||||||
|
// MPKeyPurposeRecovery, question.keyword, question.type, question.content, site.algorithm );
|
||||||
|
// json_object_object_add( json_site_question, "answer = answerContent;
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// // Redacted
|
||||||
|
// if (site.type & MPSiteFeatureExportContent && question.content && strlen( question.content ))
|
||||||
|
// json_object_object_add( json_site_question, "answer = question.content;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// json_object *json_site_mpw = json_object_new_object();
|
||||||
|
// fileSite._ext_mpw = json_site_mpw;
|
||||||
|
// if (site.url)
|
||||||
|
// json_object_object_add( json_site_mpw, "url", site.url );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MPFileUser toUser() {
|
||||||
|
return new MPFileUser( user.fullName, CodeUtils.decodeHex( user.keyId ), user.algorithm.getAlgorithm(), user.avatar, user.defaultType, dateFormatter.parseDateTime( user.lastUsed ), MPMarshalFormat.JSON );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Export {
|
||||||
|
|
||||||
|
int format;
|
||||||
|
boolean redacted;
|
||||||
|
String date;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class User {
|
||||||
|
|
||||||
|
String fullName;
|
||||||
|
|
||||||
|
MPMasterKey.Version algorithm;
|
||||||
|
boolean redacted;
|
||||||
|
|
||||||
|
int avatar;
|
||||||
|
MPResultType defaultType;
|
||||||
|
String lastUsed;
|
||||||
|
String keyId;
|
||||||
|
|
||||||
|
Map<String, Site> sites;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Site {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
String password;
|
||||||
|
@Nullable
|
||||||
|
String login_name;
|
||||||
|
String name;
|
||||||
|
String content;
|
||||||
|
MPResultType type;
|
||||||
|
UnsignedInteger counter;
|
||||||
|
MPMasterKey.Version algorithm;
|
||||||
|
|
||||||
|
String loginContent;
|
||||||
|
MPResultType loginType;
|
||||||
|
|
||||||
|
String url;
|
||||||
|
int uses;
|
||||||
|
String lastUsed;
|
||||||
|
|
||||||
|
Map<String, Question> questions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Question {
|
||||||
|
|
||||||
|
String keyword;
|
||||||
|
String content;
|
||||||
|
MPResultType type;
|
||||||
|
}
|
||||||
|
}
|
@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword.model;
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
import com.lyndir.masterpassword.MPInvalidatedException;
|
import com.google.gson.*;
|
||||||
import com.lyndir.masterpassword.MPMasterKey;
|
import com.lyndir.masterpassword.*;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
|
||||||
@ -28,10 +28,17 @@ import javax.annotation.Nonnull;
|
|||||||
*/
|
*/
|
||||||
public class MPJSONMarshaller implements MPMarshaller {
|
public class MPJSONMarshaller implements MPMarshaller {
|
||||||
|
|
||||||
|
private final Gson gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter( MPMasterKey.Version.class, new EnumOrdinalAdapter() )
|
||||||
|
.registerTypeAdapter( MPResultType.class, new MPResultTypeAdapter() )
|
||||||
|
.setFieldNamingStrategy( FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES )
|
||||||
|
.setPrettyPrinting().create();
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode)
|
public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode)
|
||||||
throws MPInvalidatedException, MPMarshalException {
|
throws MPInvalidatedException, MPMarshalException {
|
||||||
throw new MPMarshalException( "Not yet implemented" );
|
|
||||||
|
return gson.toJson( new MPJSONFile( user, masterKey, contentMode ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,11 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword.model;
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
import java.io.File;
|
import com.google.gson.*;
|
||||||
import java.io.IOException;
|
import com.lyndir.masterpassword.MPMasterKey;
|
||||||
|
import com.lyndir.masterpassword.MPResultType;
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
|
||||||
@ -28,17 +31,27 @@ import javax.annotation.Nonnull;
|
|||||||
*/
|
*/
|
||||||
public class MPJSONUnmarshaller implements MPUnmarshaller {
|
public class MPJSONUnmarshaller implements MPUnmarshaller {
|
||||||
|
|
||||||
|
private final Gson gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter( MPMasterKey.Version.class, new EnumOrdinalAdapter() )
|
||||||
|
.registerTypeAdapter( MPResultType.class, new MPResultTypeAdapter() )
|
||||||
|
.setFieldNamingStrategy( FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES )
|
||||||
|
.setPrettyPrinting().create();
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public MPFileUser unmarshall(@Nonnull final File file)
|
public MPFileUser unmarshall(@Nonnull final File file)
|
||||||
throws IOException, MPMarshalException {
|
throws IOException, MPMarshalException {
|
||||||
throw new MPMarshalException( "Not yet implemented" );
|
|
||||||
|
try (Reader reader = new InputStreamReader( new FileInputStream( file ), StandardCharsets.UTF_8 )) {
|
||||||
|
return gson.fromJson( reader, MPJSONFile.class ).toUser();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public MPFileUser unmarshall(@Nonnull final String content)
|
public MPFileUser unmarshall(@Nonnull final String content)
|
||||||
throws MPMarshalException {
|
throws MPMarshalException {
|
||||||
throw new MPMarshalException( "Not yet implemented" );
|
|
||||||
|
return gson.fromJson( content, MPJSONFile.class ).toUser();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword.model;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
import com.lyndir.masterpassword.MPResultType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 2018-04-27
|
||||||
|
*/
|
||||||
|
public class MPResultTypeAdapter implements JsonSerializer<MPResultType>, JsonDeserializer<MPResultType> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPResultType deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
|
||||||
|
throws JsonParseException {
|
||||||
|
try {
|
||||||
|
return MPResultType.forType( json.getAsInt() );
|
||||||
|
}
|
||||||
|
catch (final ClassCastException | IllegalStateException e) {
|
||||||
|
throw new JsonParseException( "Not an ordinal value: " + json, e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(final MPResultType src, final Type typeOfSrc, final JsonSerializationContext context) {
|
||||||
|
return new JsonPrimitive( src.getType() );
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ description = 'Master Password Test Suite'
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project( ':masterpassword-algorithm' )
|
compile project( ':masterpassword-algorithm' )
|
||||||
|
compile project( ':masterpassword-model' )
|
||||||
|
|
||||||
testCompile group: 'org.testng', name: 'testng', version: '6.8.5'
|
testCompile group: 'org.testng', name: 'testng', version: '6.8.5'
|
||||||
testCompile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.2'
|
testCompile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.2'
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// This file is part of Master Password.
|
||||||
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
||||||
|
//
|
||||||
|
// Master Password is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Master Password is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You can find a copy of the GNU General Public License in the
|
||||||
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
import com.lyndir.masterpassword.model.MPJSONUnmarshaller;
|
||||||
|
import java.io.File;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lhunath, 2018-04-27
|
||||||
|
*/
|
||||||
|
public class MPModelTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMasterKey()
|
||||||
|
throws Exception {
|
||||||
|
System.err.println( new MPJSONUnmarshaller().unmarshall(
|
||||||
|
new File( "/Users/lhunath/.mpw.d/Maarten Billemont.mpsites.json" ) ) );
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user