aethex-forge/api/games/roblox-auth.ts
2025-11-08 11:03:25 +00:00

114 lines
3.2 KiB
TypeScript

import type { VercelRequest, VercelResponse } from "@vercel/node";
import { createClient } from "@supabase/supabase-js";
import { createHmac } from "crypto";
const supabase = createClient(
process.env.SUPABASE_URL || "",
process.env.SUPABASE_SERVICE_ROLE || "",
);
// Verify Roblox signature for server-to-server requests
function verifyRobloxSignature(
payload: string,
signature: string,
secret: string,
): boolean {
const hmac = createHmac("sha256", secret);
hmac.update(payload);
const computedSignature = hmac.digest("base64");
return computedSignature === signature;
}
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== "POST") {
res.setHeader("Allow", "POST");
return res.status(405).json({ error: "Method not allowed" });
}
try {
const signature = req.headers["x-roblox-signature"] as string;
const payload = JSON.stringify(req.body);
const secret = process.env.ROBLOX_SHARED_SECRET || "";
// Verify signature for security
if (
signature &&
secret &&
!verifyRobloxSignature(payload, signature, secret)
) {
console.warn("Invalid Roblox signature");
return res.status(401).json({ error: "Invalid signature" });
}
const {
roblox_user_id,
roblox_username,
player_token,
action = "authenticate",
} = req.body;
if (!roblox_user_id || !roblox_username) {
return res.status(400).json({ error: "Missing Roblox user info" });
}
// Find or create user linked to Roblox account
let { data: userData } = await supabase
.from("user_profiles")
.select("id, auth_id, email")
.eq("roblox_user_id", String(roblox_user_id))
.single();
if (!userData) {
// Create new user linked to Roblox
const { data: newUser, error: createError } = await supabase
.from("user_profiles")
.insert({
roblox_user_id: String(roblox_user_id),
roblox_username,
username: roblox_username,
user_type: "game_developer",
full_name: roblox_username,
email: `${roblox_user_id}@roblox.aethex.dev`,
})
.select()
.single();
if (createError) {
console.error("Failed to create Roblox user:", createError);
return res.status(500).json({ error: "Failed to create user" });
}
userData = newUser;
}
// Generate game token for in-game authentication
const gameToken = require("crypto").randomBytes(32).toString("hex");
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
// Store game token
await supabase.from("game_auth_tokens").insert({
user_id: userData.id,
game: "roblox",
token: gameToken,
player_token,
expires_at: expiresAt.toISOString(),
metadata: {
roblox_user_id,
roblox_username,
},
});
return res.status(200).json({
success: true,
game_token: gameToken,
user_id: userData.id,
username: userData.username,
expires_in: 86400, // seconds
});
} catch (error: any) {
console.error("Roblox game auth error:", error);
return res.status(500).json({
error: error?.message || "Authentication failed",
});
}
}