wip
This commit is contained in:
parent
79c7edb30f
commit
3140da7bab
30 changed files with 1148 additions and 95 deletions
|
|
@ -14,6 +14,7 @@ const kRouteAuthDone = Symbol('shared-route-auth-done');
|
|||
type AuthedUser = {
|
||||
id: UserId;
|
||||
name: string;
|
||||
guest: boolean;
|
||||
};
|
||||
|
||||
declare module 'fastify' {
|
||||
|
|
@ -118,7 +119,7 @@ export const authPlugin = fp<{ onlySchema?: boolean }>(async (fastify, { onlySch
|
|||
.clearCookie('token', { path: '/' })
|
||||
.makeResponse(401, 'notLoggedIn', 'auth.noUser');
|
||||
}
|
||||
req.authUser = { id: user.id, name: user.display_name };
|
||||
req.authUser = { id: user.id, name: user.name, guest: user.guest };
|
||||
}
|
||||
catch {
|
||||
return res
|
||||
|
|
|
|||
|
|
@ -38,6 +38,32 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"disableOtp.failure.guest"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
|
|
@ -139,6 +165,32 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"enableOtp.failure.guest"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
|
|
@ -846,12 +898,12 @@
|
|||
"payload": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
"secret"
|
||||
],
|
||||
"properties": {
|
||||
"url": {
|
||||
"secret": {
|
||||
"type": "string",
|
||||
"description": "The otp url to feed into a 2fa app"
|
||||
"description": "The otp secret"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { typeResponse, isNullish } from '@shared/utils';
|
|||
export const DisableOtpRes = {
|
||||
'200': typeResponse('success', 'disableOtp.success'),
|
||||
'500': typeResponse('failure', 'disableOtp.failure.generic'),
|
||||
'400': typeResponse('failure', 'disableOtp.failure.guest'),
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -18,6 +19,13 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
|||
async function(req, res) {
|
||||
void res;
|
||||
if (isNullish(req.authUser)) { return res.makeResponse(500, 'failure', 'disableOtp.failure.generic'); }
|
||||
if (req.authUser.guest) {
|
||||
return res.makeResponse(
|
||||
400,
|
||||
'failure',
|
||||
'disableOtp.failure.guest',
|
||||
);
|
||||
}
|
||||
this.db.deleteUserOtpSecret(req.authUser.id);
|
||||
return res.makeResponse(200, 'success', 'disableOtp.success');
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export const EnableOtpRes = {
|
|||
url: Type.String({ description: 'The otp url to feed into a 2fa app' }),
|
||||
}),
|
||||
'401': typeResponse('failure', ['enableOtp.failure.noUser', 'enableOtp.failure.noSecret']),
|
||||
'400': typeResponse('failure', ['enableOtp.failure.guest']),
|
||||
};
|
||||
|
||||
export type EnableOtpRes = MakeStaticResponse<typeof EnableOtpRes>;
|
||||
|
|
@ -21,6 +22,13 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
|||
{ schema: { response: EnableOtpRes, operationId: 'enableOtp' }, config: { requireAuth: true } },
|
||||
async function(req, res) {
|
||||
if (isNullish(req.authUser)) { return res.makeResponse(403, 'failure', 'enableOtp.failure.noUser'); }
|
||||
if (req.authUser.guest) {
|
||||
return res.makeResponse(
|
||||
400,
|
||||
'failure',
|
||||
'enableOtp.failure.guest',
|
||||
);
|
||||
}
|
||||
|
||||
const otpSecret = this.db.ensureUserOtpSecret(req.authUser!.id);
|
||||
if (isNullish(otpSecret)) { return res.makeResponse(403, 'failure', 'enableOtp.failure.noSecret'); }
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ import { FastifyPluginAsync } from 'fastify';
|
|||
|
||||
import { Type } from 'typebox';
|
||||
import { isNullish, MakeStaticResponse, typeResponse } from '@shared/utils';
|
||||
import { Otp } from '@shared/auth';
|
||||
|
||||
|
||||
export const StatusOtpRes = {
|
||||
200: Type.Union([
|
||||
typeResponse('success', 'statusOtp.success.enabled', { url: Type.String({ description: 'The otp url to feed into a 2fa app' }) }),
|
||||
typeResponse('success', 'statusOtp.success.enabled', {
|
||||
secret: Type.String({ description: 'The otp secret' }),
|
||||
}),
|
||||
typeResponse('success', 'statusOtp.success.disabled'),
|
||||
]),
|
||||
500: typeResponse('failure', 'statusOtp.failure.generic'),
|
||||
|
|
@ -19,13 +19,32 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
|||
void _opts;
|
||||
fastify.get(
|
||||
'/api/auth/statusOtp',
|
||||
{ schema: { response: StatusOtpRes, operationId: 'statusOtp' }, config: { requireAuth: true } },
|
||||
{
|
||||
schema: { response: StatusOtpRes, operationId: 'statusOtp' },
|
||||
config: { requireAuth: true },
|
||||
},
|
||||
async function(req, res) {
|
||||
if (isNullish(req.authUser)) { return res.makeResponse(500, 'failure', 'statusOtp.failure.generic'); }
|
||||
if (isNullish(req.authUser)) {
|
||||
return res.makeResponse(
|
||||
500,
|
||||
'failure',
|
||||
'statusOtp.failure.generic',
|
||||
);
|
||||
}
|
||||
const otpSecret = this.db.getUserOtpSecret(req.authUser.id);
|
||||
if (isNullish(otpSecret)) { return res.makeResponse(200, 'success', 'statusOtp.success.disabled'); }
|
||||
const otp = new Otp({ secret: otpSecret });
|
||||
return res.makeResponse(200, 'success', 'statusOtp.success.enabled', { url: otp.totpURL });
|
||||
if (isNullish(otpSecret)) {
|
||||
return res.makeResponse(
|
||||
200,
|
||||
'success',
|
||||
'statusOtp.success.disabled',
|
||||
);
|
||||
}
|
||||
return res.makeResponse(
|
||||
200,
|
||||
'success',
|
||||
'statusOtp.success.enabled',
|
||||
{ secret: otpSecret },
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -51,6 +51,32 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"disableOtp.failure.guest"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
|
|
@ -155,6 +181,32 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"msg"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"msg": {
|
||||
"enum": [
|
||||
"enableOtp.failure.guest"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Default Response",
|
||||
"content": {
|
||||
|
|
@ -883,12 +935,12 @@
|
|||
"payload": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
"secret"
|
||||
],
|
||||
"properties": {
|
||||
"url": {
|
||||
"secret": {
|
||||
"type": "string",
|
||||
"description": "The otp url to feed into a 2fa app"
|
||||
"description": "The otp secret"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1069,6 +1121,20 @@
|
|||
},
|
||||
"guest": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"selfInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"login_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"provider_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"provider_user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,20 @@
|
|||
},
|
||||
"guest": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"selfInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"login_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"provider_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"provider_user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@ import { isNullish, MakeStaticResponse, typeResponse } from '@shared/utils';
|
|||
export const UserInfoRes = {
|
||||
'200': typeResponse('success', 'userinfo.success', {
|
||||
name: Type.String(), id: Type.String(), guest: Type.Boolean(),
|
||||
selfInfo: Type.Optional(Type.Object({
|
||||
login_name: Type.Optional(Type.String()),
|
||||
provider_id: Type.Optional(Type.String()),
|
||||
provider_user: Type.Optional(Type.String()),
|
||||
})),
|
||||
}),
|
||||
'403': typeResponse('failure', 'userinfo.failure.notLoggedIn'),
|
||||
'404': typeResponse('failure', 'userinfo.failure.unknownUser'),
|
||||
|
|
@ -38,6 +43,7 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
|||
if (req.params.user === 'me') {
|
||||
req.params.user = req.authUser.id;
|
||||
}
|
||||
const askSelf = req.params.user === req.authUser.id;
|
||||
|
||||
const user = this.db.getUser(req.params.user);
|
||||
if (isNullish(user)) {
|
||||
|
|
@ -57,6 +63,11 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
|||
// ```
|
||||
// is the same as `val = !!something`
|
||||
guest: !!user.guest,
|
||||
selfInfo: askSelf ? {
|
||||
login_name: user.login,
|
||||
provider_id: user.provider_name,
|
||||
provider_user: user.provider_unique,
|
||||
} : null,
|
||||
};
|
||||
|
||||
return res.makeResponse(200, 'success', 'userinfo.success', payload);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue