/** * Copyright (C) 2012 Iordan Iordanov * Copyright (C) 2010 Michael A. MacDonald * * This 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 2 of the License, or * (at your option) any later version. * * This software 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 should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ package com.iiordanov.bVNC; import java.io.File; import javax.crypto.NullCipher; import android.content.Context; import net.sqlcipher.database.SQLiteDatabase; import net.sqlcipher.database.SQLiteException; import net.sqlcipher.database.SQLiteOpenHelper; import android.util.Log; import com.iiordanov.bVNC.*; import com.iiordanov.freebVNC.*; import com.iiordanov.aRDP.*; import com.iiordanov.freeaRDP.*; import com.iiordanov.aSPICE.*; import com.iiordanov.freeaSPICE.*; /** * @author Michael A. MacDonald * */ public class Database extends SQLiteOpenHelper { static final int DBV_0_5_0 = 12; static final int DBV_1_2_0 = 20; static final int DBV_1_5_0 = 22; static final int DBV_1_6_0 = 291; static final int DBV_1_7_0 = 292; static final int DBV_1_8_0 = 293; static final int DBV_1_9_0 = 308; static final int DBV_2_0_0 = 309; static final int DBV_2_1_0 = 329; static final int DBV_2_1_1 = 335; static final int DBV_2_1_2 = 336; static final int DBV_2_1_3 = 360; static final int DBV_2_1_4 = 367; static final int DBV_2_1_5 = 374; static final int CURRVERS = DBV_2_1_5; private static String dbName = "VncDatabase"; private static String password = ""; public final static String TAG = Database.class.toString(); public Database(Context context) { super(context, dbName, null, DBV_2_1_5); SQLiteDatabase.loadLibs(context); } /* (non-Javadoc) * @see net.sqlcipher.database.SQLiteOpenHelper#onCreate(net.sqlcipher.database.SQLiteDatabase) */ @Override public void onCreate(SQLiteDatabase db) { db.execSQL(AbstractConnectionBean.GEN_CREATE); db.execSQL(MostRecentBean.GEN_CREATE); db.execSQL(MetaList.GEN_CREATE); db.execSQL(AbstractMetaKeyBean.GEN_CREATE); db.execSQL(SentTextBean.GEN_CREATE); db.execSQL("INSERT INTO " + MetaList.GEN_TABLE_NAME + " VALUES ( 1, 'DEFAULT')"); } public SQLiteDatabase getWritableDatabase() { return getWritableDatabase(Database.password); } public SQLiteDatabase getReadableDatabase() { return getReadableDatabase(Database.password); } public static String getPassword() { return password; } public static void setPassword (String newPassword) { Database.password = newPassword; } public boolean changeDatabasePassword (String newPassword) { // Get readable database with old password SQLiteDatabase db = getReadableDatabase(Database.password); int version = db.getVersion(); String pathToDb = db.getPath(); // Delete any temp db that may be in the way. deleteTempDatabase(pathToDb, "-temp"); String newFormat = null; // If the previous key is an empty string, we must encrypt a plaintext DB. if (Database.password.equals("")) { Log.i(TAG, "Previous database unencrypted, encrypting."); newFormat = "encrypted"; // If the previous key is not an empty string, then we must rekey an existing DB. } else if (newPassword.equals("")) { Log.i(TAG, "Previous database encrypted, decrypting."); newFormat = "plaintext"; // If both the previous and new password are non-empty, we are rekeying the DB. } else { Log.i(TAG, "Previous database encrypted, rekeying."); db.rawExecSQL(String.format("PRAGMA key = '%s'", Database.password)); Database.setPassword(newPassword); // Rekey the database db.rawExecSQL(String.format("PRAGMA rekey = '%s'", Database.password)); } if (newFormat != null) { // Write out the database in the new format. db.rawExecSQL(String.format("ATTACH DATABASE '%s' AS %s KEY '%s'", db.getPath()+"-temp", newFormat, newPassword)); db.rawExecSQL(String.format("select sqlcipher_export('%s')", newFormat)); db.rawExecSQL(String.format("DETACH DATABASE '%s'", newFormat)); db.close(); this.close(); Log.i(TAG, "Done exporting to: " + newFormat); try { // Set version of database SQLiteDatabase tempDb = SQLiteDatabase.openDatabase(db.getPath()+"-temp", newPassword, null, SQLiteDatabase.OPEN_READWRITE); tempDb.setVersion(version); tempDb.close(); } catch (Exception e) { // If we could not open the temp database, delete it and return failure. deleteTempDatabase(pathToDb, "-temp"); return false; } try { // Save away the old database moveFile(pathToDb, pathToDb + "-BAK"); // Move the temp database file over the old database moveFile(pathToDb + "-temp", pathToDb); // Test-open the new database and read off the version. SQLiteDatabase newDb = SQLiteDatabase.openDatabase(db.getPath(), newPassword, null, SQLiteDatabase.OPEN_READWRITE); newDb.getVersion(); newDb.close(); } catch (Exception e) { // Having received an exception in testing the DB above, restore the old DB and return failure. moveFile(pathToDb + "-BAK", pathToDb); return false; } finally { // Having succeeded to open the database without an exception, delete the backup of the old DB. deleteTempDatabase(pathToDb, "-BAK"); // And set the password to the new password. Database.setPassword(newPassword); } } else { db.close(); this.close(); } return true; } private void moveFile(String from, String to) { new File(from).renameTo(new File(to)); } private void deleteTempDatabase(String pathToDb, String suffix) { String tempDbPath = pathToDb + suffix; File temp = new File(tempDbPath); if (temp.exists()) { temp.delete(); } } /* (non-Javadoc) * @see net.sqlcipher.database.SQLiteOpenHelper#onUpgrade(net.sqlcipher.database.SQLiteDatabase, int, int) */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion == DBV_0_5_0) { Log.i(TAG,"Doing upgrade from 12 to 20"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_CONNECTIONTYPE + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHSERVER + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHPORT + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHUSER + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHPASSWORD + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_KEEPSSHPASSWORD + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHPUBKEY + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHPRIVKEY + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHPASSPHRASE + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_USESSHPUBKEY + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHHOSTKEY + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHREMOTECOMMANDOS + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHREMOTECOMMAND + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHREMOTECOMMANDTIMEOUT + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_USESSHREMOTECOMMAND + " BOOLEAN DEFAULT FALSE"); oldVersion = DBV_1_2_0; } if (oldVersion == DBV_1_2_0) { Log.i(TAG,"Doing upgrade from 20 to 22"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_USEDPADASARROWS + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_ROTATEDPAD + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_USEPORTRAIT + " BOOLEAN DEFAULT FALSE"); oldVersion = DBV_1_5_0; } if (oldVersion == DBV_1_5_0) { Log.i(TAG,"Doing upgrade from 22 to 291"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_SSHREMOTECOMMANDTYPE + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_AUTOXENABLED + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_AUTOXTYPE + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_AUTOXCOMMAND + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_AUTOXRESTYPE + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_AUTOXWIDTH + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_AUTOXHEIGHT + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_AUTOXSESSIONTYPE + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_AUTOXSESSIONPROG + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_AUTOXRANDFILENM + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_AUTOXUNIXPW + " BOOLEAN DEFAULT FALSE"); oldVersion = DBV_1_6_0; } if (oldVersion == DBV_1_6_0) { Log.i(TAG,"Doing upgrade from 291 to 292"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_AUTOXUNIXAUTH + " BOOLEAN DEFAULT FALSE"); oldVersion = DBV_1_7_0; } if (oldVersion == DBV_1_7_0) { Log.i(TAG,"Doing upgrade from 292 to 293"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_EXTRAKEYSTOGGLETYPE + " INTEGER"); oldVersion = DBV_1_8_0; } if (oldVersion == DBV_1_8_0) { Log.i(TAG,"Doing upgrade from 293 to 308"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_PREFENCODING + " INTEGER"); oldVersion = DBV_1_9_0; } if (oldVersion == DBV_1_9_0) { Log.i(TAG,"Doing upgrade from 308 to 309"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_RDPDOMAIN + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_RDPRESTYPE + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_RDPWIDTH + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_RDPHEIGHT + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_RDPCOLOR + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_REMOTEFX + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_DESKTOPBACKGROUND + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_FONTSMOOTHING + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_DESKTOPCOMPOSITION + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_WINDOWCONTENTS + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_MENUANIMATION + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_VISUALSTYLES + " BOOLEAN DEFAULT FALSE"); oldVersion = DBV_2_0_0; } if (oldVersion == DBV_2_0_0) { Log.i(TAG,"Doing upgrade from 309 to 329"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_CACERT + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_CACERTPATH + " TEXT"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_TLSPORT + " INTEGER"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_CERTSUBJECT + " TEXT"); oldVersion = DBV_2_1_0; } if (oldVersion == DBV_2_1_0) { Log.i(TAG,"Doing upgrade from 329 to 335"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_ENABLESOUND + " BOOLEAN DEFAULT FALSE"); oldVersion = DBV_2_1_1; } if (oldVersion == DBV_2_1_1) { Log.i(TAG,"Doing upgrade from 335 to 336"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_VIEWONLY + " BOOLEAN DEFAULT FALSE"); oldVersion = DBV_2_1_2; } if (oldVersion == DBV_2_1_2) { Log.i(TAG,"Doing upgrade from 336 to 360"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_CONSOLEMODE + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_REDIRECTSDCARD + " BOOLEAN DEFAULT FALSE"); oldVersion = DBV_2_1_3; } if (oldVersion == DBV_2_1_3) { Log.i(TAG,"Doing upgrade from 360 to 367"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_LAYOUTMAP + " TEXT DEFAULT 'English (US)'"); oldVersion = DBV_2_1_4; } if (oldVersion == DBV_2_1_4) { Log.i(TAG,"Doing upgrade from 367 to 374"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_ENABLERECORDING + " BOOLEAN DEFAULT FALSE"); db.execSQL("ALTER TABLE " + AbstractConnectionBean.GEN_TABLE_NAME + " ADD COLUMN " +AbstractConnectionBean.GEN_FIELD_REMOTESOUNDTYPE + " INTEGER DEFAULT " + Constants.REMOTE_SOUND_DISABLED); oldVersion = DBV_2_1_5; } } }