feat(auth): working plugin
This commit is contained in:
parent
c545499c73
commit
ddde700494
5 changed files with 140 additions and 31 deletions
|
|
@ -63,13 +63,11 @@ const route: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
|
|||
if (user.otp !== null) {
|
||||
// yes -> we ask them to fill it,
|
||||
// send them somehting to verify that they indeed passed throught the user+password phase
|
||||
let otpToken = this.jwt.sign({ kind: "otp", user: user.name, createAt: Date.now() / 1000 });
|
||||
return { kind: "otpRequired", msg_key: "login.otpRequired", token: otpToken };
|
||||
return { kind: "otpRequired", msg_key: "login.otpRequired", token: this.signJwt("otp", user.name) };
|
||||
}
|
||||
|
||||
// every check has been passed, they are now logged in, using this token to say who they are...
|
||||
let userToken = this.jwt.sign({ kind: "auth", user: user.name, createAt: Date.now() / 1000 });
|
||||
return { kind: "success", msg_key: "login.success", token: userToken }
|
||||
return { kind: "success", msg_key: "login.success", token: this.signJwt("auth", user.name) }
|
||||
}
|
||||
catch {
|
||||
return { kind: "failed", msg_key: "login.failed.generic" };
|
||||
|
|
|
|||
86
src/auth/src/routes/otp.ts
Normal file
86
src/auth/src/routes/otp.ts
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import { FastifyPluginAsync } from "fastify";
|
||||
|
||||
import { Static, Type } from "@sinclair/typebox";
|
||||
import { JwtType, Otp } from "@shared/auth";
|
||||
|
||||
export const OtpReq = Type.Object({
|
||||
token: Type.String({ description: "The token given at the login phase" }),
|
||||
code: Type.String({ description: "The OTP given by the user" }),
|
||||
});
|
||||
|
||||
export type OtpReq = Static<typeof OtpReq>;
|
||||
|
||||
export const OtpRes = Type.Union([
|
||||
Type.Object({
|
||||
kind: Type.Const("failed"),
|
||||
msg_key: Type.Union([
|
||||
Type.Const("otp.failed.generic"),
|
||||
Type.Const("otp.failed.invalid"),
|
||||
Type.Const("otp.failed.timeout"),
|
||||
]),
|
||||
}),
|
||||
Type.Object({
|
||||
kind: Type.Const("success"),
|
||||
msg_key: Type.Const("otp.success"),
|
||||
token: Type.String({ description: "The JWT token" }),
|
||||
}),
|
||||
]);
|
||||
|
||||
export type OtpRes = Static<typeof OtpRes>;
|
||||
|
||||
const OTP_TOKEN_TIMEOUT_SEC = 120;
|
||||
|
||||
const route: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
|
||||
fastify.get<{ Body: OtpReq }>(
|
||||
"/whoami",
|
||||
{ schema: { body: OtpReq, response: { "2xx": OtpRes } } },
|
||||
async function(req, res) {
|
||||
try {
|
||||
const { token, code } = req.body;
|
||||
// lets try to decode+verify the jwt
|
||||
let dJwt = this.jwt.verify<JwtType>(token);
|
||||
|
||||
// is the jwt a valid `otp` jwt ?
|
||||
if (dJwt.kind != "otp")
|
||||
// no ? fuck off then
|
||||
return { kind: "failed", msg_key: "otp.failed.invalid" };
|
||||
// is it too old ?
|
||||
if (dJwt.createdAt + OTP_TOKEN_TIMEOUT_SEC * 1000 > Date.now())
|
||||
// yes ? fuck off then, redo the password
|
||||
return { kind: "failed", msg_key: "otp.failed.timeout" };
|
||||
|
||||
// get the Otp sercret from the db
|
||||
let otpSecret = this.db.getUserFromName(dJwt.who)?.otp;
|
||||
if (otpSecret === null)
|
||||
// oops, either no user, or user without otpSecret
|
||||
// fuck off
|
||||
return { kind: "failed", msg_key: "otp.failed.invalid" };
|
||||
|
||||
// good lets now verify the token you gave us is the correct one...
|
||||
let otpHandle = new Otp({ secret: otpSecret });
|
||||
|
||||
let now = Date.now();
|
||||
const tokens = [
|
||||
// we also get the last code, to mitiage the delay between client<->server roundtrip...
|
||||
otpHandle.totp(now - 30 * 1000),
|
||||
// this is the current token :)
|
||||
otpHandle.totp(now),
|
||||
];
|
||||
|
||||
// checking if any of the array match
|
||||
if (tokens.some((c) => c === code))
|
||||
// they do !
|
||||
// gg you are now logged in !
|
||||
return {
|
||||
kind: "success",
|
||||
msg_key: "otp.success",
|
||||
token: this.signJwt("auth", dJwt.who),
|
||||
};
|
||||
} catch {
|
||||
return { kind: "failed", msg_key: "otp.failed.generic" };
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export default route;
|
||||
Loading…
Add table
Add a link
Reference in a new issue