@dnsid-ai/sdk 0.21.0 → 0.23.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 +23 -6
- package/dist/node.cjs +284 -217
- package/dist/node.d.cts +70 -135
- package/dist/node.d.ts +70 -135
- package/dist/node.js +283 -212
- package/package.json +8 -8
package/dist/node.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
// src/node.ts
|
|
2
|
-
import * as fs3 from "fs/promises";
|
|
3
|
-
import * as os2 from "os";
|
|
4
|
-
import * as path2 from "path";
|
|
5
|
-
import { IdentityManager, ArgumentError as ArgumentError2, normalizeFQDN as normalizeFQDN2, validateDnsidConfig } from "@dnsid-ai/protocol";
|
|
6
|
-
import { DEFAULT_REGISTRY_URL as DEFAULT_REGISTRY_URL2 } from "@dnsid-ai/registry";
|
|
7
|
-
|
|
8
1
|
// src/local-key-provider.ts
|
|
9
2
|
import * as fs2 from "fs/promises";
|
|
10
3
|
import * as os from "os";
|
|
@@ -59,9 +52,6 @@ var LocalKeyProvider = class _LocalKeyProvider {
|
|
|
59
52
|
}
|
|
60
53
|
return new _LocalKeyProvider(store, filePath);
|
|
61
54
|
}
|
|
62
|
-
static async fromEnvironment(env, options = {}) {
|
|
63
|
-
return _LocalKeyProvider.load(keyStorePathFromEnvironment(env, options.defaultPath), options.createIfMissing, options.algorithm);
|
|
64
|
-
}
|
|
65
55
|
static async generate(algorithm = "EdDSA") {
|
|
66
56
|
return new _LocalKeyProvider(await buildInitialStore(algorithm), null);
|
|
67
57
|
}
|
|
@@ -188,9 +178,6 @@ async function syncDirectory(dir) {
|
|
|
188
178
|
await directory.close();
|
|
189
179
|
}
|
|
190
180
|
}
|
|
191
|
-
function keyStorePathFromEnvironment(env = process.env, defaultPath = ".dnsid/keys.json") {
|
|
192
|
-
return env["DNSID_KEY_STORE"] || env["DNSID_KEY_STORE_PATH"] || env["DNSID_KEYSTORE_PATH"] || defaultPath;
|
|
193
|
-
}
|
|
194
181
|
function toPublicJwk(key) {
|
|
195
182
|
const { d: _d, ...pub } = key;
|
|
196
183
|
return pub;
|
|
@@ -263,215 +250,269 @@ async function importPrivateKey(key) {
|
|
|
263
250
|
);
|
|
264
251
|
}
|
|
265
252
|
|
|
266
|
-
// src/
|
|
267
|
-
import {
|
|
268
|
-
import { DEFAULT_REGISTRY_URL } from "@dnsid-ai/registry";
|
|
269
|
-
var dnsidEnvironmentVariables = {
|
|
270
|
-
domain: "DNSID_DOMAIN",
|
|
271
|
-
governanceId: "DNSID_GOVERNANCE_ID",
|
|
272
|
-
registryUrl: "DNSID_REGISTRY_URL",
|
|
273
|
-
apiKey: "DNSID_API_KEY",
|
|
274
|
-
statusUrl: "DNSID_STATUS_URL",
|
|
275
|
-
logRef: "DNSID_LOG_REF",
|
|
276
|
-
ekUrl: "DNSID_EK_URL",
|
|
277
|
-
kuUrl: "DNSID_KU_URL",
|
|
278
|
-
dnsServer: "DNSID_DNS_SERVER",
|
|
279
|
-
caBundlePath: "DNSID_CA_BUNDLE",
|
|
280
|
-
dnssecMode: "DNSID_DNSSEC_MODE",
|
|
281
|
-
publicUrl: "DNSID_PUBLIC_URL",
|
|
282
|
-
keyStorePath: "DNSID_KEY_STORE",
|
|
283
|
-
agentPort: "DNSID_AGENT_PORT",
|
|
284
|
-
agentName: "DNSID_AGENT_NAME"
|
|
285
|
-
};
|
|
286
|
-
var environmentSchema = {
|
|
287
|
-
domain: stringField(dnsidEnvironmentVariables.domain),
|
|
288
|
-
governanceId: stringField(dnsidEnvironmentVariables.governanceId),
|
|
289
|
-
registryUrl: stringField(dnsidEnvironmentVariables.registryUrl),
|
|
290
|
-
apiKey: stringField(dnsidEnvironmentVariables.apiKey),
|
|
291
|
-
statusUrl: stringField(dnsidEnvironmentVariables.statusUrl),
|
|
292
|
-
logRef: stringField(dnsidEnvironmentVariables.logRef),
|
|
293
|
-
ekUrl: stringField(dnsidEnvironmentVariables.ekUrl),
|
|
294
|
-
kuUrl: stringField(dnsidEnvironmentVariables.kuUrl),
|
|
295
|
-
dnsServer: stringField(dnsidEnvironmentVariables.dnsServer),
|
|
296
|
-
caBundlePath: stringField(dnsidEnvironmentVariables.caBundlePath),
|
|
297
|
-
dnssecMode: dnssecModeField(dnsidEnvironmentVariables.dnssecMode),
|
|
298
|
-
publicUrl: stringField(dnsidEnvironmentVariables.publicUrl),
|
|
299
|
-
keyStorePath: stringField(dnsidEnvironmentVariables.keyStorePath),
|
|
300
|
-
agentPort: positiveIntField(dnsidEnvironmentVariables.agentPort),
|
|
301
|
-
agentName: stringField(dnsidEnvironmentVariables.agentName)
|
|
302
|
-
};
|
|
303
|
-
function configFromEnvironment(envOrOptions = process.env, options = {}) {
|
|
304
|
-
const receivedOptions = isConfigFromEnvironmentOptions(envOrOptions);
|
|
305
|
-
const env = receivedOptions ? process.env : envOrOptions ?? process.env;
|
|
306
|
-
const resolvedOptions = receivedOptions ? envOrOptions : options;
|
|
307
|
-
const parsed = parseEnvironment(env);
|
|
308
|
-
requireFields(parsed, ["domain", "governanceId", ...resolvedOptions.require ?? []]);
|
|
309
|
-
const registryUrl = parsed.registryUrl ?? DEFAULT_REGISTRY_URL;
|
|
310
|
-
const statusUrl = parsed.statusUrl ?? protocolStatusUrl(registryUrl, parsed.domain);
|
|
311
|
-
const config = {
|
|
312
|
-
identity: defined({
|
|
313
|
-
domain: parsed.domain,
|
|
314
|
-
governanceId: parsed.governanceId,
|
|
315
|
-
logRef: parsed.logRef ?? "noop:0",
|
|
316
|
-
statusUrl,
|
|
317
|
-
ekUrl: parsed.ekUrl,
|
|
318
|
-
kuUrl: parsed.kuUrl
|
|
319
|
-
}),
|
|
320
|
-
verification: defined({ dnssecMode: parsed.dnssecMode }),
|
|
321
|
-
transport: defined({ dnsServer: parsed.dnsServer, caBundlePath: parsed.caBundlePath })
|
|
322
|
-
};
|
|
323
|
-
return {
|
|
324
|
-
config,
|
|
325
|
-
registryUrl,
|
|
326
|
-
apiKey: parsed.apiKey,
|
|
327
|
-
publicUrl: parsed.publicUrl,
|
|
328
|
-
keyStorePath: parsed.keyStorePath,
|
|
329
|
-
agentName: parsed.agentName,
|
|
330
|
-
agentPort: parsed.agentPort
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
function registryClientOptionsFromEnvironment(env = process.env) {
|
|
334
|
-
const parsed = parseEnvironment(env);
|
|
335
|
-
return defined({ baseUrl: parsed.registryUrl ?? DEFAULT_REGISTRY_URL, token: parsed.apiKey });
|
|
336
|
-
}
|
|
337
|
-
function defined(value) {
|
|
338
|
-
return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== void 0));
|
|
339
|
-
}
|
|
340
|
-
function isConfigFromEnvironmentOptions(value) {
|
|
341
|
-
if (value === void 0) return false;
|
|
342
|
-
const keys = Object.keys(value);
|
|
343
|
-
if (keys.length === 0) return true;
|
|
344
|
-
return keys.every((key) => key === "require") && Array.isArray(value.require);
|
|
345
|
-
}
|
|
346
|
-
function parseEnvironment(env) {
|
|
347
|
-
const parsed = {};
|
|
348
|
-
for (const fieldName of Object.keys(environmentSchema)) {
|
|
349
|
-
const value = readEnvironmentField(env, fieldName);
|
|
350
|
-
if (value !== void 0) parsed[fieldName] = value;
|
|
351
|
-
}
|
|
352
|
-
return parsed;
|
|
353
|
-
}
|
|
354
|
-
function readEnvironmentField(env, fieldName) {
|
|
355
|
-
const field = environmentSchema[fieldName];
|
|
356
|
-
const raw = env[field.variable];
|
|
357
|
-
if (raw === void 0 || raw === "") return void 0;
|
|
358
|
-
return field.parse(raw, field.variable);
|
|
359
|
-
}
|
|
360
|
-
function requireFields(parsed, fields) {
|
|
361
|
-
for (const field of fields) {
|
|
362
|
-
if (parsed[field] === void 0) throw new Error(`${environmentSchema[field].variable} is required`);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
function stringField(variable) {
|
|
366
|
-
return { variable, parse: (value) => value };
|
|
367
|
-
}
|
|
368
|
-
function positiveIntField(variable) {
|
|
369
|
-
return {
|
|
370
|
-
variable,
|
|
371
|
-
parse(value, name) {
|
|
372
|
-
const parsed = Number(value);
|
|
373
|
-
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
374
|
-
throw new Error(`${name} must be a positive integer`);
|
|
375
|
-
}
|
|
376
|
-
return parsed;
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
function dnssecModeField(variable) {
|
|
381
|
-
return {
|
|
382
|
-
variable,
|
|
383
|
-
parse(value, name) {
|
|
384
|
-
if (!Object.values(DNSSECMode).includes(value)) {
|
|
385
|
-
throw new Error(`invalid ${name} "${value}"; expected one of: ${Object.values(DNSSECMode).join(", ")}`);
|
|
386
|
-
}
|
|
387
|
-
return value;
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
function protocolStatusUrl(registryUrl, domain) {
|
|
392
|
-
return `${registryUrl.replace(/\/$/, "")}/v1/status/${encodeURIComponent(domain)}`;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// src/node.ts
|
|
253
|
+
// src/node-identity-manager.ts
|
|
254
|
+
import { IdentityManager, ArgumentError as ArgumentError2, validateDnsidConfig } from "@dnsid-ai/protocol";
|
|
396
255
|
async function createNodeIdentityManager(config, deps = {}) {
|
|
397
256
|
const { transport, ...core } = validateDnsidConfig(config);
|
|
398
|
-
const { dnsServer, caBundlePath,
|
|
257
|
+
const { dnsServer, caBundlePath, privateAddressHosts } = transport;
|
|
399
258
|
if (dnsServer !== void 0 && deps.dnsResolver && deps.fetchJson) {
|
|
400
259
|
throw new ArgumentError2("config.transport.dnsServer has no SDK-managed consumer when both dnsResolver and fetchJson are injected");
|
|
401
260
|
}
|
|
402
261
|
if (caBundlePath !== void 0 && deps.fetchJson) {
|
|
403
262
|
throw new ArgumentError2("config.transport.caBundlePath has no SDK-managed consumer when fetchJson is injected");
|
|
404
263
|
}
|
|
405
|
-
if (
|
|
406
|
-
throw new ArgumentError2("config.transport.
|
|
264
|
+
if (privateAddressHosts !== void 0 && deps.fetchJson) {
|
|
265
|
+
throw new ArgumentError2("config.transport.privateAddressHosts has no SDK-managed consumer when fetchJson is injected");
|
|
407
266
|
}
|
|
408
267
|
const transportModule = deps.fetchJson && deps.dnsResolver ? null : await loadNodeTransport();
|
|
409
|
-
const fetchJson = deps.fetchJson ?? ((url, fetchOptions) => transportModule.fetchJson(url, { ...fetchOptions, dnsServer, caBundlePath,
|
|
268
|
+
const fetchJson = deps.fetchJson ?? ((url, fetchOptions) => transportModule.fetchJson(url, { ...fetchOptions, dnsServer, caBundlePath, privateAddressHosts }));
|
|
410
269
|
const dnsResolver = deps.dnsResolver ?? transportModule.createDefaultDnsResolver({ dnsServer });
|
|
411
270
|
return new IdentityManager(core, { ...deps, dnsResolver, fetchJson });
|
|
412
271
|
}
|
|
413
272
|
async function createNodeIdentityVerifier(config = {}, deps = {}) {
|
|
414
273
|
return createNodeIdentityManager(config, deps);
|
|
415
274
|
}
|
|
416
|
-
async function
|
|
417
|
-
|
|
275
|
+
async function loadNodeTransport() {
|
|
276
|
+
try {
|
|
277
|
+
return await import("@dnsid-ai/transport");
|
|
278
|
+
} catch (e) {
|
|
279
|
+
const err = e;
|
|
280
|
+
if (err.code === "ERR_MODULE_NOT_FOUND" || err.code === "MODULE_NOT_FOUND") {
|
|
281
|
+
throw new Error("`@dnsid-ai/sdk/node` HTTPS defaults require optional peer `@dnsid-ai/transport`; install it or inject fetchJson.");
|
|
282
|
+
}
|
|
283
|
+
throw e;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// src/config-loading.ts
|
|
288
|
+
import * as fs3 from "fs/promises";
|
|
289
|
+
import * as os2 from "os";
|
|
290
|
+
import * as path2 from "path";
|
|
291
|
+
import {
|
|
292
|
+
ArgumentError as ArgumentError3,
|
|
293
|
+
DNSSECMode,
|
|
294
|
+
normalizeFQDN as normalizeFQDN2,
|
|
295
|
+
parseJsonNoDuplicateMembers,
|
|
296
|
+
validateDnsidConfig as validateDnsidConfig2
|
|
297
|
+
} from "@dnsid-ai/protocol";
|
|
298
|
+
import {
|
|
299
|
+
createC2spTlogVerificationRegistry,
|
|
300
|
+
createDnsidManagedVerificationRegistry,
|
|
301
|
+
parseC2spTlogTrustProfile
|
|
302
|
+
} from "@dnsid-ai/log-c2sp-tlog";
|
|
303
|
+
import { RegistryClient } from "@dnsid-ai/registry";
|
|
304
|
+
var IDENTITY_VARIABLES = {
|
|
305
|
+
DNSID_DOMAIN: "domain",
|
|
306
|
+
DNSID_GOVERNANCE_ID: "governanceId",
|
|
307
|
+
DNSID_STATUS_URL: "statusUrl",
|
|
308
|
+
DNSID_LOG_REF: "logRef",
|
|
309
|
+
DNSID_EK_URL: "ekUrl",
|
|
310
|
+
DNSID_KU_URL: "kuUrl",
|
|
311
|
+
DNSID_PUBLISH_PROFILE: "publishProfile",
|
|
312
|
+
DNSID_CAPABILITIES_URL: "capabilitiesUrl"
|
|
313
|
+
};
|
|
314
|
+
async function loadEnvironment(env = process.env) {
|
|
315
|
+
const get = (name) => {
|
|
316
|
+
const value = env[name]?.trim();
|
|
317
|
+
return value ? value : void 0;
|
|
318
|
+
};
|
|
319
|
+
const identity = compact(Object.fromEntries(
|
|
320
|
+
Object.entries(IDENTITY_VARIABLES).map(([variable, field]) => [field, get(variable)])
|
|
321
|
+
));
|
|
322
|
+
const dnssecMode = get("DNSID_DNSSEC_MODE");
|
|
323
|
+
if (dnssecMode !== void 0 && !Object.values(DNSSECMode).includes(dnssecMode)) {
|
|
324
|
+
throw new ArgumentError3(`invalid DNSID_DNSSEC_MODE "${dnssecMode}"; expected one of: ${Object.values(DNSSECMode).join(", ")}`);
|
|
325
|
+
}
|
|
326
|
+
const hosts = get("DNSID_PRIVATE_HOSTS")?.split(",").map((h) => h.trim()).filter(Boolean);
|
|
327
|
+
const dnsid = compact({
|
|
328
|
+
identity,
|
|
329
|
+
verification: compact({ dnssecMode }),
|
|
330
|
+
transport: compact({
|
|
331
|
+
dnsServer: get("DNSID_DNS_SERVER"),
|
|
332
|
+
caBundlePath: get("DNSID_CA_BUNDLE"),
|
|
333
|
+
privateAddressHosts: hosts?.length ? hosts : void 0
|
|
334
|
+
})
|
|
335
|
+
});
|
|
336
|
+
const policyFile = get("DNSID_LOG_POLICY_FILE");
|
|
337
|
+
const profileFile = get("DNSID_LOG_TRUST_PROFILE_FILE");
|
|
338
|
+
const logTrust = compact({
|
|
339
|
+
policyUrl: get("DNSID_LOG_POLICY_URL"),
|
|
340
|
+
policyDocument: policyFile === void 0 ? void 0 : new Uint8Array(await fs3.readFile(policyFile)),
|
|
341
|
+
profile: profileFile === void 0 ? void 0 : jsonObject(await fs3.readFile(profileFile), profileFile)
|
|
342
|
+
});
|
|
343
|
+
return top({
|
|
344
|
+
dnsid,
|
|
345
|
+
logTrust,
|
|
346
|
+
registry: compact({ registryUrl: get("DNSID_REGISTRY_URL") }),
|
|
347
|
+
keySource: compact({ cliDirectory: get("DNSID_CONFIG_DIR"), keyStorePath: get("DNSID_KEY_STORE") })
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
async function loadFile(filePath) {
|
|
351
|
+
const root = jsonObject(await fs3.readFile(filePath), filePath);
|
|
352
|
+
rejectUnknown(root, filePath, ["dnsid", "logTrust", "registry"]);
|
|
353
|
+
const loaded = {};
|
|
354
|
+
if (root.dnsid !== void 0) loaded.dnsid = loadedDnsid(root.dnsid, `${filePath}: dnsid`);
|
|
355
|
+
if (root.logTrust !== void 0) {
|
|
356
|
+
const trust = object(root.logTrust, `${filePath}: logTrust`);
|
|
357
|
+
rejectUnknown(trust, `${filePath}: logTrust`, ["managed", "profile", "policyUrl"]);
|
|
358
|
+
loaded.logTrust = compact({
|
|
359
|
+
managed: optional(trust, "managed", "boolean", `${filePath}: logTrust`),
|
|
360
|
+
profile: trust.profile === void 0 ? void 0 : object(trust.profile, `${filePath}: logTrust.profile`),
|
|
361
|
+
policyUrl: optional(trust, "policyUrl", "string", `${filePath}: logTrust`)
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
if (root.registry !== void 0) {
|
|
365
|
+
const registry = object(root.registry, `${filePath}: registry`);
|
|
366
|
+
rejectUnknown(registry, `${filePath}: registry`, ["registryUrl"]);
|
|
367
|
+
loaded.registry = compact({ registryUrl: optional(registry, "registryUrl", "string", `${filePath}: registry`) });
|
|
368
|
+
}
|
|
369
|
+
return loaded;
|
|
370
|
+
}
|
|
371
|
+
function loadedDnsid(value, source) {
|
|
372
|
+
const raw = object(value, source);
|
|
373
|
+
rejectUnknown(raw, source, ["identity", "verification", "transport"]);
|
|
374
|
+
if (raw.identity !== void 0) {
|
|
375
|
+
const identity = object(raw.identity, `${source}.identity`);
|
|
376
|
+
const keys = ["domain", "governanceId", "logRef", "statusUrl", "policyFlags", "maxKeyAge", "ekUrl", "kuUrl", "publishProfile", "capabilitiesUrl"];
|
|
377
|
+
rejectUnknown(identity, `${source}.identity`, keys);
|
|
378
|
+
for (const key of keys) optional(identity, key, "string", `${source}.identity`);
|
|
379
|
+
}
|
|
380
|
+
if (raw.verification !== void 0) {
|
|
381
|
+
const verification = object(raw.verification, `${source}.verification`);
|
|
382
|
+
rejectUnknown(verification, `${source}.verification`, ["statusCheckInterval", "dnssecMode", "trustedEntities"]);
|
|
383
|
+
if (verification.statusCheckInterval !== void 0 && (typeof verification.statusCheckInterval !== "number" || !Number.isFinite(verification.statusCheckInterval))) {
|
|
384
|
+
throw new ArgumentError3(`${source}.verification.statusCheckInterval must be a finite number`);
|
|
385
|
+
}
|
|
386
|
+
const mode = optional(verification, "dnssecMode", "string", `${source}.verification`);
|
|
387
|
+
if (mode !== void 0 && !Object.values(DNSSECMode).includes(mode)) {
|
|
388
|
+
throw new ArgumentError3(`${source}.verification.dnssecMode is invalid`);
|
|
389
|
+
}
|
|
390
|
+
if (verification.trustedEntities !== void 0) {
|
|
391
|
+
if (!Array.isArray(verification.trustedEntities)) throw new ArgumentError3(`${source}.verification.trustedEntities must be an array`);
|
|
392
|
+
for (const [index, entry] of verification.trustedEntities.entries()) {
|
|
393
|
+
const label = `${source}.verification.trustedEntities[${index}]`;
|
|
394
|
+
const entity = object(entry, label);
|
|
395
|
+
rejectUnknown(entity, label, ["governanceId", "entityKeyThumbprints"]);
|
|
396
|
+
if (typeof entity.governanceId !== "string") throw new ArgumentError3(`${label}.governanceId must be a string`);
|
|
397
|
+
if (entity.entityKeyThumbprints !== void 0 && (!Array.isArray(entity.entityKeyThumbprints) || entity.entityKeyThumbprints.some((pin) => typeof pin !== "string"))) {
|
|
398
|
+
throw new ArgumentError3(`${label}.entityKeyThumbprints must be an array of strings`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (raw.transport !== void 0) {
|
|
404
|
+
const transport = object(raw.transport, `${source}.transport`);
|
|
405
|
+
rejectUnknown(transport, `${source}.transport`, ["dnsServer", "caBundlePath", "privateAddressHosts"]);
|
|
406
|
+
for (const key of ["dnsServer", "caBundlePath"]) optional(transport, key, "string", `${source}.transport`);
|
|
407
|
+
if (transport.privateAddressHosts !== void 0 && (!Array.isArray(transport.privateAddressHosts) || transport.privateAddressHosts.some((host) => typeof host !== "string"))) {
|
|
408
|
+
throw new ArgumentError3(`${source}.transport.privateAddressHosts must be an array of strings`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return raw;
|
|
412
|
+
}
|
|
413
|
+
var CLI_IDENTITY_FIELDS = {
|
|
414
|
+
domain: "domain",
|
|
415
|
+
governance_id: "governanceId",
|
|
416
|
+
status_url: "statusUrl",
|
|
417
|
+
log_ref: "logRef",
|
|
418
|
+
ek_url: "ekUrl",
|
|
419
|
+
ku_url: "kuUrl",
|
|
420
|
+
capabilities_url: "capabilitiesUrl",
|
|
421
|
+
publish_profile: "publishProfile",
|
|
422
|
+
max_key_age: "maxKeyAge"
|
|
423
|
+
};
|
|
424
|
+
async function loadCliDirectory(dnsidDir = path2.join(os2.homedir(), ".dnsid")) {
|
|
418
425
|
let configPath = path2.join(dnsidDir, "config.json");
|
|
419
|
-
let raw
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
426
|
+
let raw;
|
|
427
|
+
try {
|
|
428
|
+
raw = jsonObject(await fs3.readFile(configPath), configPath);
|
|
429
|
+
} catch (e) {
|
|
430
|
+
if (e.code !== "ENOENT") throw e;
|
|
431
|
+
throw new Error(`${configPath} not found; run the DNSid CLI to register your domain first`);
|
|
432
|
+
}
|
|
433
|
+
if (typeof raw.domain === "string" && raw.domain !== "") {
|
|
434
|
+
const identityConfigPath = path2.join(dnsidDir, normalizeFQDN2(raw.domain, true), "config.json");
|
|
423
435
|
try {
|
|
424
|
-
raw = await
|
|
436
|
+
raw = jsonObject(await fs3.readFile(identityConfigPath), identityConfigPath);
|
|
425
437
|
configPath = identityConfigPath;
|
|
426
438
|
} catch (e) {
|
|
427
439
|
if (e.code !== "ENOENT") throw e;
|
|
428
440
|
}
|
|
429
441
|
}
|
|
430
|
-
const
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
};
|
|
442
|
-
const identity = { ...definedOnly(loaded), ...definedOnly(options.config?.identity ?? {}) };
|
|
443
|
-
if (!identity.domain) throw new Error(`${configPath} must include domain`);
|
|
444
|
-
if (!identity.governanceId) throw new Error(`${configPath} must include governanceId or governance_id`);
|
|
445
|
-
identity.logRef ??= "noop:0";
|
|
446
|
-
identity.statusUrl ??= protocolStatusUrl2(field("registryUrl", "registry_url", "server_url") ?? DEFAULT_REGISTRY_URL2, identity.domain);
|
|
447
|
-
const keyProvider = deps.keyProvider ?? await LocalKeyProvider.fromDirectory(await identityKeyDir(dnsidDir, identity.domain));
|
|
448
|
-
const entityKeyProvider = deps.entityKeyProvider ?? await optionalEntityKeyProvider(
|
|
449
|
-
path2.dirname(configPath),
|
|
450
|
-
field("entityKeyPath", "entity_key_path"),
|
|
451
|
-
field("entityKeyDir", "entity_key_dir")
|
|
452
|
-
);
|
|
453
|
-
return createNodeIdentityManager(
|
|
454
|
-
{ identity, verification: options.config?.verification, transport: options.config?.transport },
|
|
455
|
-
{ ...deps, keyProvider, entityKeyProvider }
|
|
456
|
-
);
|
|
442
|
+
const str = (key) => optional(raw, key, "string", configPath) || void 0;
|
|
443
|
+
const identity = compact(Object.fromEntries(
|
|
444
|
+
Object.entries(CLI_IDENTITY_FIELDS).map(([key, field]) => [field, str(key)])
|
|
445
|
+
));
|
|
446
|
+
const entityKeyPath = str("entity_key_path");
|
|
447
|
+
return top({
|
|
448
|
+
dnsid: compact({ identity }),
|
|
449
|
+
keySource: compact({
|
|
450
|
+
cliDirectory: dnsidDir,
|
|
451
|
+
entityKeyPath: entityKeyPath === void 0 ? void 0 : path2.resolve(path2.dirname(configPath), entityKeyPath)
|
|
452
|
+
})
|
|
453
|
+
});
|
|
457
454
|
}
|
|
458
|
-
function
|
|
459
|
-
return
|
|
455
|
+
function mergeLoadedConfig(base, overlay) {
|
|
456
|
+
return top({
|
|
457
|
+
dnsid: mergeDnsid(base.dnsid, overlay.dnsid),
|
|
458
|
+
logTrust: overlay.logTrust ?? base.logTrust,
|
|
459
|
+
registry: mergeSection(base.registry, overlay.registry),
|
|
460
|
+
keySource: mergeSection(base.keySource, overlay.keySource)
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
function mergeDnsid(base, overlay) {
|
|
464
|
+
if (!base || !overlay) return overlay ?? base;
|
|
465
|
+
return compact({
|
|
466
|
+
identity: mergeSection(base.identity, overlay.identity),
|
|
467
|
+
verification: mergeSection(base.verification, overlay.verification),
|
|
468
|
+
transport: mergeSection(base.transport, overlay.transport)
|
|
469
|
+
});
|
|
460
470
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
471
|
+
function mergeSection(base, overlay) {
|
|
472
|
+
if (!base || !overlay) return overlay ?? base;
|
|
473
|
+
return { ...base, ...definedEntries(overlay) };
|
|
474
|
+
}
|
|
475
|
+
var MANAGED_DEFAULTS_MS = 10 * 60 * 1e3;
|
|
476
|
+
async function constructIdentityManager(loaded, deps = {}) {
|
|
477
|
+
validateDnsidConfig2(loaded.dnsid ?? {});
|
|
478
|
+
const filled = { ...deps };
|
|
479
|
+
if (!filled.logRegistry && loaded.logTrust) {
|
|
480
|
+
filled.logRegistry = await logRegistryFromTrust(loaded.logTrust, loaded.dnsid?.transport);
|
|
481
|
+
}
|
|
482
|
+
const identity = loaded.dnsid?.identity;
|
|
483
|
+
if (identity && loaded.keySource) {
|
|
484
|
+
if (!filled.keyProvider) filled.keyProvider = await operationalKeyProvider(loaded.keySource, identity.domain);
|
|
485
|
+
if (!filled.entityKeyProvider && loaded.keySource.entityKeyPath !== void 0) {
|
|
486
|
+
filled.entityKeyProvider = await LocalKeyProvider.fromFile(loaded.keySource.entityKeyPath);
|
|
465
487
|
}
|
|
466
|
-
|
|
488
|
+
}
|
|
489
|
+
return createNodeIdentityManager(loaded.dnsid ?? {}, filled);
|
|
490
|
+
}
|
|
491
|
+
async function logRegistryFromTrust(trust, transport) {
|
|
492
|
+
const variants = ["managed", "profile", "policyDocument", "policyUrl"].filter((k) => trust[k] !== void 0);
|
|
493
|
+
if (variants.length !== 1) {
|
|
494
|
+
throw new ArgumentError3(`logTrust requires exactly one of managed, profile, policyDocument, policyUrl; got ${variants.length}`);
|
|
495
|
+
}
|
|
496
|
+
if (trust.managed !== void 0) {
|
|
497
|
+
if (trust.managed !== true) throw new ArgumentError3("logTrust.managed must be true when present");
|
|
498
|
+
return createDnsidManagedVerificationRegistry();
|
|
499
|
+
}
|
|
500
|
+
return createC2spTlogVerificationRegistry({
|
|
501
|
+
trustProfile: trust.profile && parseC2spTlogTrustProfile(new TextEncoder().encode(JSON.stringify(trust.profile))),
|
|
502
|
+
policyDocument: trust.policyDocument,
|
|
503
|
+
policyUrl: trust.policyUrl,
|
|
504
|
+
transport,
|
|
505
|
+
checkpointMaxAge: MANAGED_DEFAULTS_MS,
|
|
506
|
+
maxBundleLifetimeMs: trust.profile ? MANAGED_DEFAULTS_MS : void 0,
|
|
507
|
+
allowedClockSkew: 0
|
|
467
508
|
});
|
|
468
509
|
}
|
|
469
|
-
async function
|
|
470
|
-
if (
|
|
471
|
-
return LocalKeyProvider.
|
|
510
|
+
async function operationalKeyProvider(source, domain) {
|
|
511
|
+
if (source.cliDirectory !== void 0) {
|
|
512
|
+
return LocalKeyProvider.fromDirectory(await identityKeyDir(source.cliDirectory, domain));
|
|
472
513
|
}
|
|
473
|
-
if (
|
|
474
|
-
return
|
|
514
|
+
if (source.keyStorePath !== void 0) return LocalKeyProvider.load(source.keyStorePath);
|
|
515
|
+
return void 0;
|
|
475
516
|
}
|
|
476
517
|
async function identityKeyDir(dnsidDir, domain) {
|
|
477
518
|
for (const filename of ["private.jwk", "private.pem"]) {
|
|
@@ -484,35 +525,65 @@ async function identityKeyDir(dnsidDir, domain) {
|
|
|
484
525
|
}
|
|
485
526
|
return path2.join(dnsidDir, normalizeFQDN2(domain, true));
|
|
486
527
|
}
|
|
487
|
-
function
|
|
488
|
-
return
|
|
528
|
+
function createNodeIdentityManagerFromEnvironment(env, overlay, deps) {
|
|
529
|
+
return loadEnvironment(env).then((loaded) => constructIdentityManager(mergeLoadedConfig(loaded, top({ dnsid: overlay })), deps));
|
|
489
530
|
}
|
|
490
|
-
function
|
|
491
|
-
|
|
492
|
-
if (["24h", "7d", "30d", "90d"].includes(String(value))) return value;
|
|
493
|
-
throw new Error(`${configPath} has invalid maxKeyAge "${String(value)}"`);
|
|
531
|
+
function createNodeIdentityManagerFromDnsid(dnsidDir, overlay, deps) {
|
|
532
|
+
return loadCliDirectory(dnsidDir).then((loaded) => constructIdentityManager(mergeLoadedConfig(loaded, top({ dnsid: overlay })), deps));
|
|
494
533
|
}
|
|
495
|
-
function
|
|
496
|
-
return
|
|
534
|
+
function createNodeIdentityManagerFromFile(filePath, overlay, deps) {
|
|
535
|
+
return loadFile(filePath).then((loaded) => constructIdentityManager(mergeLoadedConfig(loaded, top({ dnsid: overlay })), deps));
|
|
497
536
|
}
|
|
498
|
-
async function
|
|
537
|
+
async function createRegistryClientFromEnvironment(env) {
|
|
538
|
+
const source = env ?? process.env;
|
|
539
|
+
const loaded = await loadEnvironment(source);
|
|
540
|
+
return new RegistryClient(compact({ baseUrl: loaded.registry?.registryUrl, token: source.DNSID_API_KEY?.trim() || void 0 }));
|
|
541
|
+
}
|
|
542
|
+
function definedEntries(value) {
|
|
543
|
+
return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== void 0));
|
|
544
|
+
}
|
|
545
|
+
function top(value) {
|
|
546
|
+
return definedEntries(value);
|
|
547
|
+
}
|
|
548
|
+
function compact(value) {
|
|
549
|
+
const defined = definedEntries(value);
|
|
550
|
+
return Object.keys(defined).length > 0 ? defined : void 0;
|
|
551
|
+
}
|
|
552
|
+
function jsonObject(bytes, source) {
|
|
553
|
+
let value;
|
|
499
554
|
try {
|
|
500
|
-
|
|
555
|
+
value = parseJsonNoDuplicateMembers(bytes);
|
|
501
556
|
} catch (e) {
|
|
502
|
-
|
|
503
|
-
if (err.code === "ERR_MODULE_NOT_FOUND" || err.code === "MODULE_NOT_FOUND") {
|
|
504
|
-
throw new Error("`@dnsid-ai/sdk/node` HTTPS defaults require optional peer `@dnsid-ai/transport`; install it or inject fetchJson.");
|
|
505
|
-
}
|
|
506
|
-
throw e;
|
|
557
|
+
throw new ArgumentError3(`${source}: ${e.message}`);
|
|
507
558
|
}
|
|
559
|
+
return object(value, source);
|
|
560
|
+
}
|
|
561
|
+
function object(value, source) {
|
|
562
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new ArgumentError3(`${source} must be a JSON object`);
|
|
563
|
+
return value;
|
|
564
|
+
}
|
|
565
|
+
function rejectUnknown(raw, source, allowed) {
|
|
566
|
+
for (const key of Object.keys(raw)) {
|
|
567
|
+
if (!allowed.includes(key)) throw new ArgumentError3(`${source} has unknown member "${key}"`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
function optional(raw, key, type, source) {
|
|
571
|
+
const value = raw[key];
|
|
572
|
+
if (value === void 0) return void 0;
|
|
573
|
+
if (typeof value !== type) throw new ArgumentError3(`${source}.${key} must be a ${type}`);
|
|
574
|
+
return value;
|
|
508
575
|
}
|
|
509
576
|
export {
|
|
510
577
|
LocalKeyProvider,
|
|
511
|
-
|
|
578
|
+
constructIdentityManager,
|
|
512
579
|
createNodeIdentityManager,
|
|
513
580
|
createNodeIdentityManagerFromDnsid,
|
|
581
|
+
createNodeIdentityManagerFromEnvironment,
|
|
582
|
+
createNodeIdentityManagerFromFile,
|
|
514
583
|
createNodeIdentityVerifier,
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
584
|
+
createRegistryClientFromEnvironment,
|
|
585
|
+
loadCliDirectory,
|
|
586
|
+
loadEnvironment,
|
|
587
|
+
loadFile,
|
|
588
|
+
mergeLoadedConfig
|
|
518
589
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dnsid-ai/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Runtime-neutral DNSid SDK entrypoint with optional Node.js convenience helpers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -39,15 +39,15 @@
|
|
|
39
39
|
"typecheck": "tsc --noEmit"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@dnsid-ai/protocol": "^0.
|
|
43
|
-
"@dnsid-ai/http-signatures": "^0.
|
|
44
|
-
"@dnsid-ai/jose": "^0.
|
|
45
|
-
"@dnsid-ai/log-c2sp-tlog": "^0.
|
|
46
|
-
"@dnsid-ai/registry": "^0.
|
|
47
|
-
"@dnsid-ai/web-bot-auth": "^0.
|
|
42
|
+
"@dnsid-ai/protocol": "^0.23.0",
|
|
43
|
+
"@dnsid-ai/http-signatures": "^0.23.0",
|
|
44
|
+
"@dnsid-ai/jose": "^0.23.0",
|
|
45
|
+
"@dnsid-ai/log-c2sp-tlog": "^0.23.0",
|
|
46
|
+
"@dnsid-ai/registry": "^0.23.0",
|
|
47
|
+
"@dnsid-ai/web-bot-auth": "^0.23.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@dnsid-ai/transport": "^0.
|
|
50
|
+
"@dnsid-ai/transport": "^0.23.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependenciesMeta": {
|
|
53
53
|
"@dnsid-ai/transport": {
|