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

Sign up to get free protection for your applications and to get access to all the features.
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.