Update all packages, fix critical bugs

This commit is contained in:
Jesse Wierzbinski 2024-03-03 17:29:44 -10:00
parent d85fe9efb6
commit 64629754ca
No known key found for this signature in database
15 changed files with 48217 additions and 113 deletions

BIN
bun.lockb

Binary file not shown.

View file

@ -6,8 +6,8 @@
*/
import { parse, stringify } from "@iarna/toml";
import { deepMerge, deepMergeArray } from "@merge";
import chalk from "chalk";
import merge from "merge-deep-ts";
const scanConfig = async () => {
const config = Bun.file(process.cwd() + "/config/config.toml");
@ -92,6 +92,7 @@ export interface ConfigType {
bind: string;
bind_port: string;
banned_ips: string[];
banned_user_agents: string[];
};
instance: {
@ -215,6 +216,7 @@ export const configDefaults: ConfigType = {
bind_port: "8000",
base_url: "http://lysand.localhost:8000",
banned_ips: [],
banned_user_agents: [],
},
database: {
host: "localhost",
@ -398,11 +400,7 @@ export const configDefaults: ConfigType = {
export const getConfig = () => {
// Deeply merge configDefaults, config and internalConfig
return deepMergeArray([
configDefaults,
config,
internalConfig,
]) as any as ConfigType;
return merge([configDefaults, config, internalConfig]) as any as ConfigType;
};
/**
@ -410,13 +408,16 @@ export const getConfig = () => {
* @param newConfig Any part of ConfigType
*/
export const setConfig = async (newConfig: Partial<ConfigType>) => {
const newInternalConfig = deepMerge(internalConfig, newConfig);
const newInternalConfig = merge([
internalConfig,
newConfig,
]) as any as ConfigType;
// Prepend a warning comment and write the new TOML to the file
await Bun.write(
Bun.file(process.cwd() + "/config/config.internal.toml"),
`# This file is automatically generated. Do not modify it manually.\n${stringify(
newInternalConfig
newInternalConfig as any
)}`
);
};

5
cli.ts
View file

@ -1013,7 +1013,10 @@ switch (command) {
const content_type = emoji.type;
const hash = await uploadFile(emoji as File, config);
const hash = await uploadFile(
emoji as unknown as File,
config
);
if (!hash) {
console.log(

View file

@ -310,10 +310,10 @@ export const getRelationshipToOtherUser = async (
* Generates keys for the user.
*/
export const generateUserKeys = async () => {
const keys = (await crypto.subtle.generateKey("Ed25519", true, [
const keys = await crypto.subtle.generateKey("Ed25519", true, [
"sign",
"verify",
])) as CryptoKeyPair;
]);
const privateKey = btoa(
String.fromCharCode.apply(null, [

View file

@ -97,7 +97,6 @@ Bun.serve({
}
// TODO: Check for ratelimits
const auth = await getFromRequest(req);
// Check for authentication if required
@ -126,16 +125,12 @@ Bun.serve({
if (new URL(req.url).pathname.startsWith("/assets")) {
// Serve from pages/dist/assets
return new Response(
// @ts-expect-error Custom Bun extension
Bun.file(`./pages/dist${new URL(req.url).pathname}`)
);
}
// Serve from pages/dist
return new Response(
// @ts-expect-error Custom Bun extension
Bun.file(`./pages/dist/index.html`)
);
return new Response(Bun.file(`./pages/dist/index.html`));
} else {
const proxy = await fetch(
req.url.replace(
@ -167,7 +162,7 @@ const logRequest = async (req: Request) => {
);
// Add headers
// @ts-expect-error TypeScript is missing entries for some reason
const headers = req.headers.entries();
for (const [key, value] of headers) {

48086
log.txt Normal file

File diff suppressed because it is too large Load diff

View file

@ -32,7 +32,7 @@
},
"private": true,
"scripts": {
"dev": "bun run index.ts",
"dev": "bun run --watch index.ts",
"vite:dev": "bunx --bun vite pages",
"vite:build": "bunx --bun vite build pages",
"start": "NODE_ENV=production bun run dist/index.js --prod",
@ -57,9 +57,9 @@
"@types/html-to-text": "^9.0.4",
"@types/ioredis": "^5.0.0",
"@types/jsonld": "^1.5.13",
"@typescript-eslint/eslint-plugin": "^6.13.1",
"@typescript-eslint/parser": "^6.13.1",
"@unocss/cli": "^0.57.7",
"@typescript-eslint/eslint-plugin": "latest",
"@typescript-eslint/parser": "latest",
"@unocss/cli": "latest",
"activitypub-types": "^1.0.3",
"bun-types": "latest",
"eslint": "^8.54.0",
@ -69,14 +69,14 @@
"eslint-plugin-prettier": "^5.0.1",
"prettier": "^3.1.0",
"typescript": "^5.3.2",
"unocss": "^0.57.7",
"@vitejs/plugin-vue": "^4.5.1",
"unocss": "latest",
"@vitejs/plugin-vue": "latest",
"@vueuse/head": "^2.0.0",
"vite": "^5.0.4",
"vite-ssr": "^0.17.1",
"vue": "^3.3.9",
"vue-router": "^4.2.5",
"vue-tsc": "^1.8.24"
"vue-tsc": "latest"
},
"peerDependencies": {
"typescript": "^5.3.2"
@ -86,7 +86,7 @@
"@iarna/toml": "^2.2.5",
"@prisma/client": "^5.6.0",
"blurhash": "^2.0.5",
"bullmq": "^4.14.4",
"bullmq": "latest",
"chalk": "^5.3.0",
"cli-table": "^0.3.11",
"eventemitter3": "^5.0.1",
@ -95,14 +95,15 @@
"ioredis": "^5.3.2",
"ip-matching": "^2.1.2",
"iso-639-1": "^3.1.0",
"isomorphic-dompurify": "^1.10.0",
"isomorphic-dompurify": "latest",
"jsonld": "^8.3.1",
"linkify-html": "^4.1.3",
"linkify-string": "^4.1.3",
"linkifyjs": "^4.1.3",
"marked": "^9.1.2",
"marked": "latest",
"megalodon": "^9.1.1",
"meilisearch": "^0.36.0",
"meilisearch": "latest",
"merge-deep-ts": "^1.2.6",
"next-route-matcher": "^1.0.1",
"oauth4webapi": "^2.4.0",
"prisma": "^5.6.0",

View file

@ -29,6 +29,10 @@ export default async (
matchedRoute: MatchedRoute
): Promise<Response> => {
const id = matchedRoute.params.id;
// Check if ID is valid UUID
if (!id.match(/^[0-9a-fA-F]{24}$/)) {
return errorResponse("Invalid ID", 404);
}
const { user } = await getFromRequest(req);

View file

@ -2,9 +2,9 @@ import { getConfig } from "~classes/configmanager";
import { parseRequest } from "@request";
import { errorResponse, jsonResponse } from "@response";
import {
getFromRequest,
userRelations,
userToAPI,
type AuthData,
} from "~database/entities/User";
import { applyConfig } from "@api";
import { sanitize } from "isomorphic-dompurify";
@ -15,6 +15,7 @@ import { parseEmojis } from "~database/entities/Emoji";
import { client } from "~database/datasource";
import type { APISource } from "~types/entities/source";
import { convertTextToHtml } from "@formatting";
import type { MatchedRoute } from "bun";
export const meta = applyConfig({
allowedMethods: ["PATCH"],
@ -31,8 +32,12 @@ export const meta = applyConfig({
/**
* Patches a user
*/
export default async (req: Request): Promise<Response> => {
const { user } = await getFromRequest(req);
export default async (
req: Request,
matchedRoute: MatchedRoute,
auth: AuthData
): Promise<Response> => {
const { user } = auth;
if (!user) return errorResponse("Unauthorized", 401);
@ -64,7 +69,7 @@ export default async (req: Request): Promise<Response> => {
const sanitizedNote = await sanitizeHtml(note ?? "");
const sanitizedDisplayName = sanitize(display_name, {
const sanitizedDisplayName = sanitize(display_name ?? "", {
ALLOWED_TAGS: [],
ALLOWED_ATTR: [],
});

View file

@ -87,16 +87,11 @@ export default async (
});
// Create notification for reblog if reblogged user is on the same instance
if (
// @ts-expect-error Prisma relations not showing in types
(status.reblog?.author as UserWithRelations).instanceId ===
user.instanceId
) {
if ((status.author as UserWithRelations).instanceId === user.instanceId) {
await client.notification.create({
data: {
accountId: user.id,
// @ts-expect-error Prisma relations not showing in types
notifiedId: status.reblog.authorId,
notifiedId: status.authorId,
type: "reblog",
statusId: status.reblogId,
},

View file

@ -153,11 +153,11 @@ export default async (
let sanitizedStatus: string;
if (content_type === "text/markdown") {
sanitizedStatus = await sanitizeHtml(parse(status ?? ""));
sanitizedStatus = await sanitizeHtml(parse(status ?? "") as any);
} else if (content_type === "text/x.misskeymarkdown") {
// Parse as MFM
// TODO: Parse as MFM
sanitizedStatus = await sanitizeHtml(parse(status ?? ""));
sanitizedStatus = await sanitizeHtml(parse(status ?? "") as any);
} else {
sanitizedStatus = await sanitizeHtml(status ?? "");
}

View file

@ -61,6 +61,12 @@ describe("API Tests", () => {
},
},
});
await client.application.deleteMany({
where: {
client_id: "test",
},
});
});
describe("GET /api/v1/instance", () => {
@ -130,8 +136,8 @@ describe("API Tests", () => {
const emojis = (await response.json()) as APIEmoji[];
expect(emojis.length).toBeGreaterThan(0);
expect(emojis[0].shortcode).toBe("test");
expect(emojis[0].url).toBe("https://example.com/test.png");
expect(emojis[0].shortcode).toBeString();
expect(emojis[0].url).toBeString();
});
afterAll(async () => {
await client.emoji.deleteMany({

View file

@ -19,15 +19,14 @@ let token: Token;
let user: UserWithRelations;
let user2: UserWithRelations;
describe("API Tests", () => {
beforeAll(async () => {
await client.user.deleteMany({
beforeAll(async () => {
/* await client.user.deleteMany({
where: {
username: {
in: ["test", "test2"],
},
},
});
}); */
user = await createNewLocalUser({
email: "test@test.com",
@ -67,9 +66,9 @@ describe("API Tests", () => {
},
},
});
});
});
afterAll(async () => {
afterAll(async () => {
await client.user.deleteMany({
where: {
username: {
@ -77,8 +76,15 @@ describe("API Tests", () => {
},
},
});
});
await client.application.deleteMany({
where: {
client_id: "test",
},
});
});
describe("API Tests", () => {
describe("POST /api/v1/accounts/:id", () => {
test("should return a 404 error when trying to fetch a non-existent user", async () => {
const response = await fetch(

View file

@ -73,6 +73,12 @@ describe("API Tests", () => {
},
},
});
await client.application.deleteMany({
where: {
client_id: "test",
},
});
});
describe("POST /api/v2/media", () => {
@ -80,7 +86,6 @@ describe("API Tests", () => {
const formData = new FormData();
formData.append("file", new Blob(["test"], { type: "text/plain" }));
// @ts-expect-error FormData is not iterable
const response = await fetch(
`${config.http.base_url}/api/v2/media`,
{
@ -130,14 +135,14 @@ describe("API Tests", () => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
status = (await response.json()) as APIStatus;
expect(status.content).toBe("Hello, world!");
expect(status.content).toContain("Hello, world!");
expect(status.visibility).toBe("public");
expect(status.account.id).toBe(user.id);
expect(status.replies_count).toBe(0);
expect(status.favourites_count).toBe(0);
expect(status.reblogged).toBe(false);
expect(status.favourited).toBe(false);
expect(status.media_attachments).toEqual([]);
expect(status.media_attachments).toBeArrayOfSize(1);
expect(status.mentions).toEqual([]);
expect(status.tags).toEqual([]);
expect(status.sensitive).toBe(false);
@ -176,7 +181,7 @@ describe("API Tests", () => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
status2 = (await response.json()) as APIStatus;
expect(status2.content).toBe("This is a reply!");
expect(status2.content).toContain("This is a reply!");
expect(status2.visibility).toBe("public");
expect(status2.account.id).toBe(user.id);
expect(status2.replies_count).toBe(0);
@ -371,7 +376,7 @@ describe("API Tests", () => {
const status1 = statuses[0];
// Basic validation
expect(status1.content).toBe("This is a reply!");
expect(status1.content).toContain("This is a reply!");
expect(status1.visibility).toBe("public");
expect(status1.account.id).toBe(user.id);
});

View file

@ -30,7 +30,6 @@ describe("POST /api/v1/apps/", () => {
formData.append("redirect_uris", "https://example.com");
formData.append("scopes", "read write");
// @ts-expect-error FormData works
const response = await fetch(`${config.http.base_url}/api/v1/apps/`, {
method: "POST",
body: formData,
@ -40,7 +39,7 @@ describe("POST /api/v1/apps/", () => {
expect(response.headers.get("content-type")).toBe("application/json");
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const json = (await response.json()) as any;
const json = await response.json();
expect(json).toEqual({
id: expect.any(String),
@ -66,7 +65,6 @@ describe("POST /auth/login/", () => {
formData.append("email", "test@test.com");
formData.append("password", "test");
// @ts-expect-error FormData works
const response = await fetch(
`${config.http.base_url}/auth/login/?client_id=${client_id}&redirect_uri=https://example.com&response_type=code&scope=read+write`,
{
@ -96,7 +94,6 @@ describe("POST /oauth/token/", () => {
formData.append("client_secret", client_secret);
formData.append("scope", "read+write");
// @ts-expect-error FormData works
const response = await fetch(`${config.http.base_url}/oauth/token/`, {
method: "POST",
// Do not set the Content-Type header for some reason
@ -104,7 +101,7 @@ describe("POST /oauth/token/", () => {
});
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const json = (await response.json()) as any;
const json = await response.json();
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toBe("application/json");