@metalabel/dfos-protocol 0.7.1 → 0.8.0
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/README.md +8 -21
- package/dist/chain/index.d.ts +54 -148
- package/dist/chain/index.js +15 -8
- package/dist/{chunk-QKHP7UVL.js → chunk-LQ56P4SU.js} +137 -110
- package/dist/chunk-MEV6QVLC.js +402 -0
- package/dist/credentials/index.d.ts +133 -117
- package/dist/credentials/index.js +17 -21
- package/dist/index.d.ts +3 -2
- package/dist/index.js +30 -28
- package/dist/schemas-BEl38wrI.d.ts +148 -0
- package/examples/beacon.json +5 -5
- package/examples/content-delegated.json +3 -3
- package/examples/credential-read.json +4 -5
- package/examples/credential-write.json +5 -6
- package/package.json +2 -2
- package/dist/chunk-CZSEEZLL.js +0 -258
package/examples/beacon.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "Beacon: signed
|
|
2
|
+
"description": "Beacon: signed manifest content ID announcement with witness countersignature",
|
|
3
3
|
"type": "beacon",
|
|
4
|
-
"controllerJws": "
|
|
5
|
-
"witnessJws": "
|
|
4
|
+
"controllerJws": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmJlYWNvbiIsImtpZCI6ImRpZDpkZm9zOmUzdnZ0Y2s0MmQ0ZWFjZG56dnRybjYja2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgiLCJjaWQiOiJiYWZ5cmVpYzJtdXg0cGxpNXFmZDVzYnAyeXh5MmdqbTU0Zmc1Z2NpNm02YnBldm9pdXdmZGc2cG91NCJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiYmVhY29uIiwiZGlkIjoiZGlkOmRmb3M6ZTN2dnRjazQyZDRlYWNkbnp2dHJuNiIsIm1hbmlmZXN0Q29udGVudElkIjoiYTgyejkyYTNobmRrNmM5N3RoY3JuOCIsImNyZWF0ZWRBdCI6IjIwMjYtMDMtMDdUMDA6MDU6MDAuMDAwWiJ9._EKV036utOU-oMHwMyJ1Om1QhJzN-g9DTRbMz0U7L9SzQR-sHIeC6iNreYN-oV-mBvo5RPLg4TJ0UNv-PNBzDQ",
|
|
5
|
+
"witnessJws": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmJlYWNvbiIsImtpZCI6ImRpZDpkZm9zOmUzdnZ0Y2s0MmQ0ZWFjZG56dnRybjYja2V5X2V6OWE4NzR0Y2tyM2R2OTMzZDNja2QiLCJjaWQiOiJiYWZ5cmVpYzJtdXg0cGxpNXFmZDVzYnAyeXh5MmdqbTU0Zmc1Z2NpNm02YnBldm9pdXdmZGc2cG91NCJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiYmVhY29uIiwiZGlkIjoiZGlkOmRmb3M6ZTN2dnRjazQyZDRlYWNkbnp2dHJuNiIsIm1hbmlmZXN0Q29udGVudElkIjoiYTgyejkyYTNobmRrNmM5N3RoY3JuOCIsImNyZWF0ZWRBdCI6IjIwMjYtMDMtMDdUMDA6MDU6MDAuMDAwWiJ9.a2BN31Mqi296FJ8wIVOwy7zdTR4fEL2TVy2A6xG6SGUBmJdUdnlqro5JbjIOF-h5RSA1SW0i4WvIK-AeiB27BQ",
|
|
6
6
|
"controllerPublicKey": "z6MkrzLMNwoJSV4P3YccWcbtk8vd9LtgMKnLeaDLUqLuASjb",
|
|
7
7
|
"witnessPublicKey": "z6MkfUd65JrAhfdgFuMCccU9ThQvjB2fJAMUHkuuajF992gK",
|
|
8
8
|
"expected": {
|
|
9
|
-
"beaconCID": "
|
|
9
|
+
"beaconCID": "bafyreic2mux4pli5qfd5sbp2yxy2gjm54fg5gci6m6bpevoiuwfdg6pou4",
|
|
10
10
|
"did": "did:dfos:e3vvtck42d4eacdnzvtrn6",
|
|
11
|
-
"
|
|
11
|
+
"manifestContentId": "a82z92a3hndk6c97thcrn8",
|
|
12
12
|
"createdAt": "2026-03-07T00:05:00.000Z"
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "Content chain: creator signs genesis, delegate signs update with write
|
|
2
|
+
"description": "Content chain: creator signs genesis, delegate signs update with write credential",
|
|
3
3
|
"type": "content-delegated",
|
|
4
4
|
"chain": [
|
|
5
5
|
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNvbnRlbnQtb3AiLCJraWQiOiJkaWQ6ZGZvczplM3Z2dGNrNDJkNGVhY2RuenZ0cm42I2tleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4IiwiY2lkIjoiYmFmeXJlaWFmeG9ka290ZzJpZGE1eHBjZWR2MzdrMmtqZDdqbmJ5Z2hhamhub3VvYm9qaWF4eGo1eGkifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiY3JlYXRlIiwiZGlkIjoiZGlkOmRmb3M6ZTN2dnRjazQyZDRlYWNkbnp2dHJuNiIsImRvY3VtZW50Q0lEIjoiYmFmeXJlaWduN2dmdXU1NHdvMmdlZzN0ZjV0ZXBlcGxibGt0YWhqZnpxanB1aml6YzdhMmJvZXljY2EiLCJiYXNlRG9jdW1lbnRDSUQiOm51bGwsImNyZWF0ZWRBdCI6IjIwMjYtMDMtMDdUMDA6MTA6MDAuMDAwWiIsIm5vdGUiOm51bGx9.oanyS9rbkqrxd1j8T172jVG4ILKFwW2t1JhkQLxsFqHMMURqA5Hl-0GzGFrfSkQT02Nq5RMYXzhcToqbjoV8AQ",
|
|
6
|
-
"
|
|
6
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNvbnRlbnQtb3AiLCJraWQiOiJkaWQ6ZGZvczpuemtmODM4ZWZyNDI0NDMzcm4ycnprI2tleV9hOHIyNzQzNGFhcjc2YWU3MmM4NzdmIiwiY2lkIjoiYmFmeXJlaWE1M3JheWl5djNuY2Z6ZnNmdzJ2cXczeG5sZ2ZibGFiNjNnN2xrbG9laXFhb2Jxc25yenEifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoidXBkYXRlIiwiZGlkIjoiZGlkOmRmb3M6bnprZjgzOGVmcjQyNDQzM3JuMnJ6ayIsInByZXZpb3VzT3BlcmF0aW9uQ0lEIjoiYmFmeXJlaWFmeG9ka290ZzJpZGE1eHBjZWR2MzdrMmtqZDdqbmJ5Z2hhamhub3VvYm9qaWF4eGo1eGkiLCJkb2N1bWVudENJRCI6ImJhZnlyZWlmbml5bmQ2aGV2NjQ2dW9hamFjM2VnYWs3cDJxZmhyaGhvNG1mbXBwYTNydGNqcGV0Z2RlIiwiYmFzZURvY3VtZW50Q0lEIjoiYmFmeXJlaWduN2dmdXU1NHdvMmdlZzN0ZjV0ZXBlcGxibGt0YWhqZnpxanB1aml6YzdhMmJvZXljY2EiLCJjcmVhdGVkQXQiOiIyMDI2LTAzLTA3VDAwOjExOjAwLjAwMFoiLCJub3RlIjoiZGVsZWdhdGVkIGVkaXQgYnkga2V5MyIsImF1dGhvcml6YXRpb24iOiJleUpoYkdjaU9pSkZaRVJUUVNJc0luUjVjQ0k2SW1ScFpEcGtabTl6T21OeVpXUmxiblJwWVd3aUxDSnJhV1FpT2lKa2FXUTZaR1p2Y3pwbE0zWjJkR05yTkRKa05HVmhZMlJ1ZW5aMGNtNDJJMnRsZVY5eU9XVjJNelJtZG1NeU0zbzVPVGwyWldGaFpuUTRJaXdpWTJsa0lqb2lZbUZtZVhKbGFXVnNjemRvYmpkd2NXWjRlV1JvZFhWbmJXWnFiV2t5WTJWb2QyTjNiV3R1WVRJM2IyUjFhWGxvTm5VMmJYcHZaR051YnpRaWZRLmV5SjJaWEp6YVc5dUlqb3hMQ0owZVhCbElqb2lSRVpQVTBOeVpXUmxiblJwWVd3aUxDSnBjM01pT2lKa2FXUTZaR1p2Y3pwbE0zWjJkR05yTkRKa05HVmhZMlJ1ZW5aMGNtNDJJaXdpWVhWa0lqb2laR2xrT21SbWIzTTZibnByWmpnek9HVm1jalF5TkRRek0zSnVNbko2YXlJc0ltRjBkQ0k2VzNzaWNtVnpiM1Z5WTJVaU9pSmphR0ZwYmpwaFl6STJlamg2YTJ0bE5qZDZORGhoWmpOeWFHZzVJaXdpWVdOMGFXOXVJam9pZDNKcGRHVWlmVjBzSW5CeVppSTZXMTBzSW1WNGNDSTZNVGM1T0RjMk1UWXdNQ3dpYVdGMElqb3hOemN5T0RReE5qQXdmUS41ak5SeWdvSUNvX05iMWhoR3JTRkU0c2JEaWgzQU92dWhVVUFVNzBZOThDejdkaEkzakVNclJqZGZpbHh5OTgtOEJBU2VzbEpsMGtEd0ZJc1VUM0lEdyJ9.pmlU0CwctVJJL4eUlrrkUQ52266UtGnV1liETpZ6N-Ui8K-Aob58LdPbAJsk_NpiiFmyeyRiJfUnp-ADCkWqAQ"
|
|
7
7
|
],
|
|
8
8
|
"creatorPublicKey": "z6MkrzLMNwoJSV4P3YccWcbtk8vd9LtgMKnLeaDLUqLuASjb",
|
|
9
9
|
"delegatePublicKey": "z6MkvsvmSh2dGnu2qw1Tnw7M5fz98ycfuYGxqnpfgmPkLv7o",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"createdAt": "2026-03-07T00:11:00.000Z"
|
|
34
34
|
}
|
|
35
35
|
],
|
|
36
|
-
"authorization": "
|
|
36
|
+
"authorization": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNyZWRlbnRpYWwiLCJraWQiOiJkaWQ6ZGZvczplM3Z2dGNrNDJkNGVhY2RuenZ0cm42I2tleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4IiwiY2lkIjoiYmFmeXJlaWVsczdobjdwcWZ4eWRodXVnbWZqbWkyY2Vod2N3bWtuYTI3b2R1aXloNnU2bXpvZGNubzQifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiREZPU0NyZWRlbnRpYWwiLCJpc3MiOiJkaWQ6ZGZvczplM3Z2dGNrNDJkNGVhY2RuenZ0cm42IiwiYXVkIjoiZGlkOmRmb3M6bnprZjgzOGVmcjQyNDQzM3JuMnJ6ayIsImF0dCI6W3sicmVzb3VyY2UiOiJjaGFpbjphYzI2ejh6a2tlNjd6NDhhZjNyaGg5IiwiYWN0aW9uIjoid3JpdGUifV0sInByZiI6W10sImV4cCI6MTc5ODc2MTYwMCwiaWF0IjoxNzcyODQxNjAwfQ.5jNRygoICo_Nb1hhGrSFE4sbDih3AOvuhUUAU70Y98Cz7dhI3jEMrRjdfilxy98-8BASeslJl0kDwFIsUT3IDw",
|
|
37
37
|
"expected": {
|
|
38
38
|
"contentId": "ac26z8zkke67z48af3rhh9",
|
|
39
39
|
"creatorDID": "did:dfos:e3vvtck42d4eacdnzvtrn6",
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "
|
|
2
|
+
"description": "DFOS credential: read access",
|
|
3
3
|
"type": "credential",
|
|
4
|
-
"credential": "
|
|
4
|
+
"credential": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNyZWRlbnRpYWwiLCJraWQiOiJkaWQ6ZGZvczplM3Z2dGNrNDJkNGVhY2RuenZ0cm42I2tleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4IiwiY2lkIjoiYmFmeXJlaWMzbmJxemFicmxtbnl2a3o3cXI3Znk2cGd4NGFwdm52eWJvNWtzaGN6bXViaXFzemdod2EifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiREZPU0NyZWRlbnRpYWwiLCJpc3MiOiJkaWQ6ZGZvczplM3Z2dGNrNDJkNGVhY2RuenZ0cm42IiwiYXVkIjoiZGlkOmRmb3M6bnprZjgzOGVmcjQyNDQzM3JuMnJ6ayIsImF0dCI6W3sicmVzb3VyY2UiOiJjaGFpbjoqIiwiYWN0aW9uIjoicmVhZCJ9XSwicHJmIjpbXSwiZXhwIjoxNzk4NzYxNjAwLCJpYXQiOjE3NzI4NDE2MDB9.QB-qK89S-sYXaDUkJJSF5ZbsV2djFFvRQlHCj6UDyl-47LZI-ISwwyqRV-zi6MEGdHb0seSkPxpE4if6HHvvCw",
|
|
5
5
|
"issuerPublicKey": "z6MkrzLMNwoJSV4P3YccWcbtk8vd9LtgMKnLeaDLUqLuASjb",
|
|
6
|
-
"
|
|
6
|
+
"audiencePublicKey": "z6MkvsvmSh2dGnu2qw1Tnw7M5fz98ycfuYGxqnpfgmPkLv7o",
|
|
7
7
|
"expected": {
|
|
8
8
|
"iss": "did:dfos:e3vvtck42d4eacdnzvtrn6",
|
|
9
|
-
"
|
|
10
|
-
"vcType": "DFOSContentRead"
|
|
9
|
+
"aud": "did:dfos:nzkf838efr424433rn2rzk"
|
|
11
10
|
}
|
|
12
11
|
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "
|
|
2
|
+
"description": "DFOS credential: write access (broad + narrowed)",
|
|
3
3
|
"type": "credential",
|
|
4
|
-
"broadCredential": "
|
|
5
|
-
"narrowCredential": "
|
|
4
|
+
"broadCredential": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNyZWRlbnRpYWwiLCJraWQiOiJkaWQ6ZGZvczplM3Z2dGNrNDJkNGVhY2RuenZ0cm42I2tleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4IiwiY2lkIjoiYmFmeXJlaWh6dDV3Nmt4YnlsZWZ1N2R3ZDRmbnZxdnlueHphNnhud3N6bXpoYml6anVjNnhjeHFkNmEifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiREZPU0NyZWRlbnRpYWwiLCJpc3MiOiJkaWQ6ZGZvczplM3Z2dGNrNDJkNGVhY2RuenZ0cm42IiwiYXVkIjoiZGlkOmRmb3M6bnprZjgzOGVmcjQyNDQzM3JuMnJ6ayIsImF0dCI6W3sicmVzb3VyY2UiOiJjaGFpbjoqIiwiYWN0aW9uIjoid3JpdGUifV0sInByZiI6W10sImV4cCI6MTc5ODc2MTYwMCwiaWF0IjoxNzcyODQxNjAwfQ.brsN3WSdTLhN5-c0mhDriiKa2FuDD3eW5Mlj3KJYcj0cKQH0RDSACMp3qLeN2DGop-kfOtqtxlS7SAMIuCZGAw",
|
|
5
|
+
"narrowCredential": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNyZWRlbnRpYWwiLCJraWQiOiJkaWQ6ZGZvczplM3Z2dGNrNDJkNGVhY2RuenZ0cm42I2tleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4IiwiY2lkIjoiYmFmeXJlaWFreDQ1ZTJnZm5udmF2a25la3YzMnJleTU3a2lybXA3cTV2YW5teHZ0ajc0NjRqbWJpcXUifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiREZPU0NyZWRlbnRpYWwiLCJpc3MiOiJkaWQ6ZGZvczplM3Z2dGNrNDJkNGVhY2RuenZ0cm42IiwiYXVkIjoiZGlkOmRmb3M6bnprZjgzOGVmcjQyNDQzM3JuMnJ6ayIsImF0dCI6W3sicmVzb3VyY2UiOiJjaGFpbjphODJ6OTJhM2huZGs2Yzk3dGhjcm44IiwiYWN0aW9uIjoid3JpdGUifV0sInByZiI6W10sImV4cCI6MTc5ODc2MTYwMCwiaWF0IjoxNzcyODQxNjAwfQ.ep3NgoKLuKQBohx0Gn6FmroBxEJiV1A3PzKWoBqIJAt6UZqw6f2sLOFNSTb8t9PnONHh5aXuG99OmF7Fyv4mBA",
|
|
6
6
|
"issuerPublicKey": "z6MkrzLMNwoJSV4P3YccWcbtk8vd9LtgMKnLeaDLUqLuASjb",
|
|
7
|
-
"
|
|
7
|
+
"audiencePublicKey": "z6MkvsvmSh2dGnu2qw1Tnw7M5fz98ycfuYGxqnpfgmPkLv7o",
|
|
8
8
|
"expected": {
|
|
9
9
|
"iss": "did:dfos:e3vvtck42d4eacdnzvtrn6",
|
|
10
|
-
"
|
|
11
|
-
"vcType": "DFOSContentWrite",
|
|
10
|
+
"aud": "did:dfos:nzkf838efr424433rn2rzk",
|
|
12
11
|
"narrowContentId": "a82z92a3hndk6c97thcrn8"
|
|
13
12
|
}
|
|
14
13
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metalabel/dfos-protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DFOS Protocol — Ed25519 signed chain primitives, beacons, merkle trees, and verification",
|
|
6
6
|
"license": "MIT",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"ajv-formats": "^3.0.1",
|
|
67
67
|
"tsup": "^8.5.1",
|
|
68
68
|
"tsx": "^4.21.0",
|
|
69
|
-
"vitest": "^4.1.
|
|
69
|
+
"vitest": "^4.1.2"
|
|
70
70
|
},
|
|
71
71
|
"scripts": {
|
|
72
72
|
"build": "tsup",
|
package/dist/chunk-CZSEEZLL.js
DELETED
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
base64urlDecode,
|
|
3
|
-
base64urlEncode,
|
|
4
|
-
createJwt,
|
|
5
|
-
isValidEd25519Signature,
|
|
6
|
-
verifyJwt
|
|
7
|
-
} from "./chunk-ZXXP5W5N.js";
|
|
8
|
-
|
|
9
|
-
// src/credentials/schemas.ts
|
|
10
|
-
import { z } from "zod";
|
|
11
|
-
var MAX_DID = 256;
|
|
12
|
-
var MAX_AUD = 512;
|
|
13
|
-
var MAX_CONTENT_ID = 256;
|
|
14
|
-
var VC_TYPE_CONTENT_WRITE = "DFOSContentWrite";
|
|
15
|
-
var VC_TYPE_CONTENT_READ = "DFOSContentRead";
|
|
16
|
-
var DFOSCredentialType = z.enum([VC_TYPE_CONTENT_WRITE, VC_TYPE_CONTENT_READ]);
|
|
17
|
-
var AuthTokenClaims = z.strictObject({
|
|
18
|
-
/** Issuer — the DID proving identity */
|
|
19
|
-
iss: z.string().max(MAX_DID),
|
|
20
|
-
/** Subject — same as iss for auth tokens */
|
|
21
|
-
sub: z.string().max(MAX_DID),
|
|
22
|
-
/** Audience — target relay hostname (prevents cross-relay replay) */
|
|
23
|
-
aud: z.string().max(MAX_AUD),
|
|
24
|
-
/** Expiration — unix seconds, short-lived (minutes) */
|
|
25
|
-
exp: z.number().int().positive(),
|
|
26
|
-
/** Issued at — unix seconds */
|
|
27
|
-
iat: z.number().int().positive()
|
|
28
|
-
});
|
|
29
|
-
var ContentWriteSubject = z.strictObject({
|
|
30
|
-
/** Optional content chain narrowing — if absent, grants broad write access */
|
|
31
|
-
contentId: z.string().max(MAX_CONTENT_ID).optional()
|
|
32
|
-
});
|
|
33
|
-
var ContentReadSubject = z.strictObject({
|
|
34
|
-
/** Optional content chain narrowing — if absent, grants broad read access */
|
|
35
|
-
contentId: z.string().max(MAX_CONTENT_ID).optional()
|
|
36
|
-
});
|
|
37
|
-
var VCClaim = z.strictObject({
|
|
38
|
-
"@context": z.tuple([z.literal("https://www.w3.org/ns/credentials/v2")]),
|
|
39
|
-
type: z.tuple([z.literal("VerifiableCredential"), DFOSCredentialType]).transform((t) => t),
|
|
40
|
-
credentialSubject: z.union([ContentWriteSubject, ContentReadSubject])
|
|
41
|
-
});
|
|
42
|
-
var CredentialClaims = z.strictObject({
|
|
43
|
-
/** Issuer — the DID granting the credential */
|
|
44
|
-
iss: z.string().max(MAX_DID),
|
|
45
|
-
/** Subject — the DID receiving the credential */
|
|
46
|
-
sub: z.string().max(MAX_DID),
|
|
47
|
-
/** Expiration — unix seconds */
|
|
48
|
-
exp: z.number().int().positive(),
|
|
49
|
-
/** Issued at — unix seconds */
|
|
50
|
-
iat: z.number().int().positive(),
|
|
51
|
-
/** Verifiable credential claim */
|
|
52
|
-
vc: VCClaim
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
// src/credentials/auth-token.ts
|
|
56
|
-
var createAuthToken = async (options) => {
|
|
57
|
-
if (!options.kid.includes("#")) {
|
|
58
|
-
throw new Error("kid must be a DID URL (did:dfos:xxx#key_yyy)");
|
|
59
|
-
}
|
|
60
|
-
const kidDid = options.kid.substring(0, options.kid.indexOf("#"));
|
|
61
|
-
if (kidDid !== options.iss) {
|
|
62
|
-
throw new Error("kid DID does not match iss");
|
|
63
|
-
}
|
|
64
|
-
const now = options.iat ?? Math.floor(Date.now() / 1e3);
|
|
65
|
-
const header = { alg: "EdDSA", typ: "JWT", kid: options.kid };
|
|
66
|
-
const payload = {
|
|
67
|
-
iss: options.iss,
|
|
68
|
-
sub: options.iss,
|
|
69
|
-
aud: options.aud,
|
|
70
|
-
exp: options.exp,
|
|
71
|
-
iat: now
|
|
72
|
-
};
|
|
73
|
-
return createJwt({ header, payload, sign: options.sign });
|
|
74
|
-
};
|
|
75
|
-
var verifyAuthToken = (options) => {
|
|
76
|
-
const { header, payload } = verifyJwt({
|
|
77
|
-
token: options.token,
|
|
78
|
-
publicKey: options.publicKey,
|
|
79
|
-
audience: options.audience,
|
|
80
|
-
...options.currentTime !== void 0 ? { currentTime: options.currentTime } : {}
|
|
81
|
-
});
|
|
82
|
-
const result = AuthTokenClaims.safeParse(payload);
|
|
83
|
-
if (!result.success) {
|
|
84
|
-
const messages = result.error.issues.map((e) => e.message).join(", ");
|
|
85
|
-
throw new AuthTokenVerificationError(`invalid auth token claims: ${messages}`);
|
|
86
|
-
}
|
|
87
|
-
const currentTime = options.currentTime ?? Math.floor(Date.now() / 1e3);
|
|
88
|
-
if (result.data.iat > currentTime) {
|
|
89
|
-
throw new AuthTokenVerificationError("auth token not yet valid (iat is in the future)");
|
|
90
|
-
}
|
|
91
|
-
const kid = header.kid;
|
|
92
|
-
if (!kid || !kid.includes("#")) {
|
|
93
|
-
throw new AuthTokenVerificationError("auth token kid must be a DID URL");
|
|
94
|
-
}
|
|
95
|
-
const kidDid = kid.substring(0, kid.indexOf("#"));
|
|
96
|
-
if (kidDid !== result.data.iss) {
|
|
97
|
-
throw new AuthTokenVerificationError("auth token kid DID does not match iss");
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
iss: result.data.iss,
|
|
101
|
-
aud: result.data.aud,
|
|
102
|
-
exp: result.data.exp,
|
|
103
|
-
kid
|
|
104
|
-
};
|
|
105
|
-
};
|
|
106
|
-
var AuthTokenVerificationError = class extends Error {
|
|
107
|
-
constructor(message) {
|
|
108
|
-
super(message);
|
|
109
|
-
this.name = "AuthTokenVerificationError";
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
// src/credentials/credential.ts
|
|
114
|
-
var createCredential = async (options) => {
|
|
115
|
-
if (!options.kid.includes("#")) {
|
|
116
|
-
throw new Error("kid must be a DID URL (did:dfos:xxx#key_yyy)");
|
|
117
|
-
}
|
|
118
|
-
const kidDid = options.kid.substring(0, options.kid.indexOf("#"));
|
|
119
|
-
if (kidDid !== options.iss) {
|
|
120
|
-
throw new Error("kid DID does not match iss");
|
|
121
|
-
}
|
|
122
|
-
const now = options.iat ?? Math.floor(Date.now() / 1e3);
|
|
123
|
-
const header = { alg: "EdDSA", typ: "vc+jwt", kid: options.kid };
|
|
124
|
-
const credentialSubject = {};
|
|
125
|
-
if (options.contentId) {
|
|
126
|
-
credentialSubject.contentId = options.contentId;
|
|
127
|
-
}
|
|
128
|
-
const payload = {
|
|
129
|
-
iss: options.iss,
|
|
130
|
-
sub: options.sub,
|
|
131
|
-
exp: options.exp,
|
|
132
|
-
iat: now,
|
|
133
|
-
vc: {
|
|
134
|
-
"@context": ["https://www.w3.org/ns/credentials/v2"],
|
|
135
|
-
type: ["VerifiableCredential", options.type],
|
|
136
|
-
credentialSubject
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
const headerB64 = base64urlEncode(JSON.stringify(header));
|
|
140
|
-
const payloadB64 = base64urlEncode(JSON.stringify(payload));
|
|
141
|
-
const signingInput = `${headerB64}.${payloadB64}`;
|
|
142
|
-
const signingInputBytes = new TextEncoder().encode(signingInput);
|
|
143
|
-
const signatureBytes = await options.sign(signingInputBytes);
|
|
144
|
-
const signatureB64 = base64urlEncode(signatureBytes);
|
|
145
|
-
return `${signingInput}.${signatureB64}`;
|
|
146
|
-
};
|
|
147
|
-
var verifyCredential = (options) => {
|
|
148
|
-
const parts = options.token.split(".");
|
|
149
|
-
if (parts.length !== 3) {
|
|
150
|
-
throw new CredentialVerificationError("invalid token format");
|
|
151
|
-
}
|
|
152
|
-
const [headerB64, payloadB64, signatureB64] = parts;
|
|
153
|
-
let header;
|
|
154
|
-
let payload;
|
|
155
|
-
try {
|
|
156
|
-
header = JSON.parse(new TextDecoder().decode(base64urlDecode(headerB64)));
|
|
157
|
-
payload = JSON.parse(new TextDecoder().decode(base64urlDecode(payloadB64)));
|
|
158
|
-
} catch {
|
|
159
|
-
throw new CredentialVerificationError("failed to decode token");
|
|
160
|
-
}
|
|
161
|
-
if (header.alg !== "EdDSA") {
|
|
162
|
-
throw new CredentialVerificationError(`unsupported algorithm: ${header.alg}`);
|
|
163
|
-
}
|
|
164
|
-
if (header.typ !== "vc+jwt") {
|
|
165
|
-
throw new CredentialVerificationError(`invalid typ: ${header.typ}`);
|
|
166
|
-
}
|
|
167
|
-
const signingInput = `${headerB64}.${payloadB64}`;
|
|
168
|
-
const signingInputBytes = new TextEncoder().encode(signingInput);
|
|
169
|
-
let signatureBytes;
|
|
170
|
-
try {
|
|
171
|
-
signatureBytes = base64urlDecode(signatureB64);
|
|
172
|
-
} catch {
|
|
173
|
-
throw new CredentialVerificationError("failed to decode signature");
|
|
174
|
-
}
|
|
175
|
-
const isValid = isValidEd25519Signature(signingInputBytes, signatureBytes, options.publicKey);
|
|
176
|
-
if (!isValid) {
|
|
177
|
-
throw new CredentialVerificationError("invalid signature");
|
|
178
|
-
}
|
|
179
|
-
const result = CredentialClaims.safeParse(payload);
|
|
180
|
-
if (!result.success) {
|
|
181
|
-
const messages = result.error.issues.map((e) => e.message).join(", ");
|
|
182
|
-
throw new CredentialVerificationError(`invalid credential claims: ${messages}`);
|
|
183
|
-
}
|
|
184
|
-
const claims = result.data;
|
|
185
|
-
const kid = header.kid;
|
|
186
|
-
if (!kid || !kid.includes("#")) {
|
|
187
|
-
throw new CredentialVerificationError("credential kid must be a DID URL");
|
|
188
|
-
}
|
|
189
|
-
const kidDid = kid.substring(0, kid.indexOf("#"));
|
|
190
|
-
if (kidDid !== claims.iss) {
|
|
191
|
-
throw new CredentialVerificationError("credential kid DID does not match iss");
|
|
192
|
-
}
|
|
193
|
-
const currentTime = options.currentTime ?? Math.floor(Date.now() / 1e3);
|
|
194
|
-
if (claims.iat > currentTime) {
|
|
195
|
-
throw new CredentialVerificationError("credential not yet valid (iat is in the future)");
|
|
196
|
-
}
|
|
197
|
-
if (claims.exp <= currentTime) {
|
|
198
|
-
throw new CredentialVerificationError("credential expired");
|
|
199
|
-
}
|
|
200
|
-
if (options.subject !== void 0 && claims.sub !== options.subject) {
|
|
201
|
-
throw new CredentialVerificationError(
|
|
202
|
-
`subject mismatch: expected ${options.subject}, got ${claims.sub}`
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
const vcType = claims.vc.type[1];
|
|
206
|
-
if (options.expectedType !== void 0 && vcType !== options.expectedType) {
|
|
207
|
-
throw new CredentialVerificationError(
|
|
208
|
-
`type mismatch: expected ${options.expectedType}, got ${vcType}`
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
const contentId = claims.vc.credentialSubject.contentId;
|
|
212
|
-
return {
|
|
213
|
-
iss: claims.iss,
|
|
214
|
-
sub: claims.sub,
|
|
215
|
-
exp: claims.exp,
|
|
216
|
-
type: vcType,
|
|
217
|
-
kid,
|
|
218
|
-
...contentId !== void 0 ? { contentId } : {}
|
|
219
|
-
};
|
|
220
|
-
};
|
|
221
|
-
var decodeCredentialUnsafe = (token) => {
|
|
222
|
-
const parts = token.split(".");
|
|
223
|
-
if (parts.length !== 3) return null;
|
|
224
|
-
try {
|
|
225
|
-
const [headerB64, payloadB64] = parts;
|
|
226
|
-
const header = JSON.parse(new TextDecoder().decode(base64urlDecode(headerB64)));
|
|
227
|
-
const payload = JSON.parse(new TextDecoder().decode(base64urlDecode(payloadB64)));
|
|
228
|
-
const result = CredentialClaims.safeParse(payload);
|
|
229
|
-
if (!result.success) return null;
|
|
230
|
-
return { header, claims: result.data };
|
|
231
|
-
} catch {
|
|
232
|
-
return null;
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
|
-
var CredentialVerificationError = class extends Error {
|
|
236
|
-
constructor(message) {
|
|
237
|
-
super(message);
|
|
238
|
-
this.name = "CredentialVerificationError";
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
export {
|
|
243
|
-
VC_TYPE_CONTENT_WRITE,
|
|
244
|
-
VC_TYPE_CONTENT_READ,
|
|
245
|
-
DFOSCredentialType,
|
|
246
|
-
AuthTokenClaims,
|
|
247
|
-
ContentWriteSubject,
|
|
248
|
-
ContentReadSubject,
|
|
249
|
-
VCClaim,
|
|
250
|
-
CredentialClaims,
|
|
251
|
-
createAuthToken,
|
|
252
|
-
verifyAuthToken,
|
|
253
|
-
AuthTokenVerificationError,
|
|
254
|
-
createCredential,
|
|
255
|
-
verifyCredential,
|
|
256
|
-
decodeCredentialUnsafe,
|
|
257
|
-
CredentialVerificationError
|
|
258
|
-
};
|