@fedify/fedify 0.10.0-dev.200 → 0.10.0-dev.203

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGES.md CHANGED
@@ -95,6 +95,11 @@ To be released.
95
95
  - Added `VerifyProofOptions` interface.
96
96
  - Added `fetchKey()` function.
97
97
  - Added `FetchKeyOptions` interface.
98
+ - Added `SenderKeyPair` interface.
99
+ - The type of `Federation.sendActivity()` method's first parameter became
100
+ `SenderKeyPair[]` (was `{ keyId: URL; privateKey: CryptoKey }`).
101
+ - The `Context.sendActivity()` method's first parameter now accepts
102
+ `SenderKeyPair[]` as well.
98
103
 
99
104
  - Added `context` option to `Object.toJsonLd()` method. This applies to
100
105
  any subclasses of the `Object` class too.
@@ -123,6 +128,15 @@ To be released.
123
128
  [x-forwarded-fetch]: https://github.com/dahlia/x-forwarded-fetch
124
129
 
125
130
 
131
+ Version 0.9.1
132
+ -------------
133
+
134
+ Released on June 13, 2024.
135
+
136
+ - Fixed a bug of Activity Vocabulary API that `clone()` method of Vocabulary
137
+ classes had not cloned the `id` property from the source object.
138
+
139
+
126
140
  Version 0.9.0
127
141
  -------------
128
142
 
@@ -98,7 +98,7 @@ export class Federation {
98
98
  async #listenQueue(message) {
99
99
  const logger = getLogger(["fedify", "federation", "outbox"]);
100
100
  const logData = {
101
- keyId: message.keyId,
101
+ keyIds: message.keys.map((pair) => pair.keyId),
102
102
  inbox: message.inbox,
103
103
  activity: message.activity,
104
104
  trial: message.trial,
@@ -106,16 +106,28 @@ export class Federation {
106
106
  };
107
107
  let activity = null;
108
108
  try {
109
- const keyId = new URL(message.keyId);
110
- const privateKey = await importJwk(message.privateKey, "private");
111
- const documentLoader = this.#authenticatedDocumentLoaderFactory({ keyId, privateKey });
109
+ const keys = [];
110
+ let rsaKeyPair = null;
111
+ for (const { keyId, privateKey } of message.keys) {
112
+ const pair = {
113
+ keyId: new URL(keyId),
114
+ privateKey: await importJwk(privateKey, "private"),
115
+ };
116
+ if (rsaKeyPair == null &&
117
+ pair.privateKey.algorithm.name === "RSASSA-PKCS1-v1_5") {
118
+ rsaKeyPair = pair;
119
+ }
120
+ keys.push(pair);
121
+ }
122
+ const documentLoader = rsaKeyPair == null
123
+ ? this.#documentLoader
124
+ : this.#authenticatedDocumentLoaderFactory(rsaKeyPair);
112
125
  activity = await Activity.fromJsonLd(message.activity, {
113
126
  documentLoader,
114
127
  contextLoader: this.#contextLoader,
115
128
  });
116
129
  await sendActivity({
117
- keyId,
118
- privateKey,
130
+ keys,
119
131
  activity,
120
132
  inbox: new URL(message.inbox),
121
133
  contextLoader: this.#contextLoader,
@@ -578,14 +590,20 @@ export class Federation {
578
590
  * Sends an activity to recipients' inboxes. You would typically use
579
591
  * {@link Context.sendActivity} instead of this method.
580
592
  *
581
- * @param sender The sender's key pair.
593
+ * @param keys The sender's key pairs.
582
594
  * @param recipients The recipients of the activity.
583
595
  * @param activity The activity to send.
584
596
  * @param options Options for sending the activity.
585
597
  * @throws {TypeError} If the activity to send does not have an actor.
586
598
  */
587
- async sendActivity({ keyId, privateKey }, recipients, activity, { preferSharedInbox, immediate, excludeBaseUris, collectionSync } = {}) {
599
+ async sendActivity(keys, recipients, activity, { preferSharedInbox, immediate, excludeBaseUris, collectionSync } = {}) {
588
600
  const logger = getLogger(["fedify", "federation", "outbox"]);
601
+ if (keys.length < 1) {
602
+ throw new TypeError("The sender's keys must not be empty.");
603
+ }
604
+ for (const { privateKey } of keys) {
605
+ validateCryptoKey(privateKey, "private");
606
+ }
589
607
  if (activity.actorId == null) {
590
608
  logger.error("Activity {activityId} to send does not have an actor.", { activity, activityId: activity?.id?.href });
591
609
  throw new TypeError("The activity to send must have at least one actor property.");
@@ -596,7 +614,6 @@ export class Federation {
596
614
  id: new URL(`urn:uuid:${dntShim.crypto.randomUUID()}`),
597
615
  });
598
616
  }
599
- validateCryptoKey(privateKey, "private");
600
617
  const inboxes = extractInboxes({
601
618
  recipients: Array.isArray(recipients) ? recipients : [recipients],
602
619
  preferSharedInbox,
@@ -618,8 +635,7 @@ export class Federation {
618
635
  const promises = [];
619
636
  for (const inbox in inboxes) {
620
637
  promises.push(sendActivity({
621
- keyId,
622
- privateKey,
638
+ keys,
623
639
  activity,
624
640
  inbox: new URL(inbox),
625
641
  contextLoader: this.#contextLoader,
@@ -632,15 +648,18 @@ export class Federation {
632
648
  return;
633
649
  }
634
650
  logger.debug("Enqueuing activity {activityId} to send later.", { activityId: activity.id?.href, activity });
635
- const privateKeyJwk = await exportJwk(privateKey);
651
+ const keyJwkPairs = [];
652
+ for (const { keyId, privateKey } of keys) {
653
+ const privateKeyJwk = await exportJwk(privateKey);
654
+ keyJwkPairs.push({ keyId: keyId.href, privateKey: privateKeyJwk });
655
+ }
636
656
  const activityJson = await activity.toJsonLd({
637
657
  contextLoader: this.#contextLoader,
638
658
  });
639
659
  for (const inbox in inboxes) {
640
660
  const message = {
641
661
  type: "outbox",
642
- keyId: keyId.href,
643
- privateKey: privateKeyJwk,
662
+ keys: keyJwkPairs,
644
663
  activity: activityJson,
645
664
  inbox,
646
665
  trial: 0,
@@ -1053,16 +1072,21 @@ class ContextImpl {
1053
1072
  return this.#authenticatedDocumentLoaderFactory(identity);
1054
1073
  }
1055
1074
  async sendActivity(sender, recipients, activity, options = {}) {
1056
- let senderPair;
1075
+ let keys;
1057
1076
  if ("handle" in sender) {
1058
- const keyPair = await this.getRsaKeyPairFromHandle(sender.handle);
1059
- if (keyPair == null) {
1060
- throw new Error(`No key pair found for actor ${sender.handle}`);
1077
+ keys = await this.getKeyPairsFromHandle(this.#url, this.data, sender.handle);
1078
+ if (keys.length < 1) {
1079
+ throw new Error(`No key pair found for actor ${JSON.stringify(sender.handle)}.`);
1080
+ }
1081
+ }
1082
+ else if (Array.isArray(sender)) {
1083
+ if (sender.length < 1) {
1084
+ throw new Error("The sender's key pairs are empty.");
1061
1085
  }
1062
- senderPair = keyPair;
1086
+ keys = sender;
1063
1087
  }
1064
1088
  else {
1065
- senderPair = sender;
1089
+ keys = [sender];
1066
1090
  }
1067
1091
  const opts = { ...options };
1068
1092
  let expandedRecipients;
@@ -1085,7 +1109,7 @@ class ContextImpl {
1085
1109
  else {
1086
1110
  expandedRecipients = [recipients];
1087
1111
  }
1088
- return await this.#federation.sendActivity(senderPair, expandedRecipients, activity, opts);
1112
+ return await this.#federation.sendActivity(keys, expandedRecipients, activity, opts);
1089
1113
  }
1090
1114
  getFollowers(_handle) {
1091
1115
  throw new Error('"followers" recipients are not supported in Context. ' +
@@ -1,5 +1,7 @@
1
1
  import { getLogger } from "@logtape/logtape";
2
2
  import { signRequest } from "../sig/http.js";
3
+ import { validateCryptoKey } from "../sig/key.js";
4
+ import { signObject } from "../sig/proof.js";
3
5
  /**
4
6
  * Extracts the inbox URLs from recipients.
5
7
  * @param parameters The parameters to extract the inboxes.
@@ -30,11 +32,40 @@ export function extractInboxes({ recipients, preferSharedInbox, excludeBaseUris
30
32
  * See also {@link SendActivityParameters}.
31
33
  * @throws {Error} If the activity fails to send.
32
34
  */
33
- export async function sendActivity({ activity, privateKey, keyId, inbox, contextLoader, headers, }) {
35
+ export async function sendActivity({ activity, keys, inbox, contextLoader, documentLoader, headers, }) {
34
36
  const logger = getLogger(["fedify", "federation", "outbox"]);
37
+ if (activity.id == null) {
38
+ throw new TypeError("The activity to send must have an id.");
39
+ }
35
40
  if (activity.actorId == null) {
36
41
  throw new TypeError("The activity to send must have at least one actor property.");
37
42
  }
43
+ else if (keys.length < 1) {
44
+ throw new TypeError("The keys must not be empty.");
45
+ }
46
+ const activityId = activity.id.href;
47
+ let proofCreated = false;
48
+ for (const { keyId, privateKey } of keys) {
49
+ validateCryptoKey(privateKey, "private");
50
+ if (privateKey.algorithm.name === "Ed25519") {
51
+ activity = await signObject(activity, privateKey, keyId, {
52
+ documentLoader,
53
+ contextLoader,
54
+ });
55
+ proofCreated = true;
56
+ }
57
+ }
58
+ if (!proofCreated) {
59
+ logger.warn("No supported key found to create a proof for the activity {activityId}. " +
60
+ "The activity will be sent without a proof. " +
61
+ "In order to create a proof, at least one Ed25519 key must be provided.", {
62
+ activityId,
63
+ keys: keys.map((pair) => ({
64
+ keyId: pair.keyId.href,
65
+ privateKey: pair.privateKey,
66
+ })),
67
+ });
68
+ }
38
69
  const jsonLd = await activity.toJsonLd({ contextLoader });
39
70
  headers = new Headers(headers);
40
71
  headers.set("Content-Type", "application/activity+json");
@@ -43,7 +74,26 @@ export async function sendActivity({ activity, privateKey, keyId, inbox, context
43
74
  headers,
44
75
  body: JSON.stringify(jsonLd),
45
76
  });
46
- request = await signRequest(request, privateKey, keyId);
77
+ let requestSigned = false;
78
+ for (const { privateKey, keyId } of keys) {
79
+ if (privateKey.algorithm.name === "RSASSA-PKCS1-v1_5") {
80
+ request = await signRequest(request, privateKey, keyId);
81
+ requestSigned = true;
82
+ break;
83
+ }
84
+ }
85
+ if (!requestSigned) {
86
+ logger.warn("No supported key found to sign the request to {inbox}. " +
87
+ "The request will be sent without a signature. " +
88
+ "In order to sign the request, at least one RSASSA-PKCS1-v1_5 key " +
89
+ "must be provided.", {
90
+ inbox: inbox.href,
91
+ keys: keys.map((pair) => ({
92
+ keyId: pair.keyId.href,
93
+ privateKey: pair.privateKey,
94
+ })),
95
+ });
96
+ }
47
97
  const response = await fetch(request);
48
98
  if (!response.ok) {
49
99
  let error;
@@ -55,13 +105,13 @@ export async function sendActivity({ activity, privateKey, keyId, inbox, context
55
105
  }
56
106
  logger.error("Failed to send activity {activityId} to {inbox} ({status} " +
57
107
  "{statusText}):\n{error}", {
58
- activityId: activity.id?.href,
108
+ activityId,
59
109
  inbox: inbox.href,
60
110
  status: response.status,
61
111
  statusText: response.statusText,
62
112
  error,
63
113
  });
64
- throw new Error(`Failed to send activity ${activity?.id?.href} to ${inbox.href} ` +
114
+ throw new Error(`Failed to send activity ${activityId} to ${inbox.href} ` +
65
115
  `(${response.status} ${response.statusText}):\n${error}`);
66
116
  }
67
117
  }
@@ -0,0 +1,182 @@
1
+ import * as dntShim from "../_dnt.shims.js";
2
+ // @ts-ignore: json-canon is not typed
3
+ import serialize from "json-canon";
4
+ import { DataIntegrityProof, Object } from "../vocab/vocab.js";
5
+ import { fetchKey, validateCryptoKey } from "./key.js";
6
+ import { Activity, Multikey } from "../vocab/mod.js";
7
+ import { getLogger } from "@logtape/logtape";
8
+ const logger = getLogger(["fedify", "sig", "proof"]);
9
+ /**
10
+ * Creates a proof for the given object.
11
+ * @param object The object to create a proof for.
12
+ * @param privateKey The private key to sign the proof with.
13
+ * @param keyId The key ID to use in the proof. It will be used by the verifier.
14
+ * @param options Additional options. See also {@link CreateProofOptions}.
15
+ * @returns The created proof.
16
+ * @throws {TypeError} If the private key is invalid or unsupported.
17
+ * @since 0.10.0
18
+ */
19
+ export async function createProof(object, privateKey, keyId, { contextLoader, context, created } = {}) {
20
+ validateCryptoKey(privateKey, "private");
21
+ if (privateKey.algorithm.name !== "Ed25519") {
22
+ throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name);
23
+ }
24
+ const objectWithoutProofs = object.clone({ proofs: [] });
25
+ const compactMsg = await objectWithoutProofs.toJsonLd({
26
+ contextLoader,
27
+ context,
28
+ });
29
+ const msgCanon = serialize(compactMsg);
30
+ const encoder = new TextEncoder();
31
+ const msgBytes = encoder.encode(msgCanon);
32
+ const msgDigest = await dntShim.crypto.subtle.digest("SHA-256", msgBytes);
33
+ created ??= dntShim.Temporal.Now.instant();
34
+ const proofConfig = {
35
+ // The below commented out line is needed according to section 3.3.1 of
36
+ // the Data Integrity EdDSA Cryptosuites v1.0 spec, the FEP-8b32 spec does
37
+ // not reflect this step; however, the FEP-8b32 spec will be updated to
38
+ // be consistent with the Data Integrity EdDSA Cryptosuites v1.0 spec
39
+ // some time soon. Before that happens, the below line is commented out.
40
+ // See also: https://socialhub.activitypub.rocks/t/fep-8b32-object-integrity-proofs/2725/91?u=hongminhee
41
+ // "@context": (compactMsg as any)["@context"],
42
+ type: "DataIntegrityProof",
43
+ cryptosuite: "eddsa-jcs-2022",
44
+ verificationMethod: keyId.href,
45
+ proofPurpose: "assertionMethod",
46
+ created: created.toString(),
47
+ };
48
+ const proofCanon = serialize(proofConfig);
49
+ const proofBytes = encoder.encode(proofCanon);
50
+ const proofDigest = await dntShim.crypto.subtle.digest("SHA-256", proofBytes);
51
+ const digest = new Uint8Array(proofDigest.byteLength + msgDigest.byteLength);
52
+ digest.set(new Uint8Array(proofDigest), 0);
53
+ digest.set(new Uint8Array(msgDigest), proofDigest.byteLength);
54
+ const sig = await dntShim.crypto.subtle.sign("Ed25519", privateKey, digest);
55
+ return new DataIntegrityProof({
56
+ cryptosuite: "eddsa-jcs-2022",
57
+ verificationMethod: keyId,
58
+ proofPurpose: "assertionMethod",
59
+ created: created ?? dntShim.Temporal.Now.instant(),
60
+ proofValue: new Uint8Array(sig),
61
+ });
62
+ }
63
+ /**
64
+ * Signs the given object with the private key and returns the signed object.
65
+ * @param object The object to create a proof for.
66
+ * @param privateKey The private key to sign the proof with.
67
+ * @param keyId The key ID to use in the proof. It will be used by the verifier.
68
+ * @param options Additional options. See also {@link SignObjectOptions}.
69
+ * @returns The signed object.
70
+ * @throws {TypeError} If the private key is invalid or unsupported.
71
+ * @since 0.10.0
72
+ */
73
+ export async function signObject(object, privateKey, keyId, options = {}) {
74
+ const existingProofs = [];
75
+ for await (const proof of object.getProofs(options)) {
76
+ existingProofs.push(proof);
77
+ }
78
+ const proof = await createProof(object, privateKey, keyId, options);
79
+ return object.clone({ proofs: [...existingProofs, proof] });
80
+ }
81
+ /**
82
+ * Verifies the given proof for the object.
83
+ * @param jsonLd The JSON-LD object to verify the proof for. If it contains
84
+ * any proofs, they will be ignored.
85
+ * @param proof The proof to verify.
86
+ * @param options Additional options. See also {@link VerifyProofOptions}.
87
+ * @returns The public key that was used to sign the proof, or `null` if the
88
+ * proof is invalid.
89
+ * @since 0.10.0
90
+ */
91
+ export async function verifyProof(jsonLd, proof, options = {}) {
92
+ if (typeof jsonLd !== "object" ||
93
+ proof.cryptosuite !== "eddsa-jcs-2022" ||
94
+ proof.verificationMethodId == null ||
95
+ proof.proofPurpose !== "assertionMethod" ||
96
+ proof.proofValue == null ||
97
+ proof.created == null)
98
+ return null;
99
+ const publicKeyPromise = fetchKey(proof.verificationMethodId, Multikey, options);
100
+ const proofConfig = {
101
+ // The below commented out line is needed according to section 3.3.1 of
102
+ // the Data Integrity EdDSA Cryptosuites v1.0 spec, the FEP-8b32 spec does
103
+ // not reflect this step; however, the FEP-8b32 spec will be updated to
104
+ // be consistent with the Data Integrity EdDSA Cryptosuites v1.0 spec
105
+ // some time soon. Before that happens, the below line is commented out.
106
+ // See also: https://socialhub.activitypub.rocks/t/fep-8b32-object-integrity-proofs/2725/91?u=hongminhee
107
+ // "@context": (jsonLd as any)["@context"],
108
+ type: "DataIntegrityProof",
109
+ cryptosuite: proof.cryptosuite,
110
+ verificationMethod: proof.verificationMethodId.href,
111
+ proofPurpose: proof.proofPurpose,
112
+ created: proof.created.toString(),
113
+ };
114
+ const proofCanon = serialize(proofConfig);
115
+ const encoder = new TextEncoder();
116
+ const proofBytes = encoder.encode(proofCanon);
117
+ const proofDigest = await dntShim.crypto.subtle.digest("SHA-256", proofBytes);
118
+ const msg = { ...jsonLd };
119
+ if ("proof" in msg)
120
+ delete msg.proof;
121
+ const msgCanon = serialize(msg);
122
+ const msgBytes = encoder.encode(msgCanon);
123
+ const msgDigest = await dntShim.crypto.subtle.digest("SHA-256", msgBytes);
124
+ const digest = new Uint8Array(proofDigest.byteLength + msgDigest.byteLength);
125
+ digest.set(new Uint8Array(proofDigest), 0);
126
+ digest.set(new Uint8Array(msgDigest), proofDigest.byteLength);
127
+ let publicKey;
128
+ try {
129
+ publicKey = await publicKeyPromise;
130
+ }
131
+ catch (error) {
132
+ logger.debug("Failed to get the key (verificationMethod) for the proof:\n{proof}", { proof, error });
133
+ return null;
134
+ }
135
+ if (publicKey == null || publicKey.publicKey.algorithm.name !== "Ed25519") {
136
+ logger.debug("The key (verificationMethod) for the proof is not a valid Ed25519 " +
137
+ "key:\n{keyId}", { proof, keyId: proof.verificationMethodId.href });
138
+ return null;
139
+ }
140
+ const verified = await dntShim.crypto.subtle.verify("Ed25519", publicKey.publicKey, proof.proofValue, digest);
141
+ if (!verified) {
142
+ logger.debug("The proof's signature is invalid.", { proof });
143
+ return null;
144
+ }
145
+ return publicKey;
146
+ }
147
+ /**
148
+ * Verifies the given object. It will verify all the proofs in the object,
149
+ * and succeed only if all the proofs are valid and all attributions and
150
+ * actors are authenticated by the proofs.
151
+ * @param jsonLd The JSON-LD object to verify. It's assumed that the object
152
+ * is a compacted JSON-LD representation of an {@link Object}
153
+ * with `@context`.
154
+ * @param options Additional options. See also {@link VerifyObjectOptions}.
155
+ * @returns The object if it's verified, or `null` if it's not.
156
+ * @throws {TypeError} If the object is invalid or unsupported.
157
+ * @since 0.10.0
158
+ */
159
+ export async function verifyObject(jsonLd, options = {}) {
160
+ const logger = getLogger(["fedify", "sig", "proof"]);
161
+ const object = await Object.fromJsonLd(jsonLd, options);
162
+ const attributions = new Set(object.attributionIds.map((uri) => uri.href));
163
+ if (object instanceof Activity) {
164
+ for (const uri of object.actorIds)
165
+ attributions.add(uri.href);
166
+ }
167
+ for await (const proof of object.getProofs(options)) {
168
+ const key = await verifyProof(jsonLd, proof, options);
169
+ if (key === null)
170
+ return null;
171
+ if (key.controllerId == null) {
172
+ logger.debug("Key {keyId} does not have a controller.", { keyId: key.id?.href });
173
+ continue;
174
+ }
175
+ attributions.delete(key.controllerId.href);
176
+ }
177
+ if (attributions.size > 0) {
178
+ logger.debug("Some attributions are not authenticated by the proofs: {attributions}.", { attributions: [...attributions] });
179
+ return null;
180
+ }
181
+ return object;
182
+ }
@@ -288,7 +288,7 @@ export class Object {
288
288
  */
289
289
  clone(values = {}, options = {}) {
290
290
  // @ts-ignore: this.constructor is not recognized as a constructor, but it is.
291
- const clone = new this.constructor({ id: values.id }, options);
291
+ const clone = new this.constructor({ id: values.id ?? this.id }, options);
292
292
  clone.#_49BipA5dq9eoH8LX8xdsVumveTca = this.#_49BipA5dq9eoH8LX8xdsVumveTca;
293
293
  if ("attachments" in values && values.attachments != null) {
294
294
  clone.#_49BipA5dq9eoH8LX8xdsVumveTca = values.attachments;
@@ -3625,7 +3625,7 @@ export class PropertyValue {
3625
3625
  */
3626
3626
  clone(values = {}, options = {}) {
3627
3627
  // @ts-ignore: this.constructor is not recognized as a constructor, but it is.
3628
- const clone = new this.constructor({ id: values.id }, options);
3628
+ const clone = new this.constructor({ id: values.id ?? this.id }, options);
3629
3629
  clone.#_4ZHbBuK7PrsvGgrjM8wgc6KMWjav = this.#_4ZHbBuK7PrsvGgrjM8wgc6KMWjav;
3630
3630
  if ("name" in values && values.name != null) {
3631
3631
  clone.#_4ZHbBuK7PrsvGgrjM8wgc6KMWjav = [values.name];
@@ -3867,7 +3867,7 @@ export class DataIntegrityProof {
3867
3867
  */
3868
3868
  clone(values = {}, options = {}) {
3869
3869
  // @ts-ignore: this.constructor is not recognized as a constructor, but it is.
3870
- const clone = new this.constructor({ id: values.id }, options);
3870
+ const clone = new this.constructor({ id: values.id ?? this.id }, options);
3871
3871
  clone.#_3RurJsa7tnptyqMFR5hDGcP9pMs5 = this.#_3RurJsa7tnptyqMFR5hDGcP9pMs5;
3872
3872
  if ("cryptosuite" in values && values.cryptosuite != null) {
3873
3873
  clone.#_3RurJsa7tnptyqMFR5hDGcP9pMs5 = [values.cryptosuite];
@@ -4235,7 +4235,7 @@ export class CryptographicKey {
4235
4235
  */
4236
4236
  clone(values = {}, options = {}) {
4237
4237
  // @ts-ignore: this.constructor is not recognized as a constructor, but it is.
4238
- const clone = new this.constructor({ id: values.id }, options);
4238
+ const clone = new this.constructor({ id: values.id ?? this.id }, options);
4239
4239
  clone.#_5UJq9NDh3ZHgswFwwdVxQvJxdx2 = this.#_5UJq9NDh3ZHgswFwwdVxQvJxdx2;
4240
4240
  if ("owner" in values && values.owner != null) {
4241
4241
  clone.#_5UJq9NDh3ZHgswFwwdVxQvJxdx2 = [values.owner];
@@ -4543,7 +4543,7 @@ export class Multikey {
4543
4543
  */
4544
4544
  clone(values = {}, options = {}) {
4545
4545
  // @ts-ignore: this.constructor is not recognized as a constructor, but it is.
4546
- const clone = new this.constructor({ id: values.id }, options);
4546
+ const clone = new this.constructor({ id: values.id ?? this.id }, options);
4547
4547
  clone.#_2yr3eUBTP6cNcyaxKzAXWjFsnGzN = this.#_2yr3eUBTP6cNcyaxKzAXWjFsnGzN;
4548
4548
  if ("controller" in values && values.controller != null) {
4549
4549
  clone.#_2yr3eUBTP6cNcyaxKzAXWjFsnGzN = [values.controller];
@@ -9103,7 +9103,7 @@ export class Endpoints {
9103
9103
  */
9104
9104
  clone(values = {}, options = {}) {
9105
9105
  // @ts-ignore: this.constructor is not recognized as a constructor, but it is.
9106
- const clone = new this.constructor({ id: values.id }, options);
9106
+ const clone = new this.constructor({ id: values.id ?? this.id }, options);
9107
9107
  clone.#_2JCYDbSxEHCCLdBYed33cCETfGyR = this.#_2JCYDbSxEHCCLdBYed33cCETfGyR;
9108
9108
  if ("proxyUrl" in values && values.proxyUrl != null) {
9109
9109
  clone.#_2JCYDbSxEHCCLdBYed33cCETfGyR = [values.proxyUrl];
@@ -11120,7 +11120,7 @@ export class Link {
11120
11120
  */
11121
11121
  clone(values = {}, options = {}) {
11122
11122
  // @ts-ignore: this.constructor is not recognized as a constructor, but it is.
11123
- const clone = new this.constructor({ id: values.id }, options);
11123
+ const clone = new this.constructor({ id: values.id ?? this.id }, options);
11124
11124
  clone.#_pVjLsybKQdmkjuU7MHjiVmNnuj7 = this.#_pVjLsybKQdmkjuU7MHjiVmNnuj7;
11125
11125
  if ("href" in values && values.href != null) {
11126
11126
  clone.#_pVjLsybKQdmkjuU7MHjiVmNnuj7 = [values.href];
@@ -7,10 +7,8 @@ import { Link as LinkObject } from "../vocab/mod.js";
7
7
  * @returns The response to the request.
8
8
  */
9
9
  export async function handleWebFinger(request, { context, actorDispatcher, onNotFound, }) {
10
- if (actorDispatcher == null) {
11
- const response = onNotFound(request);
12
- return response instanceof Promise ? await response : response;
13
- }
10
+ if (actorDispatcher == null)
11
+ return await onNotFound(request);
14
12
  const resource = context.url.searchParams.get("resource");
15
13
  if (resource == null) {
16
14
  return new Response("Missing resource parameter.", { status: 400 });
@@ -30,20 +28,16 @@ export async function handleWebFinger(request, { context, actorDispatcher, onNot
30
28
  if (uriParsed?.type != "actor") {
31
29
  const match = /^acct:([^@]+)@([^@]+)$/.exec(resource);
32
30
  if (match == null || match[2] != context.url.host) {
33
- const response = onNotFound(request);
34
- return response instanceof Promise ? await response : response;
31
+ return await onNotFound(request);
35
32
  }
36
33
  handle = match[1];
37
34
  }
38
35
  else {
39
36
  handle = uriParsed.handle;
40
37
  }
41
- const key = await context.getActorKey(handle);
42
- const actor = await actorDispatcher(context, handle, key);
43
- if (actor == null) {
44
- const response = onNotFound(request);
45
- return response instanceof Promise ? await response : response;
46
- }
38
+ const actor = await context.getActor(handle);
39
+ if (actor == null)
40
+ return await onNotFound(request);
47
41
  const links = [
48
42
  {
49
43
  rel: "self",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "0.10.0-dev.200+e581ce37",
3
+ "version": "0.10.0-dev.203+43162fc2",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -85,6 +85,7 @@
85
85
  "@logtape/logtape": "^0.4.0",
86
86
  "@phensley/language-tag": "^1.8.0",
87
87
  "asn1js": "^3.0.5",
88
+ "json-canon": "^1.0.1",
88
89
  "jsonld": "^8.3.2",
89
90
  "multibase": "^4.0.6",
90
91
  "multicodec": "^3.2.1",
@@ -100,8 +101,7 @@
100
101
  "@types/node": "^20.9.0",
101
102
  "picocolors": "^1.0.0",
102
103
  "@cfworker/json-schema": "^1.12.8",
103
- "fast-check": "^3.18.0",
104
- "json-canon": "^1.0.1"
104
+ "fast-check": "^3.18.0"
105
105
  },
106
106
  "_generatedBy": "dnt@dev"
107
107
  }
@@ -4,6 +4,7 @@ import * as dntShim from "../_dnt.shims.js";
4
4
  import type { DocumentLoader } from "../runtime/docloader.js";
5
5
  import type { Actor, Recipient } from "../vocab/actor.js";
6
6
  import type { Activity, CryptographicKey, Multikey, Object } from "../vocab/mod.js";
7
+ import type { SenderKeyPair } from "./send.js";
7
8
  /**
8
9
  * A context.
9
10
  */
@@ -138,15 +139,12 @@ export interface Context<TContextData> {
138
139
  }): DocumentLoader;
139
140
  /**
140
141
  * Sends an activity to recipients' inboxes.
141
- * @param sender The sender's handle or the sender's key pair.
142
+ * @param sender The sender's handle or the sender's key pair(s).
142
143
  * @param recipients The recipients of the activity.
143
144
  * @param activity The activity to send.
144
145
  * @param options Options for sending the activity.
145
146
  */
146
- sendActivity(sender: {
147
- keyId: URL;
148
- privateKey: dntShim.CryptoKey;
149
- } | {
147
+ sendActivity(sender: SenderKeyPair | SenderKeyPair[] | {
150
148
  handle: string;
151
149
  }, recipients: Recipient | Recipient[], activity: Activity, options?: SendActivityOptions): Promise<void>;
152
150
  }
@@ -212,15 +210,12 @@ export interface RequestContext<TContextData> extends Context<TContextData> {
212
210
  getSignedKeyOwner(): Promise<Actor | null>;
213
211
  /**
214
212
  * Sends an activity to recipients' inboxes.
215
- * @param sender The sender's handle or the sender's key pair.
213
+ * @param sender The sender's handle or the sender's key pair(s).
216
214
  * @param recipients The recipients of the activity.
217
215
  * @param activity The activity to send.
218
216
  * @param options Options for sending the activity.
219
217
  */
220
- sendActivity(sender: {
221
- keyId: URL;
222
- privateKey: dntShim.CryptoKey;
223
- } | {
218
+ sendActivity(sender: SenderKeyPair | SenderKeyPair[] | {
224
219
  handle: string;
225
220
  }, recipients: Recipient | Recipient[], activity: Activity, options?: SendActivityOptions): Promise<void>;
226
221
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/federation/context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/federation/context.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ import type { ActorDispatcher, ActorKeyPairDispatcher, ActorKeyPairsDispatcher,
8
8
  import type { Context, RequestContext, SendActivityOptions } from "./context.js";
9
9
  import type { KvKey, KvStore } from "./kv.js";
10
10
  import type { MessageQueue } from "./mq.js";
11
+ import { type SenderKeyPair } from "./send.js";
11
12
  /**
12
13
  * Parameters for initializing a {@link Federation} instance.
13
14
  */
@@ -346,16 +347,13 @@ export declare class Federation<TContextData> {
346
347
  * Sends an activity to recipients' inboxes. You would typically use
347
348
  * {@link Context.sendActivity} instead of this method.
348
349
  *
349
- * @param sender The sender's key pair.
350
+ * @param keys The sender's key pairs.
350
351
  * @param recipients The recipients of the activity.
351
352
  * @param activity The activity to send.
352
353
  * @param options Options for sending the activity.
353
354
  * @throws {TypeError} If the activity to send does not have an actor.
354
355
  */
355
- sendActivity({ keyId, privateKey }: {
356
- keyId: URL;
357
- privateKey: dntShim.CryptoKey;
358
- }, recipients: Recipient | Recipient[], activity: Activity, { preferSharedInbox, immediate, excludeBaseUris, collectionSync }?: SendActivityInternalOptions): Promise<void>;
356
+ sendActivity(keys: SenderKeyPair[], recipients: Recipient | Recipient[], activity: Activity, { preferSharedInbox, immediate, excludeBaseUris, collectionSync }?: SendActivityInternalOptions): Promise<void>;
359
357
  /**
360
358
  * Handles a request related to federation. If a request is not related to
361
359
  * federation, the `onNotFound` or `onNotAcceptable` callback is called.