diff --git a/src/backend/src/routers/signup.js b/src/backend/src/routers/signup.js index b601e7c0..d0189268 100644 --- a/src/backend/src/routers/signup.js +++ b/src/backend/src/routers/signup.js @@ -65,281 +65,277 @@ module.exports = eggspress(['/signup'], { body: req.body, }); - if(config.registration_closed==true) - { + if( config.registration_closed == true ) { return res.status(403).send('Registration is closed.'); } - else - { - - // check bot trap, if `p102xyzname` is anything but an empty string it means - // that a bot has filled the form - // doesn't apply to temp users - if(!req.body.is_temp && req.body.p102xyzname !== '') - return res.send(); - - // check if user is already logged in - if ( req.body.is_temp && req.cookies[config.cookie_name] ) { - const { user, token } = await svc_auth.check_session( - req.cookies[config.cookie_name] - ); - res.cookie(config.cookie_name, token, { - sameSite: 'none', - secure: true, - httpOnly: true, - }); - // const decoded = await jwt.verify(token, config.jwt_secret); - // const user = await get_user({ uuid: decoded.uuid }); - if ( user ) { - return res.send({ - token: token, - user: { - username: user.username, - uuid: user.uuid, - email: user.email, - email_confirmed: user.email_confirmed, - requires_email_confirmation: user.requires_email_confirmation, - is_temp: (user.password === null && user.email === null), - taskbar_items: await get_taskbar_items(user), - } - }); - } - } - - // temporary user - if(req.body.is_temp && !config.disable_temp_users){ - req.body.username = await generate_random_username(); - req.body.email = req.body.username + '@gmail.com'; - req.body.password = 'sadasdfasdfsadfsa'; - }else if(config.disable_temp_users){ - return res.status(400).send('Temp users are disabled.'); - } - - // send_confirmation_code - req.body.send_confirmation_code = req.body.send_confirmation_code ?? true; - - // username is required - if(!req.body.username) - return res.status(400).send('Username is required') - // username must be a string - else if (typeof req.body.username !== 'string') - return res.status(400).send('username must be a string.') - // check if username is valid - else if(!req.body.username.match(config.username_regex)) - return res.status(400).send('Username can only contain letters, numbers and underscore (_).') - // check if username is of proper length - else if(req.body.username.length > config.username_max_length) - return res.status(400).send(`Username cannot be longer than ${config.username_max_length} characters.`) - // check if username matches any reserved words - else if(config.reserved_words.includes(req.body.username)) - return res.status(400).send({message: 'This username is not available.'}); - // TODO: DRY: change_email.js - else if(!req.body.is_temp && !req.body.email) - return res.status(400).send('Email is required'); - // email, if present, must be a string - else if (req.body.email && typeof req.body.email !== 'string') - return res.status(400).send('email must be a string.') - // if email is present, validate it - else if(!req.body.is_temp && !validator.isEmail(req.body.email)) - return res.status(400).send('Please enter a valid email address.') - else if(!req.body.is_temp && !req.body.password) - return res.status(400).send('Password is required'); - // password, if present, must be a string - else if (req.body.password && typeof req.body.password !== 'string') - return res.status(400).send('password must be a string.') - else if(!req.body.is_temp && req.body.password.length < config.min_pass_length) - return res.status(400).send(`Password must be at least ${config.min_pass_length} characters long.`); - - // duplicate username check - if(await username_exists(req.body.username)) - return res.status(400).send('This username already exists in our database. Please use another one.'); - // duplicate email check (pseudo-users don't count) - let rows2 = await db.read(`SELECT EXISTS(SELECT 1 FROM user WHERE email=? AND password IS NOT NULL) AS email_exists`, [req.body.email]); - if(rows2[0].email_exists) - return res.status(400).send('This email already exists in our database. Please use another one.'); - // get pseudo user, if exists - let pseudo_user = await db.read(`SELECT * FROM user WHERE email = ? AND password IS NULL`, [req.body.email]); - pseudo_user = pseudo_user[0]; - // get uuid user, if exists - if(req.body.uuid){ - uuid_user = await db.read(`SELECT * FROM user WHERE uuid = ? LIMIT 1`, [req.body.uuid]); - uuid_user = uuid_user[0]; - } - - // email confirmation is required by default unless: - // Pseudo user converting and matching uuid is provided - let email_confirmation_required = 1; - if(pseudo_user && uuid_user && pseudo_user.id === uuid_user.id) - email_confirmation_required = 0; - - // ----------------------------------- - // Get referral user - // ----------------------------------- - let referred_by_user = undefined; - if ( req.body.referral_code ) { - referred_by_user = await get_user({ referral_code: req.body.referral_code }); - if ( ! referred_by_user ) { - return res.status(400).send('Referral code not found'); - } - } - - // ----------------------------------- - // New User - // ----------------------------------- - const user_uuid = uuidv4(); - const email_confirm_token = uuidv4(); - let insert_res; - let email_confirm_code = Math.floor(100000 + Math.random() * 900000); - - if(pseudo_user === undefined){ - insert_res = await db.write( - `INSERT INTO user - (username, email, password, uuid, referrer, email_confirm_code, email_confirm_token, free_storage, referred_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, - [ - // username - req.body.username, - // email - req.body.is_temp ? null : req.body.email, - // password - req.body.is_temp ? null : await bcrypt.hash(req.body.password, 8), - // uuid - user_uuid, - // referrer - req.body.referrer ?? null, - // email_confirm_code - email_confirm_code, - // email_confirm_token - email_confirm_token, - // free_storage - config.storage_capacity, - // referred_by - referred_by_user ? referred_by_user.id : null, - ]); - - // record activity - db.write( - 'UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', - [insert_res.insertId] - ); - - // TODO: cache group id - const svc_group = req.services.get('group'); - await svc_group.add_users({ - uid: req.body.is_temp ? - config.default_temp_group : config.default_user_group, - users: [req.body.username] - }); - } - // ----------------------------------- - // Pseudo User converting - // ----------------------------------- - else{ - insert_res = await db.write( - `UPDATE user SET - username = ?, password = ?, uuid = ?, email_confirm_code = ?, email_confirm_token = ?, email_confirmed = ?, requires_email_confirmation = 1, - referred_by = ? - WHERE id = ?`, - [ - // username - req.body.username, - // password - await bcrypt.hash(req.body.password, 8), - // uuid - user_uuid, - // email_confirm_code - email_confirm_code, - // email_confirm_token - email_confirm_token, - // email_confirmed - !email_confirmation_required, - // id - pseudo_user.id, - // referred_by - referred_by_user ? referred_by_user.id : null, - ] - ); - - // TODO: cache group ids - const svc_group = req.services.get('group'); - await svc_group.remove_users({ - uid: config.default_temp_group, - users: [req.body.username], - }); - await svc_group.add_users({ - uid: config.default_user_group, - users: [req.body.username] - }); - - // record activity - db.write('UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [pseudo_user.id]); - invalidate_cached_user_by_id(pseudo_user.id); - } - - // user id - // todo if pseudo user, assign directly no need to do another DB lookup - const user_id = (pseudo_user === undefined) ? insert_res.insertId : pseudo_user.id; - - const [user] = await db.pread( - 'SELECT * FROM `user` WHERE `id` = ? LIMIT 1', - [user_id] + + // check bot trap, if `p102xyzname` is anything but an empty string it means + // that a bot has filled the form + // doesn't apply to temp users + if(!req.body.is_temp && req.body.p102xyzname !== '') + return res.send(); + + // check if user is already logged in + if ( req.body.is_temp && req.cookies[config.cookie_name] ) { + const { user, token } = await svc_auth.check_session( + req.cookies[config.cookie_name] ); - - // create token for login - const { token } = await svc_auth.create_session_token(user, { - req, - }); - // jwt.sign({uuid: user_uuid}, config.jwt_secret); - - //------------------------------------------------------------- - // email confirmation - //------------------------------------------------------------- - if((!req.body.is_temp && email_confirmation_required) || user.requires_email_confirmation){ - if(req.body.send_confirmation_code || user.requires_email_confirmation) - send_email_verification_code(email_confirm_code, user.email); - else - send_email_verification_token(user.email_confirm_token, user.email, user.uuid); - } - - //------------------------------------------------------------- - // referral code - //------------------------------------------------------------- - let referral_code; - if ( pseudo_user === undefined ) { - const svc_referralCode = Context.get('services') - .get('referral-code', { optional: true }); - if ( svc_referralCode ) { - referral_code = await svc_referralCode.gen_referral_code(user); - } - } - - await generate_system_fsentries(user); - - //set cookie res.cookie(config.cookie_name, token, { sameSite: 'none', secure: true, httpOnly: true, }); - - // add to mailchimp - if(!req.body.is_temp){ - const svc_event = Context.get('services').get('event'); - svc_event.emit('user.save_account', { user }); + // const decoded = await jwt.verify(token, config.jwt_secret); + // const user = await get_user({ uuid: decoded.uuid }); + if ( user ) { + return res.send({ + token: token, + user: { + username: user.username, + uuid: user.uuid, + email: user.email, + email_confirmed: user.email_confirmed, + requires_email_confirmation: user.requires_email_confirmation, + is_temp: (user.password === null && user.email === null), + taskbar_items: await get_taskbar_items(user), + } + }); } - - // return results - return res.send({ - token: token, - user:{ - username: user.username, - uuid: user.uuid, - email: user.email, - email_confirmed: user.email_confirmed, - requires_email_confirmation: user.requires_email_confirmation, - is_temp: (user.password === null && user.email === null), - taskbar_items: await get_taskbar_items(user), - referral_code, - } - }) } + + // temporary user + if(req.body.is_temp && !config.disable_temp_users){ + req.body.username = await generate_random_username(); + req.body.email = req.body.username + '@gmail.com'; + req.body.password = 'sadasdfasdfsadfsa'; + }else if(config.disable_temp_users){ + return res.status(400).send('Temp users are disabled.'); + } + + // send_confirmation_code + req.body.send_confirmation_code = req.body.send_confirmation_code ?? true; + + // username is required + if(!req.body.username) + return res.status(400).send('Username is required') + // username must be a string + else if (typeof req.body.username !== 'string') + return res.status(400).send('username must be a string.') + // check if username is valid + else if(!req.body.username.match(config.username_regex)) + return res.status(400).send('Username can only contain letters, numbers and underscore (_).') + // check if username is of proper length + else if(req.body.username.length > config.username_max_length) + return res.status(400).send(`Username cannot be longer than ${config.username_max_length} characters.`) + // check if username matches any reserved words + else if(config.reserved_words.includes(req.body.username)) + return res.status(400).send({message: 'This username is not available.'}); + // TODO: DRY: change_email.js + else if(!req.body.is_temp && !req.body.email) + return res.status(400).send('Email is required'); + // email, if present, must be a string + else if (req.body.email && typeof req.body.email !== 'string') + return res.status(400).send('email must be a string.') + // if email is present, validate it + else if(!req.body.is_temp && !validator.isEmail(req.body.email)) + return res.status(400).send('Please enter a valid email address.') + else if(!req.body.is_temp && !req.body.password) + return res.status(400).send('Password is required'); + // password, if present, must be a string + else if (req.body.password && typeof req.body.password !== 'string') + return res.status(400).send('password must be a string.') + else if(!req.body.is_temp && req.body.password.length < config.min_pass_length) + return res.status(400).send(`Password must be at least ${config.min_pass_length} characters long.`); + + // duplicate username check + if(await username_exists(req.body.username)) + return res.status(400).send('This username already exists in our database. Please use another one.'); + // duplicate email check (pseudo-users don't count) + let rows2 = await db.read(`SELECT EXISTS(SELECT 1 FROM user WHERE email=? AND password IS NOT NULL) AS email_exists`, [req.body.email]); + if(rows2[0].email_exists) + return res.status(400).send('This email already exists in our database. Please use another one.'); + // get pseudo user, if exists + let pseudo_user = await db.read(`SELECT * FROM user WHERE email = ? AND password IS NULL`, [req.body.email]); + pseudo_user = pseudo_user[0]; + // get uuid user, if exists + if(req.body.uuid){ + uuid_user = await db.read(`SELECT * FROM user WHERE uuid = ? LIMIT 1`, [req.body.uuid]); + uuid_user = uuid_user[0]; + } + + // email confirmation is required by default unless: + // Pseudo user converting and matching uuid is provided + let email_confirmation_required = 1; + if(pseudo_user && uuid_user && pseudo_user.id === uuid_user.id) + email_confirmation_required = 0; + + // ----------------------------------- + // Get referral user + // ----------------------------------- + let referred_by_user = undefined; + if ( req.body.referral_code ) { + referred_by_user = await get_user({ referral_code: req.body.referral_code }); + if ( ! referred_by_user ) { + return res.status(400).send('Referral code not found'); + } + } + + // ----------------------------------- + // New User + // ----------------------------------- + const user_uuid = uuidv4(); + const email_confirm_token = uuidv4(); + let insert_res; + let email_confirm_code = Math.floor(100000 + Math.random() * 900000); + + if(pseudo_user === undefined){ + insert_res = await db.write( + `INSERT INTO user + (username, email, password, uuid, referrer, email_confirm_code, email_confirm_token, free_storage, referred_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, + [ + // username + req.body.username, + // email + req.body.is_temp ? null : req.body.email, + // password + req.body.is_temp ? null : await bcrypt.hash(req.body.password, 8), + // uuid + user_uuid, + // referrer + req.body.referrer ?? null, + // email_confirm_code + email_confirm_code, + // email_confirm_token + email_confirm_token, + // free_storage + config.storage_capacity, + // referred_by + referred_by_user ? referred_by_user.id : null, + ]); + + // record activity + db.write( + 'UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', + [insert_res.insertId] + ); + + // TODO: cache group id + const svc_group = req.services.get('group'); + await svc_group.add_users({ + uid: req.body.is_temp ? + config.default_temp_group : config.default_user_group, + users: [req.body.username] + }); + } + // ----------------------------------- + // Pseudo User converting + // ----------------------------------- + else{ + insert_res = await db.write( + `UPDATE user SET + username = ?, password = ?, uuid = ?, email_confirm_code = ?, email_confirm_token = ?, email_confirmed = ?, requires_email_confirmation = 1, + referred_by = ? + WHERE id = ?`, + [ + // username + req.body.username, + // password + await bcrypt.hash(req.body.password, 8), + // uuid + user_uuid, + // email_confirm_code + email_confirm_code, + // email_confirm_token + email_confirm_token, + // email_confirmed + !email_confirmation_required, + // id + pseudo_user.id, + // referred_by + referred_by_user ? referred_by_user.id : null, + ] + ); + + // TODO: cache group ids + const svc_group = req.services.get('group'); + await svc_group.remove_users({ + uid: config.default_temp_group, + users: [req.body.username], + }); + await svc_group.add_users({ + uid: config.default_user_group, + users: [req.body.username] + }); + + // record activity + db.write('UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [pseudo_user.id]); + invalidate_cached_user_by_id(pseudo_user.id); + } + + // user id + // todo if pseudo user, assign directly no need to do another DB lookup + const user_id = (pseudo_user === undefined) ? insert_res.insertId : pseudo_user.id; + + const [user] = await db.pread( + 'SELECT * FROM `user` WHERE `id` = ? LIMIT 1', + [user_id] + ); + + // create token for login + const { token } = await svc_auth.create_session_token(user, { + req, + }); + // jwt.sign({uuid: user_uuid}, config.jwt_secret); + + //------------------------------------------------------------- + // email confirmation + //------------------------------------------------------------- + if((!req.body.is_temp && email_confirmation_required) || user.requires_email_confirmation){ + if(req.body.send_confirmation_code || user.requires_email_confirmation) + send_email_verification_code(email_confirm_code, user.email); + else + send_email_verification_token(user.email_confirm_token, user.email, user.uuid); + } + + //------------------------------------------------------------- + // referral code + //------------------------------------------------------------- + let referral_code; + if ( pseudo_user === undefined ) { + const svc_referralCode = Context.get('services') + .get('referral-code', { optional: true }); + if ( svc_referralCode ) { + referral_code = await svc_referralCode.gen_referral_code(user); + } + } + + await generate_system_fsentries(user); + + //set cookie + res.cookie(config.cookie_name, token, { + sameSite: 'none', + secure: true, + httpOnly: true, + }); + + // add to mailchimp + if(!req.body.is_temp){ + const svc_event = Context.get('services').get('event'); + svc_event.emit('user.save_account', { user }); + } + + // return results + return res.send({ + token: token, + user:{ + username: user.username, + uuid: user.uuid, + email: user.email, + email_confirmed: user.email_confirmed, + requires_email_confirmation: user.requires_email_confirmation, + is_temp: (user.password === null && user.email === null), + taskbar_items: await get_taskbar_items(user), + referral_code, + } + }) });