@fedify/fedify 1.3.0-dev.564 → 1.3.0-dev.568
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 +15 -0
- package/esm/deno.js +1 -1
- package/esm/federation/handler.js +2 -0
- package/esm/federation/middleware.js +11 -2
- package/esm/federation/send.js +2 -2
- package/esm/sig/http.js +10 -9
- package/esm/sig/key.js +9 -3
- package/esm/sig/ld.js +83 -22
- package/esm/sig/owner.js +10 -1
- package/esm/sig/proof.js +73 -8
- package/esm/vocab/lookup.js +1 -0
- package/esm/vocab/vocab.js +7850 -2957
- package/package.json +1 -1
- package/types/federation/context.d.ts +6 -0
- package/types/federation/context.d.ts.map +1 -1
- package/types/federation/handler.d.ts.map +1 -1
- package/types/federation/middleware.d.ts +1 -0
- package/types/federation/middleware.d.ts.map +1 -1
- package/types/federation/send.d.ts +8 -1
- package/types/federation/send.d.ts.map +1 -1
- package/types/sig/key.d.ts +9 -1
- package/types/sig/key.d.ts.map +1 -1
- package/types/sig/ld.d.ts +13 -0
- package/types/sig/ld.d.ts.map +1 -1
- package/types/sig/owner.d.ts +16 -0
- package/types/sig/owner.d.ts.map +1 -1
- package/types/sig/proof.d.ts +14 -2
- package/types/sig/proof.d.ts.map +1 -1
- package/types/vocab/lookup.d.ts.map +1 -1
- package/types/vocab/vocab.d.ts +1015 -66
- package/types/vocab/vocab.d.ts.map +1 -1
package/CHANGES.md
CHANGED
@@ -61,6 +61,7 @@ To be released.
|
|
61
61
|
|
62
62
|
- Fedify now supports OpenTelemetry for tracing. [[#170]]
|
63
63
|
|
64
|
+
- Added `Context.tracerProvider` property.
|
64
65
|
- Added `CreateFederationOptions.tracerProvider` option.
|
65
66
|
- Added `LookupWebFingerOptions.tracerProvider` option.
|
66
67
|
- Added `LookupObjectOptions.tracerProvider` option.
|
@@ -68,6 +69,20 @@ To be released.
|
|
68
69
|
- Added `VerifyRequestOptions.tracerProvider` option.
|
69
70
|
- Added `SignRequestOptions` interface.
|
70
71
|
- Added the optional fourth parameter to `signRequest()` function.
|
72
|
+
- Added `VerifyProofOptions.tracerProvider` option.
|
73
|
+
- Added `VerifyObjectOptions.tracerProvider` option.
|
74
|
+
- Added `SignObjectOptions.tracerProvider` option.
|
75
|
+
- Added `VerifySignatureOptions.tracerProvider` option.
|
76
|
+
- Added `VerifyJsonLdOptions.tracerProvider` option.
|
77
|
+
- Added `SignJsonLdOptions.tracerProvider` option.
|
78
|
+
- Added `DoesActorOwnKeyOptions.tracerProvider` option.
|
79
|
+
- Added `GetKeyOwnerOptions.tracerProvider` option.
|
80
|
+
|
81
|
+
- Added `tracerProvider` option to the following Activity Vocabulary APIs:
|
82
|
+
|
83
|
+
- The second parameters of constructors.
|
84
|
+
- The second parameters of `fromJsonLd()` static methods.
|
85
|
+
- The second parameters of `get*()` methods.
|
71
86
|
|
72
87
|
- Added `@fedify/fedify/x/sveltekit` module for integrating with [SvelteKit]
|
73
88
|
hook. [[#171], [#183] by Jiyu Park]
|
package/esm/deno.js
CHANGED
@@ -259,6 +259,7 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
|
|
259
259
|
contextLoader: context.contextLoader,
|
260
260
|
documentLoader: context.documentLoader,
|
261
261
|
keyCache,
|
262
|
+
tracerProvider,
|
262
263
|
});
|
263
264
|
const jsonWithoutSig = detachSignature(json);
|
264
265
|
let activity = null;
|
@@ -273,6 +274,7 @@ export async function handleInbox(request, { recipient, context, inboxContextFac
|
|
273
274
|
contextLoader: context.contextLoader,
|
274
275
|
documentLoader: context.documentLoader,
|
275
276
|
keyCache,
|
277
|
+
tracerProvider,
|
276
278
|
});
|
277
279
|
}
|
278
280
|
catch (error) {
|
@@ -195,6 +195,7 @@ export class FederationImpl {
|
|
195
195
|
activityId: message.activityId,
|
196
196
|
inbox: new URL(message.inbox),
|
197
197
|
headers: new Headers(message.headers),
|
198
|
+
tracerProvider: this.tracerProvider,
|
198
199
|
});
|
199
200
|
}
|
200
201
|
catch (error) {
|
@@ -203,6 +204,7 @@ export class FederationImpl {
|
|
203
204
|
documentLoader: rsaKeyPair == null
|
204
205
|
? this.documentLoader
|
205
206
|
: this.authenticatedDocumentLoaderFactory(rsaKeyPair),
|
207
|
+
tracerProvider: this.tracerProvider,
|
206
208
|
});
|
207
209
|
try {
|
208
210
|
this.onOutboxError?.(error, activity);
|
@@ -927,6 +929,7 @@ export class FederationImpl {
|
|
927
929
|
if (privateKey.algorithm.name === "Ed25519") {
|
928
930
|
activity = await signObject(activity, privateKey, keyId, {
|
929
931
|
contextLoader: this.contextLoader,
|
932
|
+
tracerProvider: this.tracerProvider,
|
930
933
|
});
|
931
934
|
proofCreated = true;
|
932
935
|
}
|
@@ -950,6 +953,7 @@ export class FederationImpl {
|
|
950
953
|
else {
|
951
954
|
jsonLd = await signJsonLd(jsonLd, rsaKey.privateKey, rsaKey.keyId, {
|
952
955
|
contextLoader: this.contextLoader,
|
956
|
+
tracerProvider: this.tracerProvider,
|
953
957
|
});
|
954
958
|
}
|
955
959
|
if (!proofCreated) {
|
@@ -981,6 +985,7 @@ export class FederationImpl {
|
|
981
985
|
headers: collectionSync == null ? undefined : new Headers({
|
982
986
|
"Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox]),
|
983
987
|
}),
|
988
|
+
tracerProvider: this.tracerProvider,
|
984
989
|
}));
|
985
990
|
}
|
986
991
|
await Promise.all(promises);
|
@@ -1297,6 +1302,9 @@ export class ContextImpl {
|
|
1297
1302
|
get contextLoader() {
|
1298
1303
|
return this.federation.contextLoader;
|
1299
1304
|
}
|
1305
|
+
get tracerProvider() {
|
1306
|
+
return this.federation.tracerProvider;
|
1307
|
+
}
|
1300
1308
|
getNodeInfoUri() {
|
1301
1309
|
const path = this.federation.router.build("nodeInfo", {});
|
1302
1310
|
if (path == null) {
|
@@ -1634,7 +1642,7 @@ export class ContextImpl {
|
|
1634
1642
|
documentLoader: options.documentLoader ?? this.documentLoader,
|
1635
1643
|
contextLoader: options.contextLoader ?? this.contextLoader,
|
1636
1644
|
userAgent: options.userAgent ?? this.federation.userAgent,
|
1637
|
-
tracerProvider: options.tracerProvider ?? this.
|
1645
|
+
tracerProvider: options.tracerProvider ?? this.tracerProvider,
|
1638
1646
|
});
|
1639
1647
|
}
|
1640
1648
|
traverseCollection(collection, options = {}) {
|
@@ -1801,7 +1809,7 @@ class RequestContextImpl extends ContextImpl {
|
|
1801
1809
|
return this.#signedKey = await verifyRequest(this.request, {
|
1802
1810
|
...this,
|
1803
1811
|
timeWindow: this.federation.signatureTimeWindow,
|
1804
|
-
tracerProvider: this.
|
1812
|
+
tracerProvider: this.tracerProvider,
|
1805
1813
|
});
|
1806
1814
|
}
|
1807
1815
|
#signedKeyOwner = undefined;
|
@@ -1931,6 +1939,7 @@ export class InboxContextImpl extends ContextImpl {
|
|
1931
1939
|
activity: this.activity,
|
1932
1940
|
activityId: activityId,
|
1933
1941
|
inbox: new URL(inbox),
|
1942
|
+
tracerProvider: this.tracerProvider,
|
1934
1943
|
}));
|
1935
1944
|
}
|
1936
1945
|
await Promise.all(promises);
|
package/esm/federation/send.js
CHANGED
@@ -30,7 +30,7 @@ export function extractInboxes({ recipients, preferSharedInbox, excludeBaseUris
|
|
30
30
|
* See also {@link SendActivityParameters}.
|
31
31
|
* @throws {Error} If the activity fails to send.
|
32
32
|
*/
|
33
|
-
export async function sendActivity({ activity, activityId, keys, inbox, headers, }) {
|
33
|
+
export async function sendActivity({ activity, activityId, keys, inbox, headers, tracerProvider, }) {
|
34
34
|
const logger = getLogger(["fedify", "federation", "outbox"]);
|
35
35
|
headers = new Headers(headers);
|
36
36
|
headers.set("Content-Type", "application/activity+json");
|
@@ -59,7 +59,7 @@ export async function sendActivity({ activity, activityId, keys, inbox, headers,
|
|
59
59
|
});
|
60
60
|
}
|
61
61
|
else {
|
62
|
-
request = await signRequest(request, rsaKey.privateKey, rsaKey.keyId);
|
62
|
+
request = await signRequest(request, rsaKey.privateKey, rsaKey.keyId, { tracerProvider });
|
63
63
|
}
|
64
64
|
let response;
|
65
65
|
try {
|
package/esm/sig/http.js
CHANGED
@@ -29,7 +29,7 @@ export async function signRequest(request, privateKey, keyId, options = {}) {
|
|
29
29
|
for (const [name, value] of signed.headers) {
|
30
30
|
span.setAttribute(ATTR_HTTP_REQUEST_HEADER(name), value);
|
31
31
|
}
|
32
|
-
span.setAttribute("
|
32
|
+
span.setAttribute("http_signatures.key_id", keyId.href);
|
33
33
|
}
|
34
34
|
return signed;
|
35
35
|
}
|
@@ -62,7 +62,7 @@ async function signRequestInternal(request, privateKey, keyId, span) {
|
|
62
62
|
const digest = await dntShim.crypto.subtle.digest("SHA-256", body);
|
63
63
|
headers.set("Digest", `SHA-256=${encodeBase64(digest)}`);
|
64
64
|
if (span.isRecording()) {
|
65
|
-
span.setAttribute("
|
65
|
+
span.setAttribute("http_signatures.digest.sha-256", encodeHex(digest));
|
66
66
|
}
|
67
67
|
}
|
68
68
|
if (!headers.has("Date")) {
|
@@ -80,8 +80,8 @@ async function signRequestInternal(request, privateKey, keyId, span) {
|
|
80
80
|
const sigHeader = `keyId="${keyId.href}",algorithm="rsa-sha256",headers="${headerNames.join(" ")}",signature="${encodeBase64(signature)}"`;
|
81
81
|
headers.set("Signature", sigHeader);
|
82
82
|
if (span.isRecording()) {
|
83
|
-
span.setAttribute("
|
84
|
-
span.setAttribute("
|
83
|
+
span.setAttribute("http_signatures.algorithm", "rsa-sha256");
|
84
|
+
span.setAttribute("http_signatures.signature", encodeHex(signature));
|
85
85
|
}
|
86
86
|
return new Request(request, {
|
87
87
|
headers,
|
@@ -135,7 +135,7 @@ export async function verifyRequest(request, options = {}) {
|
|
135
135
|
}
|
136
136
|
});
|
137
137
|
}
|
138
|
-
async function verifyRequestInternal(request, span, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, } = {}) {
|
138
|
+
async function verifyRequestInternal(request, span, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, tracerProvider, } = {}) {
|
139
139
|
const logger = getLogger(["fedify", "sig", "http"]);
|
140
140
|
if (request.bodyUsed) {
|
141
141
|
logger.error("Failed to verify; the request body is already consumed.", { url: request.url });
|
@@ -184,7 +184,7 @@ async function verifyRequestInternal(request, span, { documentLoader, contextLoa
|
|
184
184
|
return null;
|
185
185
|
}
|
186
186
|
if (span.isRecording()) {
|
187
|
-
span.setAttribute(`
|
187
|
+
span.setAttribute(`http_signatures.digest.${algo}`, encodeHex(digest));
|
188
188
|
}
|
189
189
|
const expectedDigest = await dntShim.crypto.subtle.digest(supportedHashAlgorithms[algo], body);
|
190
190
|
if (!equals(digest, new Uint8Array(expectedDigest))) {
|
@@ -235,15 +235,16 @@ async function verifyRequestInternal(request, span, { documentLoader, contextLoa
|
|
235
235
|
return null;
|
236
236
|
}
|
237
237
|
const { keyId, headers, signature } = sigValues;
|
238
|
-
span?.setAttribute("
|
239
|
-
span?.setAttribute("
|
238
|
+
span?.setAttribute("http_signatures.key_id", keyId);
|
239
|
+
span?.setAttribute("http_signatures.signature", signature);
|
240
240
|
if ("algorithm" in sigValues) {
|
241
|
-
span?.setAttribute("
|
241
|
+
span?.setAttribute("http_signatures.algorithm", sigValues.algorithm);
|
242
242
|
}
|
243
243
|
const { key, cached } = await fetchKey(new URL(keyId), CryptographicKey, {
|
244
244
|
documentLoader,
|
245
245
|
contextLoader,
|
246
246
|
keyCache,
|
247
|
+
tracerProvider,
|
247
248
|
});
|
248
249
|
if (key == null)
|
249
250
|
return null;
|
package/esm/sig/key.js
CHANGED
@@ -106,7 +106,7 @@ export async function importJwk(jwk, type) {
|
|
106
106
|
*/
|
107
107
|
export async function fetchKey(keyId,
|
108
108
|
// deno-lint-ignore no-explicit-any
|
109
|
-
cls, { documentLoader, contextLoader, keyCache } = {}) {
|
109
|
+
cls, { documentLoader, contextLoader, keyCache, tracerProvider } = {}) {
|
110
110
|
const logger = getLogger(["fedify", "sig", "key"]);
|
111
111
|
const cacheKey = typeof keyId === "string" ? new URL(keyId) : keyId;
|
112
112
|
keyId = typeof keyId === "string" ? keyId : keyId.href;
|
@@ -140,6 +140,7 @@ cls, { documentLoader, contextLoader, keyCache } = {}) {
|
|
140
140
|
object = await Object.fromJsonLd(document, {
|
141
141
|
documentLoader,
|
142
142
|
contextLoader,
|
143
|
+
tracerProvider,
|
143
144
|
});
|
144
145
|
}
|
145
146
|
catch (e) {
|
@@ -149,6 +150,7 @@ cls, { documentLoader, contextLoader, keyCache } = {}) {
|
|
149
150
|
object = await cls.fromJsonLd(document, {
|
150
151
|
documentLoader,
|
151
152
|
contextLoader,
|
153
|
+
tracerProvider,
|
152
154
|
});
|
153
155
|
}
|
154
156
|
catch (e) {
|
@@ -166,8 +168,12 @@ cls, { documentLoader, contextLoader, keyCache } = {}) {
|
|
166
168
|
else if (isActor(object)) {
|
167
169
|
// @ts-ignore: cls is either CryptographicKey or Multikey
|
168
170
|
const keys = cls === CryptographicKey
|
169
|
-
? object.getPublicKeys({ documentLoader, contextLoader })
|
170
|
-
: object.getAssertionMethods({
|
171
|
+
? object.getPublicKeys({ documentLoader, contextLoader, tracerProvider })
|
172
|
+
: object.getAssertionMethods({
|
173
|
+
documentLoader,
|
174
|
+
contextLoader,
|
175
|
+
tracerProvider,
|
176
|
+
});
|
171
177
|
for await (const k of keys) {
|
172
178
|
if (k.id?.href === keyId) {
|
173
179
|
key = k;
|
package/esm/sig/ld.js
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
import * as dntShim from "../_dnt.shims.js";
|
2
2
|
import { getLogger } from "@logtape/logtape";
|
3
|
+
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
3
4
|
import { decodeBase64, encodeBase64 } from "../deps/jsr.io/@std/encoding/1.0.5/base64.js";
|
4
5
|
import { encodeHex } from "../deps/jsr.io/@std/encoding/1.0.5/hex.js";
|
5
6
|
// @ts-ignore TS7016
|
6
7
|
import jsonld from "jsonld";
|
8
|
+
import metadata from "../deno.js";
|
7
9
|
import { getDocumentLoader, } from "../runtime/docloader.js";
|
10
|
+
import { getTypeId } from "../vocab/type.js";
|
8
11
|
import { Activity, CryptographicKey, Object } from "../vocab/vocab.js";
|
9
12
|
import { fetchKey, validateCryptoKey } from "./key.js";
|
10
13
|
const logger = getLogger(["fedify", "sig", "ld"]);
|
@@ -70,8 +73,30 @@ export async function createSignature(jsonLd, privateKey, keyId, { contextLoader
|
|
70
73
|
* @since 1.0.0
|
71
74
|
*/
|
72
75
|
export async function signJsonLd(jsonLd, privateKey, keyId, options) {
|
73
|
-
const
|
74
|
-
|
76
|
+
const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
|
77
|
+
const tracer = tracerProvider.getTracer(metadata.name, metadata.version);
|
78
|
+
return await tracer.startActiveSpan("ld_signatures.sign", {
|
79
|
+
attributes: { "ld_signatures.key_id": keyId.href },
|
80
|
+
}, async (span) => {
|
81
|
+
try {
|
82
|
+
const signature = await createSignature(jsonLd, privateKey, keyId, options);
|
83
|
+
if (span.isRecording()) {
|
84
|
+
span.setAttribute("ld_signatures.type", signature.type);
|
85
|
+
span.setAttribute("ld_signatures.signature", encodeHex(decodeBase64(signature.signatureValue)));
|
86
|
+
}
|
87
|
+
return attachSignature(jsonLd, signature);
|
88
|
+
}
|
89
|
+
catch (error) {
|
90
|
+
span.setStatus({
|
91
|
+
code: SpanStatusCode.ERROR,
|
92
|
+
message: String(error),
|
93
|
+
});
|
94
|
+
throw error;
|
95
|
+
}
|
96
|
+
finally {
|
97
|
+
span.end();
|
98
|
+
}
|
99
|
+
});
|
75
100
|
}
|
76
101
|
/**
|
77
102
|
* Checks if the given JSON-LD document has a Linked Data Signature.
|
@@ -194,26 +219,62 @@ export async function verifySignature(jsonLd, options = {}) {
|
|
194
219
|
* @returns `true` if the document is authentic; `false` otherwise.
|
195
220
|
*/
|
196
221
|
export async function verifyJsonLd(jsonLd, options = {}) {
|
197
|
-
const
|
198
|
-
const
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
222
|
+
const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
|
223
|
+
const tracer = tracerProvider.getTracer(metadata.name, metadata.version);
|
224
|
+
return await tracer.startActiveSpan("ld_signatures.verify", async (span) => {
|
225
|
+
try {
|
226
|
+
const object = await Object.fromJsonLd(jsonLd, options);
|
227
|
+
if (object.id != null) {
|
228
|
+
span.setAttribute("activitypub.object.id", object.id.href);
|
229
|
+
}
|
230
|
+
span.setAttribute("activitypub.object.type", getTypeId(object).href);
|
231
|
+
if (typeof jsonLd === "object" && jsonLd != null &&
|
232
|
+
"signature" in jsonLd && typeof jsonLd.signature === "object" &&
|
233
|
+
jsonLd.signature != null) {
|
234
|
+
if ("creator" in jsonLd.signature &&
|
235
|
+
typeof jsonLd.signature.creator === "string") {
|
236
|
+
span.setAttribute("ld_signatures.key_id", jsonLd.signature.creator);
|
237
|
+
}
|
238
|
+
if ("signatureValue" in jsonLd.signature &&
|
239
|
+
typeof jsonLd.signature.signatureValue === "string") {
|
240
|
+
span.setAttribute("ld_signatures.signature", jsonLd.signature.signatureValue);
|
241
|
+
}
|
242
|
+
if ("type" in jsonLd.signature &&
|
243
|
+
typeof jsonLd.signature.type === "string") {
|
244
|
+
span.setAttribute("ld_signatures.type", jsonLd.signature.type);
|
245
|
+
}
|
246
|
+
}
|
247
|
+
const attributions = new Set(object.attributionIds.map((uri) => uri.href));
|
248
|
+
if (object instanceof Activity) {
|
249
|
+
for (const uri of object.actorIds)
|
250
|
+
attributions.add(uri.href);
|
251
|
+
}
|
252
|
+
const key = await verifySignature(jsonLd, options);
|
253
|
+
if (key == null)
|
254
|
+
return false;
|
255
|
+
if (key.ownerId == null) {
|
256
|
+
logger.debug("Key {keyId} has no owner.", { keyId: key.id?.href });
|
257
|
+
return false;
|
258
|
+
}
|
259
|
+
attributions.delete(key.ownerId.href);
|
260
|
+
if (attributions.size > 0) {
|
261
|
+
logger.debug("Some attributions are not authenticated by the Linked Data " +
|
262
|
+
"Signatures: {attributions}.", { attributions: [...attributions] });
|
263
|
+
return false;
|
264
|
+
}
|
265
|
+
return true;
|
266
|
+
}
|
267
|
+
catch (error) {
|
268
|
+
span.setStatus({
|
269
|
+
code: SpanStatusCode.ERROR,
|
270
|
+
message: String(error),
|
271
|
+
});
|
272
|
+
throw error;
|
273
|
+
}
|
274
|
+
finally {
|
275
|
+
span.end();
|
276
|
+
}
|
277
|
+
});
|
217
278
|
}
|
218
279
|
async function hashJsonLd(jsonLd, contextLoader) {
|
219
280
|
const canon = await jsonld.canonize(jsonLd, {
|
package/esm/sig/owner.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import { trace } from "@opentelemetry/api";
|
1
2
|
import { getDocumentLoader, } from "../runtime/docloader.js";
|
2
3
|
import { isActor } from "../vocab/actor.js";
|
3
4
|
import { CryptographicKey, Object as ASObject, } from "../vocab/vocab.js";
|
@@ -30,8 +31,10 @@ export async function doesActorOwnKey(activity, key, options) {
|
|
30
31
|
* @param options Options for getting the key owner.
|
31
32
|
* @returns The actor that owns the key, or `null` if the key has no known
|
32
33
|
* owner.
|
34
|
+
* @since 0.7.0
|
33
35
|
*/
|
34
36
|
export async function getKeyOwner(keyId, options) {
|
37
|
+
const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
|
35
38
|
const documentLoader = options.documentLoader ?? getDocumentLoader();
|
36
39
|
const contextLoader = options.contextLoader ?? getDocumentLoader();
|
37
40
|
let object;
|
@@ -54,6 +57,7 @@ export async function getKeyOwner(keyId, options) {
|
|
54
57
|
object = await ASObject.fromJsonLd(keyDoc, {
|
55
58
|
documentLoader,
|
56
59
|
contextLoader,
|
60
|
+
tracerProvider,
|
57
61
|
});
|
58
62
|
}
|
59
63
|
catch (e) {
|
@@ -63,6 +67,7 @@ export async function getKeyOwner(keyId, options) {
|
|
63
67
|
object = await CryptographicKey.fromJsonLd(keyDoc, {
|
64
68
|
documentLoader,
|
65
69
|
contextLoader,
|
70
|
+
tracerProvider,
|
66
71
|
});
|
67
72
|
}
|
68
73
|
catch (e) {
|
@@ -76,7 +81,11 @@ export async function getKeyOwner(keyId, options) {
|
|
76
81
|
if (object instanceof CryptographicKey) {
|
77
82
|
if (object.ownerId == null)
|
78
83
|
return null;
|
79
|
-
owner = await object.getOwner({
|
84
|
+
owner = await object.getOwner({
|
85
|
+
documentLoader,
|
86
|
+
contextLoader,
|
87
|
+
tracerProvider,
|
88
|
+
});
|
80
89
|
}
|
81
90
|
else if (isActor(object)) {
|
82
91
|
owner = object;
|
package/esm/sig/proof.js
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
import * as dntShim from "../_dnt.shims.js";
|
2
2
|
import { getLogger } from "@logtape/logtape";
|
3
|
-
import {
|
3
|
+
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
4
|
+
import { encodeHex } from "../deps/jsr.io/@std/encoding/1.0.5/hex.js";
|
4
5
|
// @ts-ignore: json-canon is not typed
|
5
6
|
import serialize from "json-canon";
|
6
|
-
import
|
7
|
+
import metadata from "../deno.js";
|
8
|
+
import { getTypeId } from "../vocab/type.js";
|
9
|
+
import { Activity, DataIntegrityProof, Multikey, } from "../vocab/vocab.js";
|
7
10
|
import { fetchKey, validateCryptoKey, } from "./key.js";
|
8
11
|
const logger = getLogger(["fedify", "sig", "proof"]);
|
9
12
|
/**
|
@@ -67,12 +70,41 @@ export async function createProof(object, privateKey, keyId, { contextLoader, co
|
|
67
70
|
* @since 0.10.0
|
68
71
|
*/
|
69
72
|
export async function signObject(object, privateKey, keyId, options = {}) {
|
70
|
-
const
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
73
|
+
const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
|
74
|
+
const tracer = tracerProvider.getTracer(metadata.name, metadata.version);
|
75
|
+
return await tracer.startActiveSpan("object_integrity_proofs.sign", {
|
76
|
+
attributes: { "activitypub.object.type": getTypeId(object).href },
|
77
|
+
}, async (span) => {
|
78
|
+
try {
|
79
|
+
if (object.id != null) {
|
80
|
+
span.setAttribute("activitypub.object.id", object.id.href);
|
81
|
+
}
|
82
|
+
const existingProofs = [];
|
83
|
+
for await (const proof of object.getProofs(options)) {
|
84
|
+
existingProofs.push(proof);
|
85
|
+
}
|
86
|
+
const proof = await createProof(object, privateKey, keyId, options);
|
87
|
+
if (span.isRecording()) {
|
88
|
+
if (proof.cryptosuite != null) {
|
89
|
+
span.setAttribute("object_integrity_proofs.cryptosuite", proof.cryptosuite);
|
90
|
+
}
|
91
|
+
if (proof.verificationMethodId != null) {
|
92
|
+
span.setAttribute("object_integrity_proofs.key_id", proof.verificationMethodId.href);
|
93
|
+
}
|
94
|
+
if (proof.proofValue != null) {
|
95
|
+
span.setAttribute("object_integrity_proofs.signature", encodeHex(proof.proofValue));
|
96
|
+
}
|
97
|
+
}
|
98
|
+
return object.clone({ proofs: [...existingProofs, proof] });
|
99
|
+
}
|
100
|
+
catch (error) {
|
101
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: String(error) });
|
102
|
+
throw error;
|
103
|
+
}
|
104
|
+
finally {
|
105
|
+
span.end();
|
106
|
+
}
|
107
|
+
});
|
76
108
|
}
|
77
109
|
/**
|
78
110
|
* Verifies the given proof for the object.
|
@@ -85,6 +117,39 @@ export async function signObject(object, privateKey, keyId, options = {}) {
|
|
85
117
|
* @since 0.10.0
|
86
118
|
*/
|
87
119
|
export async function verifyProof(jsonLd, proof, options = {}) {
|
120
|
+
const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
|
121
|
+
const tracer = tracerProvider.getTracer(metadata.name, metadata.version);
|
122
|
+
return await tracer.startActiveSpan("object_integrity_proofs.verify", async (span) => {
|
123
|
+
if (span.isRecording()) {
|
124
|
+
if (proof.cryptosuite != null) {
|
125
|
+
span.setAttribute("object_integrity_proofs.cryptosuite", proof.cryptosuite);
|
126
|
+
}
|
127
|
+
if (proof.verificationMethodId != null) {
|
128
|
+
span.setAttribute("object_integrity_proofs.key_id", proof.verificationMethodId.href);
|
129
|
+
}
|
130
|
+
if (proof.proofValue != null) {
|
131
|
+
span.setAttribute("object_integrity_proofs.signature", encodeHex(proof.proofValue));
|
132
|
+
}
|
133
|
+
}
|
134
|
+
try {
|
135
|
+
const key = await verifyProofInternal(jsonLd, proof, options);
|
136
|
+
if (key == null)
|
137
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
138
|
+
return key;
|
139
|
+
}
|
140
|
+
catch (error) {
|
141
|
+
span.setStatus({
|
142
|
+
code: SpanStatusCode.ERROR,
|
143
|
+
message: String(error),
|
144
|
+
});
|
145
|
+
throw error;
|
146
|
+
}
|
147
|
+
finally {
|
148
|
+
span.end();
|
149
|
+
}
|
150
|
+
});
|
151
|
+
}
|
152
|
+
async function verifyProofInternal(jsonLd, proof, options) {
|
88
153
|
if (typeof jsonLd !== "object" ||
|
89
154
|
proof.cryptosuite !== "eddsa-jcs-2022" ||
|
90
155
|
proof.verificationMethodId == null ||
|
package/esm/vocab/lookup.js
CHANGED