mirror of
https://github.com/versia-pub/server.git
synced 2026-01-26 04:06:01 +01:00
Modify WebFinger behaviour, add user searching
This commit is contained in:
parent
ae9698c647
commit
d5817e985d
|
|
@ -23,7 +23,7 @@ import { applicationToAPI } from "./Application";
|
||||||
import { attachmentToAPI, attachmentToLysand } from "./Attachment";
|
import { attachmentToAPI, attachmentToLysand } from "./Attachment";
|
||||||
import { emojiToAPI, emojiToLysand, parseEmojis } from "./Emoji";
|
import { emojiToAPI, emojiToLysand, parseEmojis } from "./Emoji";
|
||||||
import type { UserWithRelations } from "./User";
|
import type { UserWithRelations } from "./User";
|
||||||
import { fetchRemoteUser, parseMentionsUris, userToAPI } from "./User";
|
import { resolveUser, parseMentionsUris, userToAPI } from "./User";
|
||||||
import { statusAndUserRelations, userRelations } from "./relations";
|
import { statusAndUserRelations, userRelations } from "./relations";
|
||||||
|
|
||||||
const statusRelations = Prisma.validator<Prisma.StatusDefaultArgs>()({
|
const statusRelations = Prisma.validator<Prisma.StatusDefaultArgs>()({
|
||||||
|
|
@ -57,62 +57,9 @@ export const isViewableByUser = (status: Status, user: User | null) => {
|
||||||
return user && (status.mentions as User[]).includes(user);
|
return user && (status.mentions as User[]).includes(user);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchFromRemote = async (uri: string): Promise<Status | null> => {
|
export const fetchFromRemote = async (
|
||||||
// Check if already in database
|
uri: string,
|
||||||
/* const existingStatus: StatusWithRelations | null =
|
): Promise<StatusWithRelations | null> => {};
|
||||||
await client.status.findFirst({
|
|
||||||
where: {
|
|
||||||
uri: uri,
|
|
||||||
},
|
|
||||||
include: statusAndUserRelations,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (existingStatus) return existingStatus;
|
|
||||||
|
|
||||||
const status = await fetch(uri);
|
|
||||||
|
|
||||||
if (status.status === 404) return null;
|
|
||||||
|
|
||||||
const body = (await status.json()) as LysandPublication;
|
|
||||||
|
|
||||||
const content = getBestContentType(body.contents);
|
|
||||||
|
|
||||||
const emojis = await parseEmojis(content?.content || "");
|
|
||||||
|
|
||||||
const author = await fetchRemoteUser(body.author);
|
|
||||||
|
|
||||||
let replyStatus: Status | null = null;
|
|
||||||
let quotingStatus: Status | null = null;
|
|
||||||
|
|
||||||
if (body.replies_to.length > 0) {
|
|
||||||
replyStatus = await fetchFromRemote(body.replies_to[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (body.quotes.length > 0) {
|
|
||||||
quotingStatus = await fetchFromRemote(body.quotes[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await createNewStatus({
|
|
||||||
account: author,
|
|
||||||
content: content?.content || "",
|
|
||||||
content_type: content?.content_type,
|
|
||||||
application: null,
|
|
||||||
// TODO: Add visibility
|
|
||||||
visibility: "public",
|
|
||||||
spoiler_text: body.subject || "",
|
|
||||||
uri: body.uri,
|
|
||||||
sensitive: body.is_sensitive,
|
|
||||||
emojis: emojis,
|
|
||||||
mentions: await parseMentionsUris(body.mentions),
|
|
||||||
reply: replyStatus
|
|
||||||
? {
|
|
||||||
status: replyStatus,
|
|
||||||
user: (replyStatus as StatusWithRelations).author,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
quote: quotingStatus || undefined,
|
|
||||||
}); */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all the ancestors of this post,
|
* Return all the ancestors of this post,
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ export const followRequestUser = async (
|
||||||
return relationship;
|
return relationship;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchRemoteUser = async (uri: string) => {
|
export const resolveUser = async (uri: string) => {
|
||||||
// Check if user not already in database
|
// Check if user not already in database
|
||||||
const foundUser = await client.user.findUnique({
|
const foundUser = await client.user.findUnique({
|
||||||
where: {
|
where: {
|
||||||
|
|
@ -228,6 +228,68 @@ export const fetchRemoteUser = async (uri: string) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a WebFinger identifier to a user.
|
||||||
|
* @param identifier Either a UUID or a username
|
||||||
|
*/
|
||||||
|
export const resolveWebFinger = async (identifier: string, host: string) => {
|
||||||
|
// Check if user not already in database
|
||||||
|
const foundUser = await client.user.findUnique({
|
||||||
|
where: {
|
||||||
|
username: identifier,
|
||||||
|
instance: {
|
||||||
|
base_url: host,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
include: userRelations,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (foundUser) return foundUser;
|
||||||
|
|
||||||
|
const hostWithProtocol = host.startsWith("http") ? host : `https://${host}`;
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
new URL(
|
||||||
|
`/.well-known/webfinger?${new URLSearchParams({
|
||||||
|
resource: `acct:${identifier}@${host}`,
|
||||||
|
})}`,
|
||||||
|
hostWithProtocol,
|
||||||
|
),
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const data = (await response.json()) as {
|
||||||
|
subject: string;
|
||||||
|
links: {
|
||||||
|
rel: string;
|
||||||
|
type: string;
|
||||||
|
href: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!data.subject || !data.links) {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid WebFinger data (missing subject or links from response)",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const relevantLink = data.links.find((link) => link.rel === "self");
|
||||||
|
|
||||||
|
if (!relevantLink) {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid WebFinger data (missing link with rel: 'self')",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolveUser(relevantLink.href);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the list of followers associated with the actor and updates the user's followers
|
* Fetches the list of followers associated with the actor and updates the user's followers
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
262
package.json
262
package.json
|
|
@ -1,134 +1,134 @@
|
||||||
{
|
{
|
||||||
"name": "lysand",
|
"name": "lysand",
|
||||||
"module": "index.ts",
|
"module": "index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.3.1",
|
"version": "0.4.0",
|
||||||
"description": "A project to build a federated social network",
|
"description": "A project to build a federated social network",
|
||||||
"author": {
|
"author": {
|
||||||
"email": "contact@cpluspatch.com",
|
"email": "contact@cpluspatch.com",
|
||||||
"name": "CPlusPatch",
|
"name": "CPlusPatch",
|
||||||
"url": "https://cpluspatch.com"
|
"url": "https://cpluspatch.com"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/lysand-org/lysand/issues"
|
"url": "https://github.com/lysand-org/lysand/issues"
|
||||||
},
|
},
|
||||||
"icon": "https://github.com/lysand-org/lysand",
|
"icon": "https://github.com/lysand-org/lysand",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"keywords": ["federated", "activitypub", "bun"],
|
"keywords": ["federated", "activitypub", "bun"],
|
||||||
"workspaces": ["packages/*"],
|
"workspaces": ["packages/*"],
|
||||||
"maintainers": [
|
"maintainers": [
|
||||||
{
|
{
|
||||||
"email": "contact@cpluspatch.com",
|
"email": "contact@cpluspatch.com",
|
||||||
"name": "CPlusPatch",
|
"name": "CPlusPatch",
|
||||||
"url": "https://cpluspatch.com"
|
"url": "https://cpluspatch.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/lysand-org/lysand.git"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "bun run --watch index.ts",
|
||||||
|
"vite:dev": "bunx --bun vite pages",
|
||||||
|
"vite:build": "bunx --bun vite build pages",
|
||||||
|
"fe:dev": "bun --bun nuxt dev packages/frontend",
|
||||||
|
"fe:build": "bun --bun nuxt build packages/frontend",
|
||||||
|
"fe:analyze": "bun --bun nuxt analyze packages/frontend",
|
||||||
|
"start": "NITRO_PORT=5173 bun run dist/frontend/server/index.mjs & NODE_ENV=production bun run dist/index.js --prod",
|
||||||
|
"migrate-dev": "bun prisma migrate dev",
|
||||||
|
"migrate": "bun prisma migrate deploy",
|
||||||
|
"lint": "bunx --bun eslint --config .eslintrc.cjs --ext .ts .",
|
||||||
|
"prod-build": "bun run build.ts",
|
||||||
|
"prisma": "DATABASE_URL=$(bun run prisma.ts) bunx prisma",
|
||||||
|
"generate": "bun prisma generate",
|
||||||
|
"benchmark:timeline": "bun run benchmarks/timelines.ts",
|
||||||
|
"cloc": "cloc . --exclude-dir node_modules,dist",
|
||||||
|
"cli": "bun run cli.ts"
|
||||||
|
},
|
||||||
|
"trustedDependencies": [
|
||||||
|
"@biomejs/biome",
|
||||||
|
"@fortawesome/fontawesome-common-types",
|
||||||
|
"@fortawesome/free-regular-svg-icons",
|
||||||
|
"@fortawesome/free-solid-svg-icons",
|
||||||
|
"@prisma/client",
|
||||||
|
"@prisma/engines",
|
||||||
|
"esbuild",
|
||||||
|
"json-editor-vue",
|
||||||
|
"msgpackr-extract",
|
||||||
|
"nuxt-app",
|
||||||
|
"prisma",
|
||||||
|
"sharp",
|
||||||
|
"vue-demi"
|
||||||
|
],
|
||||||
|
"devDependencies": {
|
||||||
|
"@biomejs/biome": "1.6.4",
|
||||||
|
"@img/sharp-wasm32": "^0.33.3",
|
||||||
|
"@julr/unocss-preset-forms": "^0.1.0",
|
||||||
|
"@nuxtjs/seo": "^2.0.0-rc.10",
|
||||||
|
"@nuxtjs/tailwindcss": "^6.11.4",
|
||||||
|
"@types/cli-table": "^0.3.4",
|
||||||
|
"@types/html-to-text": "^9.0.4",
|
||||||
|
"@types/ioredis": "^5.0.0",
|
||||||
|
"@types/jsonld": "^1.5.13",
|
||||||
|
"@types/mime-types": "^2.1.4",
|
||||||
|
"@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",
|
||||||
|
"vite": "^5.2.8",
|
||||||
|
"vite-ssr": "^0.17.1",
|
||||||
|
"vue": "^3.3.9",
|
||||||
|
"vue-router": "^4.2.5",
|
||||||
|
"vue-tsc": "latest"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5.3.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@aws-sdk/client-s3": "^3.461.0",
|
||||||
|
"@iarna/toml": "^2.2.5",
|
||||||
|
"@json2csv/plainjs": "^7.0.6",
|
||||||
|
"@prisma/client": "^5.6.0",
|
||||||
|
"blurhash": "^2.0.5",
|
||||||
|
"bullmq": "latest",
|
||||||
|
"chalk": "^5.3.0",
|
||||||
|
"cli-parser": "workspace:*",
|
||||||
|
"cli-table": "^0.3.11",
|
||||||
|
"config-manager": "workspace:*",
|
||||||
|
"eventemitter3": "^5.0.1",
|
||||||
|
"extract-zip": "^2.0.1",
|
||||||
|
"html-to-text": "^9.0.5",
|
||||||
|
"ioredis": "^5.3.2",
|
||||||
|
"ip-matching": "^2.1.2",
|
||||||
|
"iso-639-1": "^3.1.0",
|
||||||
|
"isomorphic-dompurify": "latest",
|
||||||
|
"jsonld": "^8.3.1",
|
||||||
|
"linkify-html": "^4.1.3",
|
||||||
|
"linkify-string": "^4.1.3",
|
||||||
|
"linkifyjs": "^4.1.3",
|
||||||
|
"log-manager": "workspace:*",
|
||||||
|
"marked": "latest",
|
||||||
|
"media-manager": "workspace:*",
|
||||||
|
"megalodon": "^10.0.0",
|
||||||
|
"meilisearch": "latest",
|
||||||
|
"merge-deep-ts": "^1.2.6",
|
||||||
|
"mime-types": "^2.1.35",
|
||||||
|
"next-route-matcher": "^1.0.1",
|
||||||
|
"oauth4webapi": "^2.4.0",
|
||||||
|
"prisma": "^5.6.0",
|
||||||
|
"prisma-json-types-generator": "^3.0.4",
|
||||||
|
"prisma-redis-middleware": "^4.8.0",
|
||||||
|
"request-parser": "workspace:*",
|
||||||
|
"semver": "^7.5.4",
|
||||||
|
"sharp": "^0.33.3",
|
||||||
|
"strip-ansi": "^7.1.0"
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/lysand-org/lysand.git"
|
|
||||||
},
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "bun run --watch index.ts",
|
|
||||||
"vite:dev": "bunx --bun vite pages",
|
|
||||||
"vite:build": "bunx --bun vite build pages",
|
|
||||||
"fe:dev": "bun --bun nuxt dev packages/frontend",
|
|
||||||
"fe:build": "bun --bun nuxt build packages/frontend",
|
|
||||||
"fe:analyze": "bun --bun nuxt analyze packages/frontend",
|
|
||||||
"start": "NITRO_PORT=5173 bun run dist/frontend/server/index.mjs & NODE_ENV=production bun run dist/index.js --prod",
|
|
||||||
"migrate-dev": "bun prisma migrate dev",
|
|
||||||
"migrate": "bun prisma migrate deploy",
|
|
||||||
"lint": "bunx --bun eslint --config .eslintrc.cjs --ext .ts .",
|
|
||||||
"prod-build": "bun run build.ts",
|
|
||||||
"prisma": "DATABASE_URL=$(bun run prisma.ts) bunx prisma",
|
|
||||||
"generate": "bun prisma generate",
|
|
||||||
"benchmark:timeline": "bun run benchmarks/timelines.ts",
|
|
||||||
"cloc": "cloc . --exclude-dir node_modules,dist",
|
|
||||||
"cli": "bun run cli.ts"
|
|
||||||
},
|
|
||||||
"trustedDependencies": [
|
|
||||||
"@biomejs/biome",
|
|
||||||
"@fortawesome/fontawesome-common-types",
|
|
||||||
"@fortawesome/free-regular-svg-icons",
|
|
||||||
"@fortawesome/free-solid-svg-icons",
|
|
||||||
"@prisma/client",
|
|
||||||
"@prisma/engines",
|
|
||||||
"esbuild",
|
|
||||||
"json-editor-vue",
|
|
||||||
"msgpackr-extract",
|
|
||||||
"nuxt-app",
|
|
||||||
"prisma",
|
|
||||||
"sharp",
|
|
||||||
"vue-demi"
|
|
||||||
],
|
|
||||||
"devDependencies": {
|
|
||||||
"@biomejs/biome": "1.6.4",
|
|
||||||
"@img/sharp-wasm32": "^0.33.3",
|
|
||||||
"@julr/unocss-preset-forms": "^0.1.0",
|
|
||||||
"@nuxtjs/seo": "^2.0.0-rc.10",
|
|
||||||
"@nuxtjs/tailwindcss": "^6.11.4",
|
|
||||||
"@types/cli-table": "^0.3.4",
|
|
||||||
"@types/html-to-text": "^9.0.4",
|
|
||||||
"@types/ioredis": "^5.0.0",
|
|
||||||
"@types/jsonld": "^1.5.13",
|
|
||||||
"@types/mime-types": "^2.1.4",
|
|
||||||
"@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",
|
|
||||||
"vite": "^5.2.8",
|
|
||||||
"vite-ssr": "^0.17.1",
|
|
||||||
"vue": "^3.3.9",
|
|
||||||
"vue-router": "^4.2.5",
|
|
||||||
"vue-tsc": "latest"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"typescript": "^5.3.2"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@aws-sdk/client-s3": "^3.461.0",
|
|
||||||
"@iarna/toml": "^2.2.5",
|
|
||||||
"@json2csv/plainjs": "^7.0.6",
|
|
||||||
"@prisma/client": "^5.6.0",
|
|
||||||
"blurhash": "^2.0.5",
|
|
||||||
"bullmq": "latest",
|
|
||||||
"chalk": "^5.3.0",
|
|
||||||
"cli-parser": "workspace:*",
|
|
||||||
"cli-table": "^0.3.11",
|
|
||||||
"config-manager": "workspace:*",
|
|
||||||
"eventemitter3": "^5.0.1",
|
|
||||||
"extract-zip": "^2.0.1",
|
|
||||||
"html-to-text": "^9.0.5",
|
|
||||||
"ioredis": "^5.3.2",
|
|
||||||
"ip-matching": "^2.1.2",
|
|
||||||
"iso-639-1": "^3.1.0",
|
|
||||||
"isomorphic-dompurify": "latest",
|
|
||||||
"jsonld": "^8.3.1",
|
|
||||||
"linkify-html": "^4.1.3",
|
|
||||||
"linkify-string": "^4.1.3",
|
|
||||||
"linkifyjs": "^4.1.3",
|
|
||||||
"log-manager": "workspace:*",
|
|
||||||
"marked": "latest",
|
|
||||||
"media-manager": "workspace:*",
|
|
||||||
"megalodon": "^10.0.0",
|
|
||||||
"meilisearch": "latest",
|
|
||||||
"merge-deep-ts": "^1.2.6",
|
|
||||||
"mime-types": "^2.1.35",
|
|
||||||
"next-route-matcher": "^1.0.1",
|
|
||||||
"oauth4webapi": "^2.4.0",
|
|
||||||
"prisma": "^5.6.0",
|
|
||||||
"prisma-json-types-generator": "^3.0.4",
|
|
||||||
"prisma-redis-middleware": "^4.8.0",
|
|
||||||
"request-parser": "workspace:*",
|
|
||||||
"semver": "^7.5.4",
|
|
||||||
"sharp": "^0.33.3",
|
|
||||||
"strip-ansi": "^7.1.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,11 @@ import { MeiliIndexType, meilisearch } from "@meilisearch";
|
||||||
import { errorResponse, jsonResponse } from "@response";
|
import { errorResponse, jsonResponse } from "@response";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
import { statusToAPI } from "~database/entities/Status";
|
import { statusToAPI } from "~database/entities/Status";
|
||||||
import { userToAPI } from "~database/entities/User";
|
import {
|
||||||
|
resolveUser,
|
||||||
|
resolveWebFinger,
|
||||||
|
userToAPI,
|
||||||
|
} from "~database/entities/User";
|
||||||
import {
|
import {
|
||||||
statusAndUserRelations,
|
statusAndUserRelations,
|
||||||
userRelations,
|
userRelations,
|
||||||
|
|
@ -71,6 +75,42 @@ export default apiRoute<{
|
||||||
let statusResults: { id: string }[] = [];
|
let statusResults: { id: string }[] = [];
|
||||||
|
|
||||||
if (!type || type === "accounts") {
|
if (!type || type === "accounts") {
|
||||||
|
// Check if q is matching format username@domain.com or @username@domain.com
|
||||||
|
if (q?.trim().match(/@?[a-zA-Z0-9_]+(@[a-zA-Z0-9_.:]+)/g)) {
|
||||||
|
const [username, domain] = q.trim().split("@");
|
||||||
|
const account = await client.user.findFirst({
|
||||||
|
where: {
|
||||||
|
username,
|
||||||
|
instance: {
|
||||||
|
base_url: domain,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
include: userRelations,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (account) {
|
||||||
|
return jsonResponse({
|
||||||
|
accounts: [userToAPI(account)],
|
||||||
|
statuses: [],
|
||||||
|
hashtags: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolve) {
|
||||||
|
const newUser = await resolveWebFinger(username, domain).catch(
|
||||||
|
() => null,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (newUser) {
|
||||||
|
return jsonResponse({
|
||||||
|
accounts: [userToAPI(newUser)],
|
||||||
|
statuses: [],
|
||||||
|
hashtags: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
accountResults = (
|
accountResults = (
|
||||||
await meilisearch.index(MeiliIndexType.Accounts).search<{
|
await meilisearch.index(MeiliIndexType.Accounts).search<{
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ export default apiRoute(async (req, matchedRoute, extraData) => {
|
||||||
note.subject ?? "",
|
note.subject ?? "",
|
||||||
[],
|
[],
|
||||||
note.uri,
|
note.uri,
|
||||||
// TODO: Resolve mention,s
|
// TODO: Resolve mentions
|
||||||
[],
|
[],
|
||||||
// TODO: Add attachments
|
// TODO: Add attachments
|
||||||
[],
|
[],
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,10 @@ export default apiRoute<{
|
||||||
|
|
||||||
if (!resource) return errorResponse("No resource provided", 400);
|
if (!resource) return errorResponse("No resource provided", 400);
|
||||||
|
|
||||||
// Check if resource is in the correct format (acct:uuid@domain)
|
// Check if resource is in the correct format (acct:uuid/username@domain)
|
||||||
if (
|
if (!resource.match(/^acct:[a-zA-Z0-9-]+@[a-zA-Z0-9.-:]+$/)) {
|
||||||
!resource.match(
|
|
||||||
/^acct:[0-9A-F]{8}-[0-9A-F]{4}-[7][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}@.+/i,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return errorResponse(
|
return errorResponse(
|
||||||
"Invalid resource (should be acct:uuid@domain)",
|
"Invalid resource (should be acct:(id or username)@domain)",
|
||||||
400,
|
400,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -43,8 +39,17 @@ export default apiRoute<{
|
||||||
return errorResponse("User is a remote user", 404);
|
return errorResponse("User is a remote user", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isUuid = requestedUser
|
||||||
|
.split("@")[0]
|
||||||
|
.match(
|
||||||
|
/[0-9A-F]{8}-[0-9A-F]{4}-[7][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}/i,
|
||||||
|
);
|
||||||
|
|
||||||
const user = await client.user.findUnique({
|
const user = await client.user.findUnique({
|
||||||
where: { id: requestedUser.split("@")[0] },
|
where: {
|
||||||
|
id: isUuid ? requestedUser.split("@")[0] : undefined,
|
||||||
|
username: isUuid ? undefined : requestedUser.split("@")[0],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
|
@ -52,7 +57,7 @@ export default apiRoute<{
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsonResponse({
|
return jsonResponse({
|
||||||
subject: `acct:${user.id}@${host}`,
|
subject: `acct:${isUuid ? user.id : user.username}@${host}`,
|
||||||
|
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue