19 package org.sleuthkit.autopsy.centralrepository.datamodel;
22 import java.io.IOException;
23 import java.nio.file.Files;
24 import java.nio.file.InvalidPathException;
25 import java.sql.Connection;
26 import java.sql.DriverManager;
27 import java.sql.SQLException;
28 import java.sql.Statement;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.List;
32 import java.util.logging.Level;
33 import java.util.regex.Pattern;
70 if (dbName == null || dbName.isEmpty()) {
75 if (dbDirectory == null || dbDirectory.isEmpty()) {
81 if (bulkThresholdString == null || bulkThresholdString.isEmpty()) {
84 this.bulkThreshold = Integer.parseInt(bulkThresholdString);
89 }
catch (NumberFormatException ex) {
94 if (badTagsStr == null) {
97 if (badTagsStr.isEmpty()) {
98 badTags =
new ArrayList<>();
100 badTags =
new ArrayList<>(Arrays.asList(badTagsStr.split(
",")));
120 if(! dbFile.exists()){
124 return ( ! dbFile.isDirectory());
136 if (!dbDir.exists()) {
138 }
else if (!dbDir.isDirectory()) {
155 Files.createDirectories(dbDir.toPath());
156 LOGGER.log(Level.INFO,
"sqlite directory did not exist, created it at {0}.",
getDbDirectory());
157 }
catch (IOException | InvalidPathException | SecurityException ex) {
158 LOGGER.log(Level.SEVERE,
"Failed to create sqlite database directory.", ex);
172 return dbFile.delete();
181 StringBuilder url =
new StringBuilder();
185 return url.toString();
205 conn = DriverManager.getConnection(url);
206 }
catch (ClassNotFoundException | SQLException ex) {
207 LOGGER.log(Level.SEVERE,
"Failed to acquire ephemeral connection to sqlite.", ex);
264 StringBuilder createOrganizationsTable =
new StringBuilder();
265 createOrganizationsTable.append(
"CREATE TABLE IF NOT EXISTS organizations (");
266 createOrganizationsTable.append(
"id integer primary key autoincrement NOT NULL,");
267 createOrganizationsTable.append(
"org_name text NOT NULL,");
268 createOrganizationsTable.append(
"poc_name text NOT NULL,");
269 createOrganizationsTable.append(
"poc_email text NOT NULL,");
270 createOrganizationsTable.append(
"poc_phone text NOT NULL,");
271 createOrganizationsTable.append(
"CONSTRAINT org_name_unique UNIQUE (org_name)");
272 createOrganizationsTable.append(
")");
276 StringBuilder createCasesTable =
new StringBuilder();
277 createCasesTable.append(
"CREATE TABLE IF NOT EXISTS cases (");
278 createCasesTable.append(
"id integer primary key autoincrement NOT NULL,");
279 createCasesTable.append(
"case_uid text NOT NULL,");
280 createCasesTable.append(
"org_id integer,");
281 createCasesTable.append(
"case_name text NOT NULL,");
282 createCasesTable.append(
"creation_date text NOT NULL,");
283 createCasesTable.append(
"case_number text,");
284 createCasesTable.append(
"examiner_name text,");
285 createCasesTable.append(
"examiner_email text,");
286 createCasesTable.append(
"examiner_phone text,");
287 createCasesTable.append(
"notes text,");
288 createCasesTable.append(
"CONSTRAINT case_uid_unique UNIQUE(case_uid) ON CONFLICT IGNORE,");
289 createCasesTable.append(
"foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL");
290 createCasesTable.append(
")");
293 String casesIdx1 =
"CREATE INDEX IF NOT EXISTS cases_org_id ON cases (org_id)";
294 String casesIdx2 =
"CREATE INDEX IF NOT EXISTS cases_case_uid ON cases (case_uid)";
296 StringBuilder createDataSourcesTable =
new StringBuilder();
297 createDataSourcesTable.append(
"CREATE TABLE IF NOT EXISTS data_sources (");
298 createDataSourcesTable.append(
"id integer primary key autoincrement NOT NULL,");
299 createDataSourcesTable.append(
"device_id text NOT NULL,");
300 createDataSourcesTable.append(
"name text NOT NULL,");
301 createDataSourcesTable.append(
"CONSTRAINT device_id_unique UNIQUE(device_id)");
302 createDataSourcesTable.append(
")");
304 String dataSourceIdx1 =
"CREATE INDEX IF NOT EXISTS data_sources_name ON data_sources (name)";
306 StringBuilder createReferenceSetsTable =
new StringBuilder();
307 createReferenceSetsTable.append(
"CREATE TABLE IF NOT EXISTS reference_sets (");
308 createReferenceSetsTable.append(
"id integer primary key autoincrement NOT NULL,");
309 createReferenceSetsTable.append(
"org_id integer NOT NULL,");
310 createReferenceSetsTable.append(
"set_name text NOT NULL,");
311 createReferenceSetsTable.append(
"version text NOT NULL,");
312 createReferenceSetsTable.append(
"import_date text NOT NULL,");
313 createReferenceSetsTable.append(
"foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL,");
314 createReferenceSetsTable.append(
"CONSTRAINT hash_set_unique UNIQUE (set_name, version)");
315 createReferenceSetsTable.append(
")");
317 String referenceSetsIdx1 =
"CREATE INDEX IF NOT EXISTS reference_sets_org_id ON reference_sets (org_id)";
320 StringBuilder createReferenceTypesTableTemplate =
new StringBuilder();
321 createReferenceTypesTableTemplate.append(
"CREATE TABLE IF NOT EXISTS %s (");
322 createReferenceTypesTableTemplate.append(
"id integer primary key autoincrement NOT NULL,");
323 createReferenceTypesTableTemplate.append(
"reference_set_id integer,");
324 createReferenceTypesTableTemplate.append(
"value text NOT NULL,");
325 createReferenceTypesTableTemplate.append(
"known_status integer NOT NULL,");
326 createReferenceTypesTableTemplate.append(
"comment text,");
327 createReferenceTypesTableTemplate.append(
"CONSTRAINT %s_multi_unique UNIQUE(reference_set_id, value) ON CONFLICT IGNORE,");
328 createReferenceTypesTableTemplate.append(
"foreign key (reference_set_id) references reference_sets(id) ON UPDATE SET NULL ON DELETE SET NULL");
329 createReferenceTypesTableTemplate.append(
")");
332 String referenceTypesIdx1 =
"CREATE INDEX IF NOT EXISTS %s_value ON %s (value)";
333 String referenceTypesIdx2 =
"CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
335 StringBuilder createCorrelationTypesTable =
new StringBuilder();
336 createCorrelationTypesTable.append(
"CREATE TABLE IF NOT EXISTS correlation_types (");
337 createCorrelationTypesTable.append(
"id integer primary key autoincrement NOT NULL,");
338 createCorrelationTypesTable.append(
"display_name text NOT NULL,");
339 createCorrelationTypesTable.append(
"db_table_name text NOT NULL,");
340 createCorrelationTypesTable.append(
"supported integer NOT NULL,");
341 createCorrelationTypesTable.append(
"enabled integer NOT NULL,");
342 createCorrelationTypesTable.append(
"CONSTRAINT correlation_types_names UNIQUE (display_name, db_table_name)");
343 createCorrelationTypesTable.append(
")");
346 StringBuilder createArtifactInstancesTableTemplate =
new StringBuilder();
347 createArtifactInstancesTableTemplate.append(
"CREATE TABLE IF NOT EXISTS %s (");
348 createArtifactInstancesTableTemplate.append(
"id integer primary key autoincrement NOT NULL,");
349 createArtifactInstancesTableTemplate.append(
"case_id integer,");
350 createArtifactInstancesTableTemplate.append(
"data_source_id integer,");
351 createArtifactInstancesTableTemplate.append(
"value text NOT NULL,");
352 createArtifactInstancesTableTemplate.append(
"file_path text NOT NULL,");
353 createArtifactInstancesTableTemplate.append(
"known_status integer NOT NULL,");
354 createArtifactInstancesTableTemplate.append(
"comment text,");
355 createArtifactInstancesTableTemplate.append(
"CONSTRAINT %s_multi_unique UNIQUE(case_id, data_source_id, value, file_path) ON CONFLICT IGNORE,");
356 createArtifactInstancesTableTemplate.append(
"foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
357 createArtifactInstancesTableTemplate.append(
"foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
358 createArtifactInstancesTableTemplate.append(
")");
361 String instancesIdx1 =
"CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)";
362 String instancesIdx2 =
"CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)";
363 String instancesIdx3 =
"CREATE INDEX IF NOT EXISTS %s_value ON %s (value)";
364 String instancesIdx4 =
"CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
366 StringBuilder createDbInfoTable =
new StringBuilder();
367 createDbInfoTable.append(
"CREATE TABLE IF NOT EXISTS db_info (");
368 createDbInfoTable.append(
"id integer primary key NOT NULL,");
369 createDbInfoTable.append(
"name text NOT NULL,");
370 createDbInfoTable.append(
"value text NOT NULL");
371 createDbInfoTable.append(
")");
375 Connection conn = null;
381 Statement stmt = conn.createStatement();
382 stmt.execute(PRAGMA_JOURNAL_WAL);
383 stmt.execute(PRAGMA_SYNC_OFF);
384 stmt.execute(PRAGMA_READ_UNCOMMITTED_TRUE);
385 stmt.execute(PRAGMA_ENCODING_UTF8);
386 stmt.execute(PRAGMA_PAGE_SIZE_4096);
387 stmt.execute(PRAGMA_FOREIGN_KEYS_ON);
389 stmt.execute(createOrganizationsTable.toString());
391 stmt.execute(createCasesTable.toString());
392 stmt.execute(casesIdx1);
393 stmt.execute(casesIdx2);
395 stmt.execute(createDataSourcesTable.toString());
396 stmt.execute(dataSourceIdx1);
398 stmt.execute(createReferenceSetsTable.toString());
399 stmt.execute(referenceSetsIdx1);
401 stmt.execute(createCorrelationTypesTable.toString());
403 stmt.execute(createDbInfoTable.toString());
408 String reference_type_dbname;
409 String instance_type_dbname;
414 stmt.execute(String.format(createArtifactInstancesTableTemplate.toString(), instance_type_dbname, instance_type_dbname));
415 stmt.execute(String.format(instancesIdx1, instance_type_dbname, instance_type_dbname));
416 stmt.execute(String.format(instancesIdx2, instance_type_dbname, instance_type_dbname));
417 stmt.execute(String.format(instancesIdx3, instance_type_dbname, instance_type_dbname));
418 stmt.execute(String.format(instancesIdx4, instance_type_dbname, instance_type_dbname));
422 stmt.execute(String.format(createReferenceTypesTableTemplate.toString(), reference_type_dbname, reference_type_dbname));
423 stmt.execute(String.format(referenceTypesIdx1, reference_type_dbname, reference_type_dbname));
424 stmt.execute(String.format(referenceTypesIdx2, reference_type_dbname, reference_type_dbname));
427 }
catch (SQLException ex) {
428 LOGGER.log(Level.SEVERE,
"Error initializing db schema.", ex);
431 LOGGER.log(Level.SEVERE,
"Error getting default correlation types. Likely due to one or more Type's with an invalid db table name.");
456 return !dbName.equals(dbNameString)
457 || !dbDirectory.equals(dbDirectoryString)
458 || !Integer.toString(bulkThreshold).equals(bulkThresholdString);
474 if (dbName == null || dbName.isEmpty()) {
475 throw new EamDbException(
"Invalid database file name. Cannot be null or empty.");
476 }
else if (!Pattern.matches(DB_NAMES_REGEX, dbName)) {
477 throw new EamDbException(
"Invalid database file name. Name must start with a lowercase letter and can only contain lowercase letters, numbers, and '_'.");
494 if (bulkThreshold > 0) {
530 if (dbDirectory != null && !dbDirectory.isEmpty()) {
533 throw new EamDbException(
"Invalid directory for sqlite database. Cannot empty");
boolean createDbDirectory()
boolean insertDefaultDatabaseContent()
static boolean insertSchemaVersion(Connection conn)
List< String > getBadTags()
static boolean schemaVersionIsSet(Connection conn)
static final String PRAGMA_JOURNAL_WAL
static final String PRAGMA_SYNC_OFF
static boolean executeValidationQuery(Connection conn, String validationQuery)
final String DEFAULT_BAD_TAGS
static final int FILES_TYPE_ID
String getFileNameWithPath()
boolean verifyConnection()
boolean initializeDatabaseSchema()
String getConnectionURL()
String getValidationQuery()
final int DEFAULT_BULK_THRESHHOLD
Connection getEphemeralConnection()
final String VALIDATION_QUERY
static String correlationTypeToReferenceTableName(CorrelationAttribute.Type type)
final String DEFAULT_DBDIRECTORY
static final String PRAGMA_READ_UNCOMMITTED_TRUE
final String JDBC_BASE_URI
static void closeConnection(Connection conn)
static synchronized void setConfigSetting(String moduleName, String settingName, String settingVal)
boolean verifyDatabaseSchema()
static final String PRAGMA_PAGE_SIZE_4096
static boolean insertDefaultCorrelationTypes(Connection conn)
static final Logger LOGGER
void setBulkThreshold(int bulkThreshold)
static String correlationTypeToInstanceTableName(CorrelationAttribute.Type type)
static String getConfigSetting(String moduleName, String settingName)
static final String PRAGMA_SYNC_NORMAL
final String DB_NAMES_REGEX
final String DEFAULT_DBNAME
void setDbName(String dbName)
synchronized static Logger getLogger(String name)
static List< CorrelationAttribute.Type > getDefaultCorrelationTypes()
static final String PRAGMA_FOREIGN_KEYS_ON
void setBadTags(List< String > badTags)
static final String PRAGMA_ENCODING_UTF8
void setDbDirectory(String dbDirectory)
boolean dbDirectoryExists()