ncc-02-js 0.3.1 → 0.5.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 +93 -21
- package/dist/index.cjs +375 -86
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +369 -86
- package/dist/models.d.ts +33 -7
- package/dist/privacy.d.ts +44 -0
- package/dist/resolver.d.ts +78 -14
- package/package.json +1 -1
- package/src/index.js +1 -0
- package/src/models.js +117 -22
- package/src/privacy.js +217 -0
- package/src/resolver.js +162 -88
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ This library provides tools for service owners to publish records and for client
|
|
|
10
10
|
- **Verification**: Built-in signature and expiry validation.
|
|
11
11
|
- **Trust Policy**: Support for third-party attestations (Kind 30060) and revocations (Kind 30061).
|
|
12
12
|
- **Security**: Cross-validation of subject and service identifiers to prevent impersonation.
|
|
13
|
+
- **Privacy Controls**: Required `private` tags and optional encrypted `privateRecipients` listings let you declare visibility and invite-only recipients.
|
|
13
14
|
- **Fail-Closed**: Explicit error reporting for policy or verification failures.
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
@@ -48,39 +49,110 @@ try {
|
|
|
48
49
|
}
|
|
49
50
|
```
|
|
50
51
|
|
|
51
|
-
### 2. Publish
|
|
52
|
-
...
|
|
53
|
-
### Trust Model & Security
|
|
52
|
+
### 2. Publish Service Records and Attestations
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
```javascript
|
|
55
|
+
import { NCC02Builder } from 'ncc-02-js';
|
|
56
|
+
|
|
57
|
+
const builder = new NCC02Builder(privateKey);
|
|
58
|
+
|
|
59
|
+
const serviceRecord = await builder.createServiceRecord({
|
|
60
|
+
serviceId: 'api',
|
|
61
|
+
endpoint: 'https://service.example.com',
|
|
62
|
+
fingerprint: '<spki fingerprint>',
|
|
63
|
+
expiryDays: 7
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const attestation = await builder.createAttestation({
|
|
67
|
+
subjectPubkey: ownerPubkey,
|
|
68
|
+
serviceId: 'api',
|
|
69
|
+
serviceEventId: serviceRecord.id,
|
|
70
|
+
level: 'verified',
|
|
71
|
+
validDays: 30
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
await builder.createRevocation({
|
|
75
|
+
attestationId: attestation.id,
|
|
76
|
+
reason: 'Key rotation'
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The builder helpers emit the expected NCC-02 event kinds: Kind 30059 for service records, 30060 for attestations, and 30061 for revocations. `createServiceRecord` always includes the `d` and `exp` tags while optionally populating `u` and `k`. Attestations include `subj`, `srv`, `e`, `std`, `lvl`, `nbf`, and `exp`. Revocations only need the `e` tag and an optional reason. You can supply either a raw private key (hex string or `Uint8Array`) or a signer implementing `getPublicKey`/`signEvent`.
|
|
81
|
+
|
|
82
|
+
#### Private Service Metadata
|
|
83
|
+
Service records now require a boolean `private` tag (set via `isPrivate` when calling `createServiceRecord`). When private services should only be used by a curated set of users, you can provide pre-encrypted `privateRecipients` values that contain authorized `npub` identifiers. The helper utilities derive NIP-44 conversation keys: `await encryptPrivateRecipients(ownerPrivateKey, recipients)` when publishing so each recipient gets a ciphertext they can decrypt, and `await isPrivateRecipientAuthorized(privateRecipients, ownerPubkey, recipientPrivateKey)` on the client-side to verify if the signed-in key is on the allowlist (or `await decryptPrivateRecipient(...)` if you need the raw `npub`). The helpers accept either raw private keys or NIP-07/NIP-46 style signer objects (they will call `nip44Encrypt/nip44Decrypt` or fall back to legacy `nip04` if present). The resolver surfaces `isPrivate` and `privateRecipients` on the returned `ServiceStatus`.
|
|
84
|
+
|
|
85
|
+
### 3. Trust Model & Security
|
|
86
|
+
|
|
87
|
+
The resolver treats the service owner’s pubkey as the root authority. Certificates and revocations are additive layers that you opt into via `requireAttestation` or `minLevel`. Validation failures surface as `NCC02Error` instances with codes such as `INVALID_SIGNATURE`, `EXPIRED`, or `POLICY_FAILURE`, helping clients react instead of defaulting to insecure fallbacks.
|
|
88
|
+
|
|
89
|
+
### 4. Resolution Optimization
|
|
90
|
+
|
|
91
|
+
To avoid unnecessary relay traffic, attestation and revocation feeds are only fetched when the resolver’s policy requests them. Keep expiries short and rotate fingerprints with the `k` tag to reduce the blast radius of compromised keys.
|
|
59
92
|
|
|
60
|
-
###
|
|
61
|
-
The resolver is designed to be network-efficient. It will only query for attestations (Kind 30060) and revocations (Kind 30061) if the provided policy requires them (e.g., when `requireAttestation` is set to `true` or a `minLevel` higher than `self` is requested).
|
|
93
|
+
### 5. Threat Model
|
|
62
94
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
###
|
|
95
|
+
The library defends against endpoint impersonation, MITM, stale records, and relay censorship by enforcing signed records, short expiries, revocation checks, and optional third-party attestations. It deliberately keeps scope focused on application-layer trust and does not replace TLS or browser PKI.
|
|
96
|
+
|
|
97
|
+
### 6. Testing with MockRelay
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
import { MockRelay, NCC02Builder, NCC02Resolver } from 'ncc-02-js';
|
|
101
|
+
|
|
102
|
+
const mock = new MockRelay();
|
|
103
|
+
const builder = new NCC02Builder(privateKey);
|
|
104
|
+
const serviceRecord = await builder.createServiceRecord({ serviceId: 'api', endpoint: 'https://example', fingerprint: '<fp>' });
|
|
105
|
+
await mock.publish(serviceRecord);
|
|
106
|
+
|
|
107
|
+
const resolver = new NCC02Resolver(['mock://local'], { pool: mock });
|
|
108
|
+
await resolver.resolve(ownerPubkey, 'api');
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`MockRelay` mimics a Nostr relay by verifying signatures and honoring `kinds`, `authors`, `ids`, and `#tag` filters. It makes writing unit tests and integration suites deterministic without external dependencies.
|
|
112
|
+
|
|
113
|
+
### 7. Endpoint Verification Helpers
|
|
114
|
+
|
|
115
|
+
After resolving a service, call `resolver.verifyEndpoint(serviceStatus, actualFingerprint)` to ensure the runtime transport fingerprint matches the declared `k` tag. Use `verifyNCC02Event` when you ingest raw events and `isExpired` to quickly skip expired records before attempting network validation.
|
|
116
|
+
|
|
117
|
+
## API Reference
|
|
66
118
|
|
|
67
119
|
### `NCC02Resolver(relays, options)`
|
|
68
120
|
- `relays`: Array of relay URLs.
|
|
69
|
-
- `options.pool`: (Optional)
|
|
70
|
-
- `options.trustedCAPubkeys`:
|
|
121
|
+
- `options.pool`: (Optional) Shared `nostr-tools` `SimplePool`.
|
|
122
|
+
- `options.trustedCAPubkeys`: Optional array of certifier pubkeys that may issue trusted attestations.
|
|
71
123
|
|
|
72
124
|
#### `resolve(pubkey, serviceId, options)`
|
|
73
|
-
- `options.requireAttestation`:
|
|
74
|
-
- `options.minLevel`: Minimum
|
|
125
|
+
- `options.requireAttestation`: Reject if no trusted attestation is available.
|
|
126
|
+
- `options.minLevel`: Minimum `lvl` tag level (`self`, `verified`, `hardened`).
|
|
127
|
+
- `options.standard`: Expected `std` tag value (defaults to `nostr-service-trust-v0.1`).
|
|
128
|
+
- Returns `ServiceStatus` including `endpoint`, `fingerprint`, `expiry`, `attestations`, `attestationCount`, `isRevoked`, `eventId`, `pubkey`, and the raw `serviceEvent`.
|
|
129
|
+
|
|
130
|
+
#### `verifyEndpoint(resolved, actualFingerprint)`
|
|
131
|
+
- Compares the resolved fingerprint with the observed transport fingerprint for an additional rejection guard.
|
|
75
132
|
|
|
76
133
|
#### `close()`
|
|
77
|
-
Closes
|
|
134
|
+
- Closes relay subscriptions when the resolver owns the `SimplePool`.
|
|
135
|
+
|
|
136
|
+
### `NCC02Builder(signer)`
|
|
137
|
+
- `signer`: Hex private key, `Uint8Array`, or custom signer with `getPublicKey`/`signEvent`.
|
|
138
|
+
|
|
139
|
+
#### `createServiceRecord({ serviceId, endpoint?, fingerprint?, expiryDays? })`
|
|
140
|
+
- Returns a signed Kind 30059 event. `endpoint` maps to `u`, `fingerprint` to `k`, and `expiryDays` controls `exp`.
|
|
141
|
+
|
|
142
|
+
#### `createAttestation({ subjectPubkey, serviceId, serviceEventId, level?, validDays? })`
|
|
143
|
+
- Emits Kind 30060 with `subj`, `srv`, `e`, `std`, `lvl`, `nbf`, and `exp`.
|
|
144
|
+
|
|
145
|
+
#### `createRevocation({ attestationId, reason? })`
|
|
146
|
+
- Emits Kind 30061 pointing to the revoked attestation.
|
|
78
147
|
|
|
148
|
+
### `MockRelay`
|
|
149
|
+
- `publish(event)`: Verifies and stores the event (returns `true` if accepted).
|
|
150
|
+
- `query(filter)`: Filters stored events by `kinds`, `authors`, `ids`, and `#tag` criteria.
|
|
79
151
|
|
|
80
|
-
###
|
|
81
|
-
- `
|
|
82
|
-
- `
|
|
83
|
-
- `
|
|
152
|
+
### Helpers
|
|
153
|
+
- `verifyNCC02Event(event)`: Signature verification wrapper.
|
|
154
|
+
- `isExpired(event)`: Returns `true` when the `exp` tag is in the past.
|
|
155
|
+
- `KINDS`: Enum with `SERVICE_RECORD`, `ATTESTATION`, and `REVOCATION`.
|
|
84
156
|
|
|
85
157
|
## License
|
|
86
158
|
|