89 lines
3.0 KiB
PHP
89 lines
3.0 KiB
PHP
<?php
|
|
/**
|
|
* Advanced Migration Script: Schema Update + Data Encryption
|
|
*/
|
|
|
|
require_once __DIR__ . '/../app/bootstrap/init.php';
|
|
|
|
use App\Core\Database;
|
|
use App\Core\Encryption;
|
|
|
|
$db = Database::getInstance();
|
|
|
|
echo "--- Starting Security Migration ---\n";
|
|
|
|
// 1. Add email_hash column if it doesn't exist
|
|
try {
|
|
$db->exec("ALTER TABLE users ADD COLUMN email_hash VARCHAR(64) AFTER email, ADD INDEX (email_hash)");
|
|
echo "[OK] Added email_hash column and index.\n";
|
|
} catch (\Exception $e) {
|
|
echo "[SKIP] email_hash column might already exist.\n";
|
|
}
|
|
|
|
// 2. Fetch all users to encrypt their data
|
|
$stmt = $db->query("SELECT id, name, email FROM users");
|
|
$users = $stmt->fetchAll();
|
|
|
|
echo "Found " . count($users) . " users. Starting encryption...\n";
|
|
|
|
$updateStmt = $db->prepare("UPDATE users SET name = ?, email = ?, email_hash = ? WHERE id = ?");
|
|
|
|
foreach ($users as $user) {
|
|
// Check if data is already encrypted (to avoid double encryption)
|
|
$isAlreadyEncrypted = Encryption::decrypt($user['email']) !== false;
|
|
|
|
if ($isAlreadyEncrypted) {
|
|
echo "User ID {$user['id']} is already encrypted. Skipping.\n";
|
|
continue;
|
|
}
|
|
|
|
// Encrypt Name
|
|
$encryptedName = Encryption::encrypt($user['name']);
|
|
|
|
// Encrypt Email
|
|
$encryptedEmail = Encryption::encrypt($user['email']);
|
|
|
|
// Generate Hash for lookup
|
|
$emailHash = hash('sha256', strtolower($user['email']));
|
|
|
|
$updateStmt->execute([
|
|
$encryptedName,
|
|
$encryptedEmail,
|
|
$emailHash,
|
|
$user['id']
|
|
]);
|
|
|
|
echo "User ID {$user['id']} migrated successfully.\n";
|
|
}
|
|
|
|
// 4. Create user_company_assignments table
|
|
try {
|
|
$db->exec("CREATE TABLE IF NOT EXISTS user_company_assignments (
|
|
id INT AUTO_INCREMENT,
|
|
user_id VARCHAR(100) NOT NULL,
|
|
company_id VARCHAR(100) NOT NULL,
|
|
assigned_by VARCHAR(100) NOT NULL,
|
|
assigned_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
is_active TINYINT(1) NOT NULL DEFAULT 1,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uq_user_company (user_id, company_id),
|
|
CONSTRAINT fk_uca_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
CONSTRAINT fk_uca_company FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE,
|
|
CONSTRAINT fk_uca_admin FOREIGN KEY (assigned_by) REFERENCES users(id) ON DELETE RESTRICT
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
|
|
echo "[OK] User_company_assignments table created.\n";
|
|
} catch (\Exception $e) {
|
|
echo "[SKIP] user_company_assignments table: " . $e->getMessage() . "\n";
|
|
}
|
|
|
|
// 5. Update invoices table to include uploaded_by
|
|
try {
|
|
$db->exec("ALTER TABLE invoices ADD COLUMN uploaded_by VARCHAR(100) NULL AFTER status");
|
|
$db->exec("ALTER TABLE invoices ADD CONSTRAINT fk_inv_uploader FOREIGN KEY (uploaded_by) REFERENCES users(id) ON DELETE SET NULL");
|
|
echo "[OK] Updated invoices table with uploaded_by tracker.\n";
|
|
} catch (\Exception $e) {
|
|
echo "[SKIP] invoices table update: " . $e->getMessage() . "\n";
|
|
}
|
|
|
|
echo "--- Migration Complete ---\n";
|