import rndstr from "rndstr"; import { fetchMeta } from "../../../misc/fetch-meta.js"; import { verifyHcaptcha, verifyRecaptcha } from "../../../misc/captcha.js"; import { Users, RegistrationTickets, UserPendings } from "../../../models/index.js"; import { signup } from "../common/signup.js"; import config from "../../../config/index.js"; import { sendEmail } from "../../../services/send-email.js"; import { genId } from "../../../misc/gen-id.js"; import { validateEmailForAccount } from "../../../services/validate-email-for-account.js"; import { hashPassword } from "../../../misc/password.js"; export default (async (ctx)=>{ const body = ctx.request.body; const instance = await fetchMeta(true); // Verify *Captcha // ただしテスト時はこの機構は障害となるため無効にする if (process.env.NODE_ENV !== "test") { if (instance.enableHcaptcha && instance.hcaptchaSecretKey) { await verifyHcaptcha(instance.hcaptchaSecretKey, body["hcaptcha-response"]).catch((e)=>{ ctx.throw(400, e); }); } if (instance.enableRecaptcha && instance.recaptchaSecretKey) { await verifyRecaptcha(instance.recaptchaSecretKey, body["g-recaptcha-response"]).catch((e)=>{ ctx.throw(400, e); }); } } const username = body["username"]; const password = body["password"]; const host = process.env.NODE_ENV === "test" ? body["host"] || null : null; const invitationCode = body["invitationCode"]; const emailAddress = body["emailAddress"]; if (config.reservedUsernames?.includes(username.toLowerCase())) { ctx.status = 400; return; } if (instance.emailRequiredForSignup) { if (emailAddress == null || typeof emailAddress !== "string") { ctx.status = 400; return; } const { available } = await validateEmailForAccount(emailAddress); if (!available) { ctx.status = 400; return; } } if (instance.disableRegistration) { if (invitationCode == null || typeof invitationCode !== "string") { ctx.status = 400; return; } const ticket = await RegistrationTickets.findOneBy({ code: invitationCode }); if (ticket == null) { ctx.status = 400; return; } RegistrationTickets.delete(ticket.id); } if (instance.emailRequiredForSignup) { const code = rndstr("a-z0-9", 16); // Generate hash of password const hash = await hashPassword(password); await UserPendings.insert({ id: genId(), createdAt: new Date(), code, email: emailAddress, username: username, password: hash }); const link = `${config.url}/signup-complete/${code}`; sendEmail(emailAddress, "Signup", `To complete signup, please click this link:
${link}`, `To complete signup, please click this link: ${link}`); ctx.status = 204; } else { try { const { account, secret } = await signup({ username, password, host }); const res = await Users.pack(account, account, { detail: true, includeSecrets: true }); res.token = secret; ctx.body = res; } catch (e) { ctx.throw(400, e); } } });