From 3ef2525bac79e6c0e2ae3b86a913f1999e9bc7a4 Mon Sep 17 00:00:00 2001 From: s3inlc Date: Fri, 28 Nov 2025 11:32:54 +0100 Subject: [PATCH 01/42] initial rework for dual support of mysql and postgres, moved to use migrations, currently only initial setup will work --- Dockerfile | 10 +- ...er-compose.yml => docker-compose.mysql.yml | 3 +- docker-compose.postgres.yml | 45 + docker-entrypoint.sh | 39 +- env.example => env.mysql.example | 0 env.postgres.example | 10 + src/dba/AbstractModelFactory.class.php | 51 +- src/dba/init.php | 1 + src/inc/confv2.php | 22 +- src/inc/load.php | 17 +- .../updates/update_v1.0.0-rainbow4_vx.x.x.php | 5 + .../mysql/20251127000000_initial.sql} | 100 +- .../postgres/20251127000000_initial.sql | 1193 +++++++++++++++++ 13 files changed, 1410 insertions(+), 86 deletions(-) rename docker-compose.yml => docker-compose.mysql.yml (96%) create mode 100644 docker-compose.postgres.yml rename env.example => env.mysql.example (100%) create mode 100644 env.postgres.example rename src/{install/hashtopolis.sql => migrations/mysql/20251127000000_initial.sql} (96%) create mode 100644 src/migrations/postgres/20251127000000_initial.sql 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/docker-compose.yml b/docker-compose.mysql.yml similarity index 96% rename from docker-compose.yml rename to docker-compose.mysql.yml index 91b14c1ce..93cbff4c2 100644 --- a/docker-compose.yml +++ b/docker-compose.mysql.yml @@ -8,6 +8,7 @@ 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 @@ -36,7 +37,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..c576f2fa1 100755 --- a/src/dba/AbstractModelFactory.class.php +++ b/src/dba/AbstractModelFactory.class.php @@ -920,30 +920,49 @@ 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 beeing 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; } catch (PDOException $e) { + echo $e->getMessage()."\n"; if ($test) { return null; } 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 b34c38803..a588caeb2 100755 --- a/src/inc/load.php +++ b/src/inc/load.php @@ -66,13 +66,24 @@ //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; +} + + +$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]); 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..7759616ee 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`;"); diff --git a/src/install/hashtopolis.sql b/src/migrations/mysql/20251127000000_initial.sql similarity index 96% rename from src/install/hashtopolis.sql rename to src/migrations/mysql/20251127000000_initial.sql index 01072a1d1..2dc14d914 100644 --- a/src/install/hashtopolis.sql +++ b/src/migrations/mysql/20251127000000_initial.sql @@ -8,24 +8,24 @@ SET time_zone = "+00:00"; /*!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` ( +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,7 +44,7 @@ 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, `version` VARCHAR(20) NOT NULL, @@ -57,7 +57,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,7 +66,7 @@ CREATE TABLE `AgentError` ( `chunkId` INT(11) NULL ) ENGINE = InnoDB; -CREATE TABLE `AgentStat` ( +CREATE TABLE IF NOT EXISTS `AgentStat` ( `agentStatId` INT(11) NOT NULL, `agentId` INT(11) NOT NULL, `statType` INT(11) NOT NULL, @@ -74,20 +74,20 @@ CREATE TABLE `AgentStat` ( `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 `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 +102,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, @@ -175,7 +175,7 @@ INSERT INTO `Config` (`configId`, `configSectionId`, `item`, `value`) VALUES (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 +189,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 +200,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 +209,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 +219,25 @@ CREATE TABLE `File` ( `lineCount` BIGINT(20) DEFAULT NULL ) ENGINE = InnoDB; -CREATE TABLE `FilePretask` ( +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,7 +249,7 @@ 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, @@ -261,7 +261,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 +279,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 +874,7 @@ 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 `LogEntry` ( `logEntryId` INT(11) NOT NULL, `issuer` VARCHAR(50) NOT NULL, `issuerId` VARCHAR(50) NOT NULL, @@ -883,7 +883,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 +893,7 @@ CREATE TABLE `NotificationSetting` ( `isActive` TINYINT(4) NOT NULL )ENGINE = InnoDB; -CREATE TABLE `Pretask` ( +CREATE TABLE IF NOT EXISTS `Pretask` ( `pretaskId` INT(11) NOT NULL, `taskName` VARCHAR(100) NOT NULL, `attackCmd` TEXT NOT NULL, @@ -909,13 +909,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 +924,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 +934,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 +942,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 +985,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,7 +1003,7 @@ CREATE TABLE `TaskWrapper` ( `cracked` INT(11) NOT NULL )ENGINE = InnoDB; -CREATE TABLE `htp_User` ( +CREATE TABLE IF NOT EXISTS `htp_User` ( `userId` INT(11) NOT NULL, `username` VARCHAR(100) NOT NULL, `email` VARCHAR(150) NOT NULL, @@ -1022,7 +1022,7 @@ CREATE TABLE `htp_User` ( `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,7 +1030,7 @@ CREATE TABLE `Zap` ( `hashlistId` INT(11) NOT NULL ) ENGINE = InnoDB; -CREATE TABLE `ApiKey` ( +CREATE TABLE IF NOT EXISTS `ApiKey` ( `apiKeyId` INT(11) NOT NULL, `startValid` BIGINT(20) NOT NULL, `endValid` BIGINT(20) NOT NULL, @@ -1040,13 +1040,13 @@ CREATE TABLE `ApiKey` ( `apiGroupId` INT(11) NOT NULL ) ENGINE=InnoDB; -CREATE TABLE `ApiGroup` ( +CREATE TABLE IF NOT EXISTS `ApiGroup` ( `apiGroupId` INT(11) NOT NULL, `name` VARCHAR(100) NOT NULL, `permissions` TEXT NOT NULL ) ENGINE=InnoDB; -CREATE TABLE `FileDownload` ( +CREATE TABLE IF NOT EXISTS `FileDownload` ( `fileDownloadId` INT(11) NOT NULL, `time` BIGINT NOT NULL, `fileId` INT(11) NOT NULL, @@ -1056,7 +1056,7 @@ CREATE TABLE `FileDownload` ( INSERT INTO `ApiGroup` ( `apiGroupId`, `name`, `permissions`) VALUES (1, 'Administrators', 'ALL'); -CREATE TABLE `HealthCheck` ( +CREATE TABLE IF NOT EXISTS `HealthCheck` ( `healthCheckId` INT(11) NOT NULL, `time` BIGINT(20) NOT NULL, `status` INT(11) NOT NULL, @@ -1067,7 +1067,7 @@ CREATE TABLE `HealthCheck` ( `attackCmd` TEXT NOT NULL ) ENGINE=InnoDB; -CREATE TABLE `HealthCheckAgent` ( +CREATE TABLE IF NOT EXISTS `HealthCheckAgent` ( `healthCheckAgentId` INT(11) NOT NULL, `healthCheckId` INT(11) NOT NULL, `agentId` INT(11) NOT NULL, @@ -1079,7 +1079,7 @@ CREATE TABLE `HealthCheckAgent` ( `errors` TEXT NOT NULL ) ENGINE=InnoDB; -CREATE TABLE `Preprocessor` ( +CREATE TABLE IF NOT EXISTS `Preprocessor` ( `preprocessorId` INT(11) NOT NULL, `name` VARCHAR(256) NOT NULL, `url` VARCHAR(512) NOT NULL, @@ -1412,10 +1412,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 +1429,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` @@ -1484,13 +1484,13 @@ ALTER TABLE `HealthCheckAgent` ADD CONSTRAINT `HealthCheckAgent_ibfk_2` FOREIGN KEY (`healthCheckId`) REFERENCES `HealthCheck` (`healthCheckId`); 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`), diff --git a/src/migrations/postgres/20251127000000_initial.sql b/src/migrations/postgres/20251127000000_initial.sql new file mode 100644 index 000000000..273e7694d --- /dev/null +++ b/src/migrations/postgres/20251127000000_initial.sql @@ -0,0 +1,1193 @@ +-- Create tables and insert default entries +CREATE TABLE AccessGroup ( + accessGroupId SERIAL NOT NULL PRIMARY KEY, + groupName TEXT NOT NULL +); +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 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 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 FileDelete ( + fileDeleteId SERIAL NOT NULL PRIMARY KEY, + filename TEXT NOT NULL, + time BIGINT 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 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 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 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 Zap ( + zapId SERIAL NOT NULL PRIMARY KEY, + hash TEXT NOT NULL, + solveTime BIGINT NOT NULL, + agentId INT NULL, + hashlistId INT NOT 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 +); +CREATE TABLE FileDownload ( + fileDownloadId SERIAL NOT NULL PRIMARY KEY, + time BIGINT NOT NULL, + fileId INT NOT NULL, + status INT NOT NULL +); +INSERT INTO ApiGroup ( apiGroupId, name, permissions) VALUES + (1, 'Administrators', 'ALL'); + +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 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'); + +-- Add Indexes + +CREATE INDEX IF NOT EXISTS accessGroupId_idx ON AccessGroupAgent (accessGroupId); +CREATE INDEX IF NOT EXISTS agentId_idx ON AccessGroupAgent (agentId); + +CREATE INDEX IF NOT EXISTS accessGroupId_idx ON AccessGroupUser (accessGroupId); +CREATE INDEX IF NOT EXISTS userId_idx ON AccessGroupUser (userId); + +CREATE INDEX IF NOT EXISTS userId_idx ON Agent (userId); + +CREATE INDEX IF NOT EXISTS agentId_idx ON AgentError (agentId); +CREATE INDEX IF NOT EXISTS taskId_idx ON AgentError (taskId); + +CREATE INDEX IF NOT EXISTS agentId_idx ON AgentStat (agentId); + +CREATE INDEX IF NOT EXISTS agentId_idx ON AgentZap (agentId); +CREATE INDEX IF NOT EXISTS lastZapId_idx ON AgentZap (lastZapId); + +CREATE INDEX IF NOT EXISTS taskId_idx ON Assignment (taskId); +CREATE INDEX IF NOT EXISTS agentId_idx ON Assignment (agentId); + +CREATE INDEX IF NOT EXISTS taskId_idx ON Chunk (taskId); +CREATE INDEX IF NOT EXISTS progress_idx ON Chunk (progress); +CREATE INDEX IF NOT EXISTS agentId_idx ON Chunk (agentId); + +CREATE INDEX IF NOT EXISTS configSectionId_idx ON Config (configSectionId); + +CREATE INDEX IF NOT EXISTS crackerBinaryTypeId_idx ON CrackerBinary (crackerBinaryTypeId); + +CREATE INDEX IF NOT EXISTS fileId_idx ON FilePretask (fileId); +CREATE INDEX IF NOT EXISTS pretaskId_idx ON FilePretask (pretaskId); + +CREATE INDEX IF NOT EXISTS fileId_idx ON FileTask (fileId); +CREATE INDEX IF NOT EXISTS taskId_idx ON FileTask (taskId); + +CREATE INDEX IF NOT EXISTS hashlistId_idx ON Hash (hashlistId); +CREATE INDEX IF NOT EXISTS chunkId_idx ON Hash (chunkId); +CREATE INDEX IF NOT EXISTS isCracked_idx ON Hash (isCracked); +CREATE INDEX IF NOT EXISTS hash_idx ON Hash (hash); +CREATE INDEX IF NOT EXISTS timeCracked_idx ON Hash (timeCracked); + +CREATE INDEX IF NOT EXISTS hashlistId_idx ON HashBinary (hashlistId); +CREATE INDEX IF NOT EXISTS chunkId_idx ON HashBinary (chunkId); + +CREATE INDEX IF NOT EXISTS hashTypeId_idx ON Hashlist (hashTypeId); + +CREATE INDEX IF NOT EXISTS parentHashlistId_idx ON HashlistHashlist (parentHashlistId); +CREATE INDEX IF NOT EXISTS hashlistId_idx ON HashlistHashlist (hashlistId); + +CREATE INDEX IF NOT EXISTS userId_idx ON NotificationSetting (userId); + +CREATE INDEX IF NOT EXISTS userId_idx ON Session (userId); + +CREATE INDEX IF NOT EXISTS agentId_idx ON Speed (agentId); +CREATE INDEX IF NOT EXISTS taskId_idx ON Speed (taskId); + +CREATE INDEX IF NOT EXISTS supertaskId_idx ON SupertaskPretask (supertaskId); +CREATE INDEX IF NOT EXISTS pretaskId_idx ON SupertaskPretask (pretaskId); + +CREATE INDEX IF NOT EXISTS crackerBinaryId_idx ON Task (crackerBinaryId); + +CREATE INDEX IF NOT EXISTS hashlistId_idx ON TaskWrapper (hashlistId); +CREATE INDEX IF NOT EXISTS priority_idx ON TaskWrapper (priority); +CREATE INDEX IF NOT EXISTS isArchived_idx ON TaskWrapper (isArchived); +CREATE INDEX IF NOT EXISTS accessGroupId_idx ON TaskWrapper (accessGroupId); + +CREATE INDEX IF NOT EXISTS rightGroupId_idx ON htp_User (rightGroupId); + +CREATE INDEX IF NOT EXISTS agentId_idx ON Zap (agentId); +CREATE INDEX IF NOT EXISTS 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 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 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); +ALTER TABLE Zap ADD CONSTRAINT Zap_ibfk_2 FOREIGN KEY (hashlistId) REFERENCES Hashlist (hashlistId); + From a98ef7dc3e177aa586860c62f371c322f04d208c Mon Sep 17 00:00:00 2001 From: s3inlc Date: Fri, 28 Nov 2025 15:40:16 +0100 Subject: [PATCH 02/42] added update for faking sqlx migration for existing mysql systems --- src/install/updates/update_v1.0.0-rainbow4_vx.x.x.php | 8 ++++++++ 1 file changed, 8 insertions(+) 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 7759616ee..5dcbf5782 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 @@ -21,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,0x87B4F9CE14A0C5A131A84D96044E89BAD641D0043E19141341C2DE2D307A25B748EF4F356CF4E0ACE439F84EC6C8F77A," . time() . ");"); + } + $EXECUTED["v1.0.0-rainbow4_migration_to_migrations"] = true; +} From 2b0834782498e41958c16249d15c7897286f3888 Mon Sep 17 00:00:00 2001 From: s3inlc Date: Fri, 28 Nov 2025 15:57:55 +0100 Subject: [PATCH 03/42] set execution time of fake sqlx migration to 1 --- src/install/updates/update_v1.0.0-rainbow4_vx.x.x.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5dcbf5782..88134032d 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 @@ -25,7 +25,7 @@ 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,0x87B4F9CE14A0C5A131A84D96044E89BAD641D0043E19141341C2DE2D307A25B748EF4F356CF4E0ACE439F84EC6C8F77A," . time() . ");"); + Factory::getAgentFactory()->getDB()->query("INSERT INTO `_sqlx_migrations` VALUES (20251127000000,'initial','2025-11-28 14:29:13',1,0x87B4F9CE14A0C5A131A84D96044E89BAD641D0043E19141341C2DE2D307A25B748EF4F356CF4E0ACE439F84EC6C8F77A,1);"); } $EXECUTED["v1.0.0-rainbow4_migration_to_migrations"] = true; } From 7349062f2eeb196ad79b367d6f31ab8b94c49591 Mon Sep 17 00:00:00 2001 From: s3inlc Date: Fri, 28 Nov 2025 16:14:25 +0100 Subject: [PATCH 04/42] setting sequences for all tables to avoid collisions in serials --- .../postgres/20251127000000_initial.sql | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/migrations/postgres/20251127000000_initial.sql b/src/migrations/postgres/20251127000000_initial.sql index 273e7694d..a296d65eb 100644 --- a/src/migrations/postgres/20251127000000_initial.sql +++ b/src/migrations/postgres/20251127000000_initial.sql @@ -1039,8 +1039,53 @@ CREATE TABLE Preprocessor ( 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'); --- Add Indexes +-- 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('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('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('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('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('htp_User', 'userid'), MAX(userId)) from htp_User; +SELECT pg_catalog.setval(pg_get_serial_sequence('Zap', 'zapid'), MAX(zapId)) from Zap; +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('FileDownload', 'filedownloadid'), MAX(fileDownloadId)) from FileDownload; +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('Preprocessor', 'preprocessorid'), MAX(preprocessorId)) from Preprocessor; + +-- Add Indexes CREATE INDEX IF NOT EXISTS accessGroupId_idx ON AccessGroupAgent (accessGroupId); CREATE INDEX IF NOT EXISTS agentId_idx ON AccessGroupAgent (agentId); From 8ba28237883f79ebf20152eeca81cc52d435d152 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 11:15:17 +0100 Subject: [PATCH 05/42] fixed sql query for migrations insert --- src/install/updates/update_v1.0.0-rainbow4_vx.x.x.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 88134032d..2680918eb 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 @@ -24,7 +24,7 @@ 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("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,0x87B4F9CE14A0C5A131A84D96044E89BAD641D0043E19141341C2DE2D307A25B748EF4F356CF4E0ACE439F84EC6C8F77A,1);"); } $EXECUTED["v1.0.0-rainbow4_migration_to_migrations"] = true; From 14f68741e73f134be7ce74b9e8836d5fce2109a0 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 11:17:32 +0100 Subject: [PATCH 06/42] removed selective update execution part and added one last force upgrade at the beginning --- src/inc/load.php | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/src/inc/load.php b/src/inc/load.php index 43cf555c7..4e1ac868b 100755 --- a/src/inc/load.php +++ b/src/inc/load.php @@ -77,6 +77,10 @@ $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 && !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); @@ -170,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) { @@ -196,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()) { From 68a918af868b15879be500de56a4bc48a161a25b Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 12:06:43 +0100 Subject: [PATCH 07/42] prevent access to migrations dir --- src/migrations/.htaccess | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/migrations/.htaccess 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 From cd9d006735b61fc29b9998ddeed3c325159eace7 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 14:49:16 +0100 Subject: [PATCH 08/42] made style and order consistent in files --- .../mysql/20251127000000_initial.sql | 192 +++++++++--------- .../postgres/20251127000000_initial.sql | 111 ++++++---- 2 files changed, 171 insertions(+), 132 deletions(-) diff --git a/src/migrations/mysql/20251127000000_initial.sql b/src/migrations/mysql/20251127000000_initial.sql index 2dc14d914..c70d4ddb0 100644 --- a/src/migrations/mysql/20251127000000_initial.sql +++ b/src/migrations/mysql/20251127000000_initial.sql @@ -1,7 +1,6 @@ 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 */; @@ -46,7 +45,7 @@ CREATE TABLE IF NOT EXISTS `Agent` ( 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, @@ -67,10 +66,10 @@ CREATE TABLE IF NOT EXISTS `AgentError` ( ) ENGINE = InnoDB; 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, + `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; @@ -80,6 +79,25 @@ CREATE TABLE IF NOT EXISTS `AgentZap` ( `lastZapId` INT(11) NULL ) ENGINE = InnoDB; +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, @@ -174,7 +192,6 @@ INSERT INTO `Config` (`configId`, `configSectionId`, `item`, `value`) VALUES (78, 3, 'defaultPageSize', '10000'), (79, 3, 'maxPageSize', '50000'); - CREATE TABLE IF NOT EXISTS `ConfigSection` ( `configSectionId` INT(11) NOT NULL, `sectionName` VARCHAR(100) NOT NULL @@ -219,6 +236,13 @@ CREATE TABLE IF NOT EXISTS `File` ( `lineCount` BIGINT(20) DEFAULT NULL ) ENGINE = InnoDB; +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, @@ -253,7 +277,7 @@ 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, @@ -874,6 +898,48 @@ INSERT INTO `HashType` (`hashTypeId`, `description`, `isSalted`, `isSlowHash`) V (73000, 'Generic Hash [Bridged: Python Interpreter with GIL]', 0, 1), (99999, 'Plaintext', 0, 0); +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, @@ -893,6 +959,16 @@ CREATE TABLE IF NOT EXISTS `NotificationSetting` ( `isActive` TINYINT(4) NOT NULL )ENGINE = InnoDB; +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, @@ -1003,25 +1079,6 @@ CREATE TABLE IF NOT EXISTS `TaskWrapper` ( `cracked` INT(11) 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 `Zap` ( `zapId` INT(11) NOT NULL, `hash` MEDIUMTEXT NOT NULL, @@ -1030,65 +1087,6 @@ CREATE TABLE IF NOT EXISTS `Zap` ( `hashlistId` INT(11) NOT NULL ) ENGINE = InnoDB; -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; - -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; - -INSERT INTO `ApiGroup` ( `apiGroupId`, `name`, `permissions`) VALUES - (1, 'Administrators', 'ALL'); - -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 `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 +1207,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 +1262,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`), @@ -1359,6 +1357,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 +1397,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; @@ -1483,6 +1481,9 @@ 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 `htp_User` (`userId`); @@ -1512,9 +1513,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 index a296d65eb..8b6664d47 100644 --- a/src/migrations/postgres/20251127000000_initial.sql +++ b/src/migrations/postgres/20251127000000_initial.sql @@ -3,18 +3,21 @@ CREATE TABLE AccessGroup ( accessGroupId SERIAL NOT NULL PRIMARY KEY, groupName TEXT NOT NULL ); + 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, + agentId SERIAL NOT NULL PRIMARY KEY, agentName TEXT NOT NULL, uid TEXT NOT NULL, os INT NOT NULL, @@ -31,15 +34,17 @@ CREATE TABLE Agent ( cpuOnly INT NOT NULL, clientSignature TEXT NOT NULL ); + CREATE TABLE AgentBinary ( - agentBinaryId SERIAL NOT NULL PRIMARY KEY, - binaryType TEXT NOT NULL, + 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', ''); @@ -51,6 +56,7 @@ CREATE TABLE AgentError ( error TEXT NOT NULL, chunkId INT NULL ); + CREATE TABLE AgentStat ( agentStatId SERIAL NOT NULL PRIMARY KEY, agentId INT NOT NULL, @@ -58,19 +64,22 @@ CREATE TABLE AgentStat ( 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 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, + chunkId SERIAL NOT NULL PRIMARY KEY, taskId INT NOT NULL, skip BIGINT NOT NULL, length BIGINT NOT NULL, @@ -83,12 +92,14 @@ CREATE TABLE Chunk ( cracked INT NOT NULL, speed BIGINT NOT NULL ); + CREATE TABLE Config ( - configId SERIAL NOT NULL PRIMARY KEY, + 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'), @@ -154,11 +165,11 @@ INSERT INTO Config (configId, configSectionId, item, value) VALUES (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'), @@ -169,12 +180,13 @@ INSERT INTO ConfigSection (configSectionId, sectionName) VALUES (7, 'Notifications'); CREATE TABLE CrackerBinary ( - crackerBinaryId SERIAL NOT NULL PRIMARY KEY, + 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'); @@ -183,11 +195,12 @@ CREATE TABLE CrackerBinaryType ( 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, + fileId SERIAL NOT NULL PRIMARY KEY, filename TEXT NOT NULL, size BIGINT NOT NULL, isSecret INT NOT NULL, @@ -195,23 +208,27 @@ CREATE TABLE File ( accessGroupId INT NOT NULL, lineCount BIGINT DEFAULT 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 FileDelete ( fileDeleteId SERIAL NOT NULL PRIMARY KEY, filename TEXT NOT NULL, time BIGINT NOT NULL ); + CREATE TABLE Hash ( - hashId SERIAL NOT NULL PRIMARY KEY, + hashId SERIAL NOT NULL PRIMARY KEY, hashlistId INT NOT NULL, hash TEXT NOT NULL, salt TEXT DEFAULT NULL, @@ -221,6 +238,7 @@ CREATE TABLE Hash ( isCracked INT NOT NULL, crackPos BIGINT NOT NULL ); + CREATE TABLE HashBinary ( hashBinaryId SERIAL NOT NULL PRIMARY KEY, hashlistId INT NOT NULL, @@ -232,8 +250,9 @@ CREATE TABLE HashBinary ( isCracked INT NOT NULL, crackPos BIGINT NOT NULL ); + CREATE TABLE Hashlist ( - hashlistId SERIAL NOT NULL PRIMARY KEY, + hashlistId SERIAL NOT NULL PRIMARY KEY, hashlistName TEXT NOT NULL, format INT NOT NULL, hashTypeId INT NOT NULL, @@ -249,17 +268,20 @@ CREATE TABLE Hashlist ( 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, + 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), @@ -850,6 +872,7 @@ CREATE TABLE LogEntry ( message TEXT NOT NULL, time BIGINT NOT NULL ); + CREATE TABLE NotificationSetting ( notificationSettingId SERIAL NOT NULL PRIMARY KEY, action TEXT NOT NULL, @@ -859,8 +882,9 @@ CREATE TABLE NotificationSetting ( receiver TEXT NOT NULL, isActive INT NOT NULL ); + CREATE TABLE Pretask ( - pretaskId SERIAL NOT NULL PRIMARY KEY, + pretaskId SERIAL NOT NULL PRIMARY KEY, taskName TEXT NOT NULL, attackCmd TEXT NOT NULL, chunkTime INT NOT NULL, @@ -874,21 +898,24 @@ CREATE TABLE Pretask ( 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, + sessionId SERIAL NOT NULL PRIMARY KEY, userId INT NOT NULL, sessionStartDate BIGINT NOT NULL, lastActionDate BIGINT NOT NULL, @@ -896,6 +923,7 @@ CREATE TABLE Session ( sessionLifetime INT NOT NULL, sessionKey TEXT NOT NULL ); + CREATE TABLE Speed ( speedId SERIAL NOT NULL PRIMARY KEY, agentId INT NOT NULL, @@ -903,21 +931,25 @@ CREATE TABLE Speed ( 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, + 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, + taskId SERIAL NOT NULL PRIMARY KEY, taskName TEXT NOT NULL, attackCmd TEXT NOT NULL, chunkTime INT NOT NULL, @@ -942,13 +974,15 @@ CREATE TABLE Task ( 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, + taskWrapperId SERIAL NOT NULL PRIMARY KEY, priority INT NOT NULL, maxAgents INT NOT NULL, taskType INT NOT NULL, @@ -958,8 +992,9 @@ CREATE TABLE TaskWrapper ( isArchived INT NOT NULL, cracked INT NOT NULL ); + CREATE TABLE htp_User ( - userId SERIAL NOT NULL PRIMARY KEY, + userId SERIAL NOT NULL PRIMARY KEY, username TEXT NOT NULL, email TEXT NOT NULL, passwordHash TEXT NOT NULL, @@ -976,15 +1011,17 @@ CREATE TABLE htp_User ( otp3 TEXT DEFAULT NULL, otp4 TEXT DEFAULT NULL ); + CREATE TABLE Zap ( - zapId SERIAL NOT NULL PRIMARY KEY, + zapId SERIAL NOT NULL PRIMARY KEY, hash TEXT NOT NULL, solveTime BIGINT NOT NULL, agentId INT NULL, hashlistId INT NOT NULL ); + CREATE TABLE ApiKey ( - apiKeyId SERIAL NOT NULL PRIMARY KEY, + apiKeyId SERIAL NOT NULL PRIMARY KEY, startValid BIGINT NOT NULL, endValid BIGINT NOT NULL, accessKey TEXT NOT NULL, @@ -992,22 +1029,25 @@ CREATE TABLE ApiKey ( userId INT NOT NULL, apiGroupId INT NOT NULL ); + CREATE TABLE ApiGroup ( - apiGroupId SERIAL NOT NULL PRIMARY KEY, + apiGroupId SERIAL NOT NULL PRIMARY KEY, name TEXT NOT NULL, permissions TEXT NOT NULL ); + CREATE TABLE FileDownload ( fileDownloadId SERIAL NOT NULL PRIMARY KEY, time BIGINT NOT NULL, fileId INT NOT NULL, status INT NOT NULL ); + INSERT INTO ApiGroup ( apiGroupId, name, permissions) VALUES (1, 'Administrators', 'ALL'); CREATE TABLE HealthCheck ( - healthCheckId SERIAL NOT NULL PRIMARY KEY, + healthCheckId SERIAL NOT NULL PRIMARY KEY, time BIGINT NOT NULL, status INT NOT NULL, checkType INT NOT NULL, @@ -1016,6 +1056,7 @@ CREATE TABLE HealthCheck ( expectedCracks INT NOT NULL, attackCmd TEXT NOT NULL ); + CREATE TABLE HealthCheckAgent ( healthCheckAgentId SERIAL NOT NULL PRIMARY KEY, healthCheckId INT NOT NULL, @@ -1027,8 +1068,9 @@ CREATE TABLE HealthCheckAgent ( htp_end BIGINT NOT NULL, errors TEXT NOT NULL ); + CREATE TABLE Preprocessor ( - preprocessorId SERIAL NOT NULL PRIMARY KEY, + preprocessorId SERIAL NOT NULL PRIMARY KEY, name TEXT NOT NULL, url TEXT NOT NULL, binaryName TEXT NOT NULL, @@ -1036,6 +1078,7 @@ CREATE TABLE Preprocessor ( 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'); @@ -1048,6 +1091,8 @@ SELECT pg_catalog.setval(pg_get_serial_sequence('AgentBinary', 'agentbinaryid'), 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; @@ -1055,6 +1100,7 @@ SELECT pg_catalog.setval(pg_get_serial_sequence('ConfigSection', 'configsectioni 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; @@ -1063,8 +1109,12 @@ SELECT pg_catalog.setval(pg_get_serial_sequence('HashBinary', 'hashbinaryid'), M 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; @@ -1075,15 +1125,7 @@ SELECT pg_catalog.setval(pg_get_serial_sequence('SupertaskPretask', 'supertaskpr 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('htp_User', 'userid'), MAX(userId)) from htp_User; SELECT pg_catalog.setval(pg_get_serial_sequence('Zap', 'zapid'), MAX(zapId)) from Zap; -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('FileDownload', 'filedownloadid'), MAX(fileDownloadId)) from FileDownload; -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('Preprocessor', 'preprocessorid'), MAX(preprocessorId)) from Preprocessor; - -- Add Indexes CREATE INDEX IF NOT EXISTS accessGroupId_idx ON AccessGroupAgent (accessGroupId); @@ -1133,6 +1175,8 @@ CREATE INDEX IF NOT EXISTS hashTypeId_idx ON Hashlist (hashTypeId); CREATE INDEX IF NOT EXISTS parentHashlistId_idx ON HashlistHashlist (parentHashlistId); CREATE INDEX IF NOT EXISTS hashlistId_idx ON HashlistHashlist (hashlistId); +CREATE INDEX IF NOT EXISTS rightGroupId_idx ON htp_User (rightGroupId); + CREATE INDEX IF NOT EXISTS userId_idx ON NotificationSetting (userId); CREATE INDEX IF NOT EXISTS userId_idx ON Session (userId); @@ -1150,8 +1194,6 @@ CREATE INDEX IF NOT EXISTS priority_idx ON TaskWrapper (priority); CREATE INDEX IF NOT EXISTS isArchived_idx ON TaskWrapper (isArchived); CREATE INDEX IF NOT EXISTS accessGroupId_idx ON TaskWrapper (accessGroupId); -CREATE INDEX IF NOT EXISTS rightGroupId_idx ON htp_User (rightGroupId); - CREATE INDEX IF NOT EXISTS agentId_idx ON Zap (agentId); CREATE INDEX IF NOT EXISTS hashlistId_idx ON Zap (hashlistId); @@ -1210,6 +1252,8 @@ ALTER TABLE HealthCheck ADD CONSTRAINT HealthCheck_ibfk_1 FOREIGN KEY (crackerBi 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); @@ -1231,8 +1275,5 @@ ALTER TABLE TaskDebugOutput ADD CONSTRAINT TaskDebugOutput_ibfk_1 FOREIGN KEY (t 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 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); ALTER TABLE Zap ADD CONSTRAINT Zap_ibfk_2 FOREIGN KEY (hashlistId) REFERENCES Hashlist (hashlistId); - From bd8ddb7353d7803d396b8d391af4fee198045aa3 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 14:58:06 +0100 Subject: [PATCH 09/42] added checksum for existing upgrades --- src/install/updates/update_v1.0.0-rainbow4_vx.x.x.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2680918eb..45bd0ccc5 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 @@ -25,7 +25,7 @@ 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,0x87B4F9CE14A0C5A131A84D96044E89BAD641D0043E19141341C2DE2D307A25B748EF4F356CF4E0ACE439F84EC6C8F77A,1);"); + Factory::getAgentFactory()->getDB()->query("INSERT INTO `_sqlx_migrations` VALUES (20251127000000,'initial','2025-11-28 14:29:13',1,0x22F3A0D84CF66E9694946A244FBC19B314F0EA85B9B5C66A3C2BB67EE365AA78D025D9C90FBCCE8E4896FD20988A6740,1);"); } $EXECUTED["v1.0.0-rainbow4_migration_to_migrations"] = true; } From c3c02093f3cbf94e2491100eb194fd1c742aeb35 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 15:28:58 +0100 Subject: [PATCH 10/42] updated github actions to run both systems --- ...r-compose.yml => docker-compose.mysql.yml} | 1 + .devcontainer/docker-compose.postgres.yml | 51 +++++++++++++++++++ .github/actions/start-hashtopolis/action.yml | 8 ++- .github/workflows/ci.yml | 7 +++ .github/workflows/docs-build.yml | 2 + .github/workflows/docs.yml | 4 +- 6 files changed, 71 insertions(+), 2 deletions(-) rename .devcontainer/{docker-compose.yml => docker-compose.mysql.yml} (97%) create mode 100644 .devcontainer/docker-compose.postgres.yml 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..3cabdf5db --- /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: 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: + # 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..f2cd6c7c9 100644 --- a/.github/actions/start-hashtopolis/action.yml +++ b/.github/actions/start-hashtopolis/action.yml @@ -1,12 +1,18 @@ 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" + runs: using: "composite" steps: - name: Start application containers working-directory: .devcontainer - run: docker compose up -d + run: docker compose up -f docker-compose.${{ env.INPUT_DB_SYSTEM }}.yml shell: bash - name: Install composer dependencies packages run: docker exec hashtopolis-server-dev composer install --working-dir=/var/www/html/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc14f4d88..7a8fe8fa9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,11 +13,18 @@ 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 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/ From 73b1bdc2d27a861f09da26c729e5e601b6b3fa85 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 15:35:51 +0100 Subject: [PATCH 11/42] fixed github input --- .github/actions/start-hashtopolis/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/start-hashtopolis/action.yml b/.github/actions/start-hashtopolis/action.yml index f2cd6c7c9..014031dad 100644 --- a/.github/actions/start-hashtopolis/action.yml +++ b/.github/actions/start-hashtopolis/action.yml @@ -12,7 +12,7 @@ runs: steps: - name: Start application containers working-directory: .devcontainer - run: docker compose up -f docker-compose.${{ env.INPUT_DB_SYSTEM }}.yml + run: docker compose -f docker-compose.${{ github.event.inputs.db_system }}.yml -f shell: bash - name: Install composer dependencies packages run: docker exec hashtopolis-server-dev composer install --working-dir=/var/www/html/ From bf3b2cdfdcf56e2f08a4504581d747b34146db9b Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 15:36:40 +0100 Subject: [PATCH 12/42] removed double -f --- .github/actions/start-hashtopolis/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/start-hashtopolis/action.yml b/.github/actions/start-hashtopolis/action.yml index 014031dad..bfd935c39 100644 --- a/.github/actions/start-hashtopolis/action.yml +++ b/.github/actions/start-hashtopolis/action.yml @@ -12,7 +12,7 @@ runs: steps: - name: Start application containers working-directory: .devcontainer - run: docker compose -f docker-compose.${{ github.event.inputs.db_system }}.yml -f + run: docker compose -f docker-compose.${{ github.event.inputs.db_system }}.yml shell: bash - name: Install composer dependencies packages run: docker exec hashtopolis-server-dev composer install --working-dir=/var/www/html/ From e06acaed90ad0640ab3a898d480695a50bbeee63 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 15:38:41 +0100 Subject: [PATCH 13/42] input style fix --- .github/actions/start-hashtopolis/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/start-hashtopolis/action.yml b/.github/actions/start-hashtopolis/action.yml index bfd935c39..cab103fde 100644 --- a/.github/actions/start-hashtopolis/action.yml +++ b/.github/actions/start-hashtopolis/action.yml @@ -12,7 +12,7 @@ runs: steps: - name: Start application containers working-directory: .devcontainer - run: docker compose -f docker-compose.${{ github.event.inputs.db_system }}.yml + run: docker compose -f docker-compose.${{ inputs.db_system }}.yml shell: bash - name: Install composer dependencies packages run: docker exec hashtopolis-server-dev composer install --working-dir=/var/www/html/ From 9a26d1c6dd918356dba216a47ccd61e3e41a47df Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 15:39:22 +0100 Subject: [PATCH 14/42] syntax fix --- .github/actions/start-hashtopolis/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/start-hashtopolis/action.yml b/.github/actions/start-hashtopolis/action.yml index cab103fde..30f8cc8f0 100644 --- a/.github/actions/start-hashtopolis/action.yml +++ b/.github/actions/start-hashtopolis/action.yml @@ -12,7 +12,7 @@ runs: steps: - name: Start application containers working-directory: .devcontainer - run: docker compose -f docker-compose.${{ inputs.db_system }}.yml + run: docker compose -f docker-compose.${{ inputs.db_system }}.yml up shell: bash - name: Install composer dependencies packages run: docker exec hashtopolis-server-dev composer install --working-dir=/var/www/html/ From 4a076e69cd7a679303f5e6c44ed08a9044130e6b Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 15:45:36 +0100 Subject: [PATCH 15/42] fix workflow with -d on compose and postgres config --- .devcontainer/docker-compose.postgres.yml | 16 ++++++---------- .github/actions/start-hashtopolis/action.yml | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/.devcontainer/docker-compose.postgres.yml b/.devcontainer/docker-compose.postgres.yml index 3cabdf5db..6b7181c84 100644 --- a/.devcontainer/docker-compose.postgres.yml +++ b/.devcontainer/docker-compose.postgres.yml @@ -28,19 +28,15 @@ services: - hashtopolis_dev hashtopolis-db-dev: container_name: hashtopolis-db-dev - image: mysql:8.0 + image: postgres:13 restart: always - ports: - - "3306:3306" volumes: - - hashtopolis-db-dev:/var/lib/mysql + - db:/var/lib/postgresql/data environment: - MYSQL_ROOT_PASSWORD: hashtopolis - MYSQL_DATABASE: hashtopolis - MYSQL_USER: hashtopolis - MYSQL_PASSWORD: hashtopolis - networks: - - hashtopolis_dev + POSTGRES_DB: hashtopolis + POSTGRES_USER: hashtopolis + POSTGRES_PASSWORD: hashtopolis + volumes: hashtopolis-db-dev: hashtopolis-server-dev: diff --git a/.github/actions/start-hashtopolis/action.yml b/.github/actions/start-hashtopolis/action.yml index 30f8cc8f0..764854f7e 100644 --- a/.github/actions/start-hashtopolis/action.yml +++ b/.github/actions/start-hashtopolis/action.yml @@ -12,7 +12,7 @@ runs: steps: - name: Start application containers working-directory: .devcontainer - run: docker compose -f docker-compose.${{ inputs.db_system }}.yml up + run: docker compose -f docker-compose.${{ inputs.db_system }}.yml up -d shell: bash - name: Install composer dependencies packages run: docker exec hashtopolis-server-dev composer install --working-dir=/var/www/html/ From 445e1bc74fa1b30f65845f27aa86000c457dc16c Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 15:47:32 +0100 Subject: [PATCH 16/42] fixed docker compose refer --- .devcontainer/docker-compose.postgres.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/docker-compose.postgres.yml b/.devcontainer/docker-compose.postgres.yml index 6b7181c84..da92d3ef2 100644 --- a/.devcontainer/docker-compose.postgres.yml +++ b/.devcontainer/docker-compose.postgres.yml @@ -31,7 +31,7 @@ services: image: postgres:13 restart: always volumes: - - db:/var/lib/postgresql/data + - hashtopolis-db-dev:/var/lib/postgresql/data environment: POSTGRES_DB: hashtopolis POSTGRES_USER: hashtopolis From 309bcf4b668d5183857d2c68df3605cc206aff8c Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 15:59:26 +0100 Subject: [PATCH 17/42] add exposed port --- .devcontainer/docker-compose.postgres.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.devcontainer/docker-compose.postgres.yml b/.devcontainer/docker-compose.postgres.yml index da92d3ef2..73f1556b5 100644 --- a/.devcontainer/docker-compose.postgres.yml +++ b/.devcontainer/docker-compose.postgres.yml @@ -30,6 +30,8 @@ services: container_name: hashtopolis-db-dev image: postgres:13 restart: always + ports: + - "5432:5432" volumes: - hashtopolis-db-dev:/var/lib/postgresql/data environment: From 18230a76eb8255386c4f655cfa14de1d0e4a1268 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 16:18:46 +0100 Subject: [PATCH 18/42] fixed postgres devcontainer compose --- .devcontainer/docker-compose.postgres.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.devcontainer/docker-compose.postgres.yml b/.devcontainer/docker-compose.postgres.yml index 73f1556b5..0a7747910 100644 --- a/.devcontainer/docker-compose.postgres.yml +++ b/.devcontainer/docker-compose.postgres.yml @@ -38,6 +38,8 @@ services: POSTGRES_DB: hashtopolis POSTGRES_USER: hashtopolis POSTGRES_PASSWORD: hashtopolis + networks: + - hashtopolis_dev volumes: hashtopolis-db-dev: From ba5b1acc2989aff733d50c02f2bb1feb9706d70f Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 16:19:03 +0100 Subject: [PATCH 19/42] execute legacy test framework only with mysql --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a8fe8fa9..8ddd46e12 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,7 @@ jobs: - 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 + if: ${{ matrix.db_system == 'mysql' }} # the legacy is only supposed to work with mysql 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 From 2d34f61f7e3d4e6594d6f945442bb6ab0cf176ac Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 16:25:51 +0100 Subject: [PATCH 20/42] fixed path to initial sql --- ci/server/setup.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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()); From 9910401f70a18050b30ce693cf2f03f17ce2dcfa Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 16:30:48 +0100 Subject: [PATCH 21/42] fix second occurrence of initial sql --- ci/HashtopolisTest.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/HashtopolisTest.class.php b/ci/HashtopolisTest.class.php index 47031a970..26d7d7968 100644 --- a/ci/HashtopolisTest.class.php +++ b/ci/HashtopolisTest.class.php @@ -76,7 +76,7 @@ public function init($version) { // 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")); From fb707140b1a80e33954469990d11d359cac830c3 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 16:42:40 +0100 Subject: [PATCH 22/42] create separate compose files for the tests to avoid clashing with devcontainer specific mount --- .github/actions/start-hashtopolis/action.yml | 2 +- .github/docker-compose.mysql.yml | 47 ++++++++++++++++++++ .github/docker-compose.postgres.yml | 47 ++++++++++++++++++++ ci/apiv2/hashtopolis-test-defaults.yaml | 2 +- docker-compose.mysql.yml | 2 +- 5 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 .github/docker-compose.mysql.yml create mode 100644 .github/docker-compose.postgres.yml diff --git a/.github/actions/start-hashtopolis/action.yml b/.github/actions/start-hashtopolis/action.yml index 764854f7e..aed00868d 100644 --- a/.github/actions/start-hashtopolis/action.yml +++ b/.github/actions/start-hashtopolis/action.yml @@ -11,7 +11,7 @@ runs: using: "composite" steps: - name: Start application containers - working-directory: .devcontainer + working-directory: .github run: docker compose -f docker-compose.${{ inputs.db_system }}.yml up -d shell: bash - name: Install composer dependencies packages 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/ci/apiv2/hashtopolis-test-defaults.yaml b/ci/apiv2/hashtopolis-test-defaults.yaml index 1b0a7eb66..d24a95c4b 100644 --- a/ci/apiv2/hashtopolis-test-defaults.yaml +++ b/ci/apiv2/hashtopolis-test-defaults.yaml @@ -1,3 +1,3 @@ -hashtopolis_uri: 'http://localhost:80' +hashtopolis_uri: 'http://localhost:8080' username: 'admin' password: 'hashtopolis' diff --git a/docker-compose.mysql.yml b/docker-compose.mysql.yml index 416f5290b..03010d489 100644 --- a/docker-compose.mysql.yml +++ b/docker-compose.mysql.yml @@ -15,7 +15,7 @@ services: 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 From 7861d4d775662cdcec64ad4d8e1857dea4cf243c Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 16:43:24 +0100 Subject: [PATCH 23/42] comment out unnecessary part --- .github/actions/start-hashtopolis/action.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/actions/start-hashtopolis/action.yml b/.github/actions/start-hashtopolis/action.yml index aed00868d..d7d180a14 100644 --- a/.github/actions/start-hashtopolis/action.yml +++ b/.github/actions/start-hashtopolis/action.yml @@ -14,9 +14,10 @@ runs: working-directory: .github run: docker compose -f docker-compose.${{ inputs.db_system }}.yml up -d shell: bash - - name: Install composer dependencies packages - run: docker exec hashtopolis-server-dev composer install --working-dir=/var/www/html/ - 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 From d2059a59d38a44ebe83ec67cdabc5274e5a720c0 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 16:54:32 +0100 Subject: [PATCH 24/42] really only call upgrade on mysql setups --- src/inc/load.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inc/load.php b/src/inc/load.php index 4e1ac868b..e2ac8502f 100755 --- a/src/inc/load.php +++ b/src/inc/load.php @@ -78,7 +78,7 @@ } // 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 && !Util::databaseTableExists("_sqlx_migrations")) { +if (!$initialSetup && DBA_TYPE == "mysql" && !Util::databaseTableExists("_sqlx_migrations")) { include(dirname(__FILE__) . "/../install/updates/update.php"); } From b17e8cbbc4311256f3bae45a23dd99d4f1742ab1 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 16:55:25 +0100 Subject: [PATCH 25/42] no manual init for test needed --- ci/HashtopolisTest.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/HashtopolisTest.class.php b/ci/HashtopolisTest.class.php index 26d7d7968..1ed518c3f 100644 --- a/ci/HashtopolisTest.class.php +++ b/ci/HashtopolisTest.class.php @@ -70,7 +70,7 @@ 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"); @@ -92,7 +92,7 @@ public function init($version) { $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->apiKey = Factory::getApiKeyFactory()->save($this->apiKey); + $this->apiKey = Factory::getApiKeyFactory()->save($this->apiKey);*/ // $versionStore = new StoredValue("version", ($version == 'master') ? explode("+", $VERSION)[0] : $version); // Factory::getStoredValueFactory()->save($versionStore); // $buildStore = new StoredValue("build", ($version == 'master') ? Util::getGitCommit(true) : $this->RELEASES[$version]); From 69e8372c57b0bf50d2ab3f05de1f19f5d89af97c Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 16:56:59 +0100 Subject: [PATCH 26/42] just only create api key, everything else should be created from basic setup --- ci/HashtopolisTest.class.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ci/HashtopolisTest.class.php b/ci/HashtopolisTest.class.php index 1ed518c3f..fb59bf071 100644 --- a/ci/HashtopolisTest.class.php +++ b/ci/HashtopolisTest.class.php @@ -82,17 +82,17 @@ public function init($version) { 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->apiKey = Factory::getApiKeyFactory()->save($this->apiKey);*/ + Factory::getAccessGroupUserFactory()->save($accessGroup);*/ + $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); // $buildStore = new StoredValue("build", ($version == 'master') ? Util::getGitCommit(true) : $this->RELEASES[$version]); From 05682a9cd4a4178918fd2689cf820bb29aef2d39 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 17:09:39 +0100 Subject: [PATCH 27/42] set test user pass to default --- ci/HashtopolisTest.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/HashtopolisTest.class.php b/ci/HashtopolisTest.class.php index fb59bf071..76b321440 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; From 468456c7faabfcbeaad3b71a53023272cef8d110 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 17:10:27 +0100 Subject: [PATCH 28/42] reversed hashtopolis test parameters to default --- ci/apiv2/hashtopolis-test-defaults.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/apiv2/hashtopolis-test-defaults.yaml b/ci/apiv2/hashtopolis-test-defaults.yaml index d24a95c4b..1b0a7eb66 100644 --- a/ci/apiv2/hashtopolis-test-defaults.yaml +++ b/ci/apiv2/hashtopolis-test-defaults.yaml @@ -1,3 +1,3 @@ -hashtopolis_uri: 'http://localhost:8080' +hashtopolis_uri: 'http://localhost:80' username: 'admin' password: 'hashtopolis' From 342cc1b031e247ace3527d393c50901c0be4d864 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 17:17:49 +0100 Subject: [PATCH 29/42] create additional access group on tests --- ci/HashtopolisTest.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/HashtopolisTest.class.php b/ci/HashtopolisTest.class.php index 76b321440..40d1ee5cf 100644 --- a/ci/HashtopolisTest.class.php +++ b/ci/HashtopolisTest.class.php @@ -88,9 +88,9 @@ public function init($version) { /*$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->user = Factory::getUserFactory()->save($this->user);*/ + $accessGroup = new AccessGroupUser(null, 1, 1); + Factory::getAccessGroupUserFactory()->save($accessGroup); $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); From 19d5453f1ceea767f8c874213adc640b2232c06f Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 17:26:12 +0100 Subject: [PATCH 30/42] avoid creating multiple relations --- ci/HashtopolisTest.class.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ci/HashtopolisTest.class.php b/ci/HashtopolisTest.class.php index 40d1ee5cf..87d3f7b16 100644 --- a/ci/HashtopolisTest.class.php +++ b/ci/HashtopolisTest.class.php @@ -89,8 +89,7 @@ public function init($version) { $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, 1); - Factory::getAccessGroupUserFactory()->save($accessGroup); + 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); From e6c0e9841a20fc0b0fae3181a226d3afcc5c54d2 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Sat, 29 Nov 2025 17:35:45 +0100 Subject: [PATCH 31/42] deactivate legacy tests for now --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ddd46e12..02a3260ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,9 +27,9 @@ jobs: 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 - if: ${{ matrix.db_system == 'mysql' }} # the legacy is only supposed to work with mysql - run: docker exec hashtopolis-server-dev php /var/www/html/ci/run.php -vmaster +# - name: Run test suite +# if: ${{ matrix.db_system == 'mysql' }} # the legacy is only supposed to work with mysql +# 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 From 1ba1c0996a54a048f1874e23d39480ab140ac95f Mon Sep 17 00:00:00 2001 From: s3inlc Date: Mon, 1 Dec 2025 12:17:59 +0100 Subject: [PATCH 32/42] removed order filter default on sum and minmax filters --- src/dba/AbstractModelFactory.class.php | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/dba/AbstractModelFactory.class.php b/src/dba/AbstractModelFactory.class.php index c576f2fa1..cd98eaf7d 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); From d029205f8c5867e7bbc061d58b26bf6303f06943 Mon Sep 17 00:00:00 2001 From: s3inlc Date: Mon, 1 Dec 2025 12:18:25 +0100 Subject: [PATCH 33/42] changed mysql specific LIKE BINARY to LIKE .. COLLATE C to achieve binary comparision --- src/dba/LikeFilter.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dba/LikeFilter.class.php b/src/dba/LikeFilter.class.php index 8de40e3fd..ce68a82ac 100755 --- a/src/dba/LikeFilter.class.php +++ b/src/dba/LikeFilter.class.php @@ -36,7 +36,7 @@ function getQueryString(AbstractModelFactory $factory, bool $includeTable = fals $inv = " NOT"; } - return $table . AbstractModelFactory::getMappedModelKey($factory->getNullObject(), $this->key) . $inv . " LIKE BINARY ?"; + return $table . AbstractModelFactory::getMappedModelKey($factory->getNullObject(), $this->key) . $inv . " LIKE ? COLLATE \"C\""; } function getValue() { From 7103ac92282e442b274562a19e839a0c5e10fcfa Mon Sep 17 00:00:00 2001 From: s3inlc Date: Mon, 1 Dec 2025 13:28:15 +0100 Subject: [PATCH 34/42] differ between mysql and postgres in this very specific case of like comparision --- src/dba/LikeFilter.class.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dba/LikeFilter.class.php b/src/dba/LikeFilter.class.php index ce68a82ac..0c4413652 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 ? COLLATE \"C\""; + // 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 = " BINARY LIKE ?"; + if (DBA_TYPE == 'postgres') { + $likeStatement = " LIKE ? COLLATE \"C\""; + } + return $table . AbstractModelFactory::getMappedModelKey($factory->getNullObject(), $this->key) . $inv . $likeStatement; } function getValue() { From f124259cfe4ef73cc07cdfe832aa45c23ef053bc Mon Sep 17 00:00:00 2001 From: s3inlc Date: Mon, 1 Dec 2025 14:35:15 +0100 Subject: [PATCH 35/42] make the default access group created on migration to avoid primary key sequence issues --- src/inc/utils/AccessUtils.class.php | 1 + src/install/updates/update_v1.0.0-rainbow4_vx.x.x.php | 2 +- src/migrations/mysql/20251127000000_initial.sql | 6 +++++- src/migrations/postgres/20251127000000_initial.sql | 3 +++ 4 files changed, 10 insertions(+), 2 deletions(-) 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 45bd0ccc5..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 @@ -25,7 +25,7 @@ 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,0x22F3A0D84CF66E9694946A244FBC19B314F0EA85B9B5C66A3C2BB67EE365AA78D025D9C90FBCCE8E4896FD20988A6740,1);"); + 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/mysql/20251127000000_initial.sql b/src/migrations/mysql/20251127000000_initial.sql index c70d4ddb0..3e0f0dfba 100644 --- a/src/migrations/mysql/20251127000000_initial.sql +++ b/src/migrations/mysql/20251127000000_initial.sql @@ -12,6 +12,9 @@ CREATE TABLE IF NOT EXISTS `AccessGroup` ( `groupName` VARCHAR(50) NOT NULL ) ENGINE = InnoDB; +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, @@ -1272,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; diff --git a/src/migrations/postgres/20251127000000_initial.sql b/src/migrations/postgres/20251127000000_initial.sql index 8b6664d47..cfab4cf07 100644 --- a/src/migrations/postgres/20251127000000_initial.sql +++ b/src/migrations/postgres/20251127000000_initial.sql @@ -4,6 +4,9 @@ CREATE TABLE AccessGroup ( 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, From 364ca92798c5b27166a8ef33c3144fa711d8bdf4 Mon Sep 17 00:00:00 2001 From: s3inlc Date: Mon, 1 Dec 2025 14:45:34 +0100 Subject: [PATCH 36/42] fixed order typo in like filter --- src/dba/LikeFilter.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dba/LikeFilter.class.php b/src/dba/LikeFilter.class.php index 0c4413652..eedccaaf6 100755 --- a/src/dba/LikeFilter.class.php +++ b/src/dba/LikeFilter.class.php @@ -37,7 +37,7 @@ function getQueryString(AbstractModelFactory $factory, bool $includeTable = fals } // 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 = " BINARY LIKE ?"; + $likeStatement = " LIKE BINARY ?"; if (DBA_TYPE == 'postgres') { $likeStatement = " LIKE ? COLLATE \"C\""; } From 7650aef16b23b4c75ea75e14d89be3dd8a623386 Mon Sep 17 00:00:00 2001 From: s3inlc Date: Mon, 1 Dec 2025 16:07:22 +0100 Subject: [PATCH 37/42] removed debug output --- src/dba/AbstractModelFactory.class.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dba/AbstractModelFactory.class.php b/src/dba/AbstractModelFactory.class.php index cd98eaf7d..e78ced3ae 100755 --- a/src/dba/AbstractModelFactory.class.php +++ b/src/dba/AbstractModelFactory.class.php @@ -938,7 +938,6 @@ public function getDB(bool $test = false): ?PDO { return self::$dbh; } catch (PDOException $e) { - echo $e->getMessage()."\n"; if ($test) { return null; } From 7f74e6df056027acb8f622fc7c3c053abe59d7cf Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 1 Dec 2025 16:34:41 +0100 Subject: [PATCH 38/42] Update src/dba/AbstractModelFactory.class.php Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/dba/AbstractModelFactory.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dba/AbstractModelFactory.class.php b/src/dba/AbstractModelFactory.class.php index e78ced3ae..c17de0893 100755 --- a/src/dba/AbstractModelFactory.class.php +++ b/src/dba/AbstractModelFactory.class.php @@ -906,7 +906,7 @@ public function getDB(bool $test = false): ?PDO { $dbHost = @DBA_SERVER; $dbPort = @DBA_PORT; $dbDB = @DBA_DB; - if ($test) { // if the connection is beeing tested, take credentials from legacy global variable + if ($test) { // if the connection is being tested, take credentials from legacy global variable global $CONN; $dbUser = $CONN['user']; $dbPass = $CONN['pass']; From b7e749f07e29c5e46523f33d23f8d6ba8f0e16be Mon Sep 17 00:00:00 2001 From: s3inlc Date: Tue, 2 Dec 2025 09:55:31 +0100 Subject: [PATCH 39/42] added options list to github action --- .github/actions/start-hashtopolis/action.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/actions/start-hashtopolis/action.yml b/.github/actions/start-hashtopolis/action.yml index d7d180a14..8af48aa9b 100644 --- a/.github/actions/start-hashtopolis/action.yml +++ b/.github/actions/start-hashtopolis/action.yml @@ -6,6 +6,9 @@ inputs: description: "Used to set which DB system should be used" required: true default: "mysql" + options: + - "mysql" + - "postgres" runs: using: "composite" From c9ae11a2e47b5a181238a7073bc8add8ac091b1a Mon Sep 17 00:00:00 2001 From: s3inlc Date: Tue, 2 Dec 2025 10:37:49 +0100 Subject: [PATCH 40/42] test running old test suite with changes --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02a3260ff..8ddd46e12 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,9 +27,9 @@ jobs: 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 -# if: ${{ matrix.db_system == 'mysql' }} # the legacy is only supposed to work with mysql -# run: docker exec hashtopolis-server-dev php /var/www/html/ci/run.php -vmaster + - name: Run test suite + if: ${{ matrix.db_system == 'mysql' }} # the legacy is only supposed to work with mysql + 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 From 3c4df126c8b81a87d41b2999717f39a3e51cba64 Mon Sep 17 00:00:00 2001 From: s3inlc Date: Tue, 2 Dec 2025 11:01:25 +0100 Subject: [PATCH 41/42] definitely removing old legacy test in ci workflow --- .github/workflows/ci.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ddd46e12..22dbc4653 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,9 +27,6 @@ jobs: 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 - if: ${{ matrix.db_system == 'mysql' }} # the legacy is only supposed to work with mysql - 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 From 9f90283f9fb172cebac183b9399d7fd5c963d069 Mon Sep 17 00:00:00 2001 From: s3inlc Date: Wed, 3 Dec 2025 09:28:05 +0100 Subject: [PATCH 42/42] renamed all indexes to be unique, restructured file to have alphabetical order and readable spacing --- .../postgres/20251127000000_initial.sql | 598 +++++++++--------- 1 file changed, 299 insertions(+), 299 deletions(-) diff --git a/src/migrations/postgres/20251127000000_initial.sql b/src/migrations/postgres/20251127000000_initial.sql index cfab4cf07..cbf8aec8a 100644 --- a/src/migrations/postgres/20251127000000_initial.sql +++ b/src/migrations/postgres/20251127000000_initial.sql @@ -1,7 +1,7 @@ -- Create tables and insert default entries CREATE TABLE AccessGroup ( accessGroupId SERIAL NOT NULL PRIMARY KEY, - groupName TEXT NOT NULL + groupName TEXT NOT NULL ); INSERT INTO AccessGroup (accessGroupId, groupName) VALUES @@ -9,43 +9,43 @@ INSERT INTO AccessGroup (accessGroupId, groupName) VALUES CREATE TABLE AccessGroupAgent ( accessGroupAgentId SERIAL NOT NULL PRIMARY KEY, - accessGroupId INT NOT NULL, - agentId INT NOT NULL + 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 + 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 + 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 + 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 @@ -53,43 +53,62 @@ INSERT INTO AgentBinary (agentBinaryId, binaryType, version, operatingSystems, f 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 + 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 + 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 + 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 + 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, + skip BIGINT NOT NULL, + length BIGINT NOT NULL, agentId INT NULL, - dispatchTime BIGINT NOT NULL, - solveTime BIGINT NOT NULL, - checkpoint BIGINT NOT NULL, + dispatchTime BIGINT NOT NULL, + solveTime BIGINT NOT NULL, + checkpoint BIGINT NOT NULL, progress INT NULL, state INT NOT NULL, cracked INT NOT NULL, @@ -98,9 +117,9 @@ CREATE TABLE Chunk ( CREATE TABLE Config ( configId SERIAL NOT NULL PRIMARY KEY, - configSectionId INT NOT NULL, - item TEXT NOT NULL, - value TEXT NOT NULL + configSectionId INT NOT NULL, + item TEXT NOT NULL, + value TEXT NOT NULL ); INSERT INTO Config (configId, configSectionId, item, value) VALUES @@ -170,7 +189,7 @@ INSERT INTO Config (configId, configSectionId, item, value) VALUES CREATE TABLE ConfigSection ( configSectionId SERIAL NOT NULL PRIMARY KEY, - sectionName TEXT NOT NULL + sectionName TEXT NOT NULL ); INSERT INTO ConfigSection (configSectionId, sectionName) VALUES @@ -184,10 +203,10 @@ INSERT INTO ConfigSection (configSectionId, sectionName) VALUES 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 + 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 @@ -195,8 +214,8 @@ INSERT INTO CrackerBinary (crackerBinaryId, crackerBinaryTypeId, version, downlo CREATE TABLE CrackerBinaryType ( crackerBinaryTypeId SERIAL NOT NULL PRIMARY KEY, - typeName TEXT NOT NULL, - isChunkingAvailable INT NOT NULL + typeName TEXT NOT NULL, + isChunkingAvailable INT NOT NULL ); INSERT INTO CrackerBinaryType (crackerBinaryTypeId, typeName, isChunkingAvailable) VALUES @@ -204,12 +223,25 @@ INSERT INTO CrackerBinaryType (crackerBinaryTypeId, typeName, isChunkingAvailabl 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 + 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 ( @@ -220,69 +252,63 @@ CREATE TABLE FilePretask ( CREATE TABLE FileTask ( fileTaskId SERIAL NOT NULL PRIMARY KEY, - fileId INT NOT NULL, - taskId INT NOT NULL -); - -CREATE TABLE FileDelete ( - fileDeleteId SERIAL NOT NULL PRIMARY KEY, - filename TEXT NOT NULL, - time BIGINT NOT NULL + fileId INT NOT NULL, + taskId INT NOT NULL ); CREATE TABLE Hash ( hashId SERIAL NOT NULL PRIMARY KEY, - hashlistId INT NOT NULL, + 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 + 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, + 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 + 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 + 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 + 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 + description TEXT NOT NULL, + isSalted INT NOT NULL, + isSlowHash INT NOT NULL ); INSERT INTO HashType (hashTypeId, description, isSalted, isSlowHash) VALUES @@ -867,51 +893,106 @@ INSERT INTO HashType (hashTypeId, description, isSalted, isSlowHash) VALUES (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 + 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 + 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 + 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 + 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 + groupName TEXT NOT NULL, + permissions TEXT NOT NULL ); INSERT INTO RightGroup (rightGroupId, groupName, permissions) VALUES @@ -919,12 +1000,12 @@ INSERT INTO RightGroup (rightGroupId, groupName, permissions) VALUES 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 + 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 ( @@ -942,149 +1023,68 @@ CREATE TABLE StoredValue ( CREATE TABLE Supertask ( supertaskId SERIAL NOT NULL PRIMARY KEY, - supertaskName TEXT NOT NULL + supertaskName TEXT NOT NULL ); CREATE TABLE SupertaskPretask ( supertaskPretaskId SERIAL NOT NULL PRIMARY KEY, - supertaskId INT NOT NULL, - pretaskId INT NOT NULL + 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 + 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 + 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 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 + 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, + hash TEXT NOT NULL, + solveTime BIGINT NOT NULL, agentId INT NULL, hashlistId INT NOT 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 -); - -CREATE TABLE FileDownload ( - fileDownloadId SERIAL NOT NULL PRIMARY KEY, - time BIGINT NOT NULL, - fileId INT NOT NULL, - status INT NOT NULL -); - -INSERT INTO ApiGroup ( apiGroupId, name, permissions) VALUES - (1, 'Administrators', 'ALL'); - -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 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'); - -- 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; @@ -1131,74 +1131,74 @@ SELECT pg_catalog.setval(pg_get_serial_sequence('TaskWrapper', 'taskwrapperid'), SELECT pg_catalog.setval(pg_get_serial_sequence('Zap', 'zapid'), MAX(zapId)) from Zap; -- Add Indexes -CREATE INDEX IF NOT EXISTS accessGroupId_idx ON AccessGroupAgent (accessGroupId); -CREATE INDEX IF NOT EXISTS agentId_idx ON AccessGroupAgent (agentId); +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 accessGroupId_idx ON AccessGroupUser (accessGroupId); -CREATE INDEX IF NOT EXISTS userId_idx ON AccessGroupUser (userId); +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 userId_idx ON Agent (userId); +CREATE INDEX IF NOT EXISTS Agent_userId_idx ON Agent (userId); -CREATE INDEX IF NOT EXISTS agentId_idx ON AgentError (agentId); -CREATE INDEX IF NOT EXISTS taskId_idx ON AgentError (taskId); +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 agentId_idx ON AgentStat (agentId); +CREATE INDEX IF NOT EXISTS AgentStat_agentId_idx ON AgentStat (agentId); -CREATE INDEX IF NOT EXISTS agentId_idx ON AgentZap (agentId); -CREATE INDEX IF NOT EXISTS lastZapId_idx ON AgentZap (lastZapId); +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 taskId_idx ON Assignment (taskId); -CREATE INDEX IF NOT EXISTS agentId_idx ON Assignment (agentId); +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 taskId_idx ON Chunk (taskId); -CREATE INDEX IF NOT EXISTS progress_idx ON Chunk (progress); -CREATE INDEX IF NOT EXISTS agentId_idx ON Chunk (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 configSectionId_idx ON Config (configSectionId); +CREATE INDEX IF NOT EXISTS Config_configSectionId_idx ON Config (configSectionId); -CREATE INDEX IF NOT EXISTS crackerBinaryTypeId_idx ON CrackerBinary (crackerBinaryTypeId); +CREATE INDEX IF NOT EXISTS CrackerBinary_crackerBinaryTypeId_idx ON CrackerBinary (crackerBinaryTypeId); -CREATE INDEX IF NOT EXISTS fileId_idx ON FilePretask (fileId); -CREATE INDEX IF NOT EXISTS pretaskId_idx ON FilePretask (pretaskId); +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 fileId_idx ON FileTask (fileId); -CREATE INDEX IF NOT EXISTS taskId_idx ON FileTask (taskId); +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 hashlistId_idx ON Hash (hashlistId); -CREATE INDEX IF NOT EXISTS chunkId_idx ON Hash (chunkId); -CREATE INDEX IF NOT EXISTS isCracked_idx ON Hash (isCracked); -CREATE INDEX IF NOT EXISTS hash_idx ON Hash (hash); -CREATE INDEX IF NOT EXISTS timeCracked_idx ON Hash (timeCracked); +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 hashlistId_idx ON HashBinary (hashlistId); -CREATE INDEX IF NOT EXISTS chunkId_idx ON HashBinary (chunkId); +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 hashTypeId_idx ON Hashlist (hashTypeId); +CREATE INDEX IF NOT EXISTS Hashlist_hashTypeId_idx ON Hashlist (hashTypeId); -CREATE INDEX IF NOT EXISTS parentHashlistId_idx ON HashlistHashlist (parentHashlistId); -CREATE INDEX IF NOT EXISTS hashlistId_idx ON HashlistHashlist (hashlistId); +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 rightGroupId_idx ON htp_User (rightGroupId); +CREATE INDEX IF NOT EXISTS htp_User_rightGroupId_idx ON htp_User (rightGroupId); -CREATE INDEX IF NOT EXISTS userId_idx ON NotificationSetting (userId); +CREATE INDEX IF NOT EXISTS NotificationSetting_userId_idx ON NotificationSetting (userId); -CREATE INDEX IF NOT EXISTS userId_idx ON Session (userId); +CREATE INDEX IF NOT EXISTS Session_userId_idx ON Session (userId); -CREATE INDEX IF NOT EXISTS agentId_idx ON Speed (agentId); -CREATE INDEX IF NOT EXISTS taskId_idx ON Speed (taskId); +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 supertaskId_idx ON SupertaskPretask (supertaskId); -CREATE INDEX IF NOT EXISTS pretaskId_idx ON SupertaskPretask (pretaskId); +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 crackerBinaryId_idx ON Task (crackerBinaryId); +CREATE INDEX IF NOT EXISTS Task_crackerBinaryId_idx ON Task (crackerBinaryId); -CREATE INDEX IF NOT EXISTS hashlistId_idx ON TaskWrapper (hashlistId); -CREATE INDEX IF NOT EXISTS priority_idx ON TaskWrapper (priority); -CREATE INDEX IF NOT EXISTS isArchived_idx ON TaskWrapper (isArchived); -CREATE INDEX IF NOT EXISTS accessGroupId_idx ON TaskWrapper (accessGroupId); +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 agentId_idx ON Zap (agentId); -CREATE INDEX IF NOT EXISTS hashlistId_idx ON Zap (hashlistId); +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);