MeteoriteH/Back/routes/login.js

168 lines
6.1 KiB
JavaScript

const express = require("express")
const router = express.Router()
const bodyParser = require('body-parser')
var sanitize = require('mongo-sanitize');
const mongoose = require('mongoose');
const User = require('./../model/user.js')
const bcrypt = require('bcrypt')
const jwt = require('jsonwebtoken')
require('dotenv').config()
const JWT_SECRET = process.env.JWT_SECRET
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
const speakeasy = require('speakeasy')
const rateLimit = require('express-rate-limit')
const limiter = rateLimit({
windowMs: 5 * 1000, // 5 seconds
max: 1, // Limit each IP to 1 requests per `window`
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
handler: (request, response, next, options) =>{
return response.json({status: 'error', error: 'Too many requests try again later.'})
}
})
router.use(bodyParser.json())
router.get("/", (req, res) => {
res.redirect('/')
})
router.get(["/RequestAuth","/RequestAuth.ashx"], (req, res) => {
if (!req.cookies['.ROBLOSECURITY']){
res.status(403).end()
}
res.send('https://www.mete0r.xyz/Login/Negotiate.ashx?suggest='+req.cookies['.ROBLOSECURITY'])
}) // studio
router.get(["/Negotiate","/Negotiate.ashx"], (req, res) => {
if (!req.query.suggest){
res.status(403).end()
}
//res.cookie('jwt', req.query.suggest) // maxage is 24 hours
res.cookie('.ROBLOSECURITY', req.query.suggest)
res.cookie('.RBXID', req.query.suggest)
res.send(req.query.suggest)
}) // studio
router.post("/",limiter,async (req, res) => {
//console.log(req.headers)
let {username, password, _2fa} = req.body
if (!username && req.headers?.["user-agent"]?.includes("RobloxStudio/WinInet") === true){ // Studio login
username = req.body.cvalue??req.body.username
password = req.body.password??req.body.ticket
_2fa = req.body.code
}
if (!username || typeof username !== 'string') {
return res.json({status: 'error', error: 'Usernames needs to be sent and it needs to be a string'})
}
if (!password || typeof password !== 'string') {
return res.json({status: 'error', error: 'Password needs to be sent and it needs to be a string'})
}
if(password.length < 4) {
return res.json({status: 'error', error: 'Password needs to be at least 5 characters'})
}
sanitizedusername = sanitize(username)
const user = await User.findOne({username: sanitizedusername})/*.lean()*/
if (!user) {
if (req.headers?.["user-agent"] === "RobloxStudio/WinInet"){ // studio response
return res.json({
"errors": [
{
"code": 1,
"message": "Incorrect password"
}
]
})
}
return res.json({status: 'error', error: 'Invalid username/password'})
}
if (user.twofasecrets){
const json = JSON.parse(user.twofasecrets)
if (json.verified === true){
if (!_2fa){
if (req.headers?.["user-agent"] === "RobloxStudio/WinInet"){ // studio response
return res.json({
"user": {
"id": user.userid,
"name": user.username,
},
"twoStepVerificationData": {
"mediaType": "Email",
"ticket": password
},
"isBanned": false
})
}
return res.json({status: 'error', error: '2FA Enabled on account but 2fa not sent'})
}
const valid = speakeasy.totp.verify({
secret: json.secret,
encoding: 'ascii',
token: _2fa
})
if (valid === false){
if (req.headers?.["user-agent"] === "RobloxStudio/WinInet"){ // studio response
return res.json({
"errors": [
{
"code": 6,
"message": "Invalid two step verify code."
}
]
})
}
return res.json({status: 'error', error: 'Invalid 2FA Code'})
}
}else{
// basically if they haven't verified that they know the secret before we will just remove it for them
user.twofasecrets = undefined
user.markModified('twofasecrets')
user.save()
}
}
if(await bcrypt.compare(password, user.password) || password === user.password) {
// the username and password match
// lets make a token for them using the data from our database
const ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress
const token = jwt.sign({ id: user._id, username: user.username, admin: user.admin, userid: user.userid, ip, furry: true },JWT_SECRET,{expiresIn: '24h'})
if (req.headers?.["user-agent"] != "RobloxStudio/WinInet"){
res.cookie('jwt', token, {SameSite: "Strict",httpOnly: true,maxAge: 24 * 60 * 60 * 1000 }) // maxage is 24 hours
}
res.cookie('.ROBLOSECURITY', token, {SameSite: "Strict",httpOnly: true,maxAge: 24 * 60 * 60 * 1000 })
res.cookie('.RBXID', token, {SameSite: "Strict",httpOnly: true,maxAge: 24 * 60 * 60 * 1000 })
if (req.url === "/v2/twostepverification/verify"){
return res.json({})
}
if (req.headers?.["user-agent"] === "RobloxStudio/WinInet"){ // studio response
return res.json({
"user": {
"id": user.userid,
"name": user.username,
},
"isBanned": false
})
}
return res.json({status: 'ok', cookie: token})
}
if (req.headers?.["user-agent"] === "RobloxStudio/WinInet"){ // studio response
return res.json({
"errors": [
{
"code": 1,
"message": "Incorrect password"
}
]
})
}
res.status(403).json({status: 'error', error: 'Invalid username/password'})
})
module.exports = router