135 lines
4.5 KiB
TypeScript
135 lines
4.5 KiB
TypeScript
import { Request, Response } from "express";
|
|
import User, { IUser } from "../../models/user";
|
|
import { randomBytes } from "crypto";
|
|
import moment = require("moment");
|
|
import LoginToken from "../../models/login_token";
|
|
import promiseMiddleware from "../../helper/promiseMiddleware";
|
|
import TwoFactor, { TFATypes, TFANames } from "../../models/twofactor";
|
|
import * as crypto from "crypto";
|
|
import Logging from "@hibas123/nodelogging";
|
|
|
|
const Login = promiseMiddleware(async (req: Request, res: Response) => {
|
|
let type = req.query.type;
|
|
if (type === "username") {
|
|
let { username, uid } = req.query;
|
|
let user = await User.findOne(
|
|
username ? { username: username.toLowerCase() } : { uid: uid }
|
|
);
|
|
if (!user) {
|
|
res.json({ error: req.__("User not found") });
|
|
} else {
|
|
res.json({ salt: user.salt, uid: user.uid });
|
|
}
|
|
return;
|
|
} else if (type === "password") {
|
|
const sendToken = async (user: IUser, tfa?: any[]) => {
|
|
let ip =
|
|
req.headers["x-forwarded-for"] || req.connection.remoteAddress;
|
|
let client = {
|
|
ip: Array.isArray(ip) ? ip[0] : ip,
|
|
browser: req.headers["user-agent"],
|
|
};
|
|
|
|
let token_str = randomBytes(16).toString("hex");
|
|
let tfa_exp = moment().add(5, "minutes").toDate();
|
|
let token_exp = moment().add(6, "months").toDate();
|
|
let token = LoginToken.new({
|
|
token: token_str,
|
|
valid: true,
|
|
validTill: tfa ? tfa_exp : token_exp,
|
|
user: user._id,
|
|
validated: tfa ? false : true,
|
|
...client,
|
|
});
|
|
await LoginToken.save(token);
|
|
|
|
let special_str = randomBytes(24).toString("hex");
|
|
let special_exp = moment().add(30, "minutes").toDate();
|
|
let special = LoginToken.new({
|
|
token: special_str,
|
|
valid: true,
|
|
validTill: tfa ? tfa_exp : special_exp,
|
|
special: true,
|
|
user: user._id,
|
|
validated: tfa ? false : true,
|
|
...client,
|
|
});
|
|
await LoginToken.save(special);
|
|
|
|
res.json({
|
|
login: { token: token_str, expires: token.validTill.toUTCString() },
|
|
special: {
|
|
token: special_str,
|
|
expires: special.validTill.toUTCString(),
|
|
},
|
|
tfa,
|
|
});
|
|
};
|
|
|
|
let { username, password, uid, date } = req.body;
|
|
|
|
let user = await User.findOne(
|
|
username ? { username: username.toLowerCase() } : { uid: uid }
|
|
);
|
|
if (!user) {
|
|
res.json({ error: req.__("User not found") });
|
|
} else {
|
|
let upw = user.password;
|
|
if (date) {
|
|
if (
|
|
!moment(date).isBetween(
|
|
moment().subtract(1, "minute"),
|
|
moment().add(1, "minute")
|
|
)
|
|
) {
|
|
res.json({
|
|
error: req.__(
|
|
"Invalid timestamp. Please check your devices time!"
|
|
),
|
|
});
|
|
return;
|
|
} else {
|
|
upw = crypto
|
|
.createHash("sha512")
|
|
.update(upw + date.toString())
|
|
.digest("hex");
|
|
}
|
|
}
|
|
if (upw !== password) {
|
|
res.json({ error: req.__("Password or username wrong") });
|
|
} else {
|
|
let twofactor = await TwoFactor.find({
|
|
user: user._id,
|
|
valid: true,
|
|
});
|
|
let expired = twofactor.filter((e) =>
|
|
e.expires ? moment().isAfter(moment(e.expires)) : false
|
|
);
|
|
await Promise.all(
|
|
expired.map((e) => {
|
|
e.valid = false;
|
|
return TwoFactor.save(e);
|
|
})
|
|
);
|
|
twofactor = twofactor.filter((e) => e.valid);
|
|
if (twofactor && twofactor.length > 0) {
|
|
let tfa = twofactor.map((e) => {
|
|
return {
|
|
id: e._id,
|
|
name: e.name || TFANames.get(e.type),
|
|
type: e.type,
|
|
};
|
|
});
|
|
await sendToken(user, tfa);
|
|
} else {
|
|
await sendToken(user);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
res.json({ error: req.__("Invalid type!") });
|
|
}
|
|
});
|
|
|
|
export default Login;
|