From 06bcbbe4519901588a7d879050f776000e64eb7d Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Mon, 15 Apr 2024 16:09:16 -1000 Subject: [PATCH] fix(api): :bug: Fix statuses not saving the user's applicationId --- database/entities/Status.ts | 4 +- database/entities/User.ts | 55 +++++++++++++++++++++-- packages/server-handler/index.ts | 3 ++ server/api/api/v1/statuses/[id]/reblog.ts | 3 +- server/api/api/v1/statuses/index.ts | 3 +- tests/utils.ts | 1 + 6 files changed, 62 insertions(+), 7 deletions(-) diff --git a/database/entities/Status.ts b/database/entities/Status.ts index d203cca4..023e252a 100644 --- a/database/entities/Status.ts +++ b/database/entities/Status.ts @@ -40,7 +40,7 @@ import { LogLevel } from "~packages/log-manager"; import type { Note } from "~types/lysand/Object"; import type { Attachment as APIAttachment } from "~types/mastodon/attachment"; import type { Status as APIStatus } from "~types/mastodon/status"; -import { applicationToAPI } from "./Application"; +import { applicationToAPI, type Application } from "./Application"; import { attachmentFromLysand, attachmentToAPI, @@ -923,6 +923,7 @@ export const createNewStatus = async ( media_attachments?: string[], inReplyTo?: StatusWithRelations, quoting?: StatusWithRelations, + application?: Application, ): Promise => { const htmlContent = await contentToHtml(content, mentions); @@ -956,6 +957,7 @@ export const createNewStatus = async ( uri: uri || null, inReplyToPostId: inReplyTo?.id, quotingPostId: quoting?.id, + applicationId: application?.id ?? null, updatedAt: new Date().toISOString(), }) .returning() diff --git a/database/entities/User.ts b/database/entities/User.ts index df7aff85..63a7820f 100644 --- a/database/entities/User.ts +++ b/database/entities/User.ts @@ -7,10 +7,12 @@ import { htmlToText } from "html-to-text"; import type * as Lysand from "lysand-types"; import { db } from "~drizzle/db"; import { + application, emojiToUser, instance, notification, relationship, + token, user, } from "~drizzle/schema"; import { LogLevel } from "~packages/log-manager"; @@ -25,6 +27,8 @@ import { import { objectToInboxRequest } from "./Federation"; import { addInstanceIfNotExists } from "./Instance"; import { createNewRelationship } from "./Relationship"; +import type { Token } from "./Token"; +import type { Application } from "./Application"; export type User = InferSelectModel & { endpoints?: Partial<{ @@ -123,6 +127,7 @@ export const userExtrasTemplate = (name: string) => ({ export interface AuthData { user: UserWithRelations | null; token: string; + application: Application | null; } /** @@ -153,7 +158,10 @@ export const getFromRequest = async (req: Request): Promise => { // Check auth token const token = req.headers.get("Authorization")?.split(" ")[1] || ""; - return { user: await retrieveUserFromToken(token), token }; + const { user, application } = + await retrieveUserAndApplicationFromToken(token); + + return { user, token, application }; }; export const followRequestUser = async ( @@ -652,9 +660,7 @@ export const retrieveUserFromToken = async ( ): Promise => { if (!access_token) return null; - const token = await db.query.token.findFirst({ - where: (tokens, { eq }) => eq(tokens.accessToken, access_token), - }); + const token = await retrieveToken(access_token); if (!token || !token.userId) return null; @@ -665,6 +671,47 @@ export const retrieveUserFromToken = async ( return user; }; +export const retrieveUserAndApplicationFromToken = async ( + access_token: string, +): Promise<{ + user: UserWithRelations | null; + application: Application | null; +}> => { + if (!access_token) return { user: null, application: null }; + + const output = ( + await db + .select({ + token: token, + application: application, + }) + .from(token) + .leftJoin(application, eq(token.applicationId, application.id)) + .where(eq(token.accessToken, access_token)) + .limit(1) + )[0]; + + if (!output?.token.userId) return { user: null, application: null }; + + const user = await findFirstUser({ + where: (user, { eq }) => eq(user.id, output.token.userId ?? ""), + }); + + return { user, application: output.application ?? null }; +}; + +export const retrieveToken = async ( + access_token: string, +): Promise => { + if (!access_token) return null; + + return ( + (await db.query.token.findFirst({ + where: (tokens, { eq }) => eq(tokens.accessToken, access_token), + })) ?? null + ); +}; + /** * Gets the relationship to another user. * @param other The other user to get the relationship to. diff --git a/packages/server-handler/index.ts b/packages/server-handler/index.ts index 92ef062e..36569df0 100644 --- a/packages/server-handler/index.ts +++ b/packages/server-handler/index.ts @@ -6,6 +6,7 @@ import { LogLevel, type LogManager, type MultiLogManager } from "log-manager"; import { RequestParser } from "request-parser"; import type { ZodType, z } from "zod"; import { fromZodError } from "zod-validation-error"; +import type { Application } from "~database/entities/Application"; import { type AuthData, type UserWithRelations, @@ -31,6 +32,7 @@ export type RouteHandler< token: RouteMeta["auth"]["required"] extends true ? string : string | null; + application: Application | null; }; parsedRequest: z.infer; configManager: { @@ -140,6 +142,7 @@ export const processRoute = async ( auth: { token: auth?.token ?? null, user: auth?.user ?? null, + application: auth?.application ?? null, }, parsedRequest: parsingResult ? (parsingResult.data as z.infer) diff --git a/server/api/api/v1/statuses/[id]/reblog.ts b/server/api/api/v1/statuses/[id]/reblog.ts index f4b3eb09..079f99f9 100644 --- a/server/api/api/v1/statuses/[id]/reblog.ts +++ b/server/api/api/v1/statuses/[id]/reblog.ts @@ -35,7 +35,7 @@ export default apiRoute( return errorResponse("Invalid ID, must be of type UUIDv7", 404); } - const { user } = extraData.auth; + const { user, application } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -70,6 +70,7 @@ export default apiRoute( visibility, sensitive: false, updatedAt: new Date().toISOString(), + applicationId: application?.id ?? null, }) .returning() )[0]; diff --git a/server/api/api/v1/statuses/index.ts b/server/api/api/v1/statuses/index.ts index 2d6af4a3..e2d7da29 100644 --- a/server/api/api/v1/statuses/index.ts +++ b/server/api/api/v1/statuses/index.ts @@ -66,7 +66,7 @@ export const schema = z.object({ */ export default apiRoute( async (req, matchedRoute, extraData) => { - const { user } = extraData.auth; + const { user, application } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -187,6 +187,7 @@ export default apiRoute( media_ids, replyStatus ?? undefined, quote ?? undefined, + application ?? undefined, ); if (!newStatus) { diff --git a/tests/utils.ts b/tests/utils.ts index 68ab26b8..d46b3612 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -95,6 +95,7 @@ export const getTestStatuses = async ( sensitive: false, updatedAt: new Date().toISOString(), visibility: "public", + applicationId: null, ...partial, }) .returning()