Unverified Commit bda6d57e authored by Hong Minhee's avatar Hong Minhee
Browse files

Instrument `fetchKey()`

parent 5eedba62
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ spans:
| `activitypub.dispatch_collection_page {collection}` | Server      | Dispatches the ActivityPub collection page.   |
| `activitypub.dispatch_inbox_listener {type}`        | Internal    | Dispatches the ActivityPub inbox listener.    |
| `activitypub.dispatch_object`                       | Server      | Dispatches the Activity Streams object.       |
| `activitypub.fetch_key`                             | Client      | Fetches the public keys for the actor.        |
| `activitypub.get_actor_handle`                      | Client      | Resolves the actor handle.                    |
| `activitypub.inbox`                                 | Consumer    | Dequeues the ActivityPub activity to receive. |
| `activitypub.inbox`                                 | Producer    | Enqueues the ActivityPub activity to receive. |
@@ -168,6 +169,7 @@ for ActivityPub:
| `activitypub.activity.bcc`            | string[] | The URI(s) of the blind carbon-copied recipient collections/actors of the activity.      | `["https://www.w3.org/ns/activitystreams#Public"]`                   |
| `activitypub.activity.retries`        | int      | The ordinal number of activity resending attempt (if and only if it's retried).          | `3`                                                                  |
| `activitypub.actor.id`                | string   | The URI of the actor object.                                                             | `"https://example.com/actor/1"`                                      |
| `activitypub.actor.key.cached`        | boolean  | Whether the actor's public keys are cached.                                              | `true`                                                               |
| `activitypub.actor.type`              | string[] | The qualified URI(s) of the actor type(s).                                               | `["https://www.w3.org/ns/activitystreams#Person"]`                   |
| `activitypub.collection.id`           | string   | The URI of the collection object.                                                        | `"https://example.com/collection/1"`                                 |
| `activitypub.collection.type`         | string[] | The qualified URI(s) of the collection type(s).                                          | `["https://www.w3.org/ns/activitystreams#OrderedCollection"]`        |
+1 −1
Original line number Diff line number Diff line
@@ -389,7 +389,6 @@ async function verifyRequestInternal(
  }
  const { keyId, headers, signature } = sigValues;
  span?.setAttribute("http_signatures.key_id", keyId);
  span?.setAttribute("http_signatures.signature", signature);
  if ("algorithm" in sigValues) {
    span?.setAttribute("http_signatures.algorithm", sigValues.algorithm);
  }
@@ -428,6 +427,7 @@ async function verifyRequestInternal(
      : request.headers.get(name))
  ).join("\n");
  const sig = decodeBase64(signature);
  span?.setAttribute("http_signatures.signature", encodeHex(sig));
  // TODO: support other than RSASSA-PKCS1-v1_5:
  const verified = await crypto.subtle.verify(
    "RSASSA-PKCS1-v1_5",
+55 −2
Original line number Diff line number Diff line
import { getLogger } from "@logtape/logtape";
import type { TracerProvider } from "@opentelemetry/api";
import {
  SpanKind,
  SpanStatusCode,
  trace,
  type TracerProvider,
} from "@opentelemetry/api";
import metadata from "../deno.json" with { type: "json" };
import {
  type DocumentLoader,
  getDocumentLoader,
@@ -190,7 +196,54 @@ export interface FetchKeyResult<T extends CryptographicKey | Multikey> {
 * @returns The fetched key or `null` if the key is not found.
 * @since 1.3.0
 */
export async function fetchKey<T extends CryptographicKey | Multikey>(
export function fetchKey<T extends CryptographicKey | Multikey>(
  keyId: URL | string,
  // deno-lint-ignore no-explicit-any
  cls: (new (...args: any[]) => T) & {
    fromJsonLd(
      jsonLd: unknown,
      options: {
        documentLoader?: DocumentLoader;
        contextLoader?: DocumentLoader;
        tracerProvider?: TracerProvider;
      },
    ): Promise<T>;
  },
  options: FetchKeyOptions = {},
): Promise<FetchKeyResult<T>> {
  const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
  const tracer = tracerProvider.getTracer(metadata.name, metadata.version);
  keyId = typeof keyId === "string" ? new URL(keyId) : keyId;
  return tracer.startActiveSpan(
    "activitypub.fetch_key",
    {
      kind: SpanKind.CLIENT,
      attributes: {
        "http.method": "GET",
        "url.full": keyId.href,
        "url.scheme": keyId.protocol.replace(/:$/, ""),
        "url.domain": keyId.hostname,
        "url.path": keyId.pathname,
        "url.query": keyId.search.replace(/^\?/, ""),
        "url.fragment": keyId.hash.replace(/^#/, ""),
      },
    },
    async (span) => {
      try {
        const result = await fetchKeyInternal(keyId, cls, options);
        span.setAttribute("activitypub.actor.key.cached", result.cached);
        return result;
      } catch (e) {
        span.setStatus({ code: SpanStatusCode.ERROR, message: String(e) });
        throw e;
      } finally {
        span.end();
      }
    },
  );
}

async function fetchKeyInternal<T extends CryptographicKey | Multikey>(
  keyId: URL | string,
  // deno-lint-ignore no-explicit-any
  cls: (new (...args: any[]) => T) & {