package de.devland.masterpassword.model; import android.database.Cursor; import android.util.Log; import android.util.Pair; import com.google.common.primitives.UnsignedInteger; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.annotations.Expose; import com.google.gson.reflect.TypeToken; import com.lyndir.masterpassword.MPSiteType; import com.lyndir.masterpassword.MPSiteVariant; import com.lyndir.masterpassword.MasterKey; import com.lyndir.masterpassword.model.MPSite; import com.lyndir.masterpassword.model.MPUser; import com.orm.SugarRecord; import com.orm.dsl.Ignore; import java.util.ArrayList; import java.util.Date; import java.util.List; import de.devland.masterpassword.util.MasterPasswordHolder; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; /** * Created by David Kunzler on 23.08.2014. */ @Getter @Setter @NoArgsConstructor public class Site extends SugarRecord { public static final String NOCASE_ORDER_SUFFIX = " COLLATE NOCASE"; public static final String DESC_ORDER_SUFFIX = " DESC"; public static final String ID = "ID"; public static final String SITE_NAME = "SITE_NAME"; public static final String USER_NAME = "USER_NAME"; public static final String GENERATED_USER_NAME = "GENERATED_USER_NAME"; public static final String SITE_COUNTER = "SITE_COUNTER"; public static final String PASSWORD_TYPE = "PASSWORD_TYPE"; public static final String ALGORITHM_VERSION = "ALGORITHM_VERSION"; public static final String CATEGORY = "CATEGORY"; public static final String LAST_USED = "LAST_USED"; @Expose protected String siteName = ""; @Expose protected String userName = ""; @Expose protected boolean generatedUserName = false; @Expose protected int siteCounter = 0; @Expose protected MPSiteType passwordType = MPSiteType.GeneratedMaximum; @Expose protected MPSiteVariant passwordVariant = MPSiteVariant.Password; @Expose protected MasterKey.Version algorithmVersion = MasterKey.Version.CURRENT; @Expose protected Date lastUsed = new Date(0); @Expose protected Date lastChange = new Date(); @Expose protected String category; @Expose protected String notes; @Expose @Setter(AccessLevel.NONE) @Getter(AccessLevel.NONE) protected String questions; @Expose @Setter(AccessLevel.NONE) @Getter(AccessLevel.NONE) protected String customFields; protected String storedPassword; @Setter(AccessLevel.NONE) @Getter(AccessLevel.NONE) @Ignore private String cachedPassword; @Setter(AccessLevel.NONE) @Getter(AccessLevel.NONE) @Ignore private String cachedUserName; public boolean complete() { boolean complete = true; if (siteName == null || siteName.isEmpty()) { complete = false; } return complete; } public void touch() { lastUsed = new Date(); // use super.save here to not trigger a change for a use super.save(); } public long change() { Date now = new Date(); this.lastUsed = now; this.lastChange = now; return super.save(); } public void setSiteName(String siteName) { this.siteName = siteName; invalidateCaches(); } public void setSiteCounter(int siteCounter) { this.siteCounter = siteCounter; invalidateCaches(); } public void setPasswordVariant(MPSiteVariant passwordVariant) { this.passwordVariant = passwordVariant; invalidateCaches(); } public void setPasswordType(MPSiteType passwordType) { this.passwordType = passwordType; invalidateCaches(); } public void setAlgorithmVersion(MasterKey.Version algorithmVersion) { this.algorithmVersion = algorithmVersion; invalidateCaches(); } public String getCurrentPassword() { if (cachedPassword == null) { cachedPassword = MasterPasswordHolder.INSTANCE.generate(passwordType, passwordVariant, siteName, siteCounter, algorithmVersion); } return cachedPassword; } public String getCurrentUserName() { if (isGeneratedUserName()) { if (cachedUserName == null) { cachedUserName = MasterPasswordHolder.INSTANCE.generate(MPSiteType.GeneratedName, MPSiteVariant.Login, siteName, siteCounter, algorithmVersion); } return cachedUserName; } else { return userName; } } public List<String> getQuestions() { List<String> result = new ArrayList<>(); if (questions != null) { try { Gson gson = new GsonBuilder().create(); result = gson.fromJson(questions, new TypeToken<List<String>>() { }.getType()); } catch (Exception e) { Log.e("Site", "Error parsing questions.", e); } } return result; } public List<Pair<String, String>> getCustomFields() { List<Pair<String, String>> result = new ArrayList<>(); if (customFields != null) { try { Gson gson = new GsonBuilder().create(); result = gson.fromJson(customFields, new TypeToken<List<Pair<String, String>>>() { }.getType()); } catch (Exception e) { Log.e("Site", "Error parsing questions.", e); } } return result; } public void setQuestions(List<String> questions) { if (questions != null) { Gson gson = new GsonBuilder().create(); this.questions = gson.toJson(questions); } else { this.questions = null; } } public void setCustomFields(List<Pair<String, String>> fields) { if (fields != null) { Gson gson = new GsonBuilder().create(); this.customFields = gson.toJson(fields); } else { this.customFields = null; } } private void invalidateCaches() { cachedPassword = null; cachedUserName = null; } public MPSite toMPSite(MPUser user) { MPSite mpSite = new MPSite(user, siteName, passwordType, UnsignedInteger.fromIntBits(siteCounter)); if (generatedUserName) { String generatedUserName = MasterPasswordHolder.INSTANCE.generate( MPSiteType.GeneratedName, MPSiteVariant.Login, siteName, siteCounter, algorithmVersion); mpSite.setLoginName(generatedUserName); } else { mpSite.setLoginName(userName); } mpSite.setAlgorithmVersion(algorithmVersion); return mpSite; } public static Site fromMPSite(MPSite mpSite) { Site site = new Site(); site.algorithmVersion = mpSite.getAlgorithmVersion(); site.lastUsed = mpSite.getLastUsed().toDate(); site.passwordType = mpSite.getSiteType(); site.siteCounter = mpSite.getSiteCounter().intValue(); site.siteName = mpSite.getSiteName(); site.userName = mpSite.getLoginName(); site.setPasswordVariant(MPSiteVariant.Password); return site; } public static Site fromCursor(Cursor cursor) { Site result = new Site(); result.setSiteName(cursor.getString(cursor.getColumnIndex(SITE_NAME))); result.setUserName(cursor.getString(cursor.getColumnIndex(USER_NAME))); result.setSiteCounter(cursor.getInt(cursor.getColumnIndex(SITE_COUNTER))); result.setPasswordType(MPSiteType.valueOf(cursor.getString(cursor.getColumnIndex(PASSWORD_TYPE)))); result.setCategory(cursor.getString(cursor.getColumnIndex(CATEGORY))); result.setId(cursor.getLong(cursor.getColumnIndex(ID))); return result; } }