Initial Commit

Commit pertama, memindahkan repository dari github ke gitea.
This commit is contained in:
dicky arya pratama committed 2026-11-04 17:18:53 +07:00
commit 13a47fbebf
41 files changed
+12327

No files matched your search

+98
View File
@@ -0,0 +1,98 @@
import { cookies } from "next/headers";
import bcrypt from "bcryptjs";
import { query } from "./db";
const SESSION_COOKIE_NAME = "aghatis_admin_session";
const SESSION_SECRET = process.env.ADMIN_SESSION_SECRET || "aghatis_stellar_session_secret_2026_secure_key";
interface DBAdminUser {
id: number;
username: string;
password_hash: string;
full_name: string;
role: string;
}
export async function verifyUserCredentials(
user: string,
pass: string
): Promise<{ success: boolean; user?: { username: string; role: string; fullName: string } }> {
try {
const rows = await query<DBAdminUser[]>(
"SELECT id, username, password_hash, full_name, role FROM admin_users WHERE username = ? LIMIT 1",
[user]
);
if (!rows || rows.length === 0) {
return { success: false };
}
const admin = rows[0];
// Check bcrypt hash or fallback to direct comparison
let isMatch = false;
if (admin.password_hash.startsWith("$2b$") || admin.password_hash.startsWith("$2a$")) {
isMatch = bcrypt.compareSync(pass, admin.password_hash);
} else {
isMatch = admin.password_hash === pass;
}
if (!isMatch) {
return { success: false };
}
return {
success: true,
user: {
username: admin.username,
role: admin.role,
fullName: admin.full_name,
},
};
} catch (err) {
console.error("Database auth verification error:", err);
return { success: false };
}
}
// Generate HMAC session token
export function createSessionToken(username: string): string {
const payload = {
username,
createdAt: Date.now(),
};
const json = JSON.stringify(payload);
const encoded = Buffer.from(json).toString("base64url");
const signature = Buffer.from(`${encoded}:${SESSION_SECRET}`).toString("base64url");
return `${encoded}.${signature}`;
}
export function verifySessionToken(token: string): { username: string } | null {
try {
const [encoded, signature] = token.split(".");
if (!encoded || !signature) return null;
const expectedSig = Buffer.from(`${encoded}:${SESSION_SECRET}`).toString("base64url");
if (signature !== expectedSig) return null;
const json = Buffer.from(encoded, "base64url").toString("utf8");
const payload = JSON.parse(json);
return { username: payload.username };
} catch {
return null;
}
}
export async function isAuthenticated(): Promise<boolean> {
const cookieStore = await cookies();
const token = cookieStore.get(SESSION_COOKIE_NAME)?.value;
if (!token) return false;
return verifySessionToken(token) !== null;
}
export async function getAuthenticatedUser(): Promise<{ username: string } | null> {
const cookieStore = await cookies();
const token = cookieStore.get(SESSION_COOKIE_NAME)?.value;
if (!token) return null;
return verifySessionToken(token);
}
export { SESSION_COOKIE_NAME };
+31
View File
@@ -0,0 +1,31 @@
import mysql from "mysql2/promise";
declare global {
// eslint-disable-next-line no-var
var mysqlPool: mysql.Pool | undefined;
}
const pool =
global.mysqlPool ||
mysql.createPool({
host: process.env.DB_HOST || "103.155.224.244",
port: Number(process.env.DB_PORT) || 3306,
user: process.env.DB_USER || "root",
password: process.env.DB_PASSWORD || "hqn9OY2pJx1oYRYJoVrC0Q64sZj8k3W3ZpoVcsKAmv1DFqO9u0DIMGCkjjXEjLaB",
database: process.env.DB_NAME || "aghatis_studio_db",
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
connectTimeout: 10000,
});
if (process.env.NODE_ENV !== "production") {
global.mysqlPool = pool;
}
export default pool;
export async function query<T = unknown>(sql: string, params?: unknown[]): Promise<T> {
const [rows] = await pool.query(sql, params);
return rows as T;
}