25 static final int DB_VERSION = 12;
26 private static final String DB_NAME =
"bookmarks.db";
30 System.loadLibrary(
"sqlcipher");
37 public static AppDatabase getInstance(Context context)
45 byte[] key = getOrCreateDbKey(context);
46 migrateUnencryptedIfNeeded(context, key);
48 instance = Room.databaseBuilder(context.getApplicationContext(),
50 .openHelperFactory(
new SupportOpenHelperFactory(key))
51 .addMigrations(MIGRATION_10_11)
52 .addMigrations(MIGRATION_11_12)
60 private static byte[] getOrCreateDbKey(Context context)
64 return KeystoreHelper.getInstance(context).getOrCreateDbKey();
66 catch (KeystoreHelper.KeystoreException e)
68 throw new RuntimeException(
"Cannot obtain database encryption key", e);
73 private static void migrateUnencryptedIfNeeded(Context context,
byte[] key)
75 File dbFile = context.getDatabasePath(DB_NAME);
79 String path = dbFile.getAbsolutePath();
84 SQLiteDatabase.openDatabase(path, key,
null, SQLiteDatabase.OPEN_READONLY,
null,
null)
88 catch (Exception ignored)
92 SQLiteDatabase db =
null;
96 db = SQLiteDatabase.openDatabase(path,
new byte[0],
null, SQLiteDatabase.OPEN_READWRITE,
102 SQLiteDatabase.deleteDatabase(dbFile);
108 String tmpPath = path +
".migrating";
109 File tmpFile =
new File(tmpPath);
110 SQLiteDatabase.deleteDatabase(tmpFile);
116 .openDatabase(tmpPath, key,
null,
117 SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.CREATE_IF_NECESSARY,
121 catch (Exception ignored)
129 db.execSQL(
"ATTACH DATABASE '" + tmpPath +
"' AS encrypted KEY X'" + toHex(key) +
131 db.rawQuery(
"SELECT sqlcipher_export('encrypted')",
null).moveToFirst();
132 db.execSQL(
"DETACH DATABASE encrypted");
140 SQLiteDatabase.deleteDatabase(dbFile);
141 if (!tmpFile.renameTo(dbFile))
142 throw new RuntimeException(
"Could not replace database file after encryption");
146 SQLiteDatabase.deleteDatabase(tmpFile);
147 throw new RuntimeException(
"Failed to encrypt existing database", e);
151 private static String toHex(
byte[] bytes)
153 StringBuilder sb =
new StringBuilder(bytes.length * 2);
155 sb.append(String.format(java.util.Locale.US,
"%02x", b));
156 return sb.toString();
159 private static final Migration MIGRATION_11_12 =
new Migration(11, 12) {
160 @Override
public void migrate(@NonNull SupportSQLiteDatabase db)
162 db.execSQL(
"ALTER TABLE 'bookmarks' ADD 'tlsSecLevel' CONSTRAINT chk_tlsSecLevel "
163 +
"CHECK (tlsSecLevel >= -1 AND tlsSecLevel <= 5) INTEGER DEFAULT -1;");
164 db.execSQL(
"ALTER TABLE 'bookmarks' ADD 'tlsMinLevel' CONSTRAINT chk_tlsMinLevel "
165 +
"CHECK (tlsSecLevel >= -1) INTEGER DEFAULT -1;");
166 final String list[] = {
"screen_3g_colors",
167 "screen_3g_resolution",
175 "perf_3g_full_window_drag",
176 "perf_3g_menu_animations",
177 "perf_3g_font_smoothing",
178 "perf_3g_desktop_composition",
179 "enable_3g_settings" };
181 for (String s : list)
183 db.execSQL(
"ALTER TABLE 'bookmarks' DROP COLUMN '" + s +
"';");
190 private static final Migration MIGRATION_10_11 =
new Migration(10, 11) {
191 @Override
public void migrate(@NonNull SupportSQLiteDatabase db)
193 db.execSQL(
"CREATE TABLE IF NOT EXISTS `bookmarks` ("
194 +
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
200 +
"`port` INTEGER NOT NULL,"
201 +
"`colors` INTEGER NOT NULL,"
202 +
"`resolution` INTEGER NOT NULL,"
203 +
"`width` INTEGER NOT NULL,"
204 +
"`height` INTEGER NOT NULL,"
205 +
"`perf_remotefx` INTEGER NOT NULL,"
206 +
"`perf_gfx` INTEGER NOT NULL,"
207 +
"`perf_gfx_h264` INTEGER NOT NULL,"
208 +
"`perf_wallpaper` INTEGER NOT NULL,"
209 +
"`perf_theming` INTEGER NOT NULL,"
210 +
"`perf_full_window_drag` INTEGER NOT NULL,"
211 +
"`perf_menu_animations` INTEGER NOT NULL,"
212 +
"`perf_font_smoothing` INTEGER NOT NULL,"
213 +
"`perf_desktop_composition` INTEGER NOT NULL,"
214 +
"`screen_3g_colors` INTEGER NOT NULL,"
215 +
"`screen_3g_resolution` INTEGER NOT NULL,"
216 +
"`screen_3g_width` INTEGER NOT NULL,"
217 +
"`screen_3g_height` INTEGER NOT NULL,"
218 +
"`perf_3g_remotefx` INTEGER NOT NULL,"
219 +
"`perf_3g_gfx` INTEGER NOT NULL,"
220 +
"`perf_3g_gfx_h264` INTEGER NOT NULL,"
221 +
"`perf_3g_wallpaper` INTEGER NOT NULL,"
222 +
"`perf_3g_theming` INTEGER NOT NULL,"
223 +
"`perf_3g_full_window_drag` INTEGER NOT NULL,"
224 +
"`perf_3g_menu_animations` INTEGER NOT NULL,"
225 +
"`perf_3g_font_smoothing` INTEGER NOT NULL,"
226 +
"`perf_3g_desktop_composition` INTEGER NOT NULL,"
227 +
"`enable_3g_settings` INTEGER NOT NULL,"
228 +
"`enable_gateway_settings` INTEGER NOT NULL,"
229 +
"`gateway_hostname` TEXT,"
230 +
"`gateway_port` INTEGER NOT NULL,"
231 +
"`gateway_username` TEXT,"
232 +
"`gateway_password` TEXT,"
233 +
"`gateway_domain` TEXT,"
234 +
"`redirect_sdcard` INTEGER NOT NULL,"
235 +
"`redirect_sound` INTEGER NOT NULL,"
236 +
"`redirect_microphone` INTEGER NOT NULL,"
237 +
"`security` INTEGER NOT NULL,"
238 +
"`remote_program` TEXT,"
240 +
"`console_mode` INTEGER NOT NULL,"
241 +
"`debug_level` TEXT,"
242 +
"`async_channel` INTEGER NOT NULL,"
243 +
"`async_update` INTEGER NOT NULL"
248 "INSERT INTO bookmarks ("
249 +
" id, label, hostname, username, password, domain, port,"
250 +
" colors, resolution, width, height,"
251 +
" perf_remotefx, perf_gfx, perf_gfx_h264, perf_wallpaper, perf_theming,"
252 +
" perf_full_window_drag, perf_menu_animations, perf_font_smoothing, "
253 +
"perf_desktop_composition,"
254 +
" screen_3g_colors, screen_3g_resolution, screen_3g_width, screen_3g_height,"
255 +
" perf_3g_remotefx, perf_3g_gfx, perf_3g_gfx_h264, perf_3g_wallpaper, "
257 +
" perf_3g_full_window_drag, perf_3g_menu_animations, perf_3g_font_smoothing, "
258 +
"perf_3g_desktop_composition,"
259 +
" enable_3g_settings, enable_gateway_settings,"
260 +
" gateway_hostname, gateway_port, gateway_username, gateway_password, "
262 +
" redirect_sdcard, redirect_sound, redirect_microphone,"
263 +
" security, remote_program, work_dir, console_mode,"
264 +
" debug_level, async_channel, async_update"
266 +
" b._id, IFNULL(b.label, ''), IFNULL(b.hostname, ''), IFNULL(b.username, ''), "
267 +
"b.password, b.domain,"
268 +
" IFNULL(CAST(NULLIF(b.port, '') AS INTEGER), 3389),"
269 +
" IFNULL(s.colors, 32), IFNULL(s.resolution, -1), IFNULL(s.width, 0), "
270 +
"IFNULL(s.height, 0),"
271 +
" IFNULL(p.perf_remotefx, 0), IFNULL(p.perf_gfx, 1), IFNULL(p.perf_gfx_h264, "
272 +
"0), IFNULL(p.perf_wallpaper, 0), IFNULL(p.perf_theming, 0),"
273 +
" IFNULL(p.perf_full_window_drag, 0), IFNULL(p.perf_menu_animations, 0), "
274 +
"IFNULL(p.perf_font_smoothing, 0), IFNULL(p.perf_desktop_composition, 0),"
275 +
" IFNULL(s3.colors, 16), IFNULL(s3.resolution, -1), IFNULL(s3.width, 0), "
276 +
"IFNULL(s3.height, 0),"
277 +
" IFNULL(p3.perf_remotefx, 0), IFNULL(p3.perf_gfx, 0), IFNULL(p3.perf_gfx_h264, "
278 +
"0), IFNULL(p3.perf_wallpaper, 0), IFNULL(p3.perf_theming, 0),"
279 +
" IFNULL(p3.perf_full_window_drag, 0), IFNULL(p3.perf_menu_animations, 0), "
280 +
"IFNULL(p3.perf_font_smoothing, 0), IFNULL(p3.perf_desktop_composition, 0),"
281 +
" IFNULL(b.enable_3g_settings, 0), IFNULL(b.enable_gateway_settings, 0),"
282 +
" b.gateway_hostname, IFNULL(b.gateway_port, 443), b.gateway_username, "
283 +
"b.gateway_password, b.gateway_domain,"
284 +
" IFNULL(b.redirect_sdcard, 0), IFNULL(b.redirect_sound, 0), "
285 +
"IFNULL(b.redirect_microphone, 0),"
287 " IFNULL(b.security, 0), b.remote_program, b.work_dir, IFNULL(b.console_mode, 0),"
288 +
" IFNULL(b.debug_level, 'INFO'), IFNULL(b.async_channel, 0), "
289 +
"IFNULL(b.async_update, 0)"
290 +
" FROM tbl_manual_bookmarks b"
291 +
" LEFT JOIN tbl_screen_settings s ON s._id = b.screen_settings"
292 +
" LEFT JOIN tbl_screen_settings s3 ON s3._id = b.screen_3g"
293 +
" LEFT JOIN tbl_performance_flags p ON p._id = b.performance_flags"
294 +
" LEFT JOIN tbl_performance_flags p3 ON p3._id = b.performance_3g");
296 db.execSQL(
"DROP TABLE IF EXISTS tbl_manual_bookmarks");
297 db.execSQL(
"DROP TABLE IF EXISTS tbl_screen_settings");
298 db.execSQL(
"DROP TABLE IF EXISTS tbl_performance_flags");