Initial commit: Cloud Control Panel

This commit is contained in:
2026-01-10 01:24:08 +07:00
commit 01d99c5054
69 changed files with 12697 additions and 0 deletions

0
db/.gitkeep Normal file
View File

72
db/migrate.php Executable file
View File

@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
$username = $_ENV['USER'] ?? null;
$password = $_ENV['PASSWORD'] ?? null;
if (!$username || !$password) {
throw new RuntimeException('Environment variable "USER" or "PASSWORD" is missing');
}
$databasePath = __DIR__ . '/database.sqlite';
$migrationsPath = __DIR__ . '/migration';
if (!is_dir(__DIR__)) {
mkdir(__DIR__, 0777, true);
}
$db = new PDO('sqlite:' . $databasePath);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->exec("
CREATE TABLE IF NOT EXISTS migrations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
migration TEXT NOT NULL UNIQUE,
ran_at INTEGER NOT NULL
);
");
$migrations = glob($migrationsPath . '/*.php');
sort($migrations);
foreach ($migrations as $file) {
$name = basename($file);
$stmt = $db->prepare(
"SELECT COUNT(*) FROM migrations WHERE migration = :migration"
);
$stmt->execute(['migration' => $name]);
if ((int)$stmt->fetchColumn() > 0) {
continue;
}
echo "Running: $name\n";
/** @var callable $migration */
$migration = require $file;
if (!is_callable($migration)) {
throw new RuntimeException("Migration $name must return callable");
}
$db->beginTransaction();
try {
$migration($db);
$stmt = $db->prepare("
INSERT INTO migrations (migration, ran_at)
VALUES (:migration, :ran_at)
");
$stmt->execute([
'migration' => $name,
'ran_at' => time(),
]);
$db->commit();
echo "✔ Migrated: $name\n";
} catch (Throwable $e) {
$db->rollBack();
echo "✖ Failed: $name\n";
throw $e;
}
}

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
return function (PDO $db): void {
$db->exec("
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL,
created_at INTEGER NOT NULL
);
");
$stmt = $db->prepare(
"SELECT COUNT(*) FROM users WHERE username = :username"
);
$stmt->execute(['username' => getenv('USER')]);
if ((int)$stmt->fetchColumn() > 0) {
return;
}
$passwordHash = password_hash(
getenv('PASSWORD'),
PASSWORD_DEFAULT
);
$stmt = $db->prepare("
INSERT INTO users (username, password, created_at)
VALUES (:username, :password, :created_at)
");
$stmt->execute([
'username' => $_ENV['USER'],
'password' => $passwordHash,
'created_at' => time(),
]);
};

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
return function (PDO $db): void {
$db->exec("
CREATE TABLE IF NOT EXISTS sessions (
id TEXT PRIMARY KEY,
user_id INTEGER NOT NULL,
auth_token TEXT NOT NULL UNIQUE,
ip TEXT,
user_agent TEXT,
created_at INTEGER NOT NULL,
last_activity_at INTEGER NOT NULL,
revoked_at INTEGER,
FOREIGN KEY (user_id) REFERENCES users(id)
);
");
};

View File

@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
return function (PDO $db): void {
$db->exec("
CREATE TABLE IF NOT EXISTS login_throttle (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip TEXT NOT NULL,
attempts INTEGER NOT NULL DEFAULT 1,
last_attempt INTEGER NOT NULL
);
");
};