✨ [Route] Register
This commit is contained in:
parent
6df4b5e56b
commit
ac8773ba59
@ -1,4 +1,224 @@
|
|||||||
import { Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
|
import Config from "../../../../util/Config";
|
||||||
|
import db from "../../../../util/Database";
|
||||||
|
import bcrypt from "bcrypt";
|
||||||
|
import { check, Email, EMAIL_REGEX, FieldErrors } from "../../../../util/instanceOf";
|
||||||
|
import { Snowflake } from "../../../../util/Snowflake";
|
||||||
|
import "missing-native-js-functions";
|
||||||
|
import { User } from "../../../../models/User";
|
||||||
|
import { generateToken } from "./login";
|
||||||
const router: Router = Router();
|
const router: Router = Router();
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
"/",
|
||||||
|
check({
|
||||||
|
username: String,
|
||||||
|
password: String,
|
||||||
|
consent: Boolean,
|
||||||
|
$email: Email,
|
||||||
|
$fingerprint: String,
|
||||||
|
$invite: String,
|
||||||
|
$date_of_birth: String, // "2000-04-03"
|
||||||
|
$gift_code_sku_id: String,
|
||||||
|
$captcha_key: String,
|
||||||
|
}),
|
||||||
|
async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
email,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
consent,
|
||||||
|
fingerprint,
|
||||||
|
invite,
|
||||||
|
date_of_birth,
|
||||||
|
gift_code_sku_id, // ? what is this
|
||||||
|
captcha_key,
|
||||||
|
} = req.body;
|
||||||
|
// TODO: automatically join invite
|
||||||
|
// TODO: gift_code_sku_id?
|
||||||
|
|
||||||
|
let adjusted_email: string = email;
|
||||||
|
let adjusted_password: string = password;
|
||||||
|
let adjusted_username: string = username;
|
||||||
|
const { register } = Config.get();
|
||||||
|
|
||||||
|
if (!register.allowNewRegistration) {
|
||||||
|
throw FieldErrors({
|
||||||
|
email: { code: "REGISTRATION_DISABLED", message: req.t("auth:register.REGISTRATION_DISABLED") },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!consent) {
|
||||||
|
throw FieldErrors({
|
||||||
|
consent: { code: "CONSENT_REQUIRED", message: req.t("auth:register.CONSENT_REQUIRED") },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (register.requireInvite && !invite) {
|
||||||
|
throw FieldErrors({
|
||||||
|
email: { code: "INVITE_ONLY", message: req.t("auth:register.INVITE_ONLY") },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (email) {
|
||||||
|
const parts = email.match(EMAIL_REGEX);
|
||||||
|
const domain = parts[5];
|
||||||
|
const user = parts[1];
|
||||||
|
|
||||||
|
if (domain === "gmail.com") {
|
||||||
|
// replace .dots and +alternatives -> Gmail Dot Trick https://support.google.com/mail/answer/7436150 and https://generator.email/blog/gmail-generator
|
||||||
|
adjusted_email = user.replace(/[.]|(\+.*)/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
const exists = await db.data.users({ email: adjusted_email }).get();
|
||||||
|
if (exists) {
|
||||||
|
throw FieldErrors({
|
||||||
|
email: {
|
||||||
|
code: "EMAIL_ALREADY_REGISTERED",
|
||||||
|
message: req.t("auth.register.EMAIL_ALREADY_REGISTERED"),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (register.email.required) {
|
||||||
|
throw FieldErrors({
|
||||||
|
email: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (register.dateOfBirth.required && !date_of_birth) {
|
||||||
|
throw FieldErrors({
|
||||||
|
date_of_birth: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") },
|
||||||
|
});
|
||||||
|
} else if (register.dateOfBirth.minimum) {
|
||||||
|
const minimum = new Date();
|
||||||
|
minimum.setFullYear(minimum.getFullYear() - register.dateOfBirth.minimum);
|
||||||
|
|
||||||
|
// higher is younger
|
||||||
|
if (date_of_birth > minimum) {
|
||||||
|
throw FieldErrors({
|
||||||
|
date_of_birth: {
|
||||||
|
code: "DATE_OF_BIRTH_UNDERAGE",
|
||||||
|
message: req.t("auth:register.DATE_OF_BIRTH_UNDERAGE"),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!register.allowMultipleAccounts) {
|
||||||
|
// TODO: check if fingerprint was eligible generated
|
||||||
|
const exists = await db.data.users({ fingerprint }).get();
|
||||||
|
if (exists) {
|
||||||
|
throw FieldErrors({
|
||||||
|
email: {
|
||||||
|
code: "EMAIL_ALREADY_REGISTERED",
|
||||||
|
message: req.t("auth:register.EMAIL_ALREADY_REGISTERED"),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (register.requireCaptcha) {
|
||||||
|
if (!captcha_key) {
|
||||||
|
const { sitekey, service } = Config.get().security.captcha;
|
||||||
|
return res
|
||||||
|
.status(400)
|
||||||
|
.json({ captcha_key: ["captcha-required"], captcha_sitekey: sitekey, captcha_service: service });
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check captcha
|
||||||
|
}
|
||||||
|
|
||||||
|
adjusted_password = await bcrypt.hash(password, 12);
|
||||||
|
adjusted_username = username.replace(/[]/g, "");
|
||||||
|
var discriminator = "";
|
||||||
|
let exists;
|
||||||
|
// TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the database?
|
||||||
|
for (let tries = 5; tries >= 0; tries--) {
|
||||||
|
discriminator = Math.randomBetween(1, 9999).toString().padStart(4, "0");
|
||||||
|
exists = await db.data.users({ discriminator, username: adjusted_username }).get({ id: true });
|
||||||
|
if (!exists) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
throw FieldErrors({
|
||||||
|
username: {
|
||||||
|
code: "USERNAME_TOO_MANY_USERS",
|
||||||
|
message: req.t("auth:register.USERNAME_TOO_MANY_USERS"),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const user: User = {
|
||||||
|
id: Snowflake.generate(),
|
||||||
|
created_at: Date.now(),
|
||||||
|
username: adjusted_username,
|
||||||
|
discriminator,
|
||||||
|
avatar: null,
|
||||||
|
bot: false,
|
||||||
|
system: false,
|
||||||
|
mfa_enabled: false,
|
||||||
|
verified: false,
|
||||||
|
email: adjusted_email,
|
||||||
|
flags: 0n, // TODO: generate default flags
|
||||||
|
hash: adjusted_password,
|
||||||
|
valid_tokens_since: Date.now(),
|
||||||
|
user_settings: {
|
||||||
|
afk_timeout: 300,
|
||||||
|
allow_accessibility_detection: true,
|
||||||
|
animate_emoji: true,
|
||||||
|
animate_stickers: 0,
|
||||||
|
contact_sync_enabled: false,
|
||||||
|
convert_emoticons: false,
|
||||||
|
custom_status: {
|
||||||
|
emoji_id: null,
|
||||||
|
emoji_name: null,
|
||||||
|
expires_at: null,
|
||||||
|
text: null,
|
||||||
|
},
|
||||||
|
default_guilds_restricted: false,
|
||||||
|
detect_platform_accounts: true,
|
||||||
|
developer_mode: false,
|
||||||
|
disable_games_tab: false,
|
||||||
|
enable_tts_command: true,
|
||||||
|
explicit_content_filter: 0,
|
||||||
|
friend_source_flags: { all: true },
|
||||||
|
gif_auto_play: true,
|
||||||
|
guild_folders: [],
|
||||||
|
guild_positions: [],
|
||||||
|
inline_attachment_media: true,
|
||||||
|
inline_embed_media: true,
|
||||||
|
locale: req.language,
|
||||||
|
message_display_compact: false,
|
||||||
|
native_phone_integration_enabled: true,
|
||||||
|
render_embeds: true,
|
||||||
|
render_reactions: true,
|
||||||
|
restricted_guilds: [],
|
||||||
|
show_current_game: true,
|
||||||
|
status: "offline",
|
||||||
|
stream_notifications_enabled: true,
|
||||||
|
theme: "dark",
|
||||||
|
timezone_offset: 0,
|
||||||
|
// timezone_offset: // TODO: timezone from request
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await db.data.users.push(user);
|
||||||
|
|
||||||
|
const token = generateToken(user.id);
|
||||||
|
|
||||||
|
return res.json({ token });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /auth/register
|
||||||
|
* @argument { "fingerprint":"805826570869932034.wR8vi8lGlFBJerErO9LG5NViJFw", "email":"qo8etzvaf@gmail.com", "username":"qp39gr98", "password":"wtp9gep9gw", "invite":null, "consent":true, "date_of_birth":"2000-04-04", "gift_code_sku_id":null, "captcha_key":null}
|
||||||
|
*
|
||||||
|
* Field Error
|
||||||
|
* @returns { "code": 50035, "errors": { "consent": { "_errors": [{ "code": "CONSENT_REQUIRED", "message": "You must agree to Discord's Terms of Service and Privacy Policy." }]}}, "message": "Invalid Form Body"}
|
||||||
|
*
|
||||||
|
* Success 201:
|
||||||
|
* @returns {token: "OMITTED"}
|
||||||
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user