@serve.zone/interfaces 30.7.0 → 30.8.1
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/changelog.md +12 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/data/index.d.ts +3 -0
- package/dist_ts/data/index.js +4 -1
- package/dist_ts/data/networkdelivery.d.ts +25 -0
- package/dist_ts/data/networkdelivery.js +38 -0
- package/dist_ts/data/networkprojection.d.ts +140 -0
- package/dist_ts/data/networkprojection.js +371 -0
- package/dist_ts/data/networksigning.d.ts +46 -0
- package/dist_ts/data/networksigning.js +52 -0
- package/dist_ts/private/networkcontract.d.ts +31 -0
- package/dist_ts/private/networkcontract.js +134 -0
- package/dist_ts/requests/runtimesession.d.ts +13 -0
- package/dist_ts/runtime.d.ts +1 -0
- package/dist_ts/runtime.js +2 -1
- package/dist_ts/runtime.networkprojection.d.ts +15 -0
- package/dist_ts/runtime.networkprojection.js +58 -0
- package/package.json +1 -1
- package/readme.md +73 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/data/index.ts +3 -0
- package/ts/data/networkdelivery.ts +58 -0
- package/ts/data/networkprojection.ts +448 -0
- package/ts/data/networksigning.ts +84 -0
- package/ts/private/networkcontract.ts +117 -0
- package/ts/requests/runtimesession.ts +19 -0
- package/ts/runtime.networkprojection.ts +64 -0
- package/ts/runtime.ts +1 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { TSha256Digest } from '../data/immutableimage.js';
|
|
2
|
+
import type { IRuntimeAuthorityReferenceV1, IRuntimeControllerV1 } from '../data/runtimeassignment.js';
|
|
3
|
+
import { canonicalizeStrictJson, createCanonicalJsonSha256Hex } from './canonicaljson.js';
|
|
4
|
+
|
|
5
|
+
export const failNetwork = (): never => { throw new Error('Runtime network projection contract rejected.'); };
|
|
6
|
+
export function requireNetwork(value: unknown): asserts value { if (!value) failNetwork(); }
|
|
7
|
+
export const networkCanonical = (value: unknown): string => canonicalizeStrictJson(value, failNetwork);
|
|
8
|
+
export const networkEqual = (left: unknown, right: unknown): boolean => networkCanonical(left) === networkCanonical(right);
|
|
9
|
+
export const networkSafe = <T>(operation: () => T): T => { try { return operation(); } catch { return failNetwork(); } };
|
|
10
|
+
|
|
11
|
+
/** Bound decoded transport input before canonicalization; never execute getters/toJSON. */
|
|
12
|
+
export const captureNetwork = (value: unknown): unknown => networkSafe(() => {
|
|
13
|
+
const encoder = new TextEncoder(), ancestors = new Set<object>();
|
|
14
|
+
let nodes = 0, bytes = 0;
|
|
15
|
+
const account = (text: string) => {
|
|
16
|
+
requireNetwork(text.length <= 1_048_576);
|
|
17
|
+
bytes += encoder.encode(text).length;
|
|
18
|
+
requireNetwork(bytes <= 1_048_576);
|
|
19
|
+
};
|
|
20
|
+
const copy = (item: unknown, depth: number): unknown => {
|
|
21
|
+
requireNetwork(++nodes <= 65_536 && depth <= 24);
|
|
22
|
+
if (typeof item === 'string') { account(item); return item; }
|
|
23
|
+
if (item === null || typeof item === 'boolean') return item;
|
|
24
|
+
if (typeof item === 'number') {
|
|
25
|
+
requireNetwork(Number.isSafeInteger(item) && !Object.is(item, -0)); return item;
|
|
26
|
+
}
|
|
27
|
+
requireNetwork(item !== null && typeof item === 'object' && !ancestors.has(item));
|
|
28
|
+
const array = Array.isArray(item), prototype = Object.getPrototypeOf(item), keys = Reflect.ownKeys(item);
|
|
29
|
+
requireNetwork(array ? prototype === Array.prototype : prototype === Object.prototype || prototype === null);
|
|
30
|
+
requireNetwork(keys.length <= 4097);
|
|
31
|
+
ancestors.add(item);
|
|
32
|
+
try {
|
|
33
|
+
if (array) {
|
|
34
|
+
const length = Object.getOwnPropertyDescriptor(item, 'length')?.value;
|
|
35
|
+
requireNetwork(Number.isSafeInteger(length) && length >= 0 && length <= 4096 && keys.length === length + 1);
|
|
36
|
+
const result: unknown[] = [];
|
|
37
|
+
for (let index = 0; index < length; index++) {
|
|
38
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, String(index));
|
|
39
|
+
requireNetwork(descriptor?.enumerable && Object.hasOwn(descriptor, 'value'));
|
|
40
|
+
result.push(copy(descriptor.value, depth + 1));
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
const result: Record<string, unknown> = Object.create(null);
|
|
45
|
+
for (const key of keys) {
|
|
46
|
+
requireNetwork(typeof key === 'string'); account(key);
|
|
47
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, key);
|
|
48
|
+
requireNetwork(descriptor?.enumerable && Object.hasOwn(descriptor, 'value'));
|
|
49
|
+
result[key] = copy(descriptor.value, depth + 1);
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
} finally { ancestors.delete(item); }
|
|
53
|
+
};
|
|
54
|
+
const result = copy(value, 0);
|
|
55
|
+
requireNetwork(encoder.encode(networkCanonical(result)).length <= 1_048_576);
|
|
56
|
+
return result;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export const networkRecord = (value: unknown, keys: string[]): Record<string, unknown> => {
|
|
60
|
+
requireNetwork(value !== null && typeof value === 'object' && !Array.isArray(value));
|
|
61
|
+
const actual = Object.keys(value);
|
|
62
|
+
requireNetwork(actual.length === keys.length && keys.every(key => Object.hasOwn(value, key)));
|
|
63
|
+
return value as Record<string, unknown>;
|
|
64
|
+
};
|
|
65
|
+
export const networkList = <T>(value: unknown, maximum: number, read: (item: unknown) => T): T[] => {
|
|
66
|
+
requireNetwork(Array.isArray(value) && value.length <= maximum); return value.map(read);
|
|
67
|
+
};
|
|
68
|
+
export const networkSorted = <T>(values: T[], key: (item: T) => string): T[] => {
|
|
69
|
+
requireNetwork(values.every((value, index) => index === 0 || key(values[index - 1]) < key(value))); return values;
|
|
70
|
+
};
|
|
71
|
+
export const networkId = (value: unknown): string => {
|
|
72
|
+
requireNetwork(typeof value === 'string' && /^[A-Za-z0-9][A-Za-z0-9:._-]{0,199}$/.test(value)); return value;
|
|
73
|
+
};
|
|
74
|
+
export const networkCounter = (value: unknown, maximum = Number.MAX_SAFE_INTEGER - 1): number => {
|
|
75
|
+
requireNetwork(typeof value === 'number' && Number.isSafeInteger(value) && value > 0 && value <= maximum); return value;
|
|
76
|
+
};
|
|
77
|
+
export const networkDigest = (value: unknown): TSha256Digest => {
|
|
78
|
+
requireNetwork(typeof value === 'string' && /^sha256:[a-f0-9]{64}$/.test(value)); return value as TSha256Digest;
|
|
79
|
+
};
|
|
80
|
+
export const networkController = (value: unknown): IRuntimeControllerV1 => {
|
|
81
|
+
const item = networkRecord(value, ['kind', 'id', 'epoch']);
|
|
82
|
+
requireNetwork(item.kind === 'cloudly' || item.kind === 'onebox');
|
|
83
|
+
return { kind: item.kind, id: networkId(item.id), epoch: networkId(item.epoch) };
|
|
84
|
+
};
|
|
85
|
+
export const networkReference = (value: unknown): IRuntimeAuthorityReferenceV1 => {
|
|
86
|
+
const item = networkRecord(value, ['id', 'generation', 'digest']);
|
|
87
|
+
return { id: networkId(item.id), generation: networkCounter(item.generation), digest: networkDigest(item.digest) };
|
|
88
|
+
};
|
|
89
|
+
export const networkReferenceOf = (value: IRuntimeAuthorityReferenceV1): IRuntimeAuthorityReferenceV1 =>
|
|
90
|
+
({ id: value.id, generation: value.generation, digest: value.digest });
|
|
91
|
+
export const networkRevision = (item: Record<string, unknown>) => {
|
|
92
|
+
const id = networkId(item.id), generation = networkCounter(item.generation);
|
|
93
|
+
const previous = item.previous === null ? null : networkReference(item.previous);
|
|
94
|
+
requireNetwork(generation === 1 ? previous === null : previous?.id === id && previous.generation === generation - 1);
|
|
95
|
+
return { id, generation, previous };
|
|
96
|
+
};
|
|
97
|
+
export const networkHash = async (domain: string, value: { digest: TSha256Digest }): Promise<TSha256Digest> => {
|
|
98
|
+
const { digest: omitted, ...payload } = value;
|
|
99
|
+
return `sha256:${await createCanonicalJsonSha256Hex(networkCanonical({ domain, payload }), failNetwork)}`;
|
|
100
|
+
};
|
|
101
|
+
export const networkIpv4 = (value: unknown): string => {
|
|
102
|
+
requireNetwork(typeof value === 'string' && value.length <= 15);
|
|
103
|
+
const parts = value.split('.');
|
|
104
|
+
requireNetwork(parts.length === 4 && parts.every(part => /^(?:0|[1-9][0-9]{0,2})$/.test(part) && Number(part) <= 255));
|
|
105
|
+
return value;
|
|
106
|
+
};
|
|
107
|
+
export const networkIpv4Number = (value: string): number => value.split('.').reduce((sum, part) => sum * 256 + Number(part), 0);
|
|
108
|
+
export const networkPrefixBounds = (value: string): [number, number] => {
|
|
109
|
+
const [address, bits] = value.split('/'), first = networkIpv4Number(address);
|
|
110
|
+
return [first, first + 2 ** (32 - Number(bits)) - 1];
|
|
111
|
+
};
|
|
112
|
+
export const networkContains = (outer: string, inner: string): boolean => {
|
|
113
|
+
const [a, b] = networkPrefixBounds(outer), [c, d] = networkPrefixBounds(inner); return a <= c && b >= d;
|
|
114
|
+
};
|
|
115
|
+
export const networkOverlaps = (left: string, right: string): boolean => {
|
|
116
|
+
const [a, b] = networkPrefixBounds(left), [c, d] = networkPrefixBounds(right); return a <= d && c <= b;
|
|
117
|
+
};
|
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import * as plugins from '../plugins.js';
|
|
2
2
|
import type * as data from '../data/runtimesession.js';
|
|
3
3
|
import type * as terminal from '../data/runtimeterminalreceipt.js';
|
|
4
|
+
import type * as network from '../data/networkdelivery.js';
|
|
5
|
+
|
|
6
|
+
/** Dedicated signing trust installed only through the current authenticated physical peer. */
|
|
7
|
+
export interface IReq_Controller_Pallet_ApplyRuntimeNetworkSigningAuthorityV1 extends plugins.typedrequestInterfaces.implementsTR<
|
|
8
|
+
plugins.typedrequestInterfaces.ITypedRequest, IReq_Controller_Pallet_ApplyRuntimeNetworkSigningAuthorityV1
|
|
9
|
+
> {
|
|
10
|
+
method: 'applyRuntimeNetworkSigningAuthorityV1';
|
|
11
|
+
request: network.IApplyRuntimeNetworkSigningAuthorityRequestV1;
|
|
12
|
+
response: network.IApplyRuntimeNetworkAuthorityResponseV1;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Complete signed node state; an ACK asserts admission only. */
|
|
16
|
+
export interface IReq_Controller_Pallet_ApplyRuntimeNetworkProjectionV1 extends plugins.typedrequestInterfaces.implementsTR<
|
|
17
|
+
plugins.typedrequestInterfaces.ITypedRequest, IReq_Controller_Pallet_ApplyRuntimeNetworkProjectionV1
|
|
18
|
+
> {
|
|
19
|
+
method: 'applyRuntimeNetworkProjectionV1';
|
|
20
|
+
request: network.IApplyRuntimeNetworkProjectionRequestV1;
|
|
21
|
+
response: network.IApplyRuntimeNetworkAuthorityResponseV1;
|
|
22
|
+
}
|
|
4
23
|
|
|
5
24
|
/** WSS-only Pallet bootstrap. Derive physical peer/process/idempotency server-side. */
|
|
6
25
|
export interface IReq_Pallet_Cloudly_RegisterPalletRuntimeSessionV1 extends plugins.typedrequestInterfaces.implementsTR<
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as plugins from './plugins.runtime.js';
|
|
2
|
+
import type { IRuntimeAuthorityReferenceV1 } from './data/runtimeassignment.js';
|
|
3
|
+
import type { IRuntimeNetworkProjectionV1 } from './data/networkprojection.js';
|
|
4
|
+
import { snapshotRuntimeNetworkNodeScopeV1, snapshotRuntimeNetworkProjectionV1, validateRuntimeNetworkProjectionV1 } from './data/networkprojection.js';
|
|
5
|
+
import type { IRuntimeNetworkSigningAuthorityV1, ISignedRuntimeNetworkProjectionV1 } from './data/networksigning.js';
|
|
6
|
+
import { computeRuntimeNetworkSigningAuthorityV1Digest, runtimeNetworkSigningV1Contract,
|
|
7
|
+
snapshotRuntimeNetworkSigningAuthorityV1, snapshotSignedRuntimeNetworkProjectionV1 } from './data/networksigning.js';
|
|
8
|
+
import { failNetwork, networkCanonical, networkEqual, networkReferenceOf, requireNetwork } from './private/networkcontract.js';
|
|
9
|
+
|
|
10
|
+
/** The private KeyObject is process-local. Persist only through the controller's encrypted secret store. */
|
|
11
|
+
export const createRuntimeNetworkSigningKeyV1 = (): { publicKey: string; privateKey: plugins.crypto.KeyObject } => {
|
|
12
|
+
const pair = plugins.crypto.generateKeyPairSync('ed25519');
|
|
13
|
+
const jwk = pair.publicKey.export({ format: 'jwk' });
|
|
14
|
+
requireNetwork(jwk.kty === 'OKP' && jwk.crv === 'Ed25519' && typeof jwk.x === 'string');
|
|
15
|
+
return { publicKey: Buffer.from(jwk.x, 'base64url').toString('hex'), privateKey: pair.privateKey };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const signatureBytes = (authority: IRuntimeAuthorityReferenceV1, projection: IRuntimeNetworkProjectionV1): Uint8Array =>
|
|
19
|
+
new TextEncoder().encode(networkCanonical({ domain: runtimeNetworkSigningV1Contract.signatureDomain, schemaVersion: 1, authority, projection }));
|
|
20
|
+
const validateAuthority = async (authority: IRuntimeNetworkSigningAuthorityV1, projection: IRuntimeNetworkProjectionV1): Promise<void> => {
|
|
21
|
+
requireNetwork(authority.publicKey !== null && networkEqual(authority.controller, projection.controller)
|
|
22
|
+
&& authority.digest === await computeRuntimeNetworkSigningAuthorityV1Digest(authority));
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** Sign only validated complete state and a matching dedicated private key. */
|
|
26
|
+
export const signRuntimeNetworkProjectionV1 = async (
|
|
27
|
+
projectionValue: unknown, authorityValue: unknown, privateKey: plugins.crypto.KeyObject,
|
|
28
|
+
): Promise<ISignedRuntimeNetworkProjectionV1> => {
|
|
29
|
+
try {
|
|
30
|
+
const input = snapshotRuntimeNetworkProjectionV1(projectionValue), authority = snapshotRuntimeNetworkSigningAuthorityV1(authorityValue);
|
|
31
|
+
requireNetwork(privateKey instanceof plugins.crypto.KeyObject && privateKey.type === 'private' && privateKey.asymmetricKeyType === 'ed25519');
|
|
32
|
+
const publicKey = plugins.crypto.createPublicKey(privateKey).export({ format: 'jwk' });
|
|
33
|
+
requireNetwork(typeof publicKey.x === 'string' && Buffer.from(publicKey.x, 'base64url').toString('hex') === authority.publicKey);
|
|
34
|
+
const projection = await validateRuntimeNetworkProjectionV1(input);
|
|
35
|
+
await validateAuthority(authority, projection);
|
|
36
|
+
const reference = networkReferenceOf(authority);
|
|
37
|
+
const signature = plugins.crypto.sign(null, signatureBytes(reference, projection), privateKey).toString('hex');
|
|
38
|
+
return { schemaVersion: 1, authority: reference, projection, signature };
|
|
39
|
+
} catch { return failNetwork(); }
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* trustedAuthorityValue is receiver-owned persisted trust, NEVER envelope material.
|
|
44
|
+
* This verifies content/scope/signature only. The owner still performs atomic revision
|
|
45
|
+
* admission, live-session fencing, allocation barriers and conservative DNS time checks.
|
|
46
|
+
*/
|
|
47
|
+
export const verifyRuntimeNetworkProjectionV1 = async (
|
|
48
|
+
value: unknown, trustedAuthorityValue: unknown, trustedScopeValue: unknown,
|
|
49
|
+
): Promise<ISignedRuntimeNetworkProjectionV1> => {
|
|
50
|
+
try {
|
|
51
|
+
const signed = snapshotSignedRuntimeNetworkProjectionV1(value);
|
|
52
|
+
const authority = snapshotRuntimeNetworkSigningAuthorityV1(trustedAuthorityValue);
|
|
53
|
+
const trusted = snapshotRuntimeNetworkNodeScopeV1(trustedScopeValue);
|
|
54
|
+
requireNetwork(networkEqual(signed.authority, networkReferenceOf(authority))
|
|
55
|
+
&& signed.projection.nodeId === trusted.nodeId && signed.projection.runtimeNamespace === trusted.runtimeNamespace
|
|
56
|
+
&& networkEqual(signed.projection.controller, trusted.controller));
|
|
57
|
+
await validateAuthority(authority, signed.projection);
|
|
58
|
+
const key = plugins.crypto.createPublicKey({ format: 'jwk', key: { kty: 'OKP', crv: 'Ed25519',
|
|
59
|
+
x: Buffer.from(authority.publicKey!, 'hex').toString('base64url') } });
|
|
60
|
+
requireNetwork(plugins.crypto.verify(null, signatureBytes(signed.authority, signed.projection), key, Buffer.from(signed.signature, 'hex')));
|
|
61
|
+
await validateRuntimeNetworkProjectionV1(signed.projection);
|
|
62
|
+
return signed;
|
|
63
|
+
} catch { return failNetwork(); }
|
|
64
|
+
};
|
package/ts/runtime.ts
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
} from './runtime.workloadinit.js';
|
|
40
40
|
|
|
41
41
|
export * from './runtime.workloadinit.js';
|
|
42
|
+
export * from './runtime.networkprojection.js';
|
|
42
43
|
export * from './runtime.corestore.js';
|
|
43
44
|
export * from './runtime.corestore.databaseexportpackage.js';
|
|
44
45
|
export * from './runtime.cloudlylegacydeploymentsettlement.js';
|