Merge branch 'refetch-key' into 'develop'

fix: Refetch user keys when HTTP Signature validation fails

Co-authored-by: Erin Shepherd <erin.shepherd@e43.eu>

See merge request firefish/firefish!10624
This commit is contained in:
Kainoa Kanter 2023-10-17 01:27:27 +00:00
commit b41fd4fef6
3 changed files with 42 additions and 4 deletions

View File

@ -95,11 +95,25 @@ export default async (job: Bull.Job<InboxJobData>): Promise<string> => {
} }
// HTTP-Signatureの検証 // HTTP-Signatureの検証
const httpSignatureValidated = httpSignature.verifySignature( let httpSignatureValidated = httpSignature.verifySignature(
signature, signature,
authUser.key.keyPem, authUser.key.keyPem,
); );
// If signature validation failed, try refetching the actor
if (!httpSignatureValidated) {
authUser.key = await dbResolver.refetchPublicKeyForApId(authUser.user);
if (authUser.key == null) {
return "skip: failed to re-resolve user publicKey";
}
httpSignatureValidated = httpSignature.verifySignature(
signature,
authUser.key.keyPem,
);
}
// また、signatureのsignerは、activity.actorと一致する必要がある // また、signatureのsignerは、activity.actorと一致する必要がある
if (!httpSignatureValidated || authUser.user.uri !== activity.actor) { if (!httpSignatureValidated || authUser.user.uri !== activity.actor) {
// 一致しなくても、でもLD-Signatureがありそうならそっちも見る // 一致しなくても、でもLD-Signatureがありそうならそっちも見る

View File

@ -86,11 +86,25 @@ export async function checkFetch(req: IncomingMessage): Promise<number> {
} }
// HTTP-Signatureの検証 // HTTP-Signatureの検証
const httpSignatureValidated = httpSignature.verifySignature( let httpSignatureValidated = httpSignature.verifySignature(
signature, signature,
authUser.key.keyPem, authUser.key.keyPem,
); );
// If signature validation failed, try refetching the actor
if (!httpSignatureValidated) {
authUser.key = await dbResolver.refetchPublicKeyForApId(authUser.user);
if (authUser.key == null) {
return 403;
}
httpSignatureValidated = httpSignature.verifySignature(
signature,
authUser.key.keyPem,
);
}
if (!httpSignatureValidated) { if (!httpSignatureValidated) {
return 403; return 403;
} }

View File

@ -17,7 +17,8 @@ import { Cache } from "@/misc/cache.js";
import { uriPersonCache, userByIdCache } from "@/services/user-cache.js"; import { uriPersonCache, userByIdCache } from "@/services/user-cache.js";
import type { IObject } from "./type.js"; import type { IObject } from "./type.js";
import { getApId } from "./type.js"; import { getApId } from "./type.js";
import { resolvePerson } from "./models/person.js"; import { resolvePerson, updatePerson } from "./models/person.js";
const publicKeyCache = new Cache<UserPublickey | null>("publicKey", 60 * 30); const publicKeyCache = new Cache<UserPublickey | null>("publicKey", 60 * 30);
const publicKeyByUserIdCache = new Cache<UserPublickey | null>( const publicKeyByUserIdCache = new Cache<UserPublickey | null>(
@ -151,7 +152,7 @@ export default class DbResolver {
*/ */
public async getAuthUserFromKeyId(keyId: string): Promise<{ public async getAuthUserFromKeyId(keyId: string): Promise<{
user: CacheableRemoteUser; user: CacheableRemoteUser;
key: UserPublickey; key: UserPublickey | null;
} | null> { } | null> {
const key = await publicKeyCache.fetch( const key = await publicKeyCache.fetch(
keyId, keyId,
@ -203,4 +204,13 @@ export default class DbResolver {
key, key,
}; };
} }
public async refetchPublicKeyForApId(user: CacheableRemoteUser): Promise<UserPublickey | null> {
await updatePerson(user.uri!, undefined, undefined, user);
let key = await UserPublickeys.findOneBy({ userId: user.id });
if (key != null) {
await publicKeyByUserIdCache.set(user.id, key);
}
return key;
}
} }