refactor(api): ♻️ Use URL literal instead of strings

This commit is contained in:
Jesse Wierzbinski 2025-02-01 16:32:18 +01:00
parent 99fac323c8
commit 76d1ccc859
No known key found for this signature in database
50 changed files with 343 additions and 256 deletions

View file

@ -76,7 +76,7 @@ mock.module("~/packages/config-manager/index.ts", () => ({
describe("InboxProcessor", () => {
let mockRequest: {
url: string;
url: URL;
method: string;
body: string;
};
@ -95,7 +95,7 @@ describe("InboxProcessor", () => {
// Setup basic mock context
mockRequest = {
url: "https://test.com",
url: new URL("https://test.com"),
method: "POST",
body: "test-body",
};
@ -196,7 +196,10 @@ describe("InboxProcessor", () => {
describe("processNote", () => {
test("successfully processes valid note", async () => {
const mockNote = { author: "test-author" };
const mockNote = {
author: "https://example.com",
uri: "https://note.example.com",
};
const mockAuthor = { id: "test-id" };
const mockInstance = { id: "test-id" };
@ -209,7 +212,9 @@ describe("InboxProcessor", () => {
// biome-ignore lint/complexity/useLiteralKeys: Private method
const result = await processor["processNote"]();
expect(User.resolve).toHaveBeenCalledWith("test-author");
expect(User.resolve).toHaveBeenCalledWith(
new URL("https://example.com"),
);
expect(Note.fromVersia).toHaveBeenCalledWith(
mockNote,
mockAuthor,
@ -220,7 +225,13 @@ describe("InboxProcessor", () => {
test("returns 404 when author not found", async () => {
User.resolve = jest.fn().mockResolvedValue(null);
const mockNote = {
author: "https://example.com",
uri: "https://note.example.com",
};
// biome-ignore lint/complexity/useLiteralKeys: Private variable
processor["body"] = mockNote as VersiaNote;
// biome-ignore lint/complexity/useLiteralKeys: Private method
const result = await processor["processNote"]();
@ -233,8 +244,8 @@ describe("InboxProcessor", () => {
describe("processFollowRequest", () => {
test("successfully processes follow request for unlocked account", async () => {
const mockFollow = {
author: "test-author",
followee: "test-followee",
author: "https://example.com",
followee: "https://followee.note.com",
};
const mockAuthor = { id: "author-id" };
const mockFollowee = {
@ -273,7 +284,13 @@ describe("InboxProcessor", () => {
test("returns 404 when author not found", async () => {
User.resolve = jest.fn().mockResolvedValue(null);
const mockFollow = {
author: "https://example.com",
followee: "https://followee.note.com",
};
// biome-ignore lint/complexity/useLiteralKeys: Private variable
processor["body"] = mockFollow as unknown as Entity;
// biome-ignore lint/complexity/useLiteralKeys: Private method
const result = await processor["processFollowRequest"]();
@ -287,7 +304,7 @@ describe("InboxProcessor", () => {
test("successfully deletes a note", async () => {
const mockDelete = {
deleted_type: "Note",
deleted: "test-uri",
deleted: "https://example.com",
};
const mockNote = {
delete: jest.fn(),
@ -307,7 +324,7 @@ describe("InboxProcessor", () => {
test("returns 404 when note not found", async () => {
const mockDelete = {
deleted_type: "Note",
deleted: "test-uri",
deleted: "https://example.com",
};
Note.fromSql = jest.fn().mockResolvedValue(null);
@ -331,9 +348,9 @@ describe("InboxProcessor", () => {
describe("processLikeRequest", () => {
test("successfully processes like request", async () => {
const mockLike = {
author: "test-author",
liked: "test-note",
uri: "test-uri",
author: "https://example.com",
liked: "https://example.note.com",
uri: "https://example.com",
};
const mockAuthor = {
like: jest.fn(),
@ -348,13 +365,23 @@ describe("InboxProcessor", () => {
// biome-ignore lint/complexity/useLiteralKeys: Private method
const result = await processor["processLikeRequest"]();
expect(mockAuthor.like).toHaveBeenCalledWith(mockNote, "test-uri");
expect(mockAuthor.like).toHaveBeenCalledWith(
mockNote,
"https://example.com",
);
expect(result).toBeNull();
});
test("returns 404 when author not found", async () => {
User.resolve = jest.fn().mockResolvedValue(null);
const mockLike = {
author: "https://example.com",
liked: "https://example.note.com",
uri: "https://example.com",
};
// biome-ignore lint/complexity/useLiteralKeys: Private variable
processor["body"] = mockLike as unknown as Entity;
// biome-ignore lint/complexity/useLiteralKeys: Private method
const result = await processor["processLikeRequest"]();
@ -367,7 +394,7 @@ describe("InboxProcessor", () => {
describe("processUserRequest", () => {
test("successfully processes user update", async () => {
const mockUser = {
uri: "test-uri",
uri: "https://example.com",
};
const mockUpdatedUser = { id: "user-id" };
@ -378,13 +405,20 @@ describe("InboxProcessor", () => {
// biome-ignore lint/complexity/useLiteralKeys: Private method
const result = await processor["processUserRequest"]();
expect(User.fetchFromRemote).toHaveBeenCalledWith("test-uri");
expect(User.fetchFromRemote).toHaveBeenCalledWith(
new URL("https://example.com"),
);
expect(result).toBeNull();
});
test("returns 500 when update fails", async () => {
const mockUser = {
uri: "https://example.com",
};
User.fetchFromRemote = jest.fn().mockResolvedValue(null);
// biome-ignore lint/complexity/useLiteralKeys: Private variable
processor["body"] = mockUser as unknown as Entity;
// biome-ignore lint/complexity/useLiteralKeys: Private method
const result = await processor["processUserRequest"]();

View file

@ -40,7 +40,7 @@ function isDefederated(hostname: string): boolean {
return (
config.federation.blocked.find(
(blocked) => pattern.match(blocked) !== null,
(blocked) => pattern.match(blocked.toString()) !== null,
) !== undefined
);
}
@ -70,7 +70,7 @@ export class InboxProcessor {
*/
public constructor(
private request: {
url: string;
url: URL;
method: string;
body: string;
},
@ -269,8 +269,8 @@ export class InboxProcessor {
*/
private async processNote(): Promise<Response | null> {
const note = this.body as VersiaNote;
const author = await User.resolve(note.author);
const instance = await Instance.resolve(note.uri);
const author = await User.resolve(new URL(note.author));
const instance = await Instance.resolve(new URL(note.uri));
if (!instance) {
return Response.json(
@ -298,8 +298,8 @@ export class InboxProcessor {
*/
private async processFollowRequest(): Promise<Response | null> {
const follow = this.body as unknown as VersiaFollow;
const author = await User.resolve(follow.author);
const followee = await User.resolve(follow.followee);
const author = await User.resolve(new URL(follow.author));
const followee = await User.resolve(new URL(follow.followee));
if (!author) {
return Response.json(
@ -352,8 +352,8 @@ export class InboxProcessor {
*/
private async processFollowAccept(): Promise<Response | null> {
const followAccept = this.body as unknown as VersiaFollowAccept;
const author = await User.resolve(followAccept.author);
const follower = await User.resolve(followAccept.follower);
const author = await User.resolve(new URL(followAccept.author));
const follower = await User.resolve(new URL(followAccept.follower));
if (!author) {
return Response.json(
@ -393,8 +393,8 @@ export class InboxProcessor {
*/
private async processFollowReject(): Promise<Response | null> {
const followReject = this.body as unknown as VersiaFollowReject;
const author = await User.resolve(followReject.author);
const follower = await User.resolve(followReject.follower);
const author = await User.resolve(new URL(followReject.author));
const follower = await User.resolve(new URL(followReject.follower));
if (!author) {
return Response.json(
@ -438,7 +438,7 @@ export class InboxProcessor {
const toDelete = delete_.deleted;
const author = delete_.author
? await User.resolve(delete_.author)
? await User.resolve(new URL(delete_.author))
: null;
switch (delete_.deleted_type) {
@ -461,7 +461,7 @@ export class InboxProcessor {
return null;
}
case "User": {
const userToDelete = await User.resolve(toDelete);
const userToDelete = await User.resolve(new URL(toDelete));
if (!userToDelete) {
return Response.json(
@ -516,8 +516,8 @@ export class InboxProcessor {
*/
private async processLikeRequest(): Promise<Response | null> {
const like = this.body as unknown as VersiaLikeExtension;
const author = await User.resolve(like.author);
const likedNote = await Note.resolve(like.liked);
const author = await User.resolve(new URL(like.author));
const likedNote = await Note.resolve(new URL(like.liked));
if (!author) {
return Response.json(
@ -546,7 +546,7 @@ export class InboxProcessor {
private async processUserRequest(): Promise<Response | null> {
const user = this.body as unknown as VersiaUser;
// FIXME: Instead of refetching the remote user, we should read the incoming json and update from that
const updatedAccount = await User.fetchFromRemote(user.uri);
const updatedAccount = await User.fetchFromRemote(new URL(user.uri));
if (!updatedAccount) {
return Response.json(