Add missing migrations
CI / check (push) Failing after 26s
CI / deploy (push) Skipped
CI / release (push) Skipped

This commit is contained in:
openhands committed 2026-08-26 14:28:28 +02:00
1 parent 0201d21c38
commit 2d09a4a92c
3 files changed
+90 -3

No files matched your search

@@ -0,0 +1,4 @@
-- Add terms/age consent columns expected by the users schema (register flow).
ALTER TABLE `users`
ADD COLUMN `terms_accepted` TINYINT(1) NOT NULL DEFAULT 0,
ADD COLUMN `age_verified` TINYINT(1) NOT NULL DEFAULT 0;
+67
View File
@@ -0,0 +1,67 @@
import { randomBytes } from "node:crypto";
import { eq } from "drizzle-orm";
import { drizzle } from "drizzle-orm/mysql2";
import { bcrypt, bcryptVerify } from "hash-wasm";
import mysql from "mysql2/promise";
import * as schema from "@/db/schema";
const url = new URL(
"mysql://cms:HeelM%3Coeikgsdgsccusygcsugy@localhost:3306/habbo",
);
const pool = mysql.createPool({
host: url.hostname,
port: Number(url.port) || 3306,
user: decodeURIComponent(url.username),
password: decodeURIComponent(url.password),
database: "habbo",
charset: "utf8mb4",
});
const db = drizzle(pool, { schema, mode: "default" });
async function main() {
const hash = await bcrypt({
password: "Test1234",
salt: randomBytes(16),
costFactor: 12,
outputType: "encoded",
});
const uname = "__e2e_test_" + Date.now();
try {
await db.insert(schema.User).values({
username: uname,
password: hash,
mail: null,
accountCreated: Math.floor(Date.now() / 1000),
ipRegister: "127.0.0.1",
ipCurrent: "127.0.0.1",
look: "hr-100-.hd-180-1.ch-255-66.lg-280-110.sh-305-62",
});
console.log("INSERT OK");
// Simuleer login-verificatie
const [user] = await db
.select()
.from(schema.User)
.where(eq(schema.User.username, uname))
.limit(1);
if (!user) throw new Error("User not found after insert");
const ok = await bcryptVerify({
password: "Test1234",
hash: user.password,
});
console.log("LOGIN VERIFY:", ok ? "OK" : "FAILED");
} catch (err) {
console.error("FAILED:", (err as Error).message);
if ((err as { cause?: Error }).cause)
console.error("CAUSE:", (err as { cause?: Error }).cause?.message);
process.exitCode = 1;
} finally {
await pool.execute(
"DELETE FROM users WHERE username LIKE '\\_\\_e2e\\_test\\_%'",
);
await pool.end();
}
}
main();
+19 -3
View File
@@ -29,6 +29,7 @@ const registerSchema = z.object({
.regex(/[A-Z]/, "Password must contain at least one uppercase letter")
.regex(/[a-z]/, "Password must contain at least one lowercase letter")
.regex(/[0-9]/, "Password must contain at least one digit"),
passwordConfirmation: z.string(),
look: z.string().optional(),
});
@@ -48,6 +49,9 @@ export async function register(
.trim()
.toLowerCase(),
password: String(formData.get("password") ?? "").normalize("NFC"),
passwordConfirmation: String(
formData.get("password_confirmation") ?? "",
).normalize("NFC"),
look:
String(formData.get("look") ?? "")
.normalize("NFC")
@@ -60,6 +64,10 @@ export async function register(
return parsed.error.issues[0]?.message ?? "Invalid input";
}
if (parsed.data.password !== parsed.data.passwordConfirmation) {
return "Passwords do not match";
}
const { username, mail, password, look } = parsed.data;
const hasEmail = !!mail;
const ip = await clientIp();
@@ -124,6 +132,7 @@ export async function register(
ipRegister: ip,
ipCurrent: ip,
look,
termsAccepted: raw.termsAccepted,
});
if (hasEmail) {
@@ -133,9 +142,16 @@ export async function register(
logger.warn("Failed to send verification email after registration");
}
}
} catch {
logger.warn("Account creation failed");
return "Could not create the account (is the username unique?)";
} catch (err) {
const code = (err as { cause?: { code?: string } }).cause?.code;
if (code === "ER_DUP_ENTRY") {
return "That username is already taken";
}
logger.error("Account creation failed", {
code,
message: err instanceof Error ? err.message : String(err),
});
return "Could not create the account. Please try again or contact staff.";
}
redirect("/login?registered=1");