From db375103707c22d74b131ed6bc3a4905644006dd Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Mon, 8 Apr 2024 18:33:59 -1000 Subject: [PATCH] Add interface to view post and user JSON data --- bun.lockb | Bin 296860 -> 297588 bytes database/entities/Status.ts | 43 +++---- database/entities/User.ts | 18 +-- package.json | 2 + pages/pages/[username]/[uuid].vue | 65 +++++++++++ pages/pages/[username]/index.vue | 82 +++++++++++++ pages/pages/oauth/authorize.vue | 2 +- pages/pages/oauth/redirect.vue | 2 +- pages/routes.ts | 4 + .../migration.sql | 5 + prisma/schema.prisma | 4 +- routes.ts | 4 +- server.ts | 109 ++++++++---------- server/api/[...404].ts | 2 +- server/api/{ => api}/auth/login/index.ts | 2 +- server/api/{ => api}/auth/redirect/index.ts | 2 +- server/api/api/v1/accounts/[id]/index.ts | 2 +- server/api/api/v1/accounts/search/index.ts | 13 +-- tests/api/accounts.test.ts | 2 +- tests/oauth.test.ts | 4 +- uno.config.ts | 3 + 21 files changed, 248 insertions(+), 122 deletions(-) create mode 100644 pages/pages/[username]/[uuid].vue create mode 100644 pages/pages/[username]/index.vue create mode 100644 prisma/migrations/20240409042719_make_uri_nullable/migration.sql rename server/api/{ => api}/auth/login/index.ts (98%) rename server/api/{ => api}/auth/redirect/index.ts (97%) diff --git a/bun.lockb b/bun.lockb index 2ac103e0e2632d1a2cc19d3b1e8335833d0ae951..2fa0247f337b80547dfdb33e711e6586bd85072d 100755 GIT binary patch delta 41380 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 delta 41206 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 MEBLCrwXpyr?!pq8M! z(9Z+i1KkJB2i4C&p$4E2QSlnkI?#I12G9)94iwx8`T!IG;u+ERAb%IM3B>PPZUdb{ zucsn!1;~c_j-&FPpeCRQ&@&+JBbR`@LFGX$pqJ4Dg}E(z3p5)_b3g+?Q6MKM1jMaZ zAL#L07F9v~nn!;GXm1cVpxkn`0o4SpRC?SYWvlYPK*s!?z*V5tph&d$z|GRp-1($H zk-MGS$oLI(2gIEYcQ$#Td!TEe%OLJ-(m;PAeIGOu>9F�-s5F+}zX-;Nn{eJQrQ= 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 OIKS0vi36{?t^Z%^=4Z$N diff --git a/database/entities/Status.ts b/database/entities/Status.ts index c82dad63..c41451f4 100644 --- a/database/entities/Status.ts +++ b/database/entities/Status.ts @@ -260,7 +260,7 @@ export const createNewStatus = async (data: { .join("\n"); } - let status = await client.status.create({ + const status = await client.status.create({ data: { authorId: data.account.id, applicationId: data.application?.id, @@ -290,12 +290,7 @@ export const createNewStatus = async (data: { quotingPostId: data.quote?.id, instanceId: data.account.instanceId || undefined, isReblog: false, - uri: - data.uri || - new URL( - `/statuses/FAKE-${crypto.randomUUID()}`, - config.http.base_url, - ).toString(), + uri: data.uri || null, mentions: { connect: mentions.map((mention) => { return { @@ -307,22 +302,6 @@ export const createNewStatus = async (data: { include: statusAndUserRelations, }); - // Update URI - status = await client.status.update({ - where: { - id: status.id, - }, - data: { - uri: - data.uri || - new URL( - `/statuses/${status.id}`, - config.http.base_url, - ).toString(), - }, - include: statusAndUserRelations, - }); - // Create notification if (status.inReplyToPost) { await client.notification.create({ @@ -503,9 +482,19 @@ export const statusToAPI = async ( sensitive: status.sensitive, spoiler_text: status.spoilerText, tags: [], - uri: new URL(`/statuses/${status.id}`, config.http.base_url).toString(), + uri: + status.uri || + new URL( + `/@${status.author.username}/${status.id}`, + config.http.base_url, + ).toString(), visibility: "public", - url: new URL(`/statuses/${status.id}`, config.http.base_url).toString(), + url: + status.uri || + new URL( + `/@${status.author.username}/${status.id}`, + config.http.base_url, + ).toString(), bookmarked: false, quote: status.quotingPost ? await statusToAPI( @@ -584,8 +573,8 @@ export const statusToLysand = (status: StatusWithRelations): Note => { // TODO: Add attachments attachments: [], is_sensitive: status.sensitive, - mentions: status.mentions.map((mention) => mention.uri), - quotes: status.quotingPost ? [status.quotingPost.uri] : [], + mentions: status.mentions.map((mention) => mention.uri || ""), + quotes: status.quotingPost ? [status.quotingPost.uri || ""] : [], replies_to: status.inReplyToPostId ? [status.inReplyToPostId] : [], subject: status.spoilerText, extensions: { diff --git a/database/entities/User.ts b/database/entities/User.ts index 69d438d6..a70155f7 100644 --- a/database/entities/User.ts +++ b/database/entities/User.ts @@ -262,7 +262,6 @@ export const createNewLocalUser = async (data: { avatar: data.avatar ?? config.defaults.avatar, header: data.header ?? config.defaults.avatar, isAdmin: data.admin ?? false, - uri: "", publicKey: keys.public_key, privateKey: keys.private_key, source: { @@ -273,20 +272,13 @@ export const createNewLocalUser = async (data: { fields: [], }, }, + include: userRelations, }); // Add to Meilisearch await addUserToMeilisearch(user); - return await client.user.update({ - where: { - id: user.id, - }, - data: { - uri: new URL(`/users/${user.id}`, config.http.base_url).toString(), - }, - include: userRelations, - }); + return user; }; /** @@ -408,7 +400,9 @@ export const userToAPI = ( username: user.username, display_name: user.displayName, note: user.note, - url: user.uri, + url: + user.uri || + new URL(`/@${user.username}`, config.http.base_url).toString(), avatar: getAvatarUrl(user, config), header: getHeaderUrl(user, config), locked: user.isLocked, @@ -458,7 +452,7 @@ export const userToLysand = (user: UserWithRelations): LysandUser => { return { id: user.id, type: "User", - uri: user.uri, + uri: user.uri || "", bio: [ { content: user.note, diff --git a/package.json b/package.json index 9377f7c4..d4df4e96 100644 --- a/package.json +++ b/package.json @@ -61,10 +61,12 @@ "@types/jsonld": "^1.5.13", "@typescript-eslint/eslint-plugin": "latest", "@unocss/cli": "latest", + "@unocss/transformer-directives": "^0.59.0", "@vitejs/plugin-vue": "latest", "@vueuse/head": "^2.0.0", "activitypub-types": "^1.0.3", "bun-types": "latest", + "shiki": "^1.2.4", "typescript": "latest", "unocss": "latest", "untyped": "^1.4.2", diff --git a/pages/pages/[username]/[uuid].vue b/pages/pages/[username]/[uuid].vue new file mode 100644 index 00000000..40b5e265 --- /dev/null +++ b/pages/pages/[username]/[uuid].vue @@ -0,0 +1,65 @@ + + + + + \ No newline at end of file diff --git a/pages/pages/[username]/index.vue b/pages/pages/[username]/index.vue new file mode 100644 index 00000000..78c07638 --- /dev/null +++ b/pages/pages/[username]/index.vue @@ -0,0 +1,82 @@ + + + + + \ No newline at end of file diff --git a/pages/pages/oauth/authorize.vue b/pages/pages/oauth/authorize.vue index 7c407f11..6a52823a 100644 --- a/pages/pages/oauth/authorize.vue +++ b/pages/pages/oauth/authorize.vue @@ -7,7 +7,7 @@
+ :action="`/api/auth/login?redirect_uri=${redirect_uri}&response_type=${response_type}&client_id=${client_id}&scope=${scope}`">

Login to your account

diff --git a/pages/pages/oauth/redirect.vue b/pages/pages/oauth/redirect.vue index 6543636f..99644a2d 100644 --- a/pages/pages/oauth/redirect.vue +++ b/pages/pages/oauth/redirect.vue @@ -7,7 +7,7 @@
+ :action="`/api/auth/redirect?redirect_uri=${encodeURIComponent(redirect_uri)}&client_id=${client_id}&code=${code}`">

Allow this application to access your account?

diff --git a/pages/routes.ts b/pages/routes.ts index 355b9236..c9278851 100644 --- a/pages/routes.ts +++ b/pages/routes.ts @@ -4,6 +4,8 @@ import authorizeVue from "./pages/oauth/authorize.vue"; import redirectVue from "./pages/oauth/redirect.vue"; import registerIndexVue from "./pages/register/index.vue"; import successVue from "./pages/register/success.vue"; +import statusVue from "./pages/[username]/[uuid].vue"; +import userVue from "./pages/[username]/index.vue"; export default [ { path: "/", component: indexVue }, @@ -11,4 +13,6 @@ export default [ { path: "/oauth/redirect", component: redirectVue }, { path: "/register", component: registerIndexVue }, { path: "/register/success", component: successVue }, + { path: "/:username/:uuid", component: statusVue }, + { path: "/:username", component: userVue }, ] as RouteRecordRaw[]; diff --git a/prisma/migrations/20240409042719_make_uri_nullable/migration.sql b/prisma/migrations/20240409042719_make_uri_nullable/migration.sql new file mode 100644 index 00000000..5b4b1d5e --- /dev/null +++ b/prisma/migrations/20240409042719_make_uri_nullable/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "Status" ALTER COLUMN "uri" DROP NOT NULL; + +-- AlterTable +ALTER TABLE "User" ALTER COLUMN "uri" DROP NOT NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9e227845..4c5098b9 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -104,7 +104,7 @@ model Relationship { model Status { id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid - uri String @unique + uri String? @unique author User @relation("UserStatuses", fields: [authorId], references: [id], onDelete: Cascade) authorId String @db.Uuid createdAt DateTime @default(now()) @@ -228,7 +228,7 @@ model Notification { model User { id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid - uri String @unique + uri String? @unique username String @unique displayName String password String? // Nullable diff --git a/routes.ts b/routes.ts index f2837784..e2b1fece 100644 --- a/routes.ts +++ b/routes.ts @@ -33,8 +33,8 @@ export const rawRoutes = { "/api/v1/timelines/public": "./server/api/api/v1/timelines/public", "/api/v2/media": "./server/api/api/v2/media/index", "/api/v2/search": "./server/api/api/v2/search/index", - "/auth/login": "./server/api/auth/login/index", - "/auth/redirect": "./server/api/auth/redirect/index", + "/api/auth/login": "./server/api/api/auth/login/index", + "/api/auth/redirect": "./server/api/api/auth/redirect/index", "/nodeinfo/2.0": "./server/api/nodeinfo/2.0/index", "/oauth/authorize-external": "./server/api/oauth/authorize-external/index", "/oauth/providers": "./server/api/oauth/providers/index", diff --git a/server.ts b/server.ts index 5629fb10..556c6ef2 100644 --- a/server.ts +++ b/server.ts @@ -124,7 +124,7 @@ export const createServer = ( // Check for allowed requests // @ts-expect-error Stupid error - if (!meta.allowedMethods.includes(req.method as string)) { + if (!meta.allowedMethods.includes(req.method)) { return errorResponse( `Method not allowed: allowed methods are: ${meta.allowedMethods.join( ", ", @@ -137,17 +137,15 @@ export const createServer = ( const auth = await getFromRequest(req); // Check for authentication if required - if (meta.auth.required) { - if (!auth.user) { - return errorResponse("Unauthorized", 401); - } - } else if ( - // @ts-expect-error Stupid error - (meta.auth.requiredOnMethods ?? []).includes(req.method) + if ( + (meta.auth.required || + (meta.auth.requiredOnMethods ?? []).includes( + // @ts-expect-error Stupid error + req.method, + )) && + !auth.user ) { - if (!auth.user) { - return errorResponse("Unauthorized", 401); - } + return errorResponse("Unauthorized", 401); } let parsedRequest = {}; @@ -172,68 +170,53 @@ export const createServer = ( }, }); } - if (matchedRoute?.name === "/[...404]" || !matchedRoute) { - if (new URL(req.url).pathname.startsWith("/api")) { - return errorResponse("Route not found", 404); + + if (new URL(req.url).pathname.startsWith("/api")) { + return errorResponse("Route not found", 404); + } + + // Proxy response from Vite at localhost:5173 if in development mode + if (isProd) { + let file = Bun.file("./pages/dist/index.html"); + if (new URL(req.url).pathname.startsWith("/assets")) { + file = Bun.file(`./pages/dist${new URL(req.url).pathname}`); } - // Proxy response from Vite at localhost:5173 if in development mode - if (isProd) { - if (new URL(req.url).pathname.startsWith("/assets")) { - const file = Bun.file( - `./pages/dist${new URL(req.url).pathname}`, - ); - - // Serve from pages/dist/assets - if (await file.exists()) { - return clientResponse(file, 200, { - "Content-Type": file.type, - }); - } - return errorResponse("Asset not found", 404); - } - if (new URL(req.url).pathname.startsWith("/api")) { - return errorResponse("Route not found", 404); - } - - const file = Bun.file("./pages/dist/index.html"); - - // Serve from pages/dist + // Serve from pages/dist/assets + if (await file.exists()) { return clientResponse(file, 200, { "Content-Type": file.type, }); } - const proxy = await fetch( - req.url.replace( + return errorResponse("Asset not found", 404); + } + + const proxy = await fetch( + req.url.replace(config.http.base_url, "http://localhost:5173"), + ).catch(async (e) => { + await logger.logError( + LogLevel.ERROR, + "Server.Proxy", + e as Error, + ); + await logger.log( + LogLevel.ERROR, + "Server.Proxy", + `The development Vite server is not running or the route is not found: ${req.url.replace( config.http.base_url, "http://localhost:5173", - ), - ).catch(async (e) => { - await logger.logError( - LogLevel.ERROR, - "Server.Proxy", - e as Error, - ); - await logger.log( - LogLevel.ERROR, - "Server.Proxy", - `The development Vite server is not running or the route is not found: ${req.url.replace( - config.http.base_url, - "http://localhost:5173", - )}`, - ); - return errorResponse("Route not found", 404); - }); - - if ( - proxy.status !== 404 && - !(await proxy.clone().text()).includes("404 Not Found") - ) { - return proxy; - } - + )}`, + ); return errorResponse("Route not found", 404); + }); + + if ( + proxy.status !== 404 && + !(await proxy.clone().text()).includes("404 Not Found") + ) { + return proxy; } + return errorResponse("Route not found", 404); }, }); diff --git a/server/api/[...404].ts b/server/api/[...404].ts index 6036c6b9..7b9dbd4c 100644 --- a/server/api/[...404].ts +++ b/server/api/[...404].ts @@ -17,5 +17,5 @@ export const meta = applyConfig({ * Default catch-all route, returns a 404 error. */ export default apiRoute(() => { - return errorResponse("This API route does not exist", 404); + return errorResponse("Route not found", 404); }); diff --git a/server/api/auth/login/index.ts b/server/api/api/auth/login/index.ts similarity index 98% rename from server/api/auth/login/index.ts rename to server/api/api/auth/login/index.ts index d2059066..8e8f78b2 100644 --- a/server/api/auth/login/index.ts +++ b/server/api/api/auth/login/index.ts @@ -10,7 +10,7 @@ export const meta = applyConfig({ max: 4, duration: 60, }, - route: "/auth/login", + route: "/api/auth/login", auth: { required: false, }, diff --git a/server/api/auth/redirect/index.ts b/server/api/api/auth/redirect/index.ts similarity index 97% rename from server/api/auth/redirect/index.ts rename to server/api/api/auth/redirect/index.ts index 90e04a49..bfe7e912 100644 --- a/server/api/auth/redirect/index.ts +++ b/server/api/api/auth/redirect/index.ts @@ -8,7 +8,7 @@ export const meta = applyConfig({ max: 4, duration: 60, }, - route: "/auth/redirect", + route: "/api/auth/redirect", auth: { required: false, }, diff --git a/server/api/api/v1/accounts/[id]/index.ts b/server/api/api/v1/accounts/[id]/index.ts index 7d09ba25..7bc86b2b 100644 --- a/server/api/api/v1/accounts/[id]/index.ts +++ b/server/api/api/v1/accounts/[id]/index.ts @@ -13,7 +13,7 @@ export const meta = applyConfig({ }, route: "/api/v1/accounts/:id", auth: { - required: true, + required: false, oauthPermissions: [], }, }); diff --git a/server/api/api/v1/accounts/search/index.ts b/server/api/api/v1/accounts/search/index.ts index 1e3e810f..0f22a66d 100644 --- a/server/api/api/v1/accounts/search/index.ts +++ b/server/api/api/v1/accounts/search/index.ts @@ -12,7 +12,7 @@ export const meta = applyConfig({ duration: 60, }, auth: { - required: true, + required: false, oauthPermissions: ["read:accounts"], }, }); @@ -25,11 +25,6 @@ export default apiRoute<{ following?: boolean; }>(async (req, matchedRoute, extraData) => { // TODO: Add checks for disabled or not email verified accounts - - const { user } = extraData.auth; - - if (!user) return errorResponse("Unauthorized", 401); - const { following = false, limit = 40, @@ -37,6 +32,10 @@ export default apiRoute<{ q, } = extraData.parsedRequest; + const { user } = extraData.auth; + + if (!user && following) return errorResponse("Unauthorized", 401); + if (limit < 1 || limit > 80) { return errorResponse("Limit must be between 1 and 80", 400); } @@ -60,7 +59,7 @@ export default apiRoute<{ relationshipSubjects: following ? { some: { - ownerId: user.id, + ownerId: user?.id, following, }, } diff --git a/tests/api/accounts.test.ts b/tests/api/accounts.test.ts index c0293c25..0b9adb9a 100644 --- a/tests/api/accounts.test.ts +++ b/tests/api/accounts.test.ts @@ -172,7 +172,7 @@ describe("API Tests", () => { expect(account.statuses_count).toBe(0); expect(account.note).toBe(""); expect(account.url).toBe( - new URL(`/users/${user.id}`, config.http.base_url).toString(), + new URL(`/@${user.username}`, config.http.base_url).toString(), ); expect(account.avatar).toBeDefined(); expect(account.avatar_static).toBeDefined(); diff --git a/tests/oauth.test.ts b/tests/oauth.test.ts index 1911d637..aaf1da00 100644 --- a/tests/oauth.test.ts +++ b/tests/oauth.test.ts @@ -57,7 +57,7 @@ describe("POST /api/v1/apps/", () => { }); }); -describe("POST /auth/login/", () => { +describe("POST /api/auth/login/", () => { test("should get a code", async () => { const formData = new FormData(); @@ -67,7 +67,7 @@ describe("POST /auth/login/", () => { const response = await sendTestRequest( new Request( wrapRelativeUrl( - `/auth/login/?client_id=${client_id}&redirect_uri=https://example.com&response_type=code&scope=read+write`, + `/api/auth/login/?client_id=${client_id}&redirect_uri=https://example.com&response_type=code&scope=read+write`, base_url, ), { diff --git a/uno.config.ts b/uno.config.ts index e120f3d3..18f92167 100644 --- a/uno.config.ts +++ b/uno.config.ts @@ -1,4 +1,6 @@ import { presetForms } from "@julr/unocss-preset-forms"; +import transformerDirectives from "@unocss/transformer-directives"; + import { defineConfig, presetTypography, @@ -19,4 +21,5 @@ export default defineConfig({ presetWebFonts(), presetForms(), ], + transformers: [transformerDirectives()], });