package org.commcare.models.legacy; import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.util.Pair; import org.commcare.models.database.AndroidTableBuilder; import org.commcare.models.database.AndroidPrototypeFactorySetup; import org.commcare.core.encryption.CryptUtil; import org.commcare.modern.database.DatabaseHelper; import org.commcare.modern.models.EncryptedModel; import org.commcare.utils.Base64; import org.javarosa.core.services.storage.IMetaData; import org.javarosa.core.services.storage.Persistable; import org.javarosa.core.util.externalizable.Externalizable; import org.javarosa.core.util.externalizable.PrototypeFactory; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.HashSet; import java.util.Set; import javax.crypto.Cipher; import javax.crypto.CipherOutputStream; /** * @author ctsims */ public abstract class LegacyDbHelper { private final Context c; private Cipher encrypter; //private Hashtable<String, EncryptedModel> encryptedModels; public LegacyDbHelper(Context c) { this.c = c; } public LegacyDbHelper(Context c, Cipher encrypter) { this.c = c; this.encrypter = encrypter; } public abstract SQLiteDatabase getHandle(); public Pair<String, String[]> createWhere(String[] fieldNames, Object[] values, EncryptedModel em, Persistable p) throws IllegalArgumentException { Set<String> fields = null; if (p instanceof IMetaData) { IMetaData m = (IMetaData)p; String[] thefields = m.getMetaDataFields(); fields = new HashSet<>(); for (String s : thefields) { fields.add(LegacyTableBuilder.scrubName(s)); } } if (em instanceof IMetaData) { IMetaData m = (IMetaData)em; String[] thefields = m.getMetaDataFields(); fields = new HashSet<>(); for (String s : thefields) { fields.add(LegacyTableBuilder.scrubName(s)); } } String ret = ""; String[] arguments = new String[fieldNames.length]; for (int i = 0; i < fieldNames.length; ++i) { String columnName = LegacyTableBuilder.scrubName(fieldNames[i]); if (fields != null) { if (!fields.contains(columnName)) { throw new IllegalArgumentException("Model does not contain the column " + columnName + "!"); } } ret += columnName + "=?"; if (em != null && em.isEncrypted(fieldNames[i])) { arguments[i] = encrypt(values[i].toString()); } else { arguments[i] = values[i].toString(); } if (i + 1 < fieldNames.length) { ret += " AND "; } } return new Pair<>(ret, arguments); } private String encrypt(String string) { byte[] encrypted = CryptUtil.encrypt(string.getBytes(), encrypter); return Base64.encode(encrypted); } public ContentValues getContentValues(Externalizable e) { boolean encrypt = e instanceof EncryptedModel; assert (!(encrypt) || encrypter != null); ByteArrayOutputStream bos = new ByteArrayOutputStream(); OutputStream out = bos; if (encrypt && ((EncryptedModel)e).isBlobEncrypted()) { out = new CipherOutputStream(bos, encrypter); } try { e.writeExternal(new DataOutputStream(out)); out.close(); } catch (IOException e1) { e1.printStackTrace(); throw new RuntimeException("Failed to serialize externalizable for content values"); } byte[] blob = bos.toByteArray(); ContentValues values = new ContentValues(); if (e instanceof IMetaData) { IMetaData m = (IMetaData)e; for (String key : m.getMetaDataFields()) { Object o = m.getMetaData(key); if (o == null) { continue; } String value = o.toString(); if (encrypt && ((EncryptedModel)e).isEncrypted(key)) { values.put(AndroidTableBuilder.scrubName(key), encrypt(value)); } else { values.put(LegacyTableBuilder.scrubName(key), value); } } } values.put(DatabaseHelper.DATA_COL, blob); return values; } public PrototypeFactory getPrototypeFactory() { return AndroidPrototypeFactorySetup.getPrototypeFactory(c); } }