diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.mysql.yml similarity index 97% rename from .devcontainer/docker-compose.yml rename to .devcontainer/docker-compose.mysql.yml index fbbd36ad1..55cb7ccc2 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.mysql.yml @@ -9,6 +9,7 @@ services: - CONTAINER_USER_CMD_PRE - CONTAINER_USER_CMD_POST environment: + HASHTOPOLIS_DB_TYPE: mysql HASHTOPOLIS_DB_USER: hashtopolis HASHTOPOLIS_DB_PASS: hashtopolis HASHTOPOLIS_DB_HOST: hashtopolis-db-dev diff --git a/.devcontainer/docker-compose.postgres.yml b/.devcontainer/docker-compose.postgres.yml new file mode 100644 index 000000000..0a7747910 --- /dev/null +++ b/.devcontainer/docker-compose.postgres.yml @@ -0,0 +1,51 @@ +version: "3.7" +services: + hashtopolis-server-dev: + container_name: hashtopolis-server-dev + build: + context: .. + target: hashtopolis-server-dev + args: + - CONTAINER_USER_CMD_PRE + - CONTAINER_USER_CMD_POST + environment: + HASHTOPOLIS_DB_TYPE: postgres + HASHTOPOLIS_DB_USER: hashtopolis + HASHTOPOLIS_DB_PASS: hashtopolis + HASHTOPOLIS_DB_HOST: hashtopolis-db-dev + HASHTOPOLIS_DB_DATABASE: hashtopolis + HASHTOPOLIS_APIV2_ENABLE: 1 + depends_on: + - hashtopolis-db-dev + ports: + - "8080:80" + volumes: + # This is where VS Code should expect to find your project's source code + # and the value of "workspaceFolder" in .devcontainer/devcontainer.json + - ..:/var/www/html + - hashtopolis-server-dev:/usr/local/share/hashtopolis:Z + networks: + - hashtopolis_dev + hashtopolis-db-dev: + container_name: hashtopolis-db-dev + image: postgres:13 + restart: always + ports: + - "5432:5432" + volumes: + - hashtopolis-db-dev:/var/lib/postgresql/data + environment: + POSTGRES_DB: hashtopolis + POSTGRES_USER: hashtopolis + POSTGRES_PASSWORD: hashtopolis + networks: + - hashtopolis_dev + +volumes: + hashtopolis-db-dev: + hashtopolis-server-dev: + +networks: + hashtopolis_dev: + # This network will also be used by the python-agent + name: hashtopolis_dev diff --git a/.github/actions/start-hashtopolis/action.yml b/.github/actions/start-hashtopolis/action.yml index 95d982955..8af48aa9b 100644 --- a/.github/actions/start-hashtopolis/action.yml +++ b/.github/actions/start-hashtopolis/action.yml @@ -1,16 +1,26 @@ name: Start Hashtopolis server description: Starts application containers and waits for Hashtopolis to be ready. +inputs: + db_system: + description: "Used to set which DB system should be used" + required: true + default: "mysql" + options: + - "mysql" + - "postgres" + runs: using: "composite" steps: - name: Start application containers - working-directory: .devcontainer - run: docker compose up -d - shell: bash - - name: Install composer dependencies packages - run: docker exec hashtopolis-server-dev composer install --working-dir=/var/www/html/ + working-directory: .github + run: docker compose -f docker-compose.${{ inputs.db_system }}.yml up -d shell: bash +# should not be needed anymore as it is installed during build +# - name: Install composer dependencies packages +# run: docker exec hashtopolis-server-dev composer install --working-dir=/var/www/html/ +# shell: bash - name: Wait until entrypoint is finished and Hashtopolis is started run: bash .github/scripts/await-hashtopolis-startup.sh shell: bash diff --git a/.github/docker-compose.mysql.yml b/.github/docker-compose.mysql.yml new file mode 100644 index 000000000..d8ed694c2 --- /dev/null +++ b/.github/docker-compose.mysql.yml @@ -0,0 +1,47 @@ +version: "3.7" +services: + hashtopolis-server-dev: + container_name: hashtopolis-server-dev + build: + context: .. + target: hashtopolis-server-dev + args: + - CONTAINER_USER_CMD_PRE + - CONTAINER_USER_CMD_POST + environment: + HASHTOPOLIS_DB_TYPE: mysql + HASHTOPOLIS_DB_USER: hashtopolis + HASHTOPOLIS_DB_PASS: hashtopolis + HASHTOPOLIS_DB_HOST: hashtopolis-db-dev + HASHTOPOLIS_DB_DATABASE: hashtopolis + HASHTOPOLIS_APIV2_ENABLE: 1 + depends_on: + - hashtopolis-db-dev + ports: + - "8080:80" + volumes: + - hashtopolis-server-dev:/usr/local/share/hashtopolis:Z + networks: + - hashtopolis_dev + hashtopolis-db-dev: + container_name: hashtopolis-db-dev + image: mysql:8.0 + restart: always + ports: + - "3306:3306" + volumes: + - hashtopolis-db-dev:/var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: hashtopolis + MYSQL_DATABASE: hashtopolis + MYSQL_USER: hashtopolis + MYSQL_PASSWORD: hashtopolis + networks: + - hashtopolis_dev +volumes: + hashtopolis-db-dev: + hashtopolis-server-dev: + +networks: + hashtopolis_dev: + name: hashtopolis_dev diff --git a/.github/docker-compose.postgres.yml b/.github/docker-compose.postgres.yml new file mode 100644 index 000000000..b4c53d290 --- /dev/null +++ b/.github/docker-compose.postgres.yml @@ -0,0 +1,47 @@ +version: "3.7" +services: + hashtopolis-server-dev: + container_name: hashtopolis-server-dev + build: + context: .. + target: hashtopolis-server-dev + args: + - CONTAINER_USER_CMD_PRE + - CONTAINER_USER_CMD_POST + environment: + HASHTOPOLIS_DB_TYPE: postgres + HASHTOPOLIS_DB_USER: hashtopolis + HASHTOPOLIS_DB_PASS: hashtopolis + HASHTOPOLIS_DB_HOST: hashtopolis-db-dev + HASHTOPOLIS_DB_DATABASE: hashtopolis + HASHTOPOLIS_APIV2_ENABLE: 1 + depends_on: + - hashtopolis-db-dev + ports: + - "8080:80" + volumes: + - hashtopolis-server-dev:/usr/local/share/hashtopolis:Z + networks: + - hashtopolis_dev + hashtopolis-db-dev: + container_name: hashtopolis-db-dev + image: postgres:13 + restart: always + ports: + - "5432:5432" + volumes: + - hashtopolis-db-dev:/var/lib/postgresql/data + environment: + POSTGRES_DB: hashtopolis + POSTGRES_USER: hashtopolis + POSTGRES_PASSWORD: hashtopolis + networks: + - hashtopolis_dev + +volumes: + hashtopolis-db-dev: + hashtopolis-server-dev: + +networks: + hashtopolis_dev: + name: hashtopolis_dev diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc14f4d88..22dbc4653 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,15 +13,20 @@ on: jobs: build: runs-on: ubuntu-latest + strategy: + matrix: + include: + - db_system: mysql + - db_system: postgres steps: - name: Checkout repository uses: actions/checkout@v3 - name: Start Hashtopolis server uses: ./.github/actions/start-hashtopolis + with: + db_system: ${{ matrix.db_system }} - name: Give Apache permissions on necessary directories # for the tests, only src/files and src/inc/utils/locks seem necessary run: docker exec -u root hashtopolis-server-dev bash -c "chown -R www-data:www-data /var/www/html/src && chmod -R g+w /var/www/html/src" - - name: Run test suite - run: docker exec hashtopolis-server-dev php /var/www/html/ci/run.php -vmaster - name: Test with pytest run: docker exec hashtopolis-server-dev pytest /var/www/html/ci/apiv2 - name: Test if pytest is removing all test objects diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml index da16380cd..5a7727326 100644 --- a/.github/workflows/docs-build.yml +++ b/.github/workflows/docs-build.yml @@ -29,6 +29,8 @@ jobs: sudo apt-get install npm - name: Start Hashtopolis server uses: ./.github/actions/start-hashtopolis + with: + db_system: "mysql" - name: Download newest apiv2 spec run: | wget http://localhost:8080/api/v2/openapi.json -P /tmp/ diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c48bf4ddc..93f1f22af 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -26,9 +26,11 @@ jobs: sudo apt-get install php sudo apt-get install -y lftp sudo apt-get install nodejs - sudo apt-get install npm + sudo apt-get install npm - name: Start Hashtopolis server uses: ./.github/actions/start-hashtopolis + with: + db_system: "mysql" - name: Download newest apiv2 spec run: | wget http://localhost:8080/api/v2/openapi.json -P /tmp/ diff --git a/Dockerfile b/Dockerfile index dbd1f3106..813615d76 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,7 @@ +FROM rust:1.91-trixie AS prebuild + +RUN cargo install sqlx-cli --no-default-features --features native-tls,mysql,postgres + FROM alpine/git AS preprocess COPY .gi[t] /.git @@ -37,12 +41,12 @@ RUN apt-get update \ # # Install git, procps, lsb-release (useful for CLI installs) && apt-get -y install git iproute2 procps lsb-release \ - && apt-get -y install mariadb-client \ + && apt-get -y install mariadb-client postgresql-client libpq-dev \ && apt-get -y install libpng-dev \ && apt-get -y install ssmtp \ \ # Install extensions (optional) - && docker-php-ext-install pdo_mysql gd \ + && docker-php-ext-install pdo_mysql pgsql pdo_pgsql gd \ \ # Install Composer && curl -sS https://getcomposer.org/installer | php \ @@ -82,6 +86,8 @@ RUN mkdir -p ${HASHTOPOLIS_DOCUMENT_ROOT} \ && chown www-data:www-data ${HASHTOPOLIS_BINARIES_PATH} \ && chmod g+w ${HASHTOPOLIS_BINARIES_PATH} +COPY --from=prebuild /usr/local/cargo/bin/sqlx /usr/bin/ + COPY --from=preprocess /HEA[D] ${HASHTOPOLIS_DOCUMENT_ROOT}/../.git/ # Install composer diff --git a/ci/HashtopolisTest.class.php b/ci/HashtopolisTest.class.php index 47031a970..87d3f7b16 100644 --- a/ci/HashtopolisTest.class.php +++ b/ci/HashtopolisTest.class.php @@ -19,7 +19,7 @@ abstract class HashtopolisTest { protected $user; protected $apiKey; - const USER_PASS = "HG78Ghdfs87gh"; + const USER_PASS = "hashtopolis"; const RUN_FULL = 0; const RUN_FAST = 1; @@ -70,28 +70,27 @@ public function init($version) { global $PEPPER, $VERSION; // drop old data and create empty DB - Factory::getAgentFactory()->getDB()->query("DROP DATABASE IF EXISTS hashtopolis"); + /*Factory::getAgentFactory()->getDB()->query("DROP DATABASE IF EXISTS hashtopolis"); Factory::getAgentFactory()->getDB()->query("CREATE DATABASE hashtopolis"); Factory::getAgentFactory()->getDB()->query("USE hashtopolis"); // load DB if ($version == "master") { - Factory::getAgentFactory()->getDB()->query(file_get_contents(dirname(__FILE__) ."/../src/install/hashtopolis.sql")); + Factory::getAgentFactory()->getDB()->query(file_get_contents(dirname(__FILE__) ."/../src/migrations/mysql/20251127000000_initial.sql")); } else { Factory::getAgentFactory()->getDB()->query(file_get_contents(dirname(__FILE__) . "/files/db_" . $version . ".sql")); } - sleep(1); + sleep(1);*/ // insert user and api key - $salt = Util::randomString(30); + /*$salt = Util::randomString(30); $hash = Encryption::passwordHash(HashtopolisTest::USER_PASS, $salt); $this->user = new User(null, 'testuser', '', $hash, $salt, 1, 0, 0, 0, 3600, AccessUtils::getOrCreateDefaultAccessGroup()->getId(), 0, '', '', '', ''); - $this->user = Factory::getUserFactory()->save($this->user); - $accessGroup = new AccessGroupUser(null, 1, $this->user->getId()); - Factory::getAccessGroupUserFactory()->save($accessGroup); - $this->apiKey = new ApiKey(null, 0, time() + 3600, 'mykey', 0, $this->user->getId(), 1); + $this->user = Factory::getUserFactory()->save($this->user);*/ + AccessUtils::getOrCreateDefaultAccessGroup(); + $this->apiKey = new ApiKey(null, 0, time() + 3600, 'mykey', 0, 1, 1); $this->apiKey = Factory::getApiKeyFactory()->save($this->apiKey); // $versionStore = new StoredValue("version", ($version == 'master') ? explode("+", $VERSION)[0] : $version); // Factory::getStoredValueFactory()->save($versionStore); diff --git a/ci/server/setup.php b/ci/server/setup.php index f78a93282..aa7f50c29 100644 --- a/ci/server/setup.php +++ b/ci/server/setup.php @@ -30,7 +30,7 @@ try { $db->query("CREATE DATABASE IF NOT EXISTS hashtopolis;"); $db->query("USE hashtopolis;"); - $db->query(file_get_contents($envPath . "src/install/hashtopolis.sql")); + $db->query(file_get_contents($envPath . "src/migrations/mysql/20251127000000_initial.sql")); } catch (PDOException $e) { fwrite(STDERR, "Failed to initialize database: " . $e->getMessage()); diff --git a/docker-compose.yml b/docker-compose.mysql.yml similarity index 92% rename from docker-compose.yml rename to docker-compose.mysql.yml index 352713e80..03010d489 100644 --- a/docker-compose.yml +++ b/docker-compose.mysql.yml @@ -8,13 +8,14 @@ services: - hashtopolis:/usr/local/share/hashtopolis:Z # - ./ssmtp.conf:/etc/ssmtp/ssmtp.conf environment: + HASHTOPOLIS_DB_TYPE: mysql HASHTOPOLIS_DB_USER: $MYSQL_USER HASHTOPOLIS_DB_PASS: $MYSQL_PASSWORD HASHTOPOLIS_DB_HOST: $HASHTOPOLIS_DB_HOST HASHTOPOLIS_DB_DATABASE: $MYSQL_DATABASE HASHTOPOLIS_ADMIN_USER: $HASHTOPOLIS_ADMIN_USER HASHTOPOLIS_ADMIN_PASSWORD: $HASHTOPOLIS_ADMIN_PASSWORD - HASHTOPOLIS_APIV2_ENABLE: $HASHTOPOLIS_APIV2_ENABLE + HASHTOPOLIS_APIV2_ENABLE: $HASHTOPOLIS_APIV2_ENABLE HASHTOPOLIS_FRONTEND_URLS: $HASHTOPOLIS_FRONTEND_URLS depends_on: - db @@ -37,7 +38,7 @@ services: environment: HASHTOPOLIS_BACKEND_URL: $HASHTOPOLIS_BACKEND_URL restart: always - depends_on: + depends_on: - hashtopolis-backend ports: - 4200:80 diff --git a/docker-compose.postgres.yml b/docker-compose.postgres.yml new file mode 100644 index 000000000..a7553595e --- /dev/null +++ b/docker-compose.postgres.yml @@ -0,0 +1,45 @@ +version: '3.7' +services: + hashtopolis-backend: + container_name: hashtopolis-backend + image: hashtopolis/backend:latest + restart: always + volumes: + - hashtopolis:/usr/local/share/hashtopolis:Z + # - ./ssmtp.conf:/etc/ssmtp/ssmtp.conf + environment: + HASHTOPOLIS_DB_TYPE: postgres + HASHTOPOLIS_DB_USER: $POSTGRES_USER + HASHTOPOLIS_DB_PASS: $POSTGRES_PASSWORD + HASHTOPOLIS_DB_HOST: $HASHTOPOLIS_DB_HOST + HASHTOPOLIS_DB_DATABASE: $POSTGRES_DATABASE + HASHTOPOLIS_ADMIN_USER: $HASHTOPOLIS_ADMIN_USER + HASHTOPOLIS_ADMIN_PASSWORD: $HASHTOPOLIS_ADMIN_PASSWORD + HASHTOPOLIS_APIV2_ENABLE: $HASHTOPOLIS_APIV2_ENABLE + depends_on: + - db + ports: + - 8080:80 + db: + container_name: db + image: postgres:13 + restart: always + volumes: + - db:/var/lib/postgresql/data + environment: + POSTGRES_DB: $POSTGRES_DATABASE + POSTGRES_USER: $POSTGRES_USER + POSTGRES_PASSWORD: $POSTGRES_PASSWORD + hashtopolis-frontend: + container_name: hashtopolis-frontend + image: hashtopolis/frontend:latest + environment: + HASHTOPOLIS_BACKEND_URL: $HASHTOPOLIS_BACKEND_URL + restart: always + depends_on: + - hashtopolis-backend + ports: + - 4200:80 +volumes: + db: + hashtopolis: diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index ac7a2cde4..5b6fc174a 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -10,20 +10,35 @@ for path in ${paths[@]}; do fi done -echo "Testing database." -MYSQL="mysql -u${HASHTOPOLIS_DB_USER} -p${HASHTOPOLIS_DB_PASS} -h ${HASHTOPOLIS_DB_HOST} --skip-ssl" -$MYSQL -e "SELECT 1" > /dev/null 2>&1 -ERROR=$? +echo "Testing database..." +if [[ "$HASHTOPOLIS_DB_TYPE" == "mysql" ]]; then + echo "Using MySQL..." + DB_CMD="mysql -u${HASHTOPOLIS_DB_USER} -p${HASHTOPOLIS_DB_PASS} -h ${HASHTOPOLIS_DB_HOST} --skip-ssl" + DB_TYPE="mysql" +elif [[ "$HASHTOPOLIS_DB_TYPE" == "postgres" ]]; then + echo "Using postgres..." + DB_CMD="psql -U${HASHTOPOLIS_DB_USER} -h ${HASHTOPOLIS_DB_HOST} ${HASHTOPOLIS_DB_DATABASE}" + DB_TYPE="postgres" +else + echo "INVALID DATABASE TYPE PROVIDED: $HASHTOPOLIS_DB_TYPE" + exit 1 +fi -while [ $ERROR -ne 0 ]; -do - echo "Database not ready or unable to connect. Retrying in 5s." - sleep 5 - $MYSQL -e "SELECT 1" > /dev/null 2>&1 - ERROR=$? +while :; do + if [[ $DB_TYPE == "mysql" ]]; then + $DB_CMD -e "SELECT 1" > /dev/null 2>&1 + ERROR=$? + elif [[ $DB_TYPE == "postgres" ]]; then + PGPASSWORD="${HASHTOPOLIS_DB_PASS}" $DB_CMD -c "SELECT 1" > /dev/null 2>&1 + ERROR=$? + fi + if [ $ERROR -eq 0 ]; then + break + fi + echo "Database not ready or unable to connect. Retrying in 5s." + sleep 5 done - -echo "Database ready." +echo "Database ready!" echo "Setting up folders" if [ ! -d ${HASHTOPOLIS_FILES_PATH} ];then diff --git a/env.example b/env.mysql.example similarity index 100% rename from env.example rename to env.mysql.example diff --git a/env.postgres.example b/env.postgres.example new file mode 100644 index 000000000..166f366d4 --- /dev/null +++ b/env.postgres.example @@ -0,0 +1,10 @@ +POSTGRES_DATABASE=hashtopolis +POSTGRES_USER=hashtopolis +POSTGRES_PASSWORD=hashtopolis + +HASHTOPOLIS_ADMIN_USER=admin +HASHTOPOLIS_ADMIN_PASSWORD=hashtopolis +HASHTOPOLIS_DB_HOST=db + +HASHTOPOLIS_APIV2_ENABLE=0 +HASHTOPOLIS_BACKEND_URL=http://localhost:8080/api/v2 diff --git a/src/dba/AbstractModelFactory.class.php b/src/dba/AbstractModelFactory.class.php index fa7dfe0db..c17de0893 100755 --- a/src/dba/AbstractModelFactory.class.php +++ b/src/dba/AbstractModelFactory.class.php @@ -427,18 +427,6 @@ public function minMaxFilter(array $options, string $sumColumn, string $op): mix $query .= $this->applyFilters($vals, $options['filter']); } - if (!array_key_exists("order", $options)) { - // Add a asc order on the primary keys as a standard - $oF = new OrderFilter($this->getNullObject()->getPrimaryKey(), "ASC"); - $orderOptions = array( - $oF - ); - $options['order'] = $orderOptions; - } - if (count($options['order']) != 0) { - $query .= $this->applyOrder($this->getOrders($options)); - } - $dbh = self::getDB(); $stmt = $dbh->prepare($query); $stmt->execute($vals); @@ -485,18 +473,6 @@ public function sumFilter($options, $sumColumn) { $query .= $this->applyFilters($vals, $options['filter']); } - if (!array_key_exists("order", $options)) { - // Add a asc order on the primary keys as a standard - $oF = new OrderFilter($this->getNullObject()->getPrimaryKey(), "ASC"); - $orderOptions = array( - $oF - ); - $options['order'] = $orderOptions; - } - if (count($options['order']) != 0) { - $query .= $this->applyOrder($this->getOrders($options)); - } - $dbh = self::getDB(); $stmt = $dbh->prepare($query); $stmt->execute($vals); @@ -920,26 +896,44 @@ public function massUpdate($options): bool { * @return PDO */ public function getDB(bool $test = false): ?PDO { - if (!$test) { - $dsn = 'mysql:dbname=' . DBA_DB . ";host=" . DBA_SERVER . ";port=" . DBA_PORT; - $user = DBA_USER; - $password = DBA_PASS; - } - else { - global $CONN; - // The utf8mb4 is here to force php to connect with that encoding, so you can save emoji's or other non ascii chars (specifically, unicode characters outside of the BMP) into the database. - // If you are running into issues with this line, we could make this configurable. - $dsn = 'mysql:dbname=' . $CONN['db'] . ";host=" . $CONN['server'] . ";port=" . $CONN['port'] . ";charset=utf8mb4"; - $user = $CONN['user']; - $password = $CONN['pass']; - } - if (self::$dbh !== null) { return self::$dbh; } - try { - self::$dbh = new PDO($dsn, $user, $password); + $dbUser = @DBA_USER; + $dbPass = @DBA_PASS; + $dbType = @DBA_TYPE; + $dbHost = @DBA_SERVER; + $dbPort = @DBA_PORT; + $dbDB = @DBA_DB; + if ($test) { // if the connection is being tested, take credentials from legacy global variable + global $CONN; + $dbUser = $CONN['user']; + $dbPass = $CONN['pass']; + $dbType = $CONN['type']; + $dbHost = $CONN['server']; + $dbPort = $CONN['port']; + $dbDB = $CONN['db']; + } + + if ($dbType == 'mysql') { + // connect as mysql + $dsn = "mysql:dbname=$dbDB;host=$dbHost;port=$dbPort;charset=utf8mb4"; + self::$dbh = new PDO($dsn, $dbUser, $dbPass); + } + else if ($dbType == 'postgres') { + // connect as postgres + $dsn = "pgsql:dbname=$dbDB;host=$dbHost;port=$dbPort;user=$dbUser;password=$dbPass"; + self::$dbh = new PDO($dsn); + } + else { + // unknown type + if ($test) { + return null; + } + throw new Exception("Fatal Error: Unknown database type specified!"); + } + self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return self::$dbh; } diff --git a/src/dba/LikeFilter.class.php b/src/dba/LikeFilter.class.php index 8de40e3fd..eedccaaf6 100755 --- a/src/dba/LikeFilter.class.php +++ b/src/dba/LikeFilter.class.php @@ -36,7 +36,12 @@ function getQueryString(AbstractModelFactory $factory, bool $includeTable = fals $inv = " NOT"; } - return $table . AbstractModelFactory::getMappedModelKey($factory->getNullObject(), $this->key) . $inv . " LIKE BINARY ?"; + // it is not ideal to have to make a distinction between the DB types here, but currently there does not seem to be another solution to achieve real case-sensitive like filtering + $likeStatement = " LIKE BINARY ?"; + if (DBA_TYPE == 'postgres') { + $likeStatement = " LIKE ? COLLATE \"C\""; + } + return $table . AbstractModelFactory::getMappedModelKey($factory->getNullObject(), $this->key) . $inv . $likeStatement; } function getValue() { diff --git a/src/dba/init.php b/src/dba/init.php index 7af80230d..04a043954 100644 --- a/src/dba/init.php +++ b/src/dba/init.php @@ -6,6 +6,7 @@ define("DBA_USER", (isset($CONN['user'])) ? $CONN['user'] : ""); define("DBA_PASS", (isset($CONN['pass'])) ? $CONN['pass'] : ""); define("DBA_PORT", (isset($CONN['port'])) ? $CONN['port'] : ""); +define("DBA_TYPE", (isset($CONN['type'])) ? $CONN['type'] : ""); require_once(dirname(__FILE__) . "/AbstractModel.class.php"); require_once(dirname(__FILE__) . "/AbstractModelFactory.class.php"); diff --git a/src/inc/confv2.php b/src/inc/confv2.php index dd63271d5..d13484e72 100644 --- a/src/inc/confv2.php +++ b/src/inc/confv2.php @@ -24,7 +24,25 @@ $CONN['pass'] = getenv('HASHTOPOLIS_DB_PASS'); $CONN['server'] = getenv('HASHTOPOLIS_DB_HOST'); $CONN['db'] = getenv('HASHTOPOLIS_DB_DATABASE'); - $CONN['port'] = 3306; + if (getenv('HASHTOPOLIS_DB_TYPE') !== false) { + $CONN['type'] = getenv('HASHTOPOLIS_DB_TYPE'); + } + else { + $CONN['type'] = 'mysql'; + } + if (getenv('HASHTOPOLIS_DB_PORT') !== false) { + $CONN['port'] = getenv('HASHTOPOLIS_DB_PORT'); + } + else { + switch($CONN['type']) { + case 'mysql': + $CONN['port'] = '3306'; + break; + case 'postgres': + $CONN['port'] = '5432'; + break; + } + } $DIRECTORIES = [ "files" => "/usr/local/share/hashtopolis/files", @@ -51,4 +69,4 @@ $PEPPER = $CONFIG['PEPPER']; } else { $CONFIG = []; -} \ No newline at end of file +} diff --git a/src/inc/load.php b/src/inc/load.php index 8a6462596..e2ac8502f 100755 --- a/src/inc/load.php +++ b/src/inc/load.php @@ -67,13 +67,28 @@ //connection not valid die("Database connection failed!"); } +$initialSetup = false; try { Factory::getAgentFactory()->filter([], true); } catch (PDOException $e) { - $query = file_get_contents(dirname(__FILE__) . "/../install/hashtopolis.sql"); - Factory::getAgentFactory()->getDB()->query($query); - + // initial setup, run only on the very first time + // the boolean is stored to later when the database is migrated, some initial queries can be done + $initialSetup = true; +} + +// this only needs to be present for the very first upgrade from non-migration to migrations to make sure the last updates are executed before migration +if (!$initialSetup && DBA_TYPE == "mysql" && !Util::databaseTableExists("_sqlx_migrations")) { + include(dirname(__FILE__) . "/../install/updates/update.php"); +} + +$database_uri = DBA_TYPE . "://" . DBA_USER . ":" . DBA_PASS . "@" . DBA_SERVER . ":" . DBA_PORT . "/" . DBA_DB; +exec('/usr/bin/sqlx migrate run --source ' . dirname(__FILE__) . '/../migrations/' . DBA_TYPE . '/ -D ' . $database_uri, $output, $retval); +if ($retval !== 0) { + die("Failed to run migrations: \n" . implode("\n", $output)); +} + +if ($initialSetup === true) { // determine the base url $baseUrl = explode("/", $_SERVER['REQUEST_URI']); unset($baseUrl[sizeof($baseUrl) - 1]); @@ -159,22 +174,6 @@ UI::add('toggledarkmode', 0); } -$updateExecuted = false; -// check if update is needed -// (note if the version was retrieved with git, but the git folder was removed, smaller updates are not recognized because the build value is missing) -$storedVersion = Factory::getStoredValueFactory()->get("version"); -if ($storedVersion == null || $storedVersion->getVal() != explode("+", $VERSION)[0] && file_exists(dirname(__FILE__) . "/../install/updates/update.php")) { - include(dirname(__FILE__) . "/../install/updates/update.php"); - $updateExecuted = $upgradePossible; -} -else { // in case it is not a version upgrade, but the person retrieved a new version via git or copying - $storedBuild = Factory::getStoredValueFactory()->get("build"); - if ($storedBuild == null || ($BUILD != 'repository' && $storedBuild->getVal() != $BUILD) || ($BUILD == 'repository' && strlen(Util::getGitCommit(true)) > 0 && $storedBuild->getVal() != Util::getGitCommit(true)) && file_exists(dirname(__FILE__) . "/../install/updates/update.php")) { - include(dirname(__FILE__) . "/../install/updates/update.php"); - $updateExecuted = $upgradePossible; - } -} - if (strlen(Util::getGitCommit()) == 0) { $storedBuild = Factory::getStoredValueFactory()->get("build"); if ($storedBuild != null) { @@ -185,10 +184,6 @@ UI::add('menu', Menu::get()); UI::add('messages', []); -if ($updateExecuted) { - UI::addMessage(UI::SUCCESS, "An automatic upgrade was executed! " . sizeof($EXECUTED) . " changes applied on DB!"); -} - UI::add('pageTitle', ""); UI::add('login', Login::getInstance()); if (Login::getInstance()->isLoggedin()) { diff --git a/src/inc/utils/AccessUtils.class.php b/src/inc/utils/AccessUtils.class.php index a1db60d7d..1b3989ed8 100644 --- a/src/inc/utils/AccessUtils.class.php +++ b/src/inc/utils/AccessUtils.class.php @@ -164,6 +164,7 @@ public static function getAccessGroupsOfAgent(Agent $agent): array { public static function getOrCreateDefaultAccessGroup() { $accessGroup = Factory::getAccessGroupFactory()->get(1); if ($accessGroup == null) { + // this should never happen anymore (unless someone deleted access group with ID 1) $accessGroup = new AccessGroup(1, "Default Group"); $accessGroup = Factory::getAccessGroupFactory()->save($accessGroup); } diff --git a/src/install/updates/update_v1.0.0-rainbow4_vx.x.x.php b/src/install/updates/update_v1.0.0-rainbow4_vx.x.x.php index 388be7f5c..29e278f86 100644 --- a/src/install/updates/update_v1.0.0-rainbow4_vx.x.x.php +++ b/src/install/updates/update_v1.0.0-rainbow4_vx.x.x.php @@ -6,6 +6,11 @@ use DBA\QueryFilter; +if (DBA_TYPE == 'postgres' || Util::databaseTableExists("_sqlx_migrations")) { + // this system is already using migrations, so it should NEVER do any of the updates + return; +} + if (!isset($PRESENT["v1.0.0-rainbow4_prefix_user_and_end"])) { if (Util::databaseColumnExists("HealthCheckAgent", "end")) { Factory::getAgentFactory()->getDB()->query("ALTER TABLE `HealthCheckAgent` RENAME COLUMN `end` to `htp_end`;"); @@ -16,3 +21,11 @@ $EXECUTED["v1.0.0-rainbow4_prefix_user_and_end"] = true; } +if (!isset($PRESENT["v1.0.0-rainbow4_migration_to_migrations"])) { + if (!Util::databaseTableExists("_sqlx_migrations")) { + // this creates the existing state for sqlx to continue with migrations for all further updates + Factory::getAgentFactory()->getDB()->query("CREATE TABLE `_sqlx_migrations` (`version` bigint NOT NULL, `description` text NOT NULL, `installed_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `success` tinyint(1) NOT NULL, `checksum` blob NOT NULL, `execution_time` bigint NOT NULL, PRIMARY KEY (`version`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;"); + Factory::getAgentFactory()->getDB()->query("INSERT INTO `_sqlx_migrations` VALUES (20251127000000,'initial','2025-11-28 14:29:13',1,0xA5A8F03AAD0827C86C4A380D935BF1CCB3B5D5F174D7FC40B3D267FD0B6BB7DD4181A9C25EFC5CFCE24DF760F4C2D881,1);"); + } + $EXECUTED["v1.0.0-rainbow4_migration_to_migrations"] = true; +} diff --git a/src/migrations/.htaccess b/src/migrations/.htaccess new file mode 100644 index 000000000..896fbc5a3 --- /dev/null +++ b/src/migrations/.htaccess @@ -0,0 +1,2 @@ +Order deny,allow +Deny from all \ No newline at end of file diff --git a/src/install/hashtopolis.sql b/src/migrations/mysql/20251127000000_initial.sql similarity index 95% rename from src/install/hashtopolis.sql rename to src/migrations/mysql/20251127000000_initial.sql index 01072a1d1..3e0f0dfba 100644 --- a/src/install/hashtopolis.sql +++ b/src/migrations/mysql/20251127000000_initial.sql @@ -1,31 +1,33 @@ SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; - /*!40101 SET @OLD_CHARACTER_SET_CLIENT = @@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS = @@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION = @@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8mb4 */; -- Create tables and insert default entries -CREATE TABLE `AccessGroup` ( +CREATE TABLE IF NOT EXISTS `AccessGroup` ( `accessGroupId` INT(11) NOT NULL, `groupName` VARCHAR(50) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `AccessGroupAgent` ( +INSERT INTO `AccessGroup` (`accessGroupId`, `groupName`) VALUES + (1, 'Default Group'); + +CREATE TABLE IF NOT EXISTS `AccessGroupAgent` ( `accessGroupAgentId` INT(11) NOT NULL, `accessGroupId` INT(11) NOT NULL, `agentId` INT(11) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `AccessGroupUser` ( +CREATE TABLE IF NOT EXISTS `AccessGroupUser` ( `accessGroupUserId` INT(11) NOT NULL, `accessGroupId` INT(11) NOT NULL, `userId` INT(11) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `Agent` ( +CREATE TABLE IF NOT EXISTS `Agent` ( `agentId` INT(11) NOT NULL, `agentName` VARCHAR(100) NOT NULL, `uid` VARCHAR(100) NOT NULL, @@ -44,9 +46,9 @@ CREATE TABLE `Agent` ( `clientSignature` VARCHAR(50) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `AgentBinary` ( +CREATE TABLE IF NOT EXISTS `AgentBinary` ( `agentBinaryId` INT(11) NOT NULL, - `binaryType` VARCHAR(20) NOT NULL, + `binaryType` VARCHAR(20) NOT NULL, `version` VARCHAR(20) NOT NULL, `operatingSystems` VARCHAR(50) NOT NULL, `filename` VARCHAR(50) NOT NULL, @@ -57,7 +59,7 @@ CREATE TABLE `AgentBinary` ( INSERT INTO `AgentBinary` (`agentBinaryId`, `binaryType`, `version`, `operatingSystems`, `filename`, `updateTrack`, `updateAvailable`) VALUES (1, 'python', '0.7.4', 'Windows, Linux, OS X', 'hashtopolis.zip', 'stable', ''); -CREATE TABLE `AgentError` ( +CREATE TABLE IF NOT EXISTS `AgentError` ( `agentErrorId` INT(11) NOT NULL, `agentId` INT(11) NOT NULL, `taskId` INT(11) DEFAULT NULL, @@ -66,28 +68,47 @@ CREATE TABLE `AgentError` ( `chunkId` INT(11) NULL ) ENGINE = InnoDB; -CREATE TABLE `AgentStat` ( - `agentStatId` INT(11) NOT NULL, - `agentId` INT(11) NOT NULL, - `statType` INT(11) NOT NULL, - `time` BIGINT NOT NULL, +CREATE TABLE IF NOT EXISTS `AgentStat` ( + `agentStatId` INT(11) NOT NULL, + `agentId` INT(11) NOT NULL, + `statType` INT(11) NOT NULL, + `time` BIGINT NOT NULL, `value` VARCHAR(128) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `AgentZap` ( +CREATE TABLE IF NOT EXISTS `AgentZap` ( `agentZapId` INT(11) NOT NULL, `agentId` INT(11) NOT NULL, `lastZapId` INT(11) NULL ) ENGINE = InnoDB; -CREATE TABLE `Assignment` ( +CREATE TABLE IF NOT EXISTS `ApiKey` ( + `apiKeyId` INT(11) NOT NULL, + `startValid` BIGINT(20) NOT NULL, + `endValid` BIGINT(20) NOT NULL, + `accessKey` VARCHAR(256) NOT NULL, + `accessCount` INT(11) NOT NULL, + `userId` INT(11) NOT NULL, + `apiGroupId` INT(11) NOT NULL +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS `ApiGroup` ( + `apiGroupId` INT(11) NOT NULL, + `name` VARCHAR(100) NOT NULL, + `permissions` TEXT NOT NULL +) ENGINE=InnoDB; + +INSERT INTO `ApiGroup` ( `apiGroupId`, `name`, `permissions`) VALUES + (1, 'Administrators', 'ALL'); + +CREATE TABLE IF NOT EXISTS `Assignment` ( `assignmentId` INT(11) NOT NULL, `taskId` INT(11) NOT NULL, `agentId` INT(11) NOT NULL, `benchmark` VARCHAR(50) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `Chunk` ( +CREATE TABLE IF NOT EXISTS `Chunk` ( `chunkId` INT(11) NOT NULL, `taskId` INT(11) NOT NULL, `skip` BIGINT(20) UNSIGNED NOT NULL, @@ -102,7 +123,7 @@ CREATE TABLE `Chunk` ( `speed` BIGINT(20) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `Config` ( +CREATE TABLE IF NOT EXISTS `Config` ( `configId` INT(11) NOT NULL, `configSectionId` INT(11) NOT NULL, `item` VARCHAR(80) NOT NULL, @@ -174,8 +195,7 @@ INSERT INTO `Config` (`configId`, `configSectionId`, `item`, `value`) VALUES (78, 3, 'defaultPageSize', '10000'), (79, 3, 'maxPageSize', '50000'); - -CREATE TABLE `ConfigSection` ( +CREATE TABLE IF NOT EXISTS `ConfigSection` ( `configSectionId` INT(11) NOT NULL, `sectionName` VARCHAR(100) NOT NULL ) ENGINE = InnoDB; @@ -189,7 +209,7 @@ INSERT INTO `ConfigSection` (`configSectionId`, `sectionName`) VALUES (6, 'Multicast'), (7, 'Notifications'); -CREATE TABLE `CrackerBinary` ( +CREATE TABLE IF NOT EXISTS `CrackerBinary` ( `crackerBinaryId` INT(11) NOT NULL, `crackerBinaryTypeId` INT(11) NOT NULL, `version` VARCHAR(20) NOT NULL, @@ -200,7 +220,7 @@ CREATE TABLE `CrackerBinary` ( INSERT INTO `CrackerBinary` (`crackerBinaryId`, `crackerBinaryTypeId`, `version`, `downloadUrl`, `binaryName`) VALUES (1, 1, '7.1.2', 'https://hashcat.net/files/hashcat-7.1.2.7z', 'hashcat'); -CREATE TABLE `CrackerBinaryType` ( +CREATE TABLE IF NOT EXISTS `CrackerBinaryType` ( `crackerBinaryTypeId` INT(11) NOT NULL, `typeName` VARCHAR(30) NOT NULL, `isChunkingAvailable` TINYINT(4) NOT NULL @@ -209,7 +229,7 @@ CREATE TABLE `CrackerBinaryType` ( INSERT INTO `CrackerBinaryType` (`crackerBinaryTypeId`, `typeName`, `isChunkingAvailable`) VALUES (1, 'hashcat', 1); -CREATE TABLE `File` ( +CREATE TABLE IF NOT EXISTS `File` ( `fileId` INT(11) NOT NULL, `filename` VARCHAR(100) NOT NULL, `size` BIGINT(20) NOT NULL, @@ -219,25 +239,32 @@ CREATE TABLE `File` ( `lineCount` BIGINT(20) DEFAULT NULL ) ENGINE = InnoDB; -CREATE TABLE `FilePretask` ( +CREATE TABLE IF NOT EXISTS `FileDownload` ( + `fileDownloadId` INT(11) NOT NULL, + `time` BIGINT NOT NULL, + `fileId` INT(11) NOT NULL, + `status` INT(11) NOT NULL +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS `FilePretask` ( `filePretaskId` INT(11) NOT NULL, `fileId` INT(11) NOT NULL, `pretaskId` INT(11) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `FileTask` ( +CREATE TABLE IF NOT EXISTS `FileTask` ( `fileTaskId` INT(11) NOT NULL, `fileId` INT(11) NOT NULL, `taskId` INT(11) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `FileDelete` ( +CREATE TABLE IF NOT EXISTS `FileDelete` ( `fileDeleteId` INT(11) NOT NULL, `filename` VARCHAR(256) NOT NULL, `time` BIGINT NOT NULL ) ENGINE=InnoDB; -CREATE TABLE `Hash` ( +CREATE TABLE IF NOT EXISTS `Hash` ( `hashId` INT(11) NOT NULL, `hashlistId` INT(11) NOT NULL, `hash` MEDIUMTEXT NOT NULL, @@ -249,11 +276,11 @@ CREATE TABLE `Hash` ( `crackPos` BIGINT NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `HashBinary` ( +CREATE TABLE IF NOT EXISTS `HashBinary` ( `hashBinaryId` INT(11) NOT NULL, `hashlistId` INT(11) NOT NULL, `essid` VARCHAR(100) NOT NULL, - `hash` LONGTEXT NOT NULL, + `hash` LONGTEXT NOT NULL, `plaintext` VARCHAR(1024) DEFAULT NULL, `timeCracked` BIGINT DEFAULT NULL, `chunkId` INT(11) DEFAULT NULL, @@ -261,7 +288,7 @@ CREATE TABLE `HashBinary` ( `crackPos` BIGINT NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `Hashlist` ( +CREATE TABLE IF NOT EXISTS `Hashlist` ( `hashlistId` INT(11) NOT NULL, `hashlistName` VARCHAR(100) NOT NULL, `format` INT(11) NOT NULL, @@ -279,13 +306,13 @@ CREATE TABLE `Hashlist` ( `isArchived` TINYINT(4) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `HashlistHashlist` ( +CREATE TABLE IF NOT EXISTS `HashlistHashlist` ( `hashlistHashlistId` INT(11) NOT NULL, `parentHashlistId` INT(11) NOT NULL, `hashlistId` INT(11) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `HashType` ( +CREATE TABLE IF NOT EXISTS `HashType` ( `hashTypeId` INT(11) NOT NULL, `description` VARCHAR(256) NOT NULL, `isSalted` TINYINT(4) NOT NULL, @@ -874,7 +901,49 @@ INSERT INTO `HashType` (`hashTypeId`, `description`, `isSalted`, `isSlowHash`) V (73000, 'Generic Hash [Bridged: Python Interpreter with GIL]', 0, 1), (99999, 'Plaintext', 0, 0); -CREATE TABLE `LogEntry` ( +CREATE TABLE IF NOT EXISTS `HealthCheck` ( + `healthCheckId` INT(11) NOT NULL, + `time` BIGINT(20) NOT NULL, + `status` INT(11) NOT NULL, + `checkType` INT(11) NOT NULL, + `hashtypeId` INT(11) NOT NULL, + `crackerBinaryId` INT(11) NOT NULL, + `expectedCracks` INT(11) NOT NULL, + `attackCmd` TEXT NOT NULL +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS `HealthCheckAgent` ( + `healthCheckAgentId` INT(11) NOT NULL, + `healthCheckId` INT(11) NOT NULL, + `agentId` INT(11) NOT NULL, + `status` INT(11) NOT NULL, + `cracked` INT(11) NOT NULL, + `numGpus` INT(11) NOT NULL, + `start` BIGINT(20) NOT NULL, + `htp_end` BIGINT(20) NOT NULL, + `errors` TEXT NOT NULL +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS `htp_User` ( + `userId` INT(11) NOT NULL, + `username` VARCHAR(100) NOT NULL, + `email` VARCHAR(150) NOT NULL, + `passwordHash` VARCHAR(256) NOT NULL, + `passwordSalt` VARCHAR(256) NOT NULL, + `isValid` TINYINT(4) NOT NULL, + `isComputedPassword` TINYINT(4) NOT NULL, + `lastLoginDate` BIGINT NOT NULL, + `registeredSince` BIGINT NOT NULL, + `sessionLifetime` INT(11) NOT NULL, + `rightGroupId` INT(11) NOT NULL, + `yubikey` VARCHAR(256) DEFAULT NULL, + `otp1` VARCHAR(256) DEFAULT NULL, + `otp2` VARCHAR(256) DEFAULT NULL, + `otp3` VARCHAR(256) DEFAULT NULL, + `otp4` VARCHAR(256) DEFAULT NULL +) ENGINE = InnoDB; + +CREATE TABLE IF NOT EXISTS `LogEntry` ( `logEntryId` INT(11) NOT NULL, `issuer` VARCHAR(50) NOT NULL, `issuerId` VARCHAR(50) NOT NULL, @@ -883,7 +952,7 @@ CREATE TABLE `LogEntry` ( `time` BIGINT NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `NotificationSetting` ( +CREATE TABLE IF NOT EXISTS `NotificationSetting` ( `notificationSettingId` INT(11) NOT NULL, `action` VARCHAR(50) NOT NULL, `objectId` INT(11) NULL, @@ -893,7 +962,17 @@ CREATE TABLE `NotificationSetting` ( `isActive` TINYINT(4) NOT NULL )ENGINE = InnoDB; -CREATE TABLE `Pretask` ( +CREATE TABLE IF NOT EXISTS `Preprocessor` ( + `preprocessorId` INT(11) NOT NULL, + `name` VARCHAR(256) NOT NULL, + `url` VARCHAR(512) NOT NULL, + `binaryName` VARCHAR(256) NOT NULL, + `keyspaceCommand` VARCHAR(256) NULL, + `skipCommand` VARCHAR(256) NULL, + `limitCommand` VARCHAR(256) NULL +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS `Pretask` ( `pretaskId` INT(11) NOT NULL, `taskName` VARCHAR(100) NOT NULL, `attackCmd` TEXT NOT NULL, @@ -909,13 +988,13 @@ CREATE TABLE `Pretask` ( `crackerBinaryTypeId` INT(11) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `RegVoucher` ( +CREATE TABLE IF NOT EXISTS `RegVoucher` ( `regVoucherId` INT(11) NOT NULL, `voucher` VARCHAR(100) NOT NULL, `time` BIGINT NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `RightGroup` ( +CREATE TABLE IF NOT EXISTS `RightGroup` ( `rightGroupId` INT(11) NOT NULL, `groupName` VARCHAR(50) NOT NULL, `permissions` TEXT NOT NULL @@ -924,7 +1003,7 @@ CREATE TABLE `RightGroup` ( INSERT INTO `RightGroup` (`rightGroupId`, `groupName`, `permissions`) VALUES (1, 'Administrator', 'ALL'); -CREATE TABLE `Session` ( +CREATE TABLE IF NOT EXISTS `Session` ( `sessionId` INT(11) NOT NULL, `userId` INT(11) NOT NULL, `sessionStartDate` BIGINT NOT NULL, @@ -934,7 +1013,7 @@ CREATE TABLE `Session` ( `sessionKey` VARCHAR(256) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `Speed` ( +CREATE TABLE IF NOT EXISTS `Speed` ( `speedId` INT(11) NOT NULL, `agentId` INT(11) NOT NULL, `taskId` INT(11) NOT NULL, @@ -942,23 +1021,23 @@ CREATE TABLE `Speed` ( `time` BIGINT(20) NOT NULL ) ENGINE=InnoDB; -CREATE TABLE `StoredValue` ( +CREATE TABLE IF NOT EXISTS `StoredValue` ( `storedValueId` VARCHAR(50) NOT NULL, `val` VARCHAR(256) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `Supertask` ( +CREATE TABLE IF NOT EXISTS `Supertask` ( `supertaskId` INT(11) NOT NULL, `supertaskName` VARCHAR(50) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `SupertaskPretask` ( +CREATE TABLE IF NOT EXISTS `SupertaskPretask` ( `supertaskPretaskId` INT(11) NOT NULL, `supertaskId` INT(11) NOT NULL, `pretaskId` INT(11) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `Task` ( +CREATE TABLE IF NOT EXISTS `Task` ( `taskId` INT(11) NOT NULL, `taskName` VARCHAR(256) NOT NULL, `attackCmd` TEXT NOT NULL, @@ -985,13 +1064,13 @@ CREATE TABLE `Task` ( `preprocessorCommand` VARCHAR(256) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `TaskDebugOutput` ( +CREATE TABLE IF NOT EXISTS `TaskDebugOutput` ( `taskDebugOutputId` INT(11) NOT NULL, `taskId` INT(11) NOT NULL, `output` VARCHAR(256) NOT NULL ) ENGINE=InnoDB; - -CREATE TABLE `TaskWrapper` ( + +CREATE TABLE IF NOT EXISTS `TaskWrapper` ( `taskWrapperId` INT(11) NOT NULL, `priority` INT(11) NOT NULL, `maxAgents` INT(11) NOT NULL, @@ -1003,26 +1082,7 @@ CREATE TABLE `TaskWrapper` ( `cracked` INT(11) NOT NULL )ENGINE = InnoDB; -CREATE TABLE `htp_User` ( - `userId` INT(11) NOT NULL, - `username` VARCHAR(100) NOT NULL, - `email` VARCHAR(150) NOT NULL, - `passwordHash` VARCHAR(256) NOT NULL, - `passwordSalt` VARCHAR(256) NOT NULL, - `isValid` TINYINT(4) NOT NULL, - `isComputedPassword` TINYINT(4) NOT NULL, - `lastLoginDate` BIGINT NOT NULL, - `registeredSince` BIGINT NOT NULL, - `sessionLifetime` INT(11) NOT NULL, - `rightGroupId` INT(11) NOT NULL, - `yubikey` VARCHAR(256) DEFAULT NULL, - `otp1` VARCHAR(256) DEFAULT NULL, - `otp2` VARCHAR(256) DEFAULT NULL, - `otp3` VARCHAR(256) DEFAULT NULL, - `otp4` VARCHAR(256) DEFAULT NULL -) ENGINE = InnoDB; - -CREATE TABLE `Zap` ( +CREATE TABLE IF NOT EXISTS `Zap` ( `zapId` INT(11) NOT NULL, `hash` MEDIUMTEXT NOT NULL, `solveTime` BIGINT NOT NULL, @@ -1030,65 +1090,6 @@ CREATE TABLE `Zap` ( `hashlistId` INT(11) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `ApiKey` ( - `apiKeyId` INT(11) NOT NULL, - `startValid` BIGINT(20) NOT NULL, - `endValid` BIGINT(20) NOT NULL, - `accessKey` VARCHAR(256) NOT NULL, - `accessCount` INT(11) NOT NULL, - `userId` INT(11) NOT NULL, - `apiGroupId` INT(11) NOT NULL -) ENGINE=InnoDB; - -CREATE TABLE `ApiGroup` ( - `apiGroupId` INT(11) NOT NULL, - `name` VARCHAR(100) NOT NULL, - `permissions` TEXT NOT NULL -) ENGINE=InnoDB; - -CREATE TABLE `FileDownload` ( - `fileDownloadId` INT(11) NOT NULL, - `time` BIGINT NOT NULL, - `fileId` INT(11) NOT NULL, - `status` INT(11) NOT NULL -) ENGINE=InnoDB; - -INSERT INTO `ApiGroup` ( `apiGroupId`, `name`, `permissions`) VALUES - (1, 'Administrators', 'ALL'); - -CREATE TABLE `HealthCheck` ( - `healthCheckId` INT(11) NOT NULL, - `time` BIGINT(20) NOT NULL, - `status` INT(11) NOT NULL, - `checkType` INT(11) NOT NULL, - `hashtypeId` INT(11) NOT NULL, - `crackerBinaryId` INT(11) NOT NULL, - `expectedCracks` INT(11) NOT NULL, - `attackCmd` TEXT NOT NULL -) ENGINE=InnoDB; - -CREATE TABLE `HealthCheckAgent` ( - `healthCheckAgentId` INT(11) NOT NULL, - `healthCheckId` INT(11) NOT NULL, - `agentId` INT(11) NOT NULL, - `status` INT(11) NOT NULL, - `cracked` INT(11) NOT NULL, - `numGpus` INT(11) NOT NULL, - `start` BIGINT(20) NOT NULL, - `htp_end` BIGINT(20) NOT NULL, - `errors` TEXT NOT NULL -) ENGINE=InnoDB; - -CREATE TABLE `Preprocessor` ( - `preprocessorId` INT(11) NOT NULL, - `name` VARCHAR(256) NOT NULL, - `url` VARCHAR(512) NOT NULL, - `binaryName` VARCHAR(256) NOT NULL, - `keyspaceCommand` VARCHAR(256) NULL, - `skipCommand` VARCHAR(256) NULL, - `limitCommand` VARCHAR(256) NULL -) ENGINE=InnoDB; - INSERT INTO `Preprocessor` ( `preprocessorId`, `name`, `url`, `binaryName`, `keyspaceCommand`, `skipCommand`, `limitCommand`) VALUES (1, 'Prince', 'https://github.com/hashcat/princeprocessor/releases/download/v0.22/princeprocessor-0.22.7z', 'pp', '--keyspace', '--skip', '--limit'); @@ -1209,6 +1210,11 @@ ALTER TABLE `HealthCheck` ALTER TABLE `HealthCheckAgent` ADD PRIMARY KEY (`healthCheckAgentId`); +ALTER TABLE `htp_User` + ADD PRIMARY KEY (`userId`), + ADD UNIQUE KEY `username` (`username`), + ADD KEY `rightGroupId` (`rightGroupId`); + ALTER TABLE `LogEntry` ADD PRIMARY KEY (`logEntryId`); @@ -1259,11 +1265,6 @@ ALTER TABLE `TaskWrapper` ADD KEY `isArchived` (`isArchived`), ADD KEY `accessGroupId` (`accessGroupId`); -ALTER TABLE `htp_User` - ADD PRIMARY KEY (`userId`), - ADD UNIQUE KEY `username` (`username`), - ADD KEY `rightGroupId` (`rightGroupId`); - ALTER TABLE `Zap` ADD PRIMARY KEY (`zapId`), ADD KEY `agentId` (`agentId`), @@ -1274,7 +1275,8 @@ ALTER TABLE `Preprocessor` -- Add AUTO_INCREMENT for tables ALTER TABLE `AccessGroup` - MODIFY `accessGroupId` INT(11) NOT NULL AUTO_INCREMENT; + MODIFY `accessGroupId` INT(11) NOT NULL AUTO_INCREMENT, + AUTO_INCREMENT = 2; ALTER TABLE `AccessGroupAgent` MODIFY `accessGroupAgentId` INT(11) NOT NULL AUTO_INCREMENT; @@ -1359,6 +1361,9 @@ ALTER TABLE `HealthCheck` ALTER TABLE `HealthCheckAgent` MODIFY `healthCheckAgentId` INT(11) NOT NULL AUTO_INCREMENT; +ALTER TABLE `htp_User` + MODIFY `userId` INT(11) NOT NULL AUTO_INCREMENT; + ALTER TABLE `LogEntry` MODIFY `logEntryId` INT(11) NOT NULL AUTO_INCREMENT; @@ -1396,9 +1401,6 @@ ALTER TABLE `TaskDebugOutput` ALTER TABLE `TaskWrapper` MODIFY `taskWrapperId` INT(11) NOT NULL AUTO_INCREMENT; -ALTER TABLE `htp_User` - MODIFY `userId` INT(11) NOT NULL AUTO_INCREMENT; - ALTER TABLE `Zap` MODIFY `zapId` INT(11) NOT NULL AUTO_INCREMENT; @@ -1412,10 +1414,10 @@ ALTER TABLE `AccessGroupAgent` ALTER TABLE `AccessGroupUser` ADD CONSTRAINT `AccessGroupUser_ibfk_1` FOREIGN KEY (`accessGroupId`) REFERENCES `AccessGroup` (`accessGroupId`), - ADD CONSTRAINT `AccessGroupUser_ibfk_2` FOREIGN KEY (`userId`) REFERENCES `User` (`userId`); + ADD CONSTRAINT `AccessGroupUser_ibfk_2` FOREIGN KEY (`userId`) REFERENCES `htp_User` (`userId`); ALTER TABLE `Agent` - ADD CONSTRAINT `Agent_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `User` (`userId`); + ADD CONSTRAINT `Agent_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `htp_User` (`userId`); ALTER TABLE `AgentError` ADD CONSTRAINT `AgentError_ibfk_1` FOREIGN KEY (`agentId`) REFERENCES `Agent` (`agentId`), @@ -1429,7 +1431,7 @@ ALTER TABLE `AgentZap` ADD CONSTRAINT `AgentZap_ibfk_2` FOREIGN KEY (`lastZapId`) REFERENCES `Zap` (`zapId`); ALTER TABLE `ApiKey` - ADD CONSTRAINT `ApiKey_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `User` (`userId`), + ADD CONSTRAINT `ApiKey_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `htp_User` (`userId`), ADD CONSTRAINT `ApiKey_ibfk_2` FOREIGN KEY (`apiGroupId`) REFERENCES `ApiGroup` (`apiGroupId`); ALTER TABLE `Assignment` @@ -1483,14 +1485,17 @@ ALTER TABLE `HealthCheckAgent` ADD CONSTRAINT `HealthCheckAgent_ibfk_1` FOREIGN KEY (`agentId`) REFERENCES `Agent` (`agentId`), ADD CONSTRAINT `HealthCheckAgent_ibfk_2` FOREIGN KEY (`healthCheckId`) REFERENCES `HealthCheck` (`healthCheckId`); +ALTER TABLE `htp_User` + ADD CONSTRAINT `User_ibfk_1` FOREIGN KEY (`rightGroupId`) REFERENCES `RightGroup` (`rightGroupId`); + ALTER TABLE `NotificationSetting` - ADD CONSTRAINT `NotificationSetting_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `User` (`userId`); + ADD CONSTRAINT `NotificationSetting_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `htp_User` (`userId`); ALTER TABLE `Pretask` ADD CONSTRAINT `Pretask_ibfk_1` FOREIGN KEY (`crackerBinaryTypeId`) REFERENCES `CrackerBinaryType` (`crackerBinaryTypeId`); ALTER TABLE `Session` - ADD CONSTRAINT `Session_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `User` (`userId`); + ADD CONSTRAINT `Session_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `htp_User` (`userId`); ALTER TABLE `Speed` ADD CONSTRAINT `Speed_ibfk_1` FOREIGN KEY (`agentId`) REFERENCES `Agent` (`agentId`), @@ -1512,9 +1517,6 @@ ALTER TABLE `TaskWrapper` ADD CONSTRAINT `TaskWrapper_ibfk_1` FOREIGN KEY (`hashlistId`) REFERENCES `Hashlist` (`hashlistId`), ADD CONSTRAINT `TaskWrapper_ibfk_2` FOREIGN KEY (`accessGroupId`) REFERENCES `AccessGroup` (`accessGroupId`); -ALTER TABLE `htp_User` - ADD CONSTRAINT `User_ibfk_1` FOREIGN KEY (`rightGroupId`) REFERENCES `RightGroup` (`rightGroupId`); - ALTER TABLE `Zap` ADD CONSTRAINT `Zap_ibfk_1` FOREIGN KEY (`agentId`) REFERENCES `Agent` (`agentId`), ADD CONSTRAINT `Zap_ibfk_2` FOREIGN KEY (`hashlistId`) REFERENCES `Hashlist` (`hashlistId`); diff --git a/src/migrations/postgres/20251127000000_initial.sql b/src/migrations/postgres/20251127000000_initial.sql new file mode 100644 index 000000000..cbf8aec8a --- /dev/null +++ b/src/migrations/postgres/20251127000000_initial.sql @@ -0,0 +1,1282 @@ +-- Create tables and insert default entries +CREATE TABLE AccessGroup ( + accessGroupId SERIAL NOT NULL PRIMARY KEY, + groupName TEXT NOT NULL +); + +INSERT INTO AccessGroup (accessGroupId, groupName) VALUES + (1, 'Default Group'); + +CREATE TABLE AccessGroupAgent ( + accessGroupAgentId SERIAL NOT NULL PRIMARY KEY, + accessGroupId INT NOT NULL, + agentId INT NOT NULL +); + +CREATE TABLE AccessGroupUser ( + accessGroupUserId SERIAL NOT NULL PRIMARY KEY, + accessGroupId INT NOT NULL, + userId INT NOT NULL +); + +CREATE TABLE Agent ( + agentId SERIAL NOT NULL PRIMARY KEY, + agentName TEXT NOT NULL, + uid TEXT NOT NULL, + os INT NOT NULL, + devices TEXT NOT NULL, + cmdPars TEXT NOT NULL, + ignoreErrors INT NOT NULL, + isActive INT NOT NULL, + isTrusted INT NOT NULL, + token TEXT NOT NULL, + lastAct TEXT NOT NULL, + lastTime BIGINT NOT NULL, + lastIp TEXT NOT NULL, + userId INT DEFAULT NULL, + cpuOnly INT NOT NULL, + clientSignature TEXT NOT NULL +); + +CREATE TABLE AgentBinary ( + agentBinaryId SERIAL NOT NULL PRIMARY KEY, + binaryType TEXT NOT NULL, + version TEXT NOT NULL, + operatingSystems TEXT NOT NULL, + filename TEXT NOT NULL, + updateTrack TEXT NOT NULL, + updateAvailable TEXT NOT NULL +); + +INSERT INTO AgentBinary (agentBinaryId, binaryType, version, operatingSystems, filename, updateTrack, updateAvailable) VALUES + (1, 'python', '0.7.4', 'Windows, Linux, OS X', 'hashtopolis.zip', 'stable', ''); + +CREATE TABLE AgentError ( + agentErrorId SERIAL NOT NULL PRIMARY KEY, + agentId INT NOT NULL, + taskId INT DEFAULT NULL, + time BIGINT NOT NULL, + error TEXT NOT NULL, + chunkId INT NULL +); + +CREATE TABLE AgentStat ( + agentStatId SERIAL NOT NULL PRIMARY KEY, + agentId INT NOT NULL, + statType INT NOT NULL, + time BIGINT NOT NULL, + value TEXT NOT NULL +); + +CREATE TABLE AgentZap ( + agentZapId SERIAL NOT NULL PRIMARY KEY, + agentId INT NOT NULL, + lastZapId INT NULL +); + +CREATE TABLE ApiKey ( + apiKeyId SERIAL NOT NULL PRIMARY KEY, + startValid BIGINT NOT NULL, + endValid BIGINT NOT NULL, + accessKey TEXT NOT NULL, + accessCount INT NOT NULL, + userId INT NOT NULL, + apiGroupId INT NOT NULL +); + +CREATE TABLE ApiGroup ( + apiGroupId SERIAL NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + permissions TEXT NOT NULL +); + +INSERT INTO ApiGroup ( apiGroupId, name, permissions) VALUES + (1, 'Administrators', 'ALL'); + +CREATE TABLE Assignment ( + assignmentId SERIAL NOT NULL PRIMARY KEY, + taskId INT NOT NULL, + agentId INT NOT NULL, + benchmark TEXT NOT NULL +); + +CREATE TABLE Chunk ( + chunkId SERIAL NOT NULL PRIMARY KEY, + taskId INT NOT NULL, + skip BIGINT NOT NULL, + length BIGINT NOT NULL, + agentId INT NULL, + dispatchTime BIGINT NOT NULL, + solveTime BIGINT NOT NULL, + checkpoint BIGINT NOT NULL, + progress INT NULL, + state INT NOT NULL, + cracked INT NOT NULL, + speed BIGINT NOT NULL +); + +CREATE TABLE Config ( + configId SERIAL NOT NULL PRIMARY KEY, + configSectionId INT NOT NULL, + item TEXT NOT NULL, + value TEXT NOT NULL +); + +INSERT INTO Config (configId, configSectionId, item, value) VALUES + (1, 1, 'agenttimeout', '30'), + (2, 1, 'benchtime', '30'), + (3, 1, 'chunktime', '600'), + (4, 1, 'chunktimeout', '30'), + (9, 1, 'fieldseparator', ':'), + (10, 1, 'hashlistAlias', '#HL#'), + (11, 1, 'statustimer', '5'), + (12, 4, 'timefmt', 'd.m.Y, H:i:s'), + (13, 1, 'blacklistChars', '&|"''{}()[]$<>;'), + (14, 3, 'numLogEntries', '5000'), + (15, 1, 'disptolerance', '20'), + (16, 3, 'batchSize', '50000'), + (18, 2, 'yubikey_id', ''), + (19, 2, 'yubikey_key', ''), + (20, 2, 'yubikey_url', 'https://api.yubico.com/wsapi/2.0/verify'), + (22, 3, 'pagingSize', '5000'), + (23, 3, 'plainTextMaxLength', '200'), + (24, 3, 'hashMaxLength', '1024'), + (25, 5, 'emailSender', 'hashtopolis@example.org'), + (26, 5, 'emailSenderName', 'Hashtopolis'), + (27, 5, 'baseHost', ''), + (28, 3, 'maxHashlistSize', '5000000'), + (29, 4, 'hideImportMasks', '1'), + (30, 7, 'telegramBotToken', ''), + (31, 5, 'contactEmail', ''), + (32, 5, 'voucherDeletion', '0'), + (33, 4, 'hashesPerPage', '1000'), + (34, 4, 'hideIpInfo', '0'), + (35, 1, 'defaultBenchmark', '1'), + (36, 4, 'showTaskPerformance', '0'), + (37, 1, 'ruleSplitSmallTasks', '0'), + (38, 1, 'ruleSplitAlways', '0'), + (39, 1, 'ruleSplitDisable', '1'), + (41, 4, 'agentStatLimit', '100'), + (42, 1, 'agentDataLifetime', '3600'), + (43, 4, 'agentStatTension', '0'), + (44, 6, 'multicastEnable', '0'), + (45, 6, 'multicastDevice', 'eth0'), + (46, 6, 'multicastTransferRateEnable', '0'), + (47, 6, 'multicastTranserRate', '500000'), + (48, 1, 'disableTrimming', '0'), + (49, 5, 'serverLogLevel', '20'), + (50, 7, 'notificationsProxyEnable', '0'), + (60, 7, 'notificationsProxyServer', ''), + (61, 7, 'notificationsProxyPort', '8080'), + (62, 7, 'notificationsProxyType', 'HTTP'), + (63, 1, 'priority0Start', '0'), + (64, 5, 'baseUrl', ''), + (65, 4, 'maxSessionLength', '48'), + (66, 1, 'hashcatBrainEnable', '0'), + (67, 1, 'hashcatBrainHost', ''), + (68, 1, 'hashcatBrainPort', '0'), + (69, 1, 'hashcatBrainPass', ''), + (70, 1, 'hashlistImportCheck', '0'), + (71, 5, 'allowDeregister', '0'), + (72, 4, 'agentTempThreshold1', '70'), + (73, 4, 'agentTempThreshold2', '80'), + (74, 4, 'agentUtilThreshold1', '90'), + (75, 4, 'agentUtilThreshold2', '75'), + (76, 3, 'uApiSendTaskIsComplete', '0'), + (77, 1, 'hcErrorIgnore', 'DeviceGetFanSpeed'), + (78, 3, 'defaultPageSize', '10000'), + (79, 3, 'maxPageSize', '50000'); + +CREATE TABLE ConfigSection ( + configSectionId SERIAL NOT NULL PRIMARY KEY, + sectionName TEXT NOT NULL +); + +INSERT INTO ConfigSection (configSectionId, sectionName) VALUES + (1, 'Cracking/Tasks'), + (2, 'Yubikey'), + (3, 'Finetuning'), + (4, 'UI'), + (5, 'Server'), + (6, 'Multicast'), + (7, 'Notifications'); + +CREATE TABLE CrackerBinary ( + crackerBinaryId SERIAL NOT NULL PRIMARY KEY, + crackerBinaryTypeId INT NOT NULL, + version TEXT NOT NULL, + downloadUrl TEXT NOT NULL, + binaryName TEXT NOT NULL +); + +INSERT INTO CrackerBinary (crackerBinaryId, crackerBinaryTypeId, version, downloadUrl, binaryName) VALUES + (1, 1, '7.1.2', 'https://hashcat.net/files/hashcat-7.1.2.7z', 'hashcat'); + +CREATE TABLE CrackerBinaryType ( + crackerBinaryTypeId SERIAL NOT NULL PRIMARY KEY, + typeName TEXT NOT NULL, + isChunkingAvailable INT NOT NULL +); + +INSERT INTO CrackerBinaryType (crackerBinaryTypeId, typeName, isChunkingAvailable) VALUES + (1, 'hashcat', 1); + +CREATE TABLE File ( + fileId SERIAL NOT NULL PRIMARY KEY, + filename TEXT NOT NULL, + size BIGINT NOT NULL, + isSecret INT NOT NULL, + fileType INT NOT NULL, + accessGroupId INT NOT NULL, + lineCount BIGINT DEFAULT NULL +); + +CREATE TABLE FileDelete ( + fileDeleteId SERIAL NOT NULL PRIMARY KEY, + filename TEXT NOT NULL, + time BIGINT NOT NULL +); + +CREATE TABLE FileDownload ( + fileDownloadId SERIAL NOT NULL PRIMARY KEY, + time BIGINT NOT NULL, + fileId INT NOT NULL, + status INT NOT NULL +); + +CREATE TABLE FilePretask ( + filePretaskId SERIAL NOT NULL PRIMARY KEY, + fileId INT NOT NULL, + pretaskId INT NOT NULL +); + +CREATE TABLE FileTask ( + fileTaskId SERIAL NOT NULL PRIMARY KEY, + fileId INT NOT NULL, + taskId INT NOT NULL +); + +CREATE TABLE Hash ( + hashId SERIAL NOT NULL PRIMARY KEY, + hashlistId INT NOT NULL, + hash TEXT NOT NULL, + salt TEXT DEFAULT NULL, + plaintext TEXT DEFAULT NULL, + timeCracked BIGINT DEFAULT NULL, + chunkId INT DEFAULT NULL, + isCracked INT NOT NULL, + crackPos BIGINT NOT NULL +); + +CREATE TABLE HashBinary ( + hashBinaryId SERIAL NOT NULL PRIMARY KEY, + hashlistId INT NOT NULL, + essid TEXT NOT NULL, + hash TEXT NOT NULL, + plaintext TEXT DEFAULT NULL, + timeCracked BIGINT DEFAULT NULL, + chunkId INT DEFAULT NULL, + isCracked INT NOT NULL, + crackPos BIGINT NOT NULL +); + +CREATE TABLE Hashlist ( + hashlistId SERIAL NOT NULL PRIMARY KEY, + hashlistName TEXT NOT NULL, + format INT NOT NULL, + hashTypeId INT NOT NULL, + hashCount INT NOT NULL, + saltSeparator TEXT DEFAULT NULL, + cracked INT NOT NULL, + isSecret INT NOT NULL, + hexSalt INT NOT NULL, + isSalted INT NOT NULL, + accessGroupId INT NOT NULL, + notes TEXT NOT NULL, + brainId INT NOT NULL, + brainFeatures INT NOT NULL, + isArchived INT NOT NULL +); + +CREATE TABLE HashlistHashlist ( + hashlistHashlistId SERIAL NOT NULL PRIMARY KEY, + parentHashlistId INT NOT NULL, + hashlistId INT NOT NULL +); + +CREATE TABLE HashType ( + hashTypeId SERIAL NOT NULL PRIMARY KEY, + description TEXT NOT NULL, + isSalted INT NOT NULL, + isSlowHash INT NOT NULL +); + +INSERT INTO HashType (hashTypeId, description, isSalted, isSlowHash) VALUES + (0, 'MD5', 0, 0), + (10, 'md5($pass.$salt)', 1, 0), + (11, 'Joomla < 2.5.18', 1, 0), + (12, 'PostgreSQL', 1, 0), + (20, 'md5($salt.$pass)', 1, 0), + (21, 'osCommerce, xt:Commerce', 1, 0), + (22, 'Juniper Netscreen/SSG (ScreenOS)', 1, 0), + (23, 'Skype', 1, 0), + (24, 'SolarWinds Serv-U', 0, 0), + (30, 'md5(utf16le($pass).$salt)', 1, 0), + (40, 'md5($salt.utf16le($pass))', 1, 0), + (50, 'HMAC-MD5 (key = $pass)', 1, 0), + (60, 'HMAC-MD5 (key = $salt)', 1, 0), + (70, 'md5(utf16le($pass))', 0, 0), + (100, 'SHA1', 0, 0), + (101, 'nsldap, SHA-1(Base64), Netscape LDAP SHA', 0, 0), + (110, 'sha1($pass.$salt)', 1, 0), + (111, 'nsldaps, SSHA-1(Base64), Netscape LDAP SSHA', 0, 0), + (112, 'Oracle S: Type (Oracle 11+)', 1, 0), + (120, 'sha1($salt.$pass)', 1, 0), + (121, 'SMF >= v1.1', 1, 0), + (122, 'OS X v10.4, v10.5, v10.6', 0, 0), + (124, 'Django (SHA-1)', 0, 0), + (125, 'ArubaOS', 0, 0), + (130, 'sha1(utf16le($pass).$salt)', 1, 0), + (131, 'MSSQL(2000)', 0, 0), + (132, 'MSSQL(2005)', 0, 0), + (133, 'PeopleSoft', 0, 0), + (140, 'sha1($salt.utf16le($pass))', 1, 0), + (141, 'EPiServer 6.x < v4', 0, 0), + (150, 'HMAC-SHA1 (key = $pass)', 1, 0), + (160, 'HMAC-SHA1 (key = $salt)', 1, 0), + (170, 'sha1(utf16le($pass))', 0, 0), + (200, 'MySQL323', 0, 0), + (300, 'MySQL4.1/MySQL5+', 0, 0), + (400, 'phpass, MD5(Wordpress), MD5(Joomla), MD5(phpBB3)', 0, 0), + (500, 'md5crypt, MD5(Unix), FreeBSD MD5, Cisco-IOS MD5 2', 0, 0), + (501, 'Juniper IVE', 0, 0), + (600, 'BLAKE2b-512', 0, 0), + (610, 'BLAKE2b-512($pass.$salt)', 1, 0), + (620, 'BLAKE2b-512($salt.$pass)', 1, 0), + (900, 'MD4', 0, 0), + (1000, 'NTLM', 0, 0), + (1100, 'Domain Cached Credentials (DCC), MS Cache', 1, 0), + (1300, 'SHA-224', 0, 0), + (1310, 'sha224($pass.$salt)', 1, 0), + (1320, 'sha224($salt.$pass)', 1, 0), + (1400, 'SHA256', 0, 0), + (1410, 'sha256($pass.$salt)', 1, 0), + (1411, 'SSHA-256(Base64), LDAP {SSHA256}', 0, 0), + (1420, 'sha256($salt.$pass)', 1, 0), + (1421, 'hMailServer', 0, 0), + (1430, 'sha256(utf16le($pass).$salt)', 1, 0), + (1440, 'sha256($salt.utf16le($pass))', 1, 0), + (1441, 'EPiServer 6.x >= v4', 0, 0), + (1450, 'HMAC-SHA256 (key = $pass)', 1, 0), + (1460, 'HMAC-SHA256 (key = $salt)', 1, 0), + (1470, 'sha256(utf16le($pass))', 0, 0), + (1500, 'descrypt, DES(Unix), Traditional DES', 0, 0), + (1600, 'md5apr1, MD5(APR), Apache MD5', 0, 0), + (1700, 'SHA512', 0, 0), + (1710, 'sha512($pass.$salt)', 1, 0), + (1711, 'SSHA-512(Base64), LDAP {SSHA512}', 0, 0), + (1720, 'sha512($salt.$pass)', 1, 0), + (1722, 'OS X v10.7', 0, 0), + (1730, 'sha512(utf16le($pass).$salt)', 1, 0), + (1731, 'MSSQL(2012), MSSQL(2014)', 0, 0), + (1740, 'sha512($salt.utf16le($pass))', 1, 0), + (1750, 'HMAC-SHA512 (key = $pass)', 1, 0), + (1760, 'HMAC-SHA512 (key = $salt)', 1, 0), + (1770, 'sha512(utf16le($pass))', 0, 0), + (1800, 'sha512crypt, SHA512(Unix)', 0, 0), + (2000, 'STDOUT', 0, 0), + (2100, 'Domain Cached Credentials 2 (DCC2), MS Cache', 0, 1), + (2400, 'Cisco-PIX MD5', 0, 0), + (2410, 'Cisco-ASA MD5', 1, 0), + (2500, 'WPA/WPA2', 0, 1), + (2501, 'WPA-EAPOL-PMK', 0, 1), + (2600, 'md5(md5($pass))', 0, 0), + (2611, 'vBulletin < v3.8.5', 1, 0), + (2612, 'PHPS', 0, 0), + (2630, 'md5(md5($pass.$salt))', 1, 0), + (2711, 'vBulletin >= v3.8.5', 1, 0), + (2811, 'IPB2+, MyBB1.2+', 1, 0), + (3000, 'LM', 0, 0), + (3100, 'Oracle H: Type (Oracle 7+), DES(Oracle)', 1, 0), + (3200, 'bcrypt, Blowfish(OpenBSD)', 0, 0), + (3500, 'md5(md5(md5($pass)))', 0, 0), + (3610, 'md5(md5(md5($pass)).$salt)', 1, 0), + (3710, 'md5($salt.md5($pass))', 1, 0), + (3711, 'Mediawiki B type', 0, 0), + (3730, 'md5($salt1.strtoupper(md5($salt2.$pass)))', 0, 0), + (3800, 'md5($salt.$pass.$salt)', 1, 0), + (3910, 'md5(md5($pass).md5($salt))', 1, 0), + (4010, 'md5($salt.md5($salt.$pass))', 1, 0), + (4110, 'md5($salt.md5($pass.$salt))', 1, 0), + (4300, 'md5(strtoupper(md5($pass)))', 0, 0), + (4400, 'md5(sha1($pass))', 0, 0), + (4410, 'md5(sha1($pass).$salt)', 1, 0), + (4420, 'md5(sha1($pass.$salt))', 1, 0), + (4430, 'md5(sha1($salt.$pass))', 1, 0), + (4500, 'sha1(sha1($pass))', 0, 0), + (4510, 'sha1(sha1($pass).$salt)', 1, 0), + (4520, 'sha1($salt.sha1($pass))', 1, 0), + (4521, 'Redmine Project Management Web App', 0, 0), + (4522, 'PunBB', 0, 0), + (4700, 'sha1(md5($pass))', 0, 0), + (4710, 'sha1(md5($pass).$salt)', 1, 0), + (4711, 'Huawei sha1(md5($pass).$salt)', 1, 0), + (4800, 'MD5(Chap), iSCSI CHAP authentication', 1, 0), + (4900, 'sha1($salt.$pass.$salt)', 1, 0), + (5000, 'SHA-3(Keccak)', 0, 0), + (5100, 'Half MD5', 0, 0), + (5200, 'Password Safe v3', 0, 1), + (5300, 'IKE-PSK MD5', 0, 0), + (5400, 'IKE-PSK SHA1', 0, 0), + (5500, 'NetNTLMv1-VANILLA / NetNTLMv1+ESS', 0, 0), + (5600, 'NetNTLMv2', 0, 0), + (5700, 'Cisco-IOS SHA256', 0, 0), + (5720, 'Cisco-ISE Hashed Password (SHA256)', 0, 0), + (5800, 'Samsung Android Password/PIN', 1, 0), + (6000, 'RipeMD160', 0, 0), + (6050, 'HMAC-RIPEMD160 (key = $pass)', 1, 0), + (6060, 'HMAC-RIPEMD160 (key = $salt)', 1, 0), + (6100, 'Whirlpool', 0, 0), + (6211, 'TrueCrypt 5.0+ PBKDF2-HMAC-RipeMD160 + AES/Serpent/Twofish', 0, 1), + (6212, 'TrueCrypt 5.0+ PBKDF2-HMAC-RipeMD160 + AES-Twofish/Serpent-AES/Twofish-Serpent', 0, 1), + (6213, 'TrueCrypt 5.0+ PBKDF2-HMAC-RipeMD160 + AES-Twofish-Serpent/Serpent-Twofish-AES', 0, 1), + (6221, 'TrueCrypt 5.0+ SHA512 + AES/Serpent/Twofish', 0, 1), + (6222, 'TrueCrypt 5.0+ SHA512 + AES-Twofish/Serpent-AES/Twofish-Serpent', 0, 1), + (6223, 'TrueCrypt 5.0+ SHA512 + AES-Twofish-Serpent/Serpent-Twofish-AES', 0, 1), + (6231, 'TrueCrypt 5.0+ Whirlpool + AES/Serpent/Twofish', 0, 1), + (6232, 'TrueCrypt 5.0+ Whirlpool + AES-Twofish/Serpent-AES/Twofish-Serpent', 0, 1), + (6233, 'TrueCrypt 5.0+ Whirlpool + AES-Twofish-Serpent/Serpent-Twofish-AES', 0, 1), + (6241, 'TrueCrypt 5.0+ PBKDF2-HMAC-RipeMD160 + AES/Serpent/Twofish + boot', 0, 1), + (6242, 'TrueCrypt 5.0+ PBKDF2-HMAC-RipeMD160 + AES-Twofish/Serpent-AES/Twofish-Serpent + boot', 0, 1), + (6243, 'TrueCrypt 5.0+ PBKDF2-HMAC-RipeMD160 + AES-Twofish-Serpent/Serpent-Twofish-AES + boot', 0, 1), + (6300, 'AIX {smd5}', 0, 0), + (6400, 'AIX {ssha256}', 0, 1), + (6500, 'AIX {ssha512}', 0, 1), + (6600, '1Password, Agile Keychain', 0, 1), + (6700, 'AIX {ssha1}', 0, 1), + (6800, 'Lastpass', 1, 1), + (6900, 'GOST R 34.11-94', 0, 0), + (7000, 'Fortigate (FortiOS)', 0, 0), + (7100, 'OS X v10.8 / v10.9', 0, 1), + (7200, 'GRUB 2', 0, 1), + (7300, 'IPMI2 RAKP HMAC-SHA1', 1, 0), + (7350, 'IPMI2 RAKP HMAC-MD5', 0, 0), + (7400, 'sha256crypt, SHA256(Unix)', 0, 0), + (7401, 'MySQL $A$ (sha256crypt)', 0, 0), + (7500, 'Kerberos 5 AS-REQ Pre-Auth', 0, 0), + (7700, 'SAP CODVN B (BCODE)', 0, 0), + (7701, 'SAP CODVN B (BCODE) from RFC_READ_TABLE', 0, 0), + (7800, 'SAP CODVN F/G (PASSCODE)', 0, 0), + (7801, 'SAP CODVN F/G (PASSCODE) from RFC_READ_TABLE', 0, 0), + (7900, 'Drupal7', 0, 0), + (8000, 'Sybase ASE', 0, 0), + (8100, 'Citrix Netscaler', 0, 0), + (8200, '1Password, Cloud Keychain', 0, 1), + (8300, 'DNSSEC (NSEC3)', 1, 0), + (8400, 'WBB3, Woltlab Burning Board 3', 1, 0), + (8500, 'RACF', 0, 0), + (8501, 'AS/400 DES', 0, 0), + (8600, 'Lotus Notes/Domino 5', 0, 0), + (8700, 'Lotus Notes/Domino 6', 0, 0), + (8800, 'Android FDE <= 4.3', 0, 1), + (8900, 'scrypt', 1, 0), + (9000, 'Password Safe v2', 0, 0), + (9100, 'Lotus Notes/Domino', 0, 1), + (9200, 'Cisco $8$', 0, 1), + (9300, 'Cisco $9$', 0, 0), + (9400, 'Office 2007', 0, 1), + (9500, 'Office 2010', 0, 1), + (9600, 'Office 2013', 0, 1), + (9700, 'MS Office ⇐ 2003 MD5 + RC4, oldoffice$0, oldoffice$1', 0, 0), + (9710, 'MS Office <= 2003 $0/$1, MD5 + RC4, collider #1', 0, 0), + (9720, 'MS Office <= 2003 $0/$1, MD5 + RC4, collider #2', 0, 0), + (9800, 'MS Office ⇐ 2003 SHA1 + RC4, oldoffice$3, oldoffice$4', 0, 0), + (9810, 'MS Office <= 2003 $3, SHA1 + RC4, collider #1', 0, 0), + (9820, 'MS Office <= 2003 $3, SHA1 + RC4, collider #2', 0, 0), + (9900, 'Radmin2', 0, 0), + (10000, 'Django (PBKDF2-SHA256)', 0, 1), + (10100, 'SipHash', 1, 0), + (10200, 'Cram MD5', 0, 0), + (10300, 'SAP CODVN H (PWDSALTEDHASH) iSSHA-1', 0, 0), + (10400, 'PDF 1.1 - 1.3 (Acrobat 2 - 4)', 0, 0), + (10410, 'PDF 1.1 - 1.3 (Acrobat 2 - 4), collider #1', 0, 0), + (10420, 'PDF 1.1 - 1.3 (Acrobat 2 - 4), collider #2', 0, 0), + (10500, 'PDF 1.4 - 1.6 (Acrobat 5 - 8)', 0, 0), + (10510, 'PDF 1.3 - 1.6 (Acrobat 4 - 8) w/ RC4-40', 0, 1), + (10600, 'PDF 1.7 Level 3 (Acrobat 9)', 0, 0), + (10700, 'PDF 1.7 Level 8 (Acrobat 10 - 11)', 0, 0), + (10800, 'SHA384', 0, 0), + (10810, 'sha384($pass.$salt)', 1, 0), + (10820, 'sha384($salt.$pass)', 1, 0), + (10830, 'sha384(utf16le($pass).$salt)', 1, 0), + (10840, 'sha384($salt.utf16le($pass))', 1, 0), + (10870, 'sha384(utf16le($pass))', 0, 0), + (10900, 'PBKDF2-HMAC-SHA256', 0, 1), + (10901, 'RedHat 389-DS LDAP (PBKDF2-HMAC-SHA256)', 0, 1), + (11000, 'PrestaShop', 1, 0), + (11100, 'PostgreSQL Challenge-Response Authentication (MD5)', 0, 0), + (11200, 'MySQL Challenge-Response Authentication (SHA1)', 0, 0), + (11300, 'Bitcoin/Litecoin wallet.dat', 0, 1), + (11400, 'SIP digest authentication (MD5)', 0, 0), + (11500, 'CRC32', 1, 0), + (11600, '7-Zip', 0, 0), + (11700, 'GOST R 34.11-2012 (Streebog) 256-bit', 0, 0), + (11750, 'HMAC-Streebog-256 (key = $pass), big-endian', 0, 0), + (11760, 'HMAC-Streebog-256 (key = $salt), big-endian', 0, 0), + (11800, 'GOST R 34.11-2012 (Streebog) 512-bit', 0, 0), + (11850, 'HMAC-Streebog-512 (key = $pass), big-endian', 0, 0), + (11860, 'HMAC-Streebog-512 (key = $salt), big-endian', 0, 0), + (11900, 'PBKDF2-HMAC-MD5', 0, 1), + (12000, 'PBKDF2-HMAC-SHA1', 0, 1), + (12001, 'Atlassian (PBKDF2-HMAC-SHA1)', 0, 1), + (12100, 'PBKDF2-HMAC-SHA512', 0, 1), + (12150, 'Apache Shiro 1 SHA-512', 0, 1), + (12200, 'eCryptfs', 0, 1), + (12300, 'Oracle T: Type (Oracle 12+)', 0, 1), + (12400, 'BSDiCrypt, Extended DES', 0, 0), + (12500, 'RAR3-hp', 0, 0), + (12600, 'ColdFusion 10+', 1, 0), + (12700, 'Blockchain, My Wallet', 0, 1), + (12800, 'MS-AzureSync PBKDF2-HMAC-SHA256', 0, 1), + (12900, 'Android FDE (Samsung DEK)', 0, 1), + (13000, 'RAR5', 0, 1), + (13100, 'Kerberos 5 TGS-REP etype 23', 0, 0), + (13200, 'AxCrypt', 0, 0), + (13300, 'AxCrypt in memory SHA1', 0, 0), + (13400, 'Keepass 1/2 AES/Twofish with/without keyfile', 0, 0), + (13500, 'PeopleSoft PS_TOKEN', 1, 0), + (13600, 'WinZip', 0, 1), + (13711, 'VeraCrypt PBKDF2-HMAC-RIPEMD160 + AES, Serpent, Twofish', 0, 1), + (13712, 'VeraCrypt PBKDF2-HMAC-RIPEMD160 + AES-Twofish, Serpent-AES, Twofish-Serpent', 0, 1), + (13713, 'VeraCrypt PBKDF2-HMAC-RIPEMD160 + Serpent-Twofish-AES', 0, 1), + (13721, 'VeraCrypt PBKDF2-HMAC-SHA512 + AES, Serpent, Twofish', 0, 1), + (13722, 'VeraCrypt PBKDF2-HMAC-SHA512 + AES-Twofish, Serpent-AES, Twofish-Serpent', 0, 1), + (13723, 'VeraCrypt PBKDF2-HMAC-SHA512 + Serpent-Twofish-AES', 0, 1), + (13731, 'VeraCrypt PBKDF2-HMAC-Whirlpool + AES, Serpent, Twofish', 0, 1), + (13732, 'VeraCrypt PBKDF2-HMAC-Whirlpool + AES-Twofish, Serpent-AES, Twofish-Serpent', 0, 1), + (13733, 'VeraCrypt PBKDF2-HMAC-Whirlpool + Serpent-Twofish-AES', 0, 1), + (13741, 'VeraCrypt PBKDF2-HMAC-RIPEMD160 + boot-mode + AES', 0, 1), + (13742, 'VeraCrypt PBKDF2-HMAC-RIPEMD160 + boot-mode + AES-Twofish', 0, 1), + (13743, 'VeraCrypt PBKDF2-HMAC-RIPEMD160 + boot-mode + AES-Twofish-Serpent', 0, 1), + (13751, 'VeraCrypt PBKDF2-HMAC-SHA256 + AES, Serpent, Twofish', 0, 1), + (13752, 'VeraCrypt PBKDF2-HMAC-SHA256 + AES-Twofish, Serpent-AES, Twofish-Serpent', 0, 1), + (13753, 'VeraCrypt PBKDF2-HMAC-SHA256 + Serpent-Twofish-AES', 0, 1), + (13761, 'VeraCrypt PBKDF2-HMAC-SHA256 + boot-mode (PIM + AES | Twofish)', 0, 1), + (13762, 'VeraCrypt PBKDF2-HMAC-SHA256 + boot-mode + Serpent-AES', 0, 1), + (13763, 'VeraCrypt PBKDF2-HMAC-SHA256 + boot-mode + Serpent-Twofish-AES', 0, 1), + (13771, 'VeraCrypt Streebog-512 + XTS 512 bit', 0, 1), + (13772, 'VeraCrypt Streebog-512 + XTS 1024 bit', 0, 1), + (13773, 'VeraCrypt Streebog-512 + XTS 1536 bit', 0, 1), + (13781, 'VeraCrypt Streebog-512 + XTS 512 bit + boot-mode (legacy)', 0, 1), + (13782, 'VeraCrypt Streebog-512 + XTS 1024 bit + boot-mode (legacy)', 0, 1), + (13783, 'VeraCrypt Streebog-512 + XTS 1536 bit + boot-mode (legacy)', 0, 1), + (13800, 'Windows 8+ phone PIN/Password', 1, 0), + (13900, 'OpenCart', 1, 0), + (14000, 'DES (PT = $salt, key = $pass)', 1, 0), + (14100, '3DES (PT = $salt, key = $pass)', 1, 0), + (14200, 'RACF KDFAES', 0, 1), + (14400, 'sha1(CX)', 1, 0), + (14500, 'Linux Kernel Crypto API (2.4)', 0, 0), + (14600, 'LUKS 10', 0, 1), + (14700, 'iTunes Backup < 10.0 11', 0, 1), + (14800, 'iTunes Backup >= 10.0 11', 0, 1), + (14900, 'Skip32 12', 1, 0), + (15000, 'FileZilla Server >= 0.9.55', 1, 0), + (15100, 'Juniper/NetBSD sha1crypt', 0, 1), + (15200, 'Blockchain, My Wallet, V2', 0, 0), + (15300, 'DPAPI masterkey file v1 and v2', 0, 1), + (15310, 'DPAPI masterkey file v1 (context 3)', 0, 1), + (15400, 'ChaCha20', 0, 0), + (15500, 'JKS Java Key Store Private Keys (SHA1)', 0, 0), + (15600, 'Ethereum Wallet, PBKDF2-HMAC-SHA256', 0, 1), + (15700, 'Ethereum Wallet, SCRYPT', 0, 0), + (15900, 'DPAPI master key file version 2 + Active Directory domain context', 0, 1), + (15910, 'DPAPI masterkey file v2 (context 3)', 0, 1), + (16000, 'Tripcode', 0, 0), + (16100, 'TACACS+', 0, 0), + (16200, 'Apple Secure Notes', 0, 1), + (16300, 'Ethereum Pre-Sale Wallet, PBKDF2-HMAC-SHA256', 0, 1), + (16400, 'CRAM-MD5 Dovecot', 0, 0), + (16500, 'JWT (JSON Web Token)', 0, 0), + (16501, 'Perl Mojolicious session cookie (HMAC-SHA256, >= v9.19)', 0, 0), + (16600, 'Electrum Wallet (Salt-Type 1-3)', 0, 0), + (16700, 'FileVault 2', 0, 1), + (16800, 'WPA-PMKID-PBKDF2', 0, 1), + (16801, 'WPA-PMKID-PMK', 0, 1), + (16900, 'Ansible Vault', 0, 1), + (17010, 'GPG (AES-128/AES-256 (SHA-1($pass)))', 0, 1), + (17020, 'GPG (AES-128/AES-256 (SHA-512($pass)))', 0, 1), + (17030, 'GPG (AES-128/AES-256 (SHA-256($pass)))', 0, 1), + (17040, 'GPG (CAST5 (SHA-1($pass)))', 0, 1), + (17200, 'PKZIP (Compressed)', 0, 0), + (17210, 'PKZIP (Uncompressed)', 0, 0), + (17220, 'PKZIP (Compressed Multi-File)', 0, 0), + (17225, 'PKZIP (Mixed Multi-File)', 0, 0), + (17230, 'PKZIP (Compressed Multi-File Checksum-Only)', 0, 0), + (17300, 'SHA3-224', 0, 0), + (17400, 'SHA3-256', 0, 0), + (17500, 'SHA3-384', 0, 0), + (17600, 'SHA3-512', 0, 0), + (17700, 'Keccak-224', 0, 0), + (17800, 'Keccak-256', 0, 0), + (17900, 'Keccak-384', 0, 0), + (18000, 'Keccak-512', 0, 0), + (18100, 'TOTP (HMAC-SHA1)', 1, 0), + (18200, 'Kerberos 5 AS-REP etype 23', 0, 1), + (18300, 'Apple File System (APFS)', 0, 1), + (18400, 'Open Document Format (ODF) 1.2 (SHA-256, AES)', 0, 1), + (18500, 'sha1(md5(md5($pass)))', 0, 0), + (18600, 'Open Document Format (ODF) 1.1 (SHA-1, Blowfish)', 0, 1), + (18700, 'Java Object hashCode()', 0, 1), + (18800, 'Blockchain, My Wallet, Second Password (SHA256)', 0, 1), + (18900, 'Android Backup', 0, 1), + (19000, 'QNX /etc/shadow (MD5)', 0, 1), + (19100, 'QNX /etc/shadow (SHA256)', 0, 1), + (19200, 'QNX /etc/shadow (SHA512)', 0, 1), + (19210, 'QNX 7 /etc/shadow (SHA512)', 0, 1), + (19300, 'sha1($salt1.$pass.$salt2)', 0, 0), + (19500, 'Ruby on Rails Restful-Authentication', 0, 0), + (19600, 'Kerberos 5 TGS-REP etype 17 (AES128-CTS-HMAC-SHA1-96)', 0, 1), + (19700, 'Kerberos 5 TGS-REP etype 18 (AES256-CTS-HMAC-SHA1-96)', 0, 1), + (19800, 'Kerberos 5, etype 17, Pre-Auth', 0, 1), + (19900, 'Kerberos 5, etype 18, Pre-Auth', 0, 1), + (20011, 'DiskCryptor SHA512 + XTS 512 bit (AES) / DiskCryptor SHA512 + XTS 512 bit (Twofish) / DiskCryptor SHA512 + XTS 512 bit (Serpent)', 0, 1), + (20012, 'DiskCryptor SHA512 + XTS 1024 bit (AES-Twofish) / DiskCryptor SHA512 + XTS 1024 bit (Twofish-Serpent) / DiskCryptor SHA512 + XTS 1024 bit (Serpent-AES)', 0, 1), + (20013, 'DiskCryptor SHA512 + XTS 1536 bit (AES-Twofish-Serpent)', 0, 1), + (20200, 'Python passlib pbkdf2-sha512', 0, 1), + (20300, 'Python passlib pbkdf2-sha256', 0, 1), + (20400, 'Python passlib pbkdf2-sha1', 0, 0), + (20500, 'PKZIP Master Key', 0, 0), + (20510, 'PKZIP Master Key (6 byte optimization)', 0, 0), + (20600, 'Oracle Transportation Management (SHA256)', 0, 0), + (20710, 'sha256(sha256($pass).$salt)', 1, 0), + (20711, 'AuthMe sha256', 0, 0), + (20712, 'RSA Security Analytics / NetWitness (sha256)', 1, 0), + (20720, 'sha256($salt.sha256($pass))', 1, 0), + (20730, 'sha256(sha256($pass.$salt))', 1, 0), + (20800, 'sha256(md5($pass))', 0, 0), + (20900, 'md5(sha1($pass).md5($pass).sha1($pass))', 0, 0), + (21000, 'BitShares v0.x - sha512(sha512_bin(pass))', 0, 0), + (21100, 'sha1(md5($pass.$salt))', 1, 0), + (21200, 'md5(sha1($salt).md5($pass))', 1, 0), + (21300, 'md5($salt.sha1($salt.$pass))', 1, 0), + (21310, 'md5($salt1.sha1($salt2.$pass))', 1, 0), + (21400, 'sha256(sha256_bin(pass))', 0, 0), + (21420, 'sha256($salt.sha256_bin($pass))', 1, 0), + (21500, 'SolarWinds Orion', 0, 0), + (21501, 'SolarWinds Orion v2', 0, 0), + (21600, 'Web2py pbkdf2-sha512', 0, 0), + (21700, 'Electrum Wallet (Salt-Type 4)', 0, 0), + (21800, 'Electrum Wallet (Salt-Type 5)', 0, 0), + (21900, 'md5(md5(md5($pass.$salt1)).$salt2)', 0, 0), + (22000, 'WPA-PBKDF2-PMKID+EAPOL', 0, 0), + (22001, 'WPA-PMK-PMKID+EAPOL', 0, 0), + (22100, 'BitLocker', 0, 0), + (22200, 'Citrix NetScaler (SHA512)', 0, 0), + (22300, 'sha256($salt.$pass.$salt)', 1, 0), + (22301, 'Telegram client app passcode (SHA256)', 0, 0), + (22400, 'AES Crypt (SHA256)', 0, 0), + (22500, 'MultiBit Classic .key (MD5)', 0, 0), + (22600, 'Telegram Desktop App Passcode (PBKDF2-HMAC-SHA1)', 0, 0), + (22700, 'MultiBit HD (scrypt)', 0, 1), + (22800, 'Simpla CMS - md5($salt.$pass.md5($pass))', 1, 0), + (22911, 'RSA/DSA/EC/OPENSSH Private Keys ($0$)', 0, 0), + (22921, 'RSA/DSA/EC/OPENSSH Private Keys ($6$)', 0, 0), + (22931, 'RSA/DSA/EC/OPENSSH Private Keys ($1, $3$)', 0, 0), + (22941, 'RSA/DSA/EC/OPENSSH Private Keys ($4$)', 0, 0), + (22951, 'RSA/DSA/EC/OPENSSH Private Keys ($5$)', 0, 0), + (23001, 'SecureZIP AES-128', 0, 0), + (23002, 'SecureZIP AES-192', 0, 0), + (23003, 'SecureZIP AES-256', 0, 0), + (23100, 'Apple Keychain', 0, 1), + (23200, 'XMPP SCRAM PBKDF2-SHA1', 0, 0), + (23300, 'Apple iWork', 0, 0), + (23400, 'Bitwarden', 0, 0), + (23500, 'AxCrypt 2 AES-128', 0, 0), + (23600, 'AxCrypt 2 AES-256', 0, 0), + (23700, 'RAR3-p (Uncompressed)', 0, 0), + (23800, 'RAR3-p (Compressed)', 0, 0), + (23900, 'BestCrypt v3 Volume Encryption', 0, 0), + (24000, 'BestCrypt v4 Volume Encryption', 0, 1), + (24100, 'MongoDB ServerKey SCRAM-SHA-1', 0, 0), + (24200, 'MongoDB ServerKey SCRAM-SHA-256', 0, 0), + (24300, 'sha1($salt.sha1($pass.$salt))', 1, 0), + (24410, 'PKCS#8 Private Keys (PBKDF2-HMAC-SHA1 + 3DES/AES)', 0, 0), + (24420, 'PKCS#8 Private Keys (PBKDF2-HMAC-SHA256 + 3DES/AES)', 0, 0), + (24500, 'Telegram Desktop >= v2.1.14 (PBKDF2-HMAC-SHA512)', 0, 0), + (24600, 'SQLCipher', 0, 0), + (24700, 'Stuffit5', 0, 0), + (24800, 'Umbraco HMAC-SHA1', 0, 0), + (24900, 'Dahua Authentication MD5', 0, 0), + (25000, 'SNMPv3 HMAC-MD5-96/HMAC-SHA1-96', 0, 1), + (25100, 'SNMPv3 HMAC-MD5-96', 0, 1), + (25200, 'SNMPv3 HMAC-SHA1-96', 0, 1), + (25300, 'MS Office 2016 - SheetProtection', 0, 0), + (25400, 'PDF 1.4 - 1.6 (Acrobat 5 - 8) - edit password', 0, 0), + (25500, 'Stargazer Stellar Wallet XLM', 0, 0), + (25600, 'bcrypt(md5($pass)) / bcryptmd5', 0, 1), + (25700, 'MurmurHash', 1, 0), + (25800, 'bcrypt(sha1($pass)) / bcryptsha1', 0, 1), + (25900, 'KNX IP Secure - Device Authentication Code', 0, 0), + (26000, 'Mozilla key3.db', 0, 0), + (26100, 'Mozilla key4.db', 0, 0), + (26200, 'OpenEdge Progress Encode', 0, 0), + (26300, 'FortiGate256 (FortiOS256)', 0, 0), + (26401, 'AES-128-ECB NOKDF (PT = $salt, key = $pass)', 0, 0), + (26402, 'AES-192-ECB NOKDF (PT = $salt, key = $pass)', 0, 0), + (26403, 'AES-256-ECB NOKDF (PT = $salt, key = $pass)', 0, 0), + (26500, 'iPhone passcode (UID key + System Keybag)', 0, 0), + (26600, 'MetaMask Wallet', 0, 1), + (26610, 'MetaMask Wallet (short hash, plaintext check)', 0, 1), + (26700, 'SNMPv3 HMAC-SHA224-128', 0, 0), + (26800, 'SNMPv3 HMAC-SHA256-192', 0, 0), + (26900, 'SNMPv3 HMAC-SHA384-256', 0, 0), + (27000, 'NetNTLMv1 / NetNTLMv1+ESS (NT)', 0, 0), + (27100, 'NetNTLMv2 (NT)', 0, 0), + (27200, 'Ruby on Rails Restful Auth (one round, no sitekey)', 1, 0), + (27300, 'SNMPv3 HMAC-SHA512-384', 0, 0), + (27400, 'VMware VMX (PBKDF2-HMAC-SHA1 + AES-256-CBC)', 0, 0), + (27500, 'VirtualBox (PBKDF2-HMAC-SHA256 & AES-128-XTS)', 0, 1), + (27600, 'VirtualBox (PBKDF2-HMAC-SHA256 & AES-256-XTS)', 0, 1), + (27700, 'MultiBit Classic .wallet (scrypt)', 0, 0), + (27800, 'MurmurHash3', 1, 0), + (27900, 'CRC32C', 1, 0), + (28000, 'CRC64Jones', 1, 0), + (28100, 'Windows Hello PIN/Password', 0, 1), + (28200, 'Exodus Desktop Wallet (scrypt)', 0, 0), + (28300, 'Teamspeak 3 (channel hash)', 0, 0), + (28400, 'bcrypt(sha512($pass)) / bcryptsha512', 0, 0), + (28501, 'Bitcoin WIF private key (P2PKH), compressed', 0, 0), + (28502, 'Bitcoin WIF private key (P2PKH), uncompressed', 0, 0), + (28503, 'Bitcoin WIF private key (P2WPKH, Bech32), compressed', 0, 0), + (28504, 'Bitcoin WIF private key (P2WPKH, Bech32), uncompressed', 0, 0), + (28505, 'Bitcoin WIF private key (P2SH(P2WPKH)), compressed', 0, 0), + (28506, 'Bitcoin WIF private key (P2SH(P2WPKH)), uncompressed', 0, 0), + (28600, 'PostgreSQL SCRAM-SHA-256', 0, 1), + (28700, 'Amazon AWS4-HMAC-SHA256', 0, 0), + (28800, 'Kerberos 5, etype 17, DB', 0, 1), + (28900, 'Kerberos 5, etype 18, DB', 0, 1), + (29000, 'sha1($salt.sha1(utf16le($username).'':''.utf16le($pass)))', 0, 0), + (29100, 'Flask Session Cookie ($salt.$salt.$pass)', 0, 0), + (29200, 'Radmin3', 0, 0), + (29311, 'TrueCrypt RIPEMD160 + XTS 512 bit', 0, 0), + (29312, 'TrueCrypt RIPEMD160 + XTS 1024 bit', 0, 0), + (29313, 'TrueCrypt RIPEMD160 + XTS 1536 bit', 0, 0), + (29321, 'TrueCrypt SHA512 + XTS 512 bit', 0, 0), + (29322, 'TrueCrypt SHA512 + XTS 1024 bit', 0, 0), + (29323, 'TrueCrypt SHA512 + XTS 1536 bit', 0, 0), + (29331, 'TrueCrypt Whirlpool + XTS 512 bit', 0, 0), + (29332, 'TrueCrypt Whirlpool + XTS 1024 bit', 0, 0), + (29333, 'TrueCrypt Whirlpool + XTS 1536 bit', 0, 0), + (29341, 'TrueCrypt RIPEMD160 + XTS 512 bit + boot-mode', 0, 0), + (29342, 'TrueCrypt RIPEMD160 + XTS 1024 bit + boot-mode', 0, 0), + (29343, 'TrueCrypt RIPEMD160 + XTS 1536 bit + boot-mode', 0, 0), + (29411, 'VeraCrypt RIPEMD160 + XTS 512 bit', 0, 0), + (29412, 'VeraCrypt RIPEMD160 + XTS 1024 bit', 0, 0), + (29413, 'VeraCrypt RIPEMD160 + XTS 1536 bit', 0, 0), + (29421, 'VeraCrypt SHA512 + XTS 512 bit', 0, 0), + (29422, 'VeraCrypt SHA512 + XTS 1024 bit', 0, 0), + (29423, 'VeraCrypt SHA512 + XTS 1536 bit', 0, 0), + (29431, 'VeraCrypt Whirlpool + XTS 512 bit', 0, 0), + (29432, 'VeraCrypt Whirlpool + XTS 1024 bit', 0, 0), + (29433, 'VeraCrypt Whirlpool + XTS 1536 bit', 0, 0), + (29441, 'VeraCrypt RIPEMD160 + XTS 512 bit + boot-mode', 0, 0), + (29442, 'VeraCrypt RIPEMD160 + XTS 1024 bit + boot-mode', 0, 0), + (29443, 'VeraCrypt RIPEMD160 + XTS 1536 bit + boot-mode', 0, 0), + (29451, 'VeraCrypt SHA256 + XTS 512 bit', 0, 0), + (29452, 'VeraCrypt SHA256 + XTS 1024 bit', 0, 0), + (29453, 'VeraCrypt SHA256 + XTS 1536 bit', 0, 0), + (29461, 'VeraCrypt SHA256 + XTS 512 bit + boot-mode', 0, 0), + (29462, 'VeraCrypt SHA256 + XTS 1024 bit + boot-mode', 0, 0), + (29463, 'VeraCrypt SHA256 + XTS 1536 bit + boot-mode', 0, 0), + (29471, 'VeraCrypt Streebog-512 + XTS 512 bit', 0, 0), + (29472, 'VeraCrypt Streebog-512 + XTS 1024 bit', 0, 0), + (29473, 'VeraCrypt Streebog-512 + XTS 1536 bit', 0, 0), + (29481, 'VeraCrypt Streebog-512 + XTS 512 bit + boot-mode', 0, 0), + (29482, 'VeraCrypt Streebog-512 + XTS 1024 bit + boot-mode', 0, 0), + (29483, 'VeraCrypt Streebog-512 + XTS 1536 bit + boot-mode', 0, 0), + (29511, 'LUKS v1 SHA-1 + AES', 0, 1), + (29512, 'LUKS v1 SHA-1 + Serpent', 0, 1), + (29513, 'LUKS v1 SHA-1 + Twofish', 0, 1), + (29521, 'LUKS v1 SHA-256 + AES', 0, 1), + (29522, 'LUKS v1 SHA-256 + Serpent', 0, 1), + (29523, 'LUKS v1 SHA-256 + Twofish', 0, 1), + (29531, 'LUKS v1 SHA-512 + AES', 0, 1), + (29532, 'LUKS v1 SHA-512 + Serpent', 0, 1), + (29533, 'LUKS v1 SHA-512 + Twofish', 0, 1), + (29541, 'LUKS v1 RIPEMD-160 + AES', 0, 1), + (29542, 'LUKS v1 RIPEMD-160 + Serpent', 0, 1), + (29543, 'LUKS v1 RIPEMD-160 + Twofish', 0, 1), + (29600, 'Terra Station Wallet (AES256-CBC(PBKDF2($pass)))', 0, 1), + (29700, 'KeePass 1 (AES/Twofish) and KeePass 2 (AES) - keyfile only mode', 0, 1), + (29800, 'Bisq .wallet (scrypt)', 0, 1), + (29910, 'ENCsecurity Datavault (PBKDF2/no keychain)', 0, 1), + (29920, 'ENCsecurity Datavault (PBKDF2/keychain)', 0, 1), + (29930, 'ENCsecurity Datavault (MD5/no keychain)', 0, 1), + (29940, 'ENCsecurity Datavault (MD5/keychain)', 0, 1), + (30000, 'Python Werkzeug MD5 (HMAC-MD5 (key = $salt))', 0, 0), + (30120, 'Python Werkzeug SHA256 (HMAC-SHA256 (key = $salt))', 0, 0), + (30420, 'DANE RFC7929/RFC8162 SHA2-256', 0, 0), + (30500, 'md5(md5($salt).md5(md5($pass)))', 1, 0), + (30600, 'bcrypt(sha256($pass))', 0, 1), + (30601, 'bcrypt(HMAC-SHA256($pass))', 0, 1), + (30700, 'Anope IRC Services (enc_sha256)', 0, 0), + (30901, 'Bitcoin raw private key (P2PKH), compressed', 0, 0), + (30902, 'Bitcoin raw private key (P2PKH), uncompressed', 0, 0), + (30903, 'Bitcoin raw private key (P2WPKH, Bech32), compressed', 0, 0), + (30904, 'Bitcoin raw private key (P2WPKH, Bech32), uncompressed', 0, 0), + (30905, 'Bitcoin raw private key (P2SH(P2WPKH)), compressed', 0, 0), + (30906, 'Bitcoin raw private key (P2SH(P2WPKH)), uncompressed', 0, 0), + (31000, 'BLAKE2s-256', 0, 0), + (31100, 'ShangMi 3 (SM3)', 0, 0), + (31200, 'Veeam VBK', 0, 1), + (31300, 'MS SNTP', 0, 0), + (31400, 'SecureCRT MasterPassphrase v2', 0, 0), + (31500, 'Domain Cached Credentials (DCC), MS Cache (NT)', 1, 1), + (31600, 'Domain Cached Credentials 2 (DCC2), MS Cache 2, (NT)', 0, 1), + (31700, 'md5(md5(md5($pass).$salt1).$salt2)', 1, 0), + (31800, '1Password, mobilekeychain (1Password 8)', 0, 1), + (31900, 'MetaMask Mobile Wallet', 0, 1), + (32000, 'NetIQ SSPR (MD5)', 0, 1), + (32010, 'NetIQ SSPR (SHA1)', 0, 1), + (32020, 'NetIQ SSPR (SHA-1 with Salt)', 0, 1), + (32030, 'NetIQ SSPR (SHA-256 with Salt)', 0, 1), + (32031, 'Adobe AEM (SSPR, SHA-256 with Salt)', 0, 1), + (32040, 'NetIQ SSPR (SHA-512 with Salt)', 0, 1), + (32041, 'Adobe AEM (SSPR, SHA-512 with Salt)', 0, 1), + (32050, 'NetIQ SSPR (PBKDF2WithHmacSHA1)', 0, 1), + (32060, 'NetIQ SSPR (PBKDF2WithHmacSHA256)', 0, 1), + (32070, 'NetIQ SSPR (PBKDF2WithHmacSHA512)', 0, 1), + (32100, 'Kerberos 5, etype 17, AS-REP', 0, 1), + (32200, 'Kerberos 5, etype 18, AS-REP', 0, 1), + (32300, 'Empire CMS (Admin password)', 1, 0), + (32410, 'sha512(sha512($pass).$salt)', 1, 0), + (32420, 'sha512(sha512_bin($pass).$salt)', 1, 0), + (32500, 'Dogechain.info Wallet', 0, 1), + (32600, 'CubeCart (whirlpool($salt.$pass.$salt))', 1, 0), + (32700, 'Kremlin Encrypt 3.0 w/NewDES', 0, 1), + (32800, 'md5(sha1(md5($pass)))', 0, 0), + (32900, 'PBKDF1-SHA1', 1, 1), + (33000, 'md5($salt1.$pass.$salt2)', 1, 0), + (33100, 'md5($salt.md5($pass).$salt)', 1, 0), + (33300, 'HMAC-BLAKE2S (key = $pass)', 1, 0), + (33400, 'mega.nz password-protected link (PBKDF2-HMAC-SHA512)', 0, 1), + (33500, 'RC4 40-bit DropN', 0, 0), + (33501, 'RC4 72-bit DropN', 0, 0), + (33502, 'RC4 104-bit DropN', 0, 0), + (33600, 'RIPEMD-320', 0, 0), + (33650, 'HMAC-RIPEMD320 (key = $pass)', 1, 0), + (33660, 'HMAC-RIPEMD320 (key = $salt)', 1, 0), + (33700, 'Microsoft Online Account (PBKDF2-HMAC-SHA256 + AES256)', 0, 1), + (33800, 'WBB4 (Woltlab Burning Board) [bcrypt(bcrypt($pass))]', 0, 1), + (33900, 'Citrix NetScaler (PBKDF2-HMAC-SHA256)', 0, 1), + (34000, 'Argon2', 0, 1), + (34100, 'LUKS v2 argon2 + SHA-256 + AES', 0, 1), + (34200, 'MurmurHash64A', 1, 0), + (34201, 'MurmurHash64A (zero seed)', 0, 0), + (34211, 'MurmurHash64A truncated (zero seed)', 0, 0), + (34300, 'KeePass (KDBX v4)', 0, 1), + (34400, 'sha224(sha224($pass))', 0, 0), + (34500, 'sha224(sha1($pass))', 0, 0), + (34600, 'MD6 (256)', 0, 0), + (34700, 'Blockchain, My Wallet, Legacy Wallets', 0, 0), + (34800, 'BLAKE2b-256', 0, 0), + (34810, 'BLAKE2b-256($pass.$salt)', 1, 0), + (34820, 'BLAKE2b-256($salt.$pass)', 1, 0), + (35000, 'SAP CODVN H (PWDSALTEDHASH) isSHA512', 1, 1), + (35100, 'sm3crypt $sm3$, SM3 (Unix)', 1, 1), + (35200, 'AS/400 SSHA1', 1, 0), + (70000, 'Argon2id [Bridged: reference implementation + tunings]', 0, 1), + (70100, 'scrypt [Bridged: Scrypt-Jane SMix]', 0, 1), + (70200, 'scrypt [Bridged: Scrypt-Yescrypt]', 0, 1), + (72000, 'Generic Hash [Bridged: Python Interpreter free-threading]', 0, 1), + (73000, 'Generic Hash [Bridged: Python Interpreter with GIL]', 0, 1), + (99999, 'Plaintext', 0, 0); + +CREATE TABLE HealthCheck ( + healthCheckId SERIAL NOT NULL PRIMARY KEY, + time BIGINT NOT NULL, + status INT NOT NULL, + checkType INT NOT NULL, + hashtypeId INT NOT NULL, + crackerBinaryId INT NOT NULL, + expectedCracks INT NOT NULL, + attackCmd TEXT NOT NULL +); + +CREATE TABLE HealthCheckAgent ( + healthCheckAgentId SERIAL NOT NULL PRIMARY KEY, + healthCheckId INT NOT NULL, + agentId INT NOT NULL, + status INT NOT NULL, + cracked INT NOT NULL, + numGpus INT NOT NULL, + start BIGINT NOT NULL, + htp_end BIGINT NOT NULL, + errors TEXT NOT NULL +); + +CREATE TABLE htp_User ( + userId SERIAL NOT NULL PRIMARY KEY, + username TEXT NOT NULL, + email TEXT NOT NULL, + passwordHash TEXT NOT NULL, + passwordSalt TEXT NOT NULL, + isValid INT NOT NULL, + isComputedPassword INT NOT NULL, + lastLoginDate BIGINT NOT NULL, + registeredSince BIGINT NOT NULL, + sessionLifetime INT NOT NULL, + rightGroupId INT NOT NULL, + yubikey TEXT DEFAULT NULL, + otp1 TEXT DEFAULT NULL, + otp2 TEXT DEFAULT NULL, + otp3 TEXT DEFAULT NULL, + otp4 TEXT DEFAULT NULL +); + +CREATE TABLE LogEntry ( + logEntryId SERIAL NOT NULL PRIMARY KEY, + issuer TEXT NOT NULL, + issuerId TEXT NOT NULL, + level TEXT NOT NULL, + message TEXT NOT NULL, + time BIGINT NOT NULL +); + +CREATE TABLE NotificationSetting ( + notificationSettingId SERIAL NOT NULL PRIMARY KEY, + action TEXT NOT NULL, + objectId INT NULL, + notification TEXT NOT NULL, + userId INT NOT NULL, + receiver TEXT NOT NULL, + isActive INT NOT NULL +); + +CREATE TABLE Preprocessor ( + preprocessorId SERIAL NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + url TEXT NOT NULL, + binaryName TEXT NOT NULL, + keyspaceCommand TEXT NULL, + skipCommand TEXT NULL, + limitCommand TEXT NULL +); + +INSERT INTO Preprocessor ( preprocessorId, name, url, binaryName, keyspaceCommand, skipCommand, limitCommand) VALUES + (1, 'Prince', 'https://github.com/hashcat/princeprocessor/releases/download/v0.22/princeprocessor-0.22.7z', 'pp', '--keyspace', '--skip', '--limit'); + +CREATE TABLE Pretask ( + pretaskId SERIAL NOT NULL PRIMARY KEY, + taskName TEXT NOT NULL, + attackCmd TEXT NOT NULL, + chunkTime INT NOT NULL, + statusTimer INT NOT NULL, + color TEXT NULL, + isSmall INT NOT NULL, + isCpuTask INT NOT NULL, + useNewBench INT NOT NULL, + priority INT NOT NULL, + maxAgents INT NOT NULL, + isMaskImport INT NOT NULL, + crackerBinaryTypeId INT NOT NULL +); + +CREATE TABLE RegVoucher ( + regVoucherId SERIAL NOT NULL PRIMARY KEY, + voucher TEXT NOT NULL, + time BIGINT NOT NULL +); + +CREATE TABLE RightGroup ( + rightGroupId SERIAL NOT NULL PRIMARY KEY, + groupName TEXT NOT NULL, + permissions TEXT NOT NULL +); + +INSERT INTO RightGroup (rightGroupId, groupName, permissions) VALUES + (1, 'Administrator', 'ALL'); + +CREATE TABLE Session ( + sessionId SERIAL NOT NULL PRIMARY KEY, + userId INT NOT NULL, + sessionStartDate BIGINT NOT NULL, + lastActionDate BIGINT NOT NULL, + isOpen INT NOT NULL, + sessionLifetime INT NOT NULL, + sessionKey TEXT NOT NULL +); + +CREATE TABLE Speed ( + speedId SERIAL NOT NULL PRIMARY KEY, + agentId INT NOT NULL, + taskId INT NOT NULL, + speed BIGINT NOT NULL, + time BIGINT NOT NULL +); + +CREATE TABLE StoredValue ( + storedValueId TEXT NOT NULL PRIMARY KEY, + val TEXT NOT NULL +); + +CREATE TABLE Supertask ( + supertaskId SERIAL NOT NULL PRIMARY KEY, + supertaskName TEXT NOT NULL +); + +CREATE TABLE SupertaskPretask ( + supertaskPretaskId SERIAL NOT NULL PRIMARY KEY, + supertaskId INT NOT NULL, + pretaskId INT NOT NULL +); + +CREATE TABLE Task ( + taskId SERIAL NOT NULL PRIMARY KEY, + taskName TEXT NOT NULL, + attackCmd TEXT NOT NULL, + chunkTime INT NOT NULL, + statusTimer INT NOT NULL, + keyspace BIGINT NOT NULL, + keyspaceProgress BIGINT NOT NULL, + priority INT NOT NULL, + maxAgents INT NOT NULL, + color TEXT NULL, + isSmall INT NOT NULL, + isCpuTask INT NOT NULL, + useNewBench INT NOT NULL, + skipKeyspace BIGINT NOT NULL, + crackerBinaryId INT DEFAULT NULL, + crackerBinaryTypeId INT NULL, + taskWrapperId INT NOT NULL, + isArchived INT NOT NULL, + notes TEXT NOT NULL, + staticChunks INT NOT NULL, + chunkSize BIGINT NOT NULL, + forcePipe INT NOT NULL, + usePreprocessor INT NOT NULL, + preprocessorCommand TEXT NOT NULL +); + +CREATE TABLE TaskDebugOutput ( + taskDebugOutputId SERIAL NOT NULL PRIMARY KEY, + taskId INT NOT NULL, + output TEXT NOT NULL +); + +CREATE TABLE TaskWrapper ( + taskWrapperId SERIAL NOT NULL PRIMARY KEY, + priority INT NOT NULL, + maxAgents INT NOT NULL, + taskType INT NOT NULL, + hashlistId INT NOT NULL, + accessGroupId INT DEFAULT NULL, + taskWrapperName TEXT NOT NULL, + isArchived INT NOT NULL, + cracked INT NOT NULL +); + +CREATE TABLE Zap ( + zapId SERIAL NOT NULL PRIMARY KEY, + hash TEXT NOT NULL, + solveTime BIGINT NOT NULL, + agentId INT NULL, + hashlistId INT NOT NULL +); + +-- Set sequences for all tables with SERIAL +SELECT pg_catalog.setval(pg_get_serial_sequence('AccessGroup', 'accessgroupid'), MAX(accessGroupId)) from AccessGroup; +SELECT pg_catalog.setval(pg_get_serial_sequence('AccessGroupAgent', 'accessgroupagentid'), MAX(accessGroupAgentId)) from AccessGroupAgent; +SELECT pg_catalog.setval(pg_get_serial_sequence('AccessGroupUser', 'accessgroupuserid'), MAX(accessGroupUserId)) from AccessGroupUser; +SELECT pg_catalog.setval(pg_get_serial_sequence('Agent', 'agentid'), MAX(agentId)) from Agent; +SELECT pg_catalog.setval(pg_get_serial_sequence('AgentBinary', 'agentbinaryid'), MAX(agentBinaryId)) from AgentBinary; +SELECT pg_catalog.setval(pg_get_serial_sequence('AgentError', 'agenterrorid'), MAX(agentErrorId)) from AgentError; +SELECT pg_catalog.setval(pg_get_serial_sequence('AgentStat', 'agentstatid'), MAX(agentStatId)) from AgentStat; +SELECT pg_catalog.setval(pg_get_serial_sequence('AgentZap', 'agentzapid'), MAX(agentZapId)) from AgentZap; +SELECT pg_catalog.setval(pg_get_serial_sequence('ApiKey', 'apikeyid'), MAX(apiKeyId)) from ApiKey; +SELECT pg_catalog.setval(pg_get_serial_sequence('ApiGroup', 'apigroupid'), MAX(apiGroupId)) from ApiGroup; +SELECT pg_catalog.setval(pg_get_serial_sequence('Assignment', 'assignmentid'), MAX(assignmentId)) from Assignment; +SELECT pg_catalog.setval(pg_get_serial_sequence('Chunk', 'chunkid'), MAX(chunkId)) from Chunk; +SELECT pg_catalog.setval(pg_get_serial_sequence('Config', 'configid'), MAX(configId)) from Config; +SELECT pg_catalog.setval(pg_get_serial_sequence('ConfigSection', 'configsectionid'), MAX(configSectionId)) from ConfigSection; +SELECT pg_catalog.setval(pg_get_serial_sequence('CrackerBinary', 'crackerbinaryid'), MAX(crackerBinaryId)) from CrackerBinary; +SELECT pg_catalog.setval(pg_get_serial_sequence('CrackerBinaryType', 'crackerbinarytypeid'), MAX(crackerBinaryTypeId)) from CrackerBinaryType; +SELECT pg_catalog.setval(pg_get_serial_sequence('File', 'fileid'), MAX(fileId)) from File; +SELECT pg_catalog.setval(pg_get_serial_sequence('FileDownload', 'filedownloadid'), MAX(fileDownloadId)) from FileDownload; +SELECT pg_catalog.setval(pg_get_serial_sequence('FilePretask', 'filepretaskid'), MAX(filePretaskId)) from FilePretask; +SELECT pg_catalog.setval(pg_get_serial_sequence('FileTask', 'filetaskid'), MAX(fileTaskId)) from FileTask; +SELECT pg_catalog.setval(pg_get_serial_sequence('FileDelete', 'filedeleteid'), MAX(fileDeleteId)) from FileDelete; +SELECT pg_catalog.setval(pg_get_serial_sequence('Hash', 'hashid'), MAX(hashId)) from Hash; +SELECT pg_catalog.setval(pg_get_serial_sequence('HashBinary', 'hashbinaryid'), MAX(hashBinaryId)) from HashBinary; +SELECT pg_catalog.setval(pg_get_serial_sequence('Hashlist', 'hashlistid'), MAX(hashlistId)) from Hashlist; +SELECT pg_catalog.setval(pg_get_serial_sequence('HashlistHashlist', 'hashlisthashlistid'), MAX(hashlistHashlistId)) from HashlistHashlist; +SELECT pg_catalog.setval(pg_get_serial_sequence('HashType', 'hashtypeid'), MAX(hashTypeId)) from HashType; +SELECT pg_catalog.setval(pg_get_serial_sequence('HealthCheck', 'healthcheckid'), MAX(healthCheckId)) from HealthCheck; +SELECT pg_catalog.setval(pg_get_serial_sequence('HealthCheckAgent', 'healthcheckagentid'), MAX(healthCheckAgentId)) from HealthCheckAgent; +SELECT pg_catalog.setval(pg_get_serial_sequence('htp_User', 'userid'), MAX(userId)) from htp_User; +SELECT pg_catalog.setval(pg_get_serial_sequence('LogEntry', 'logentryid'), MAX(logEntryId)) from LogEntry; +SELECT pg_catalog.setval(pg_get_serial_sequence('NotificationSetting', 'notificationsettingid'), MAX(notificationSettingId)) from NotificationSetting; +SELECT pg_catalog.setval(pg_get_serial_sequence('Preprocessor', 'preprocessorid'), MAX(preprocessorId)) from Preprocessor; +SELECT pg_catalog.setval(pg_get_serial_sequence('Pretask', 'pretaskid'), MAX(pretaskId)) from Pretask; +SELECT pg_catalog.setval(pg_get_serial_sequence('RegVoucher', 'regvoucherid'), MAX(regVoucherId)) from RegVoucher; +SELECT pg_catalog.setval(pg_get_serial_sequence('RightGroup', 'rightgroupid'), MAX(rightGroupId)) from RightGroup; +SELECT pg_catalog.setval(pg_get_serial_sequence('Session', 'sessionid'), MAX(sessionId)) from Session; +SELECT pg_catalog.setval(pg_get_serial_sequence('Speed', 'speedid'), MAX(speedId)) from Speed; +SELECT pg_catalog.setval(pg_get_serial_sequence('Supertask', 'supertaskid'), MAX(supertaskId)) from Supertask; +SELECT pg_catalog.setval(pg_get_serial_sequence('SupertaskPretask', 'supertaskpretaskid'), MAX(supertaskPretaskId)) from SupertaskPretask; +SELECT pg_catalog.setval(pg_get_serial_sequence('Task', 'taskid'), MAX(taskId)) from Task; +SELECT pg_catalog.setval(pg_get_serial_sequence('TaskDebugOutput', 'taskdebugoutputid'), MAX(taskDebugOutputId)) from TaskDebugOutput; +SELECT pg_catalog.setval(pg_get_serial_sequence('TaskWrapper', 'taskwrapperid'), MAX(taskWrapperId)) from TaskWrapper; +SELECT pg_catalog.setval(pg_get_serial_sequence('Zap', 'zapid'), MAX(zapId)) from Zap; + +-- Add Indexes +CREATE INDEX IF NOT EXISTS AccessGroupAgent_accessGroupId_idx ON AccessGroupAgent (accessGroupId); +CREATE INDEX IF NOT EXISTS AccessGroupAgent_agentId_idx ON AccessGroupAgent (agentId); + +CREATE INDEX IF NOT EXISTS AccessGroupUser_accessGroupId_idx ON AccessGroupUser (accessGroupId); +CREATE INDEX IF NOT EXISTS AccessGroupUser_userId_idx ON AccessGroupUser (userId); + +CREATE INDEX IF NOT EXISTS Agent_userId_idx ON Agent (userId); + +CREATE INDEX IF NOT EXISTS AgentError_agentId_idx ON AgentError (agentId); +CREATE INDEX IF NOT EXISTS AgentError_taskId_idx ON AgentError (taskId); + +CREATE INDEX IF NOT EXISTS AgentStat_agentId_idx ON AgentStat (agentId); + +CREATE INDEX IF NOT EXISTS AgentZap_agentId_idx ON AgentZap (agentId); +CREATE INDEX IF NOT EXISTS AgentZap_lastZapId_idx ON AgentZap (lastZapId); + +CREATE INDEX IF NOT EXISTS Assignment_taskId_idx ON Assignment (taskId); +CREATE INDEX IF NOT EXISTS Assignment_agentId_idx ON Assignment (agentId); + +CREATE INDEX IF NOT EXISTS Chunk_taskId_idx ON Chunk (taskId); +CREATE INDEX IF NOT EXISTS Chunk_progress_idx ON Chunk (progress); +CREATE INDEX IF NOT EXISTS Chunk_agentId_idx ON Chunk (agentId); + +CREATE INDEX IF NOT EXISTS Config_configSectionId_idx ON Config (configSectionId); + +CREATE INDEX IF NOT EXISTS CrackerBinary_crackerBinaryTypeId_idx ON CrackerBinary (crackerBinaryTypeId); + +CREATE INDEX IF NOT EXISTS FilePretask_fileId_idx ON FilePretask (fileId); +CREATE INDEX IF NOT EXISTS FilePretask_pretaskId_idx ON FilePretask (pretaskId); + +CREATE INDEX IF NOT EXISTS FileTask_fileId_idx ON FileTask (fileId); +CREATE INDEX IF NOT EXISTS FileTask_taskId_idx ON FileTask (taskId); + +CREATE INDEX IF NOT EXISTS Hash_hashlistId_idx ON Hash (hashlistId); +CREATE INDEX IF NOT EXISTS Hash_chunkId_idx ON Hash (chunkId); +CREATE INDEX IF NOT EXISTS Hash_isCracked_idx ON Hash (isCracked); +CREATE INDEX IF NOT EXISTS Hash_hash_idx ON Hash (hash); +CREATE INDEX IF NOT EXISTS Hash_timeCracked_idx ON Hash (timeCracked); + +CREATE INDEX IF NOT EXISTS HashBinary_hashlistId_idx ON HashBinary (hashlistId); +CREATE INDEX IF NOT EXISTS HashBinary_chunkId_idx ON HashBinary (chunkId); + +CREATE INDEX IF NOT EXISTS Hashlist_hashTypeId_idx ON Hashlist (hashTypeId); + +CREATE INDEX IF NOT EXISTS HashlistHashlist_parentHashlistId_idx ON HashlistHashlist (parentHashlistId); +CREATE INDEX IF NOT EXISTS HashlistHashlist_hashlistId_idx ON HashlistHashlist (hashlistId); + +CREATE INDEX IF NOT EXISTS htp_User_rightGroupId_idx ON htp_User (rightGroupId); + +CREATE INDEX IF NOT EXISTS NotificationSetting_userId_idx ON NotificationSetting (userId); + +CREATE INDEX IF NOT EXISTS Session_userId_idx ON Session (userId); + +CREATE INDEX IF NOT EXISTS Speed_agentId_idx ON Speed (agentId); +CREATE INDEX IF NOT EXISTS Speed_taskId_idx ON Speed (taskId); + +CREATE INDEX IF NOT EXISTS SupertaskPretask_supertaskId_idx ON SupertaskPretask (supertaskId); +CREATE INDEX IF NOT EXISTS SupertaskPretask_pretaskId_idx ON SupertaskPretask (pretaskId); + +CREATE INDEX IF NOT EXISTS Task_crackerBinaryId_idx ON Task (crackerBinaryId); + +CREATE INDEX IF NOT EXISTS TaskWrapper_hashlistId_idx ON TaskWrapper (hashlistId); +CREATE INDEX IF NOT EXISTS TaskWrapper_priority_idx ON TaskWrapper (priority); +CREATE INDEX IF NOT EXISTS TaskWrapper_isArchived_idx ON TaskWrapper (isArchived); +CREATE INDEX IF NOT EXISTS TaskWrapper_accessGroupId_idx ON TaskWrapper (accessGroupId); + +CREATE INDEX IF NOT EXISTS Zap_agentId_idx ON Zap (agentId); +CREATE INDEX IF NOT EXISTS Zap_hashlistId_idx ON Zap (hashlistId); + +-- Add Constraints +ALTER TABLE AccessGroupAgent ADD CONSTRAINT AccessGroupAgent_ibfk_1 FOREIGN KEY (accessGroupId) REFERENCES AccessGroup (accessGroupId); +ALTER TABLE AccessGroupAgent ADD CONSTRAINT AccessGroupAgent_ibfk_2 FOREIGN KEY (agentId) REFERENCES Agent (agentId); + +ALTER TABLE AccessGroupUser ADD CONSTRAINT AccessGroupUser_ibfk_1 FOREIGN KEY (accessGroupId) REFERENCES AccessGroup (accessGroupId); +ALTER TABLE AccessGroupUser ADD CONSTRAINT AccessGroupUser_ibfk_2 FOREIGN KEY (userId) REFERENCES htp_User (userId); + +ALTER TABLE Agent ADD CONSTRAINT Agent_ibfk_1 FOREIGN KEY (userId) REFERENCES htp_User (userId); + +ALTER TABLE AgentError ADD CONSTRAINT AgentError_ibfk_1 FOREIGN KEY (agentId) REFERENCES Agent (agentId); +ALTER TABLE AgentError ADD CONSTRAINT AgentError_ibfk_2 FOREIGN KEY (taskId) REFERENCES Task (taskId); + +ALTER TABLE AgentStat ADD CONSTRAINT AgentStat_ibfk_1 FOREIGN KEY (agentId) REFERENCES Agent (agentId); + +ALTER TABLE AgentZap ADD CONSTRAINT AgentZap_ibfk_1 FOREIGN KEY (agentId) REFERENCES Agent (agentId); +ALTER TABLE AgentZap ADD CONSTRAINT AgentZap_ibfk_2 FOREIGN KEY (lastZapId) REFERENCES Zap (zapId); + +ALTER TABLE ApiKey ADD CONSTRAINT ApiKey_ibfk_1 FOREIGN KEY (userId) REFERENCES htp_User (userId); +ALTER TABLE ApiKey ADD CONSTRAINT ApiKey_ibfk_2 FOREIGN KEY (apiGroupId) REFERENCES ApiGroup (apiGroupId); + +ALTER TABLE Assignment ADD CONSTRAINT Assignment_ibfk_1 FOREIGN KEY (taskId) REFERENCES Task (taskId); +ALTER TABLE Assignment ADD CONSTRAINT Assignment_ibfk_2 FOREIGN KEY (agentId) REFERENCES Agent (agentId); + +ALTER TABLE Chunk ADD CONSTRAINT Chunk_ibfk_1 FOREIGN KEY (taskId) REFERENCES Task (taskId); +ALTER TABLE Chunk ADD CONSTRAINT Chunk_ibfk_2 FOREIGN KEY (agentId) REFERENCES Agent (agentId); + +ALTER TABLE Config ADD CONSTRAINT Config_ibfk_1 FOREIGN KEY (configSectionId) REFERENCES ConfigSection (configSectionId); + +ALTER TABLE CrackerBinary ADD CONSTRAINT CrackerBinary_ibfk_1 FOREIGN KEY (crackerBinaryTypeId) REFERENCES CrackerBinaryType (crackerBinaryTypeId); + +ALTER TABLE File ADD CONSTRAINT File_ibfk_1 FOREIGN KEY (accessGroupId) REFERENCES AccessGroup (accessGroupId); + +ALTER TABLE FilePretask ADD CONSTRAINT FilePretask_ibfk_1 FOREIGN KEY (fileId) REFERENCES File (fileId); +ALTER TABLE FilePretask ADD CONSTRAINT FilePretask_ibfk_2 FOREIGN KEY (pretaskId) REFERENCES Pretask (pretaskId); + +ALTER TABLE FileTask ADD CONSTRAINT FileTask_ibfk_1 FOREIGN KEY (fileId) REFERENCES File (fileId); +ALTER TABLE FileTask ADD CONSTRAINT FileTask_ibfk_2 FOREIGN KEY (taskId) REFERENCES Task (taskId); + +ALTER TABLE Hash ADD CONSTRAINT Hash_ibfk_1 FOREIGN KEY (hashlistId) REFERENCES Hashlist (hashlistId); +ALTER TABLE Hash ADD CONSTRAINT Hash_ibfk_2 FOREIGN KEY (chunkId) REFERENCES Chunk (chunkId); + +ALTER TABLE HashBinary ADD CONSTRAINT HashBinary_ibfk_1 FOREIGN KEY (hashlistId) REFERENCES Hashlist (hashlistId); +ALTER TABLE HashBinary ADD CONSTRAINT HashBinary_ibfk_2 FOREIGN KEY (chunkId) REFERENCES Chunk (chunkId); + +ALTER TABLE Hashlist ADD CONSTRAINT Hashlist_ibfk_1 FOREIGN KEY (hashTypeId) REFERENCES HashType (hashTypeId); +ALTER TABLE Hashlist ADD CONSTRAINT Hashlist_ibfk_2 FOREIGN KEY (accessGroupId) REFERENCES AccessGroup (accessGroupId); + +ALTER TABLE HashlistHashlist ADD CONSTRAINT HashlistHashlist_ibfk_1 FOREIGN KEY (parentHashlistId) REFERENCES Hashlist (hashlistId); +ALTER TABLE HashlistHashlist ADD CONSTRAINT HashlistHashlist_ibfk_2 FOREIGN KEY (hashlistId) REFERENCES Hashlist (hashlistId); + +ALTER TABLE HealthCheck ADD CONSTRAINT HealthCheck_ibfk_1 FOREIGN KEY (crackerBinaryId) REFERENCES CrackerBinary (crackerBinaryId); + +ALTER TABLE HealthCheckAgent ADD CONSTRAINT HealthCheckAgent_ibfk_1 FOREIGN KEY (agentId) REFERENCES Agent (agentId); +ALTER TABLE HealthCheckAgent ADD CONSTRAINT HealthCheckAgent_ibfk_2 FOREIGN KEY (healthCheckId) REFERENCES HealthCheck (healthCheckId); + +ALTER TABLE htp_User ADD CONSTRAINT User_ibfk_1 FOREIGN KEY (rightGroupId) REFERENCES RightGroup (rightGroupId); + +ALTER TABLE NotificationSetting ADD CONSTRAINT NotificationSetting_ibfk_1 FOREIGN KEY (userId) REFERENCES htp_User (userId); + +ALTER TABLE Pretask ADD CONSTRAINT Pretask_ibfk_1 FOREIGN KEY (crackerBinaryTypeId) REFERENCES CrackerBinaryType (crackerBinaryTypeId); + +ALTER TABLE Session ADD CONSTRAINT Session_ibfk_1 FOREIGN KEY (userId) REFERENCES htp_User (userId); + +ALTER TABLE Speed ADD CONSTRAINT Speed_ibfk_1 FOREIGN KEY (agentId) REFERENCES Agent (agentId); +ALTER TABLE Speed ADD CONSTRAINT Speed_ibfk_2 FOREIGN KEY (taskId) REFERENCES Task (taskId); + +ALTER TABLE SupertaskPretask ADD CONSTRAINT SupertaskPretask_ibfk_1 FOREIGN KEY (supertaskId) REFERENCES Supertask (supertaskId); +ALTER TABLE SupertaskPretask ADD CONSTRAINT SupertaskPretask_ibfk_2 FOREIGN KEY (pretaskId) REFERENCES Pretask (pretaskId); + +ALTER TABLE Task ADD CONSTRAINT Task_ibfk_1 FOREIGN KEY (crackerBinaryId) REFERENCES CrackerBinary (crackerBinaryId); +ALTER TABLE Task ADD CONSTRAINT Task_ibfk_2 FOREIGN KEY (crackerBinaryTypeId) REFERENCES CrackerBinaryType (crackerBinaryTypeId); +ALTER TABLE Task ADD CONSTRAINT Task_ibfk_3 FOREIGN KEY (taskWrapperId) REFERENCES TaskWrapper (taskWrapperId); + +ALTER TABLE TaskDebugOutput ADD CONSTRAINT TaskDebugOutput_ibfk_1 FOREIGN KEY (taskId) REFERENCES Task (taskId); + +ALTER TABLE TaskWrapper ADD CONSTRAINT TaskWrapper_ibfk_1 FOREIGN KEY (hashlistId) REFERENCES Hashlist (hashlistId); +ALTER TABLE TaskWrapper ADD CONSTRAINT TaskWrapper_ibfk_2 FOREIGN KEY (accessGroupId) REFERENCES AccessGroup (accessGroupId); + +ALTER TABLE Zap ADD CONSTRAINT Zap_ibfk_1 FOREIGN KEY (agentId) REFERENCES Agent (agentId); +ALTER TABLE Zap ADD CONSTRAINT Zap_ibfk_2 FOREIGN KEY (hashlistId) REFERENCES Hashlist (hashlistId);