feat(federation): Add signatures to all users and objects served

This commit is contained in:
Jesse Wierzbinski 2024-07-24 23:42:00 +02:00
parent 5a52ac005b
commit d20988afa1
No known key found for this signature in database
2 changed files with 60 additions and 4 deletions

View file

@ -1,14 +1,17 @@
import { applyConfig, handleZodError } from "@/api"; import { applyConfig, handleZodError } from "@/api";
import { errorResponse, jsonResponse, response } from "@/response"; import { errorResponse, response } from "@/response";
import type { Hono } from "@hono/hono"; import type { Hono } from "@hono/hono";
import { zValidator } from "@hono/zod-validator"; import { zValidator } from "@hono/zod-validator";
import { SignatureConstructor } from "@lysand-org/federation";
import type { Entity } from "@lysand-org/federation/types"; import type { Entity } from "@lysand-org/federation/types";
import { and, eq, inArray, sql } from "drizzle-orm"; import { and, eq, inArray, sql } from "drizzle-orm";
import { z } from "zod"; import { z } from "zod";
import { type LikeType, likeToLysand } from "~/classes/functions/like"; import { type LikeType, likeToLysand } from "~/classes/functions/like";
import { db } from "~/drizzle/db"; import { db } from "~/drizzle/db";
import { Notes } from "~/drizzle/schema"; import { Notes } from "~/drizzle/schema";
import { config } from "~/packages/config-manager";
import { Note } from "~/packages/database-interface/note"; import { Note } from "~/packages/database-interface/note";
import { User } from "~/packages/database-interface/user";
export const meta = applyConfig({ export const meta = applyConfig({
allowedMethods: ["GET"], allowedMethods: ["GET"],
@ -45,6 +48,7 @@ export default (app: Hono) =>
const { debug } = context.req.valid("query"); const { debug } = context.req.valid("query");
let foundObject: Note | LikeType | null = null; let foundObject: Note | LikeType | null = null;
let foundAuthor: User | null = null;
let apiObject: Entity | null = null; let apiObject: Entity | null = null;
foundObject = await Note.fromSql( foundObject = await Note.fromSql(
@ -54,6 +58,7 @@ export default (app: Hono) =>
), ),
); );
apiObject = foundObject ? foundObject.toLysand() : null; apiObject = foundObject ? foundObject.toLysand() : null;
foundAuthor = foundObject ? foundObject.author : null;
if (!foundObject) { if (!foundObject) {
foundObject = foundObject =
@ -65,6 +70,9 @@ export default (app: Hono) =>
), ),
})) ?? null; })) ?? null;
apiObject = foundObject ? likeToLysand(foundObject) : null; apiObject = foundObject ? likeToLysand(foundObject) : null;
foundAuthor = foundObject
? await User.fromId(foundObject.likerId)
: null;
} }
if (!(foundObject && apiObject)) { if (!(foundObject && apiObject)) {
@ -77,6 +85,30 @@ export default (app: Hono) =>
}); });
} }
return jsonResponse(apiObject); const objectString = JSON.stringify(apiObject);
// If base_url uses https and request uses http, rewrite request to use https
// This fixes reverse proxy errors
const reqUrl = new URL(context.req.url);
if (
new URL(config.http.base_url).protocol === "https:" &&
reqUrl.protocol === "http:"
) {
reqUrl.protocol = "https:";
}
const author = foundAuthor ?? User.getServerActor();
const { headers } = await (
await SignatureConstructor.fromStringKey(
author.data.privateKey ?? "",
author.getUri(),
)
).sign("POST", reqUrl, objectString);
return response(objectString, 200, {
"Content-Type": "application/json",
...headers.toJSON(),
});
}, },
); );

View file

@ -1,8 +1,10 @@
import { applyConfig, handleZodError } from "@/api"; import { applyConfig, handleZodError } from "@/api";
import { errorResponse, jsonResponse, redirect, response } from "@/response"; import { errorResponse, redirect, response } from "@/response";
import type { Hono } from "@hono/hono"; import type { Hono } from "@hono/hono";
import { zValidator } from "@hono/zod-validator"; import { zValidator } from "@hono/zod-validator";
import { SignatureConstructor } from "@lysand-org/federation";
import { z } from "zod"; import { z } from "zod";
import { config } from "~/packages/config-manager";
import { User } from "~/packages/database-interface/user"; import { User } from "~/packages/database-interface/user";
export const meta = applyConfig({ export const meta = applyConfig({
@ -63,6 +65,28 @@ export default (app: Hono) =>
return redirect(user.toApi().url); return redirect(user.toApi().url);
} }
return jsonResponse(user.toLysand()); const userString = JSON.stringify(user.toLysand());
// If base_url uses https and request uses http, rewrite request to use https
// This fixes reverse proxy errors
const reqUrl = new URL(context.req.url);
if (
new URL(config.http.base_url).protocol === "https:" &&
reqUrl.protocol === "http:"
) {
reqUrl.protocol = "https:";
}
const { headers } = await (
await SignatureConstructor.fromStringKey(
user.data.privateKey ?? "",
user.getUri(),
)
).sign("POST", reqUrl, userString);
return response(userString, 200, {
"Content-Type": "application/json",
...headers.toJSON(),
});
}, },
); );