Exocore-Backend / dist /auth /register.js
ChoruYt's picture
Upload 38 files
a21d6a5 verified
Raw
History Blame Contribute Delete
4.7 kB
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = registerHandler;
const crypto_1 = __importDefault(require("crypto"));
const drive_1 = require("../services/drive");
const mailer_1 = require("../services/mailer");
const validate_1 = require("../utils/validate");
const owners_1 = require("../utils/owners");
async function registerHandler(req, res) {
try {
const { user, pass, email, bio, nickname, dob, country } = req.body || {};
const host = req.body?.host || req.query?.host || "";
const usernameCheck = (0, validate_1.validateUsername)(String(user || ""));
if (!usernameCheck.ok)
return res.status(400).json({ success: false, message: usernameCheck.message });
const emailCheck = (0, validate_1.validateEmail)(String(email || ""));
if (!emailCheck.ok)
return res.status(400).json({ success: false, message: emailCheck.message });
const passCheck = (0, validate_1.validatePassword)(String(pass || ""));
if (!passCheck.ok)
return res.status(400).json({ success: false, message: passCheck.message });
const normalizedEmail = String(email).trim().toLowerCase();
// Enforce: ONE account per email
const existing = await (0, drive_1.getAllUsers)();
const emailTaken = existing.some(u => (u.email || "").trim().toLowerCase() === normalizedEmail);
if (emailTaken) {
return res.status(409).json({ success: false, message: "An account with this email already exists" });
}
const formattedUsername = (0, validate_1.cleanUsername)(user);
const usernameTaken = existing.some(u => u.username === formattedUsername);
if (usernameTaken) {
return res.status(409).json({ success: false, message: "Username already taken" });
}
const files = req.files;
const avatarBuffer = files?.["avatar"]?.[0]?.buffer ?? null;
const coverBuffer = files?.["cover"]?.[0]?.buffer ?? null;
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const userId = Date.now() + Math.floor(Math.random() * 1000);
const otp = Math.floor(100000 + Math.random() * 900000).toString();
const generatedToken = crypto_1.default.randomBytes(32).toString("hex");
const userData = {
id: userId,
user: String(user),
username: formattedUsername,
pass: String(pass),
email: normalizedEmail,
bio: bio || "",
nickname: nickname || user,
dob: dob || "",
country: country || "",
timezone,
verified: false,
verifyOtp: otp,
token: generatedToken,
createdAt: Date.now(),
role: (0, owners_1.roleForEmail)(normalizedEmail) || "user",
level: 0,
xp: 0,
achievements: [],
bannedUntil: null,
};
await (0, drive_1.registerUserToDrive)(userData, avatarBuffer, coverBuffer);
// Best-effort send the verification email immediately.
// Prefer the public web host (the user's browser URL) so the link works
// outside the Replit container. Fall back to API_PUBLIC_BASE then localhost.
const port = process.env.PORT || 8081;
const apiBase = (host && /^https?:\/\//.test(host) ? host.replace(/\/$/, "") : null) ||
process.env.API_PUBLIC_BASE ||
`http://localhost:${port}`;
const verifyLink = `${apiBase}/exocore/api/auth/verify?username=${encodeURIComponent(formattedUsername)}&otp=${otp}&host=${encodeURIComponent(host)}`;
(0, mailer_1.sendVerifyEmail)(normalizedEmail, verifyLink, userData.nickname).catch(() => { });
return res.status(200).json({
success: true,
message: "Account created. Check your email to verify.",
data: {
id: userId,
username: formattedUsername,
email: normalizedEmail,
nickname: userData.nickname,
verified: false,
token: generatedToken,
},
});
}
catch (err) {
if (err?.message === "ALREADY_EXISTS") {
return res.status(409).json({ success: false, message: "Username already taken" });
}
console.error("[register] error:", err);
return res.status(500).json({ success: false, message: "Registration failed", error: err?.message });
}
}