Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions packages/fedify/src/federation/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,28 @@ export interface Context<TContextData> {
*/
getActorKeyPairs(identifier: string): Promise<ActorKeyPair[]>;

/**
* Gets the actor's public keys grouped by usage.
* @param identifier The actor's identifier.
* @returns The actor's public keys and assertion methods. It can be empty.
* @since 2.2.0
*/
getActorKeysByUsage(identifier: string): Promise<{
publicKeys: CryptographicKey[];
assertionMethods: Multikey[];
}>;

/**
* Gets the first actor key per usage.
* @param identifier The actor's identifier.
* @returns The first public key and assertion method, if available.
* @since 2.2.0
*/
getActorFirstKeyByUsage(identifier: string): Promise<{
publicKey: CryptographicKey | undefined;
assertionMethod: Multikey | undefined;
}>;

/**
* Gets an authenticated {@link DocumentLoader} for the given identity.
* Note that an authenticated document loader intentionally does not cache
Expand Down
11 changes: 10 additions & 1 deletion packages/fedify/src/federation/middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,9 @@ test({
{ type: "actor", identifier: "handle" },
);
assertEquals(ctx.parseUri(null), null);
const keyPairs = await ctx.getActorKeyPairs("handle");
assertEquals(
await ctx.getActorKeyPairs("handle"),
keyPairs,
[
{
keyId: new URL("https://example.com/users/handle#main-key"),
Expand Down Expand Up @@ -338,6 +339,14 @@ test({
},
],
);
assertEquals(await ctx.getActorKeysByUsage("handle"), {
publicKeys: keyPairs.map((key) => key.cryptographicKey),
assertionMethods: keyPairs.map((key) => key.multikey),
});
assertEquals(await ctx.getActorFirstKeyByUsage("handle"), {
publicKey: keyPairs[0].cryptographicKey,
assertionMethod: keyPairs[0].multikey,
});
const loader = await ctx.getDocumentLoader({ identifier: "handle" });
assertEquals(await loader("https://example.com/auth-check"), {
contextUrl: null,
Expand Down
23 changes: 23 additions & 0 deletions packages/fedify/src/federation/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1969,6 +1969,29 @@ export class ContextImpl<TContextData> implements Context<TContextData> {
return result;
}

async getActorKeysByUsage(identifier: string): Promise<{
publicKeys: CryptographicKey[];
assertionMethods: Multikey[];
}> {
const keys = await this.getActorKeyPairs(identifier);
return {
publicKeys: keys.map((key) => key.cryptographicKey),
assertionMethods: keys.map((key) => key.multikey),
};
}

async getActorFirstKeyByUsage(identifier: string): Promise<{
publicKey: CryptographicKey | undefined;
assertionMethod: Multikey | undefined;
}> {
const { publicKeys, assertionMethods } =
await this.getActorKeysByUsage(identifier);
return {
publicKey: publicKeys[0],
assertionMethod: assertionMethods[0],
};
}
Comment on lines +1983 to +1993
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This implementation is correct, but it can be made more efficient. It currently calls getActorKeysByUsage, which creates two new arrays by mapping over all key pairs, only to then use the first element of each. You can optimize this by calling getActorKeyPairs directly and accessing the first element, avoiding the creation of intermediate arrays.

  async getActorFirstKeyByUsage(identifier: string): Promise<{
    publicKey: CryptographicKey | undefined;
    assertionMethod: Multikey | undefined;
  }> {
    const keys = await this.getActorKeyPairs(identifier);
    const firstKey = keys[0];
    if (firstKey == null) {
      return { publicKey: undefined, assertionMethod: undefined };
    }
    return {
      publicKey: firstKey.cryptographicKey,
      assertionMethod: firstKey.multikey,
    };
  }


protected async getKeyPairsFromIdentifier(
identifier: string,
): Promise<(CryptoKeyPair & { keyId: URL })[]> {
Expand Down
Loading