diff --git a/pages/profile/[username].vue b/pages/profile/[username].vue index 3f432ac2c..f64471d4c 100644 --- a/pages/profile/[username].vue +++ b/pages/profile/[username].vue @@ -14,6 +14,7 @@ import { sleep } from '~/src/helpers.ts'; import opinions from '~/src/opinions.ts'; import { applyProfileVisibilityRules } from '~/src/profile.ts'; import type { UserWithProfiles, Profile } from '~/src/profile.ts'; +import type { Authenticator } from '~/src/user.ts'; definePageMeta({ translatedPaths: (config) => { @@ -96,7 +97,7 @@ const cardsEnabled = ref(true); const contentWarningDismissed = ref(false); -const authenticators = ref(); +const authenticators = ref[] | undefined>(); const showExpiredAuthenticators = ref(false); const allProfiles = computed((): Record => { diff --git a/server/api/admin/authenticators/[id].get.ts b/server/api/admin/authenticators/[id].get.ts new file mode 100644 index 000000000..dcc75a886 --- /dev/null +++ b/server/api/admin/authenticators/[id].get.ts @@ -0,0 +1,33 @@ +import SQL from 'sql-template-strings'; + +import type { AuthenticatorRow } from '~/server/express/user.ts'; +import { filterObjectKeys } from '~/src/helpers.ts'; +import type { Authenticator } from '~/src/user.ts'; + +export default defineEventHandler(async (event) => { + const { isGranted } = await useAuthentication(event); + if (!isGranted('community') && !isGranted('*')) { + throw createError({ + status: 401, + statusMessage: 'Unauthorised', + }); + } + + const db = useDatabase(); + const id = getRouterParam(event, 'id'); + return (await db.all(SQL` + SELECT * FROM authenticators + WHERE userId = ${id} + ORDER BY id DESC + `)).map((authenticatorRow): Omit => { + const payload = JSON.parse(authenticatorRow.payload); + return { + id: authenticatorRow.id, + type: authenticatorRow.type, + payload: typeof payload === 'string' + ? '' + : filterObjectKeys(payload, ['id', 'email', 'name', 'instance', 'username']), + validUntil: authenticatorRow.validUntil, + }; + }); +}); diff --git a/server/express/admin.ts b/server/express/admin.ts index 2f05cf63b..bfbad1462 100644 --- a/server/express/admin.ts +++ b/server/express/admin.ts @@ -498,28 +498,4 @@ router.get('/admin/audit-log/:username/:id', handleErrorAsync(async (req, res) = return res.json(await fetchAuditLog(req.params.username, req.params.id, req.params.id)); })); -router.get('/admin/authenticators/:id', handleErrorAsync(async (req, res) => { - if (!req.isGranted('community') && !req.isGranted('*')) { - return res.status(401).json({ error: 'Unauthorised' }); - } - - const authenticators = (await req.db.all>(SQL` - SELECT * FROM authenticators - WHERE userId = ${req.params.id} - ORDER BY id DESC - `)).map((auth) => { - delete auth.userId; - - const payload = JSON.parse(auth.payload!); - // @ts-expect-error This error really doesn't need to exist as the code handles this correctly - auth.payload = typeof payload === 'string' - ? undefined - : filterObjectKeys(payload, ['id', 'email', 'name', 'instance', 'username']); - - return auth; - }); - - return res.json(authenticators); -})); - export default router; diff --git a/server/express/user.ts b/server/express/user.ts index f3ad9c5e5..5396f4992 100644 --- a/server/express/user.ts +++ b/server/express/user.ts @@ -17,7 +17,7 @@ import { obfuscateEmail, newDate, } from '../../src/helpers.ts'; -import type { User } from '../../src/user.ts'; +import type { Authenticator, User } from '../../src/user.ts'; import { usernameRegex, usernameUnsafeRegex } from '../../src/username.ts'; import { auditLog } from '../audit.ts'; import avatar from '../avatar.ts'; @@ -69,10 +69,6 @@ export interface AuthenticatorRow { validUntil: number | null; } -interface Authenticator extends Omit { - payload: string | Record; -} - export const normalise = (s: string): string => s.trim().toLowerCase(); const isSpam = (email: string): boolean => { diff --git a/src/user.ts b/src/user.ts index 52348d26f..f8f2c024b 100644 --- a/src/user.ts +++ b/src/user.ts @@ -39,3 +39,11 @@ export interface Admin { credentialsLevel: number | null; credentialsName: string | null; } + +export interface Authenticator { + id: string; + userId: string | null; + type: string; + payload: string | Record; + validUntil: number | null; +}