style(auth): auto-correction of the linter
- using pnpm eslint --fix ./src
This commit is contained in:
parent
b56906b557
commit
38013b77d3
13 changed files with 207 additions and 223 deletions
|
|
@ -1,107 +1,104 @@
|
|||
const headers = {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const tUsername = document.querySelector("#t-username")
|
||||
const tUsername = document.querySelector('#t-username');
|
||||
|
||||
const iUsername = document.querySelector("#i-username");
|
||||
const iPassword = document.querySelector("#i-password");
|
||||
const iOtp = document.querySelector("#i-otp");
|
||||
const iUsername = document.querySelector('#i-username');
|
||||
const iPassword = document.querySelector('#i-password');
|
||||
const iOtp = document.querySelector('#i-otp');
|
||||
|
||||
const bOtpSend = document.querySelector("#b-otpSend");
|
||||
const bLogin = document.querySelector("#b-login");
|
||||
const bLogout = document.querySelector("#b-logout");
|
||||
const bSignin = document.querySelector("#b-signin");
|
||||
const bWhoami = document.querySelector("#b-whoami");
|
||||
const bOtpSend = document.querySelector('#b-otpSend');
|
||||
const bLogin = document.querySelector('#b-login');
|
||||
const bLogout = document.querySelector('#b-logout');
|
||||
const bSignin = document.querySelector('#b-signin');
|
||||
const bWhoami = document.querySelector('#b-whoami');
|
||||
|
||||
const bOtpStatus = document.querySelector("#b-otpStatus");
|
||||
const bOtpEnable = document.querySelector("#b-otpEnable");
|
||||
const bOtpDisable = document.querySelector("#b-otpDisable");
|
||||
const bOtpStatus = document.querySelector('#b-otpStatus');
|
||||
const bOtpEnable = document.querySelector('#b-otpEnable');
|
||||
const bOtpDisable = document.querySelector('#b-otpDisable');
|
||||
|
||||
const dResponse = document.querySelector("#d-response");
|
||||
const dResponse = document.querySelector('#d-response');
|
||||
|
||||
function setResponse(obj) {
|
||||
let obj_str = JSON.stringify(obj, null, 4);
|
||||
const obj_str = JSON.stringify(obj, null, 4);
|
||||
dResponse.innerText = obj_str;
|
||||
}
|
||||
let otpToken = null;
|
||||
|
||||
bOtpSend.addEventListener("click", async () => {
|
||||
let res = await fetch("/api/auth/otp", { method: "POST", body: JSON.stringify({ code: iOtp.value, token: otpToken }), headers });
|
||||
bOtpSend.addEventListener('click', async () => {
|
||||
const res = await fetch('/api/auth/otp', { method: 'POST', body: JSON.stringify({ code: iOtp.value, token: otpToken }), headers });
|
||||
const json = await res.json();
|
||||
|
||||
setResponse(json);
|
||||
if (json.kind === "success") {
|
||||
if (json?.payload?.token)
|
||||
document.cookie = `token=${json?.payload?.token}`;
|
||||
if (json.kind === 'success') {
|
||||
if (json?.payload?.token) {document.cookie = `token=${json?.payload?.token}`;}
|
||||
}
|
||||
});
|
||||
|
||||
bOtpStatus.addEventListener("click", async () => {
|
||||
let res = await fetch("/api/auth/statusOtp");
|
||||
bOtpStatus.addEventListener('click', async () => {
|
||||
const res = await fetch('/api/auth/statusOtp');
|
||||
const json = await res.json();
|
||||
|
||||
setResponse(json);
|
||||
});
|
||||
|
||||
bOtpEnable.addEventListener("click", async () => {
|
||||
let res = await fetch("/api/auth/enableOtp", { method: "PUT" });
|
||||
bOtpEnable.addEventListener('click', async () => {
|
||||
const res = await fetch('/api/auth/enableOtp', { method: 'PUT' });
|
||||
const json = await res.json();
|
||||
|
||||
setResponse(json);
|
||||
});
|
||||
|
||||
bOtpDisable.addEventListener("click", async () => {
|
||||
let res = await fetch("/api/auth/disableOtp", { method: "PUT" });
|
||||
bOtpDisable.addEventListener('click', async () => {
|
||||
const res = await fetch('/api/auth/disableOtp', { method: 'PUT' });
|
||||
const json = await res.json();
|
||||
|
||||
setResponse(json);
|
||||
});
|
||||
|
||||
bWhoami.addEventListener("click", async () => {
|
||||
let username = "";
|
||||
bWhoami.addEventListener('click', async () => {
|
||||
let username = '';
|
||||
try {
|
||||
let res = await fetch("/api/auth/whoami");
|
||||
const res = await fetch('/api/auth/whoami');
|
||||
const json = await res.json();
|
||||
setResponse(json);
|
||||
if (json?.kind === "success")
|
||||
username = json?.payload?.name;
|
||||
else
|
||||
username = `<not logged in:${json.msg}>`
|
||||
} catch {
|
||||
username = `<not logged in: threw>`
|
||||
if (json?.kind === 'success') {username = json?.payload?.name;}
|
||||
else {username = `<not logged in:${json.msg}>`;}
|
||||
}
|
||||
catch {
|
||||
username = '<not logged in: threw>';
|
||||
}
|
||||
tUsername.innerText = username;
|
||||
});
|
||||
|
||||
bLogin.addEventListener("click", async () => {
|
||||
bLogin.addEventListener('click', async () => {
|
||||
const name = iUsername.value;
|
||||
const password = iPassword.value;
|
||||
|
||||
let res = await fetch("/api/auth/login", { method: "POST", body: JSON.stringify({ name, password }), headers });
|
||||
let json = await res.json();
|
||||
if (json?.kind === "otpRequired") {
|
||||
const res = await fetch('/api/auth/login', { method: 'POST', body: JSON.stringify({ name, password }), headers });
|
||||
const json = await res.json();
|
||||
if (json?.kind === 'otpRequired') {
|
||||
otpToken = json?.payload?.token;
|
||||
} else if (json?.kind === "success") {
|
||||
if (json?.payload?.token)
|
||||
document.cookie = `token=${json?.payload?.token}`;
|
||||
}
|
||||
else if (json?.kind === 'success') {
|
||||
if (json?.payload?.token) {document.cookie = `token=${json?.payload?.token}`;}
|
||||
}
|
||||
setResponse(json);
|
||||
})
|
||||
});
|
||||
|
||||
bLogout.addEventListener("click", async () => {
|
||||
let res = await fetch("/api/auth/logout", { method: "POST" });
|
||||
bLogout.addEventListener('click', async () => {
|
||||
const res = await fetch('/api/auth/logout', { method: 'POST' });
|
||||
setResponse(await res.json());
|
||||
})
|
||||
});
|
||||
|
||||
bSignin.addEventListener("click", async () => {
|
||||
bSignin.addEventListener('click', async () => {
|
||||
const name = iUsername.value;
|
||||
const password = iPassword.value;
|
||||
|
||||
let res = await fetch("/api/auth/signin", { method: "POST", body: JSON.stringify({ name, password }), headers });
|
||||
let json = await res.json();
|
||||
if (json?.payload?.token)
|
||||
document.cookie = `token=${json?.payload?.token};`;
|
||||
const res = await fetch('/api/auth/signin', { method: 'POST', body: JSON.stringify({ name, password }), headers });
|
||||
const json = await res.json();
|
||||
if (json?.payload?.token) {document.cookie = `token=${json?.payload?.token};`;}
|
||||
setResponse(json);
|
||||
})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { FastifyPluginAsync } from 'fastify'
|
||||
import fastifyFormBody from '@fastify/formbody'
|
||||
import fastifyMultipart from '@fastify/multipart'
|
||||
import { mkdir } from 'node:fs/promises'
|
||||
import fp from 'fastify-plugin'
|
||||
import * as db from '@shared/database'
|
||||
import * as auth from '@shared/auth'
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
import fastifyFormBody from '@fastify/formbody';
|
||||
import fastifyMultipart from '@fastify/multipart';
|
||||
import { mkdir } from 'node:fs/promises';
|
||||
import fp from 'fastify-plugin';
|
||||
import * as db from '@shared/database';
|
||||
import * as auth from '@shared/auth';
|
||||
|
||||
// @ts-ignore: import.meta.glob is a vite thing. Typescript doesn't know this...
|
||||
const plugins = import.meta.glob('./plugins/**/*.ts', { eager: true });
|
||||
|
|
@ -21,12 +21,12 @@ declare module 'fastify' {
|
|||
|
||||
const app: FastifyPluginAsync = async (
|
||||
fastify,
|
||||
opts
|
||||
opts,
|
||||
): Promise<void> => {
|
||||
await fastify.register(db.useDatabase as any, {})
|
||||
await fastify.register(auth.jwtPlugin as any, {})
|
||||
await fastify.register(auth.authPlugin as any, {})
|
||||
|
||||
await fastify.register(db.useDatabase as any, {});
|
||||
await fastify.register(auth.jwtPlugin as any, {});
|
||||
await fastify.register(auth.authPlugin as any, {});
|
||||
|
||||
// Place here your custom code!
|
||||
for (const plugin of Object.values(plugins)) {
|
||||
void fastify.register(plugin as any, {});
|
||||
|
|
@ -35,9 +35,9 @@ const app: FastifyPluginAsync = async (
|
|||
void fastify.register(route as any, {});
|
||||
}
|
||||
|
||||
void fastify.register(fastifyFormBody, {})
|
||||
void fastify.register(fastifyMultipart, {})
|
||||
}
|
||||
void fastify.register(fastifyFormBody, {});
|
||||
void fastify.register(fastifyMultipart, {});
|
||||
};
|
||||
|
||||
export default app
|
||||
export { app }
|
||||
export default app;
|
||||
export { app };
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import fp from 'fastify-plugin'
|
||||
import sensible, { FastifySensibleOptions } from '@fastify/sensible'
|
||||
import fp from 'fastify-plugin';
|
||||
import sensible, { FastifySensibleOptions } from '@fastify/sensible';
|
||||
|
||||
/**
|
||||
* This plugins adds some utilities to handle http errors
|
||||
|
|
@ -7,5 +7,5 @@ import sensible, { FastifySensibleOptions } from '@fastify/sensible'
|
|||
* @see https://github.com/fastify/fastify-sensible
|
||||
*/
|
||||
export default fp<FastifySensibleOptions>(async (fastify) => {
|
||||
fastify.register(sensible)
|
||||
})
|
||||
fastify.register(sensible);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,25 +1,24 @@
|
|||
import { FastifyPluginAsync } from "fastify";
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
|
||||
import { Static, Type } from "@sinclair/typebox";
|
||||
import { makeResponse, typeResponse, isNullish } from "@shared/utils"
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { makeResponse, typeResponse, isNullish } from '@shared/utils';
|
||||
|
||||
|
||||
export const WhoAmIRes = Type.Union([
|
||||
typeResponse("success", "disableOtp.success"),
|
||||
typeResponse("failure", "disableOtp.failure.generic")
|
||||
typeResponse('success', 'disableOtp.success'),
|
||||
typeResponse('failure', 'disableOtp.failure.generic'),
|
||||
]);
|
||||
|
||||
export type WhoAmIRes = Static<typeof WhoAmIRes>;
|
||||
|
||||
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||
fastify.put(
|
||||
"/api/auth/disableOtp",
|
||||
{ schema: { response: { "2xx": WhoAmIRes } }, config: { requireAuth: true } },
|
||||
'/api/auth/disableOtp',
|
||||
{ schema: { response: { '2xx': WhoAmIRes } }, config: { requireAuth: true } },
|
||||
async function(req, _res) {
|
||||
if (isNullish(req.authUser))
|
||||
return makeResponse("failure", "disableOtp.failure.generic");
|
||||
if (isNullish(req.authUser)) {return makeResponse('failure', 'disableOtp.failure.generic');}
|
||||
this.db.deleteUserOtpSecret(req.authUser.id);
|
||||
return makeResponse("success", "disableOtp.success");
|
||||
return makeResponse('success', 'disableOtp.success');
|
||||
},
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,29 +1,27 @@
|
|||
import { FastifyPluginAsync } from "fastify";
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
|
||||
import { Static, Type } from "@sinclair/typebox";
|
||||
import { isNullish, makeResponse, typeResponse } from "@shared/utils"
|
||||
import { Otp } from "@shared/auth";
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { isNullish, makeResponse, typeResponse } from '@shared/utils';
|
||||
import { Otp } from '@shared/auth';
|
||||
|
||||
|
||||
export const WhoAmIRes = Type.Union([
|
||||
typeResponse("success", "enableOtp.success", { url: Type.String({ description: "The otp url to feed into a 2fa app" }) }),
|
||||
typeResponse("failure", ["enableOtp.failure.noUser", "enableOtp.failure.noSecret"])
|
||||
typeResponse('success', 'enableOtp.success', { url: Type.String({ description: 'The otp url to feed into a 2fa app' }) }),
|
||||
typeResponse('failure', ['enableOtp.failure.noUser', 'enableOtp.failure.noSecret']),
|
||||
]);
|
||||
|
||||
export type WhoAmIRes = Static<typeof WhoAmIRes>;
|
||||
|
||||
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||
fastify.put(
|
||||
"/api/auth/enableOtp",
|
||||
{ schema: { response: { "2xx": WhoAmIRes } }, config: { requireAuth: true } },
|
||||
'/api/auth/enableOtp',
|
||||
{ schema: { response: { '2xx': WhoAmIRes } }, config: { requireAuth: true } },
|
||||
async function(req, _res) {
|
||||
if (isNullish(req.authUser))
|
||||
return makeResponse("failure", "enableOtp.failure.noUser");
|
||||
let otpSecret = this.db.ensureUserOtpSecret(req.authUser!.id);
|
||||
if (isNullish(otpSecret))
|
||||
return makeResponse("failure", "enableOtp.failure.noSecret");
|
||||
let otp = new Otp({ secret: otpSecret });
|
||||
return makeResponse("success", "enableOtp.success", { url: otp.totpURL });
|
||||
if (isNullish(req.authUser)) {return makeResponse('failure', 'enableOtp.failure.noUser');}
|
||||
const otpSecret = this.db.ensureUserOtpSecret(req.authUser!.id);
|
||||
if (isNullish(otpSecret)) {return makeResponse('failure', 'enableOtp.failure.noSecret');}
|
||||
const otp = new Otp({ secret: otpSecret });
|
||||
return makeResponse('success', 'enableOtp.success', { url: otp.totpURL });
|
||||
},
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { FastifyPluginAsync } from "fastify";
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
|
||||
import { Static, Type } from "@sinclair/typebox";
|
||||
import { typeResponse, makeResponse, isNullish } from "@shared/utils"
|
||||
import { verifyUserPassword } from "@shared/database/mixin/user";
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { typeResponse, makeResponse, isNullish } from '@shared/utils';
|
||||
import { verifyUserPassword } from '@shared/database/mixin/user';
|
||||
|
||||
export const LoginReq = Type.Object({
|
||||
name: Type.String(),
|
||||
|
|
@ -12,9 +12,9 @@ export const LoginReq = Type.Object({
|
|||
export type LoginReq = Static<typeof LoginReq>;
|
||||
|
||||
export const LoginRes = Type.Union([
|
||||
typeResponse("failed", ["login.failed.generic", "login.failed.invalid"]),
|
||||
typeResponse("otpRequired", "login.otpRequired", { token: Type.String({ description: "JWT to send with the OTP to finish login" }) }),
|
||||
typeResponse("success", "login.success", { token: Type.String({ description: "JWT that represent a logged in user" }) }),
|
||||
typeResponse('failed', ['login.failed.generic', 'login.failed.invalid']),
|
||||
typeResponse('otpRequired', 'login.otpRequired', { token: Type.String({ description: 'JWT to send with the OTP to finish login' }) }),
|
||||
typeResponse('success', 'login.success', { token: Type.String({ description: 'JWT that represent a logged in user' }) }),
|
||||
]);
|
||||
|
||||
|
||||
|
|
@ -22,34 +22,32 @@ export type LoginRes = Static<typeof LoginRes>;
|
|||
|
||||
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||
fastify.post<{ Body: LoginReq; Response: LoginRes }>(
|
||||
"/api/auth/login",
|
||||
{ schema: { body: LoginReq, response: { "2xx": LoginRes } }, },
|
||||
'/api/auth/login',
|
||||
{ schema: { body: LoginReq, response: { '2xx': LoginRes } } },
|
||||
async function(req, _res) {
|
||||
try {
|
||||
let { name, password } = req.body;
|
||||
let user = this.db.getUserFromName(name);
|
||||
const { name, password } = req.body;
|
||||
const user = this.db.getUserFromName(name);
|
||||
|
||||
// does the user exist
|
||||
// does it have a password setup ?
|
||||
if (isNullish(user?.password))
|
||||
return makeResponse("failed", "login.failed.invalid");
|
||||
if (isNullish(user?.password)) {return makeResponse('failed', 'login.failed.invalid');}
|
||||
|
||||
// does the password he provided match the one we have
|
||||
if (!(await verifyUserPassword(user, password)))
|
||||
return makeResponse("failed", "login.failed.invalid");
|
||||
if (!(await verifyUserPassword(user, password))) {return makeResponse('failed', 'login.failed.invalid');}
|
||||
|
||||
// does the user has 2FA up ?
|
||||
if (!isNullish(user.otp)) {
|
||||
// yes -> we ask them to fill it,
|
||||
// send them somehting to verify that they indeed passed throught the user+password phase
|
||||
return makeResponse("otpRequired", "login.otpRequired", { token: this.signJwt("otp", user.name) });
|
||||
return makeResponse('otpRequired', '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...
|
||||
return makeResponse("success", "login.success", { token: this.signJwt("auth", user.name) });
|
||||
return makeResponse('success', 'login.success', { token: this.signJwt('auth', user.name) });
|
||||
}
|
||||
catch {
|
||||
return makeResponse("failed", "login.failed.generic");
|
||||
return makeResponse('failed', 'login.failed.generic');
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { FastifyPluginAsync } from "fastify";
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
|
||||
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||
fastify.post(
|
||||
"/api/auth/logout",
|
||||
'/api/auth/logout',
|
||||
async function(_req, res) {
|
||||
return res.clearCookie("token").send("{}")
|
||||
return res.clearCookie('token').send('{}');
|
||||
},
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
import { FastifyPluginAsync } from "fastify";
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
|
||||
import { Static, Type } from "@sinclair/typebox";
|
||||
import { JwtType, Otp } from "@shared/auth";
|
||||
import { typeResponse, makeResponse, isNullish } from "@shared/utils";
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { JwtType, Otp } from '@shared/auth';
|
||||
import { typeResponse, makeResponse, isNullish } from '@shared/utils';
|
||||
|
||||
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" }),
|
||||
token: Type.String({ description: 'The token given at the login phase' }),
|
||||
code: Type.String({ description: 'The OTP given by the user' }),
|
||||
});
|
||||
|
||||
type OtpReq = Static<typeof OtpReq>;
|
||||
|
||||
const OtpRes = Type.Union([
|
||||
typeResponse("failed", ["otp.failed.generic", "otp.failed.invalid", "otp.failed.timeout", "otp.failed.noSecret"]),
|
||||
typeResponse("success", "otp.success", { token: Type.String({ description: "the JWT Token" }) }),
|
||||
typeResponse('failed', ['otp.failed.generic', 'otp.failed.invalid', 'otp.failed.timeout', 'otp.failed.noSecret']),
|
||||
typeResponse('success', 'otp.success', { token: Type.String({ description: 'the JWT Token' }) }),
|
||||
]);
|
||||
|
||||
type OtpRes = Static<typeof OtpRes>;
|
||||
|
|
@ -22,34 +22,34 @@ const OTP_TOKEN_TIMEOUT_SEC = 120;
|
|||
|
||||
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||
fastify.post<{ Body: OtpReq }>(
|
||||
"/api/auth/otp",
|
||||
{ schema: { body: OtpReq, response: { "2xx": OtpRes } } },
|
||||
'/api/auth/otp',
|
||||
{ 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);
|
||||
const dJwt = this.jwt.verify<JwtType>(token);
|
||||
|
||||
// is the jwt a valid `otp` jwt ?
|
||||
if (dJwt.kind != "otp")
|
||||
// no ? fuck off then
|
||||
return makeResponse("failed", "otp.failed.invalid");
|
||||
if (dJwt.kind != 'otp')
|
||||
// no ? fuck off then
|
||||
{return makeResponse('failed', '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 makeResponse("failed", "otp.failed.timeout");
|
||||
// yes ? fuck off then, redo the password
|
||||
{return makeResponse('failed', 'otp.failed.timeout');}
|
||||
|
||||
// get the Otp sercret from the db
|
||||
let user = this.db.getUserFromName(dJwt.who);
|
||||
const user = this.db.getUserFromName(dJwt.who);
|
||||
if (isNullish(user?.otp))
|
||||
// oops, either no user, or user without otpSecret
|
||||
// fuck off
|
||||
return makeResponse("failed", "otp.failed.noSecret");
|
||||
// oops, either no user, or user without otpSecret
|
||||
// fuck off
|
||||
{return makeResponse('failed', 'otp.failed.noSecret');}
|
||||
|
||||
// good lets now verify the token you gave us is the correct one...
|
||||
let otpHandle = new Otp({ secret: user.otp });
|
||||
const otpHandle = new Otp({ secret: user.otp });
|
||||
|
||||
let now = Date.now();
|
||||
const now = Date.now();
|
||||
const tokens = [
|
||||
// we also get the last code, to mitiage the delay between client<->server roundtrip...
|
||||
otpHandle.totp(now - 30 * 1000),
|
||||
|
|
@ -59,13 +59,14 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
|||
|
||||
// checking if any of the array match
|
||||
if (tokens.some((c) => c === code))
|
||||
// they do !
|
||||
// gg you are now logged in !
|
||||
return makeResponse("success", "otp.success", { token: this.signJwt("auth", dJwt.who) });
|
||||
} catch {
|
||||
return makeResponse("failed", "otp.failed.generic");
|
||||
// they do !
|
||||
// gg you are now logged in !
|
||||
{return makeResponse('success', 'otp.success', { token: this.signJwt('auth', dJwt.who) });}
|
||||
}
|
||||
return makeResponse("failed", "otp.failed.generic");
|
||||
catch {
|
||||
return makeResponse('failed', 'otp.failed.generic');
|
||||
}
|
||||
return makeResponse('failed', 'otp.failed.generic');
|
||||
},
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { FastifyPluginAsync } from "fastify";
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
|
||||
import { Static, Type } from "@sinclair/typebox";
|
||||
import { typeResponse, makeResponse, isNullish } from "@shared/utils";
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { typeResponse, makeResponse, isNullish } from '@shared/utils';
|
||||
|
||||
const USERNAME_CHECK: RegExp = /^[a-zA-Z\_0-9]+$/;
|
||||
|
||||
|
|
@ -13,51 +13,44 @@ const SignInReq = Type.Object({
|
|||
type SignInReq = Static<typeof SignInReq>;
|
||||
|
||||
const SignInRes = Type.Union([
|
||||
typeResponse("failed", [
|
||||
"signin.failed.generic",
|
||||
"signin.failed.username.existing",
|
||||
"signin.failed.username.toolong",
|
||||
"signin.failed.username.tooshort",
|
||||
"signin.failed.username.invalid",
|
||||
"signin.failed.password.toolong",
|
||||
"signin.failed.password.tooshort",
|
||||
"signin.failed.password.invalid",
|
||||
typeResponse('failed', [
|
||||
'signin.failed.generic',
|
||||
'signin.failed.username.existing',
|
||||
'signin.failed.username.toolong',
|
||||
'signin.failed.username.tooshort',
|
||||
'signin.failed.username.invalid',
|
||||
'signin.failed.password.toolong',
|
||||
'signin.failed.password.tooshort',
|
||||
'signin.failed.password.invalid',
|
||||
]),
|
||||
typeResponse("success", "signin.success", { token: Type.String({ description: "the JWT token" }) }),
|
||||
])
|
||||
typeResponse('success', 'signin.success', { token: Type.String({ description: 'the JWT token' }) }),
|
||||
]);
|
||||
|
||||
type SignInRes = Static<typeof SignInRes>;
|
||||
|
||||
const route: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
|
||||
fastify.post<{ Body: SignInReq }>(
|
||||
"/api/auth/signin",
|
||||
{ schema: { body: SignInReq, response: { "200": SignInRes, "5xx": Type.Object({}) } }, },
|
||||
'/api/auth/signin',
|
||||
{ schema: { body: SignInReq, response: { '200': SignInRes, '5xx': Type.Object({}) } } },
|
||||
async function(req, res) {
|
||||
const { name, password } = req.body;
|
||||
|
||||
if (name.length < 4)
|
||||
return makeResponse("failed", "signin.failed.username.tooshort");
|
||||
if (name.length > 32)
|
||||
return makeResponse("failed", "signin.failed.username.toolong");
|
||||
if (!USERNAME_CHECK.test(name))
|
||||
return makeResponse("failed", "signin.failed.username.invalid");
|
||||
if (name.length < 4) {return makeResponse('failed', 'signin.failed.username.tooshort');}
|
||||
if (name.length > 32) {return makeResponse('failed', 'signin.failed.username.toolong');}
|
||||
if (!USERNAME_CHECK.test(name)) {return makeResponse('failed', 'signin.failed.username.invalid');}
|
||||
// username if good now :)
|
||||
|
||||
if (password.length < 8)
|
||||
return makeResponse("failed", "signin.failed.password.tooshort");
|
||||
if (password.length > 64)
|
||||
return makeResponse("failed", "signin.failed.password.toolong");
|
||||
if (password.length < 8) {return makeResponse('failed', 'signin.failed.password.tooshort');}
|
||||
if (password.length > 64) {return makeResponse('failed', 'signin.failed.password.toolong');}
|
||||
// password is good too !
|
||||
|
||||
if (this.db.getUserFromName(name) !== undefined)
|
||||
return makeResponse("failed", "signin.failed.username.existing");
|
||||
let u = await this.db.createUser(name, password);
|
||||
if (isNullish(u))
|
||||
return makeResponse("failed", "signin.failed.generic");
|
||||
if (this.db.getUserFromName(name) !== undefined) {return makeResponse('failed', 'signin.failed.username.existing');}
|
||||
const u = await this.db.createUser(name, password);
|
||||
if (isNullish(u)) {return makeResponse('failed', 'signin.failed.generic');}
|
||||
|
||||
// every check has been passed, they are now logged in, using this token to say who they are...
|
||||
let userToken = this.signJwt('auth', u.name);
|
||||
return makeResponse("success", "signin.success", { token: userToken });
|
||||
const userToken = this.signJwt('auth', u.name);
|
||||
return makeResponse('success', 'signin.success', { token: userToken });
|
||||
},
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,30 +1,28 @@
|
|||
import { FastifyPluginAsync } from "fastify";
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
|
||||
import { Static, Type } from "@sinclair/typebox";
|
||||
import { isNullish, makeResponse, typeResponse } from "@shared/utils"
|
||||
import { Otp } from "@shared/auth";
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { isNullish, makeResponse, typeResponse } from '@shared/utils';
|
||||
import { Otp } from '@shared/auth';
|
||||
|
||||
|
||||
export const StatusOtpRes = Type.Union([
|
||||
typeResponse("success", "statusOtp.success.enabled", { url: Type.String({ description: "The otp url to feed into a 2fa app" }) }),
|
||||
typeResponse("success", "statusOtp.success.disabled"),
|
||||
typeResponse("failure", "statusOtp.failure.generic")
|
||||
typeResponse('success', 'statusOtp.success.enabled', { url: Type.String({ description: 'The otp url to feed into a 2fa app' }) }),
|
||||
typeResponse('success', 'statusOtp.success.disabled'),
|
||||
typeResponse('failure', 'statusOtp.failure.generic'),
|
||||
]);
|
||||
|
||||
export type StatusOtpRes = Static<typeof StatusOtpRes>;
|
||||
|
||||
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||
fastify.get(
|
||||
"/api/auth/statusOtp",
|
||||
{ schema: { response: { "2xx": StatusOtpRes } }, config: { requireAuth: true } },
|
||||
'/api/auth/statusOtp',
|
||||
{ schema: { response: { '2xx': StatusOtpRes } }, config: { requireAuth: true } },
|
||||
async function(req, _res) {
|
||||
if (isNullish(req.authUser))
|
||||
return makeResponse("failure", "statusOtp.failure.generic");
|
||||
let otpSecret = this.db.getUserOtpSecret(req.authUser.id);
|
||||
if (isNullish(otpSecret))
|
||||
return makeResponse("success", "statusOtp.success.disabled");
|
||||
let otp = new Otp({ secret: otpSecret })
|
||||
return makeResponse("success", "statusOtp.success.enabled", { url: otp.totpURL });
|
||||
if (isNullish(req.authUser)) {return makeResponse('failure', 'statusOtp.failure.generic');}
|
||||
const otpSecret = this.db.getUserOtpSecret(req.authUser.id);
|
||||
if (isNullish(otpSecret)) {return makeResponse('success', 'statusOtp.success.disabled');}
|
||||
const otp = new Otp({ secret: otpSecret });
|
||||
return makeResponse('success', 'statusOtp.success.enabled', { url: otp.totpURL });
|
||||
},
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,24 +1,23 @@
|
|||
import { FastifyPluginAsync } from "fastify";
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
|
||||
import { Static, Type } from "@sinclair/typebox";
|
||||
import { isNullish, makeResponse, typeResponse } from "@shared/utils"
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { isNullish, makeResponse, typeResponse } from '@shared/utils';
|
||||
|
||||
|
||||
export const WhoAmIRes = Type.Union([
|
||||
typeResponse("success", "whoami.success", { name: Type.String() }),
|
||||
typeResponse("failure", "whoami.failure.generic")
|
||||
typeResponse('success', 'whoami.success', { name: Type.String() }),
|
||||
typeResponse('failure', 'whoami.failure.generic'),
|
||||
]);
|
||||
|
||||
export type WhoAmIRes = Static<typeof WhoAmIRes>;
|
||||
|
||||
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||
fastify.get(
|
||||
"/api/auth/whoami",
|
||||
{ schema: { response: { "2xx": WhoAmIRes } }, config: { requireAuth: true } },
|
||||
'/api/auth/whoami',
|
||||
{ schema: { response: { '2xx': WhoAmIRes } }, config: { requireAuth: true } },
|
||||
async function(req, _res) {
|
||||
if (isNullish(req.authUser))
|
||||
return makeResponse("failure", "whoami.failure.generic")
|
||||
return makeResponse("success", "whoami.success", { name: req.authUser.name })
|
||||
if (isNullish(req.authUser)) {return makeResponse('failure', 'whoami.failure.generic');}
|
||||
return makeResponse('success', 'whoami.success', { name: req.authUser.name });
|
||||
},
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// this sould only be used by the docker file !
|
||||
|
||||
import fastify, { FastifyInstance } from "fastify";
|
||||
import app from "./app"
|
||||
import fastify, { FastifyInstance } from 'fastify';
|
||||
import app from './app';
|
||||
|
||||
const start = async () => {
|
||||
const envToLogger = {
|
||||
|
|
@ -16,15 +16,16 @@ const start = async () => {
|
|||
},
|
||||
production: true,
|
||||
test: false,
|
||||
}
|
||||
};
|
||||
|
||||
const f: FastifyInstance = fastify({ logger: envToLogger.development });
|
||||
try {
|
||||
await f.register(app, {});
|
||||
await f.listen({ port: 80, host: '0.0.0.0' })
|
||||
} catch (err) {
|
||||
f.log.error(err)
|
||||
process.exit(1)
|
||||
await f.listen({ port: 80, host: '0.0.0.0' });
|
||||
}
|
||||
}
|
||||
start()
|
||||
catch (err) {
|
||||
f.log.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
start();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import tsconfigPaths from 'vite-tsconfig-paths'
|
||||
import nodeExternals from 'rollup-plugin-node-externals'
|
||||
import path from 'node:path'
|
||||
import fs from 'node:fs'
|
||||
import { defineConfig } from 'vite';
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
import nodeExternals from 'rollup-plugin-node-externals';
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
|
||||
function collectDeps(...pkgJsonPaths) {
|
||||
const allDeps = new Set();
|
||||
|
|
@ -20,7 +20,7 @@ function collectDeps(...pkgJsonPaths) {
|
|||
|
||||
const externals = collectDeps(
|
||||
'./package.json',
|
||||
'../@shared/package.json'
|
||||
'../@shared/package.json',
|
||||
);
|
||||
|
||||
|
||||
|
|
@ -42,5 +42,5 @@ export default defineConfig({
|
|||
target: 'node22', // or whatever Node version you use
|
||||
sourcemap: true,
|
||||
minify: false, // for easier debugging
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue