@nextera.one/axis-server-sdk 0.9.3 → 1.1.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/dist/index.d.mts +84 -250
- package/dist/index.d.ts +84 -250
- package/dist/index.js +389 -627
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +369 -591
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -31,20 +31,366 @@ function Handler(intent) {
|
|
|
31
31
|
|
|
32
32
|
// src/decorators/intent.decorator.ts
|
|
33
33
|
import "reflect-metadata";
|
|
34
|
+
var INTENT_METADATA_KEY = "axis:intent";
|
|
34
35
|
var INTENT_ROUTES_KEY = "axis:intent_routes";
|
|
35
36
|
function Intent(action, options) {
|
|
36
37
|
return (target, propertyKey) => {
|
|
38
|
+
Reflect.defineMetadata(
|
|
39
|
+
INTENT_METADATA_KEY,
|
|
40
|
+
{ intent: action, ...options },
|
|
41
|
+
target,
|
|
42
|
+
propertyKey
|
|
43
|
+
);
|
|
37
44
|
const routes = Reflect.getMetadata(INTENT_ROUTES_KEY, target.constructor) || [];
|
|
38
45
|
routes.push({
|
|
39
46
|
action,
|
|
40
47
|
methodName: propertyKey,
|
|
41
48
|
absolute: options?.absolute,
|
|
42
|
-
frame: options?.frame
|
|
49
|
+
frame: options?.frame,
|
|
50
|
+
kind: options?.kind,
|
|
51
|
+
bodyProfile: options?.bodyProfile,
|
|
52
|
+
tlv: options?.tlv,
|
|
53
|
+
dto: options?.dto
|
|
43
54
|
});
|
|
44
55
|
Reflect.defineMetadata(INTENT_ROUTES_KEY, routes, target.constructor);
|
|
45
56
|
};
|
|
46
57
|
}
|
|
47
58
|
|
|
59
|
+
// src/decorators/tlv-field.decorator.ts
|
|
60
|
+
import "reflect-metadata";
|
|
61
|
+
var TLV_FIELDS_KEY = "axis:tlv:fields";
|
|
62
|
+
var TLV_VALIDATORS_KEY = "axis:tlv:validators";
|
|
63
|
+
function TlvField(tag, options) {
|
|
64
|
+
return (target, propertyKey) => {
|
|
65
|
+
const existing = Reflect.getOwnMetadata(TLV_FIELDS_KEY, target.constructor) || [];
|
|
66
|
+
existing.push({
|
|
67
|
+
property: String(propertyKey),
|
|
68
|
+
tag,
|
|
69
|
+
options
|
|
70
|
+
});
|
|
71
|
+
Reflect.defineMetadata(TLV_FIELDS_KEY, existing, target.constructor);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function TlvValidate(validator) {
|
|
75
|
+
return (target, propertyKey) => {
|
|
76
|
+
const existing = Reflect.getOwnMetadata(TLV_VALIDATORS_KEY, target.constructor) || [];
|
|
77
|
+
const prop = String(propertyKey);
|
|
78
|
+
let entry = existing.find((e) => e.property === prop);
|
|
79
|
+
if (!entry) {
|
|
80
|
+
entry = { property: prop, tag: 0, validators: [] };
|
|
81
|
+
existing.push(entry);
|
|
82
|
+
}
|
|
83
|
+
entry.validators.push(validator);
|
|
84
|
+
Reflect.defineMetadata(TLV_VALIDATORS_KEY, existing, target.constructor);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function TlvUtf8Pattern(pattern, message) {
|
|
88
|
+
return TlvValidate((val, prop) => {
|
|
89
|
+
const str = new TextDecoder().decode(val);
|
|
90
|
+
return pattern.test(str) ? null : message || `${prop}: failed pattern check`;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function TlvMinLen(min, message) {
|
|
94
|
+
return TlvValidate((val, prop) => {
|
|
95
|
+
return val.length >= min ? null : message || `${prop}: too short (${val.length} < ${min})`;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function TlvEnum(allowed, message) {
|
|
99
|
+
const set = new Set(allowed);
|
|
100
|
+
return TlvValidate((val, prop) => {
|
|
101
|
+
const str = new TextDecoder().decode(val);
|
|
102
|
+
return set.has(str) ? null : message || `${prop}: must be one of [${allowed.join(", ")}]`;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function TlvRange(min, max, message) {
|
|
106
|
+
return TlvValidate((val, prop) => {
|
|
107
|
+
if (val.length !== 8) return `${prop}: u64 must be 8 bytes`;
|
|
108
|
+
let n = 0n;
|
|
109
|
+
for (const b of val) n = n << 8n | BigInt(b);
|
|
110
|
+
if (n < min || n > max) {
|
|
111
|
+
return message || `${prop}: value ${n} out of range [${min}, ${max}]`;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/decorators/dto-schema.util.ts
|
|
118
|
+
import "reflect-metadata";
|
|
119
|
+
|
|
120
|
+
// src/core/varint.ts
|
|
121
|
+
function encodeVarint(value) {
|
|
122
|
+
if (value < 0) throw new Error("Varint must be unsigned");
|
|
123
|
+
const bytes2 = [];
|
|
124
|
+
while (true) {
|
|
125
|
+
const byte = value & 127;
|
|
126
|
+
value >>>= 7;
|
|
127
|
+
if (value === 0) {
|
|
128
|
+
bytes2.push(byte);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
bytes2.push(byte | 128);
|
|
132
|
+
}
|
|
133
|
+
return new Uint8Array(bytes2);
|
|
134
|
+
}
|
|
135
|
+
function decodeVarint(buf, offset = 0) {
|
|
136
|
+
let value = 0;
|
|
137
|
+
let shift = 0;
|
|
138
|
+
let length = 0;
|
|
139
|
+
while (true) {
|
|
140
|
+
if (offset + length >= buf.length) {
|
|
141
|
+
throw new Error("Varint decode out of bounds");
|
|
142
|
+
}
|
|
143
|
+
const byte = buf[offset + length];
|
|
144
|
+
value += (byte & 127) * Math.pow(2, shift);
|
|
145
|
+
length++;
|
|
146
|
+
shift += 7;
|
|
147
|
+
if ((byte & 128) === 0) {
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
if (length > 8) throw new Error("Varint too large");
|
|
151
|
+
}
|
|
152
|
+
return { value, length };
|
|
153
|
+
}
|
|
154
|
+
function varintLength(value) {
|
|
155
|
+
if (value < 0) throw new Error("Varint must be unsigned");
|
|
156
|
+
let len = 0;
|
|
157
|
+
do {
|
|
158
|
+
value >>>= 7;
|
|
159
|
+
len++;
|
|
160
|
+
} while (value !== 0);
|
|
161
|
+
return len;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/core/tlv.ts
|
|
165
|
+
function encodeTLVs(tlvs) {
|
|
166
|
+
const sorted = [...tlvs].sort((a, b) => a.type - b.type);
|
|
167
|
+
for (let i = 0; i < sorted.length - 1; i++) {
|
|
168
|
+
if (sorted[i].type === sorted[i + 1].type) {
|
|
169
|
+
throw new Error(`Duplicate TLV type: ${sorted[i].type}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
let totalSize = 0;
|
|
173
|
+
for (const t of sorted) {
|
|
174
|
+
totalSize += varintLength(t.type);
|
|
175
|
+
totalSize += varintLength(t.value.length);
|
|
176
|
+
totalSize += t.value.length;
|
|
177
|
+
}
|
|
178
|
+
const buf = new Uint8Array(totalSize);
|
|
179
|
+
let offset = 0;
|
|
180
|
+
for (const t of sorted) {
|
|
181
|
+
const typeBytes = encodeVarint(t.type);
|
|
182
|
+
buf.set(typeBytes, offset);
|
|
183
|
+
offset += typeBytes.length;
|
|
184
|
+
const lenBytes = encodeVarint(t.value.length);
|
|
185
|
+
buf.set(lenBytes, offset);
|
|
186
|
+
offset += lenBytes.length;
|
|
187
|
+
buf.set(t.value, offset);
|
|
188
|
+
offset += t.value.length;
|
|
189
|
+
}
|
|
190
|
+
return buf;
|
|
191
|
+
}
|
|
192
|
+
function decodeTLVsList(buf, maxItems = 1024) {
|
|
193
|
+
const list = [];
|
|
194
|
+
let offset = 0;
|
|
195
|
+
while (offset < buf.length) {
|
|
196
|
+
if (list.length >= maxItems) throw new Error("TLV_LIMIT");
|
|
197
|
+
const { value: type, length: typeLen } = decodeVarint(buf, offset);
|
|
198
|
+
offset += typeLen;
|
|
199
|
+
const { value: len, length: lenLen } = decodeVarint(buf, offset);
|
|
200
|
+
offset += lenLen;
|
|
201
|
+
if (offset + len > buf.length) {
|
|
202
|
+
throw new Error(`TLV violation: Length ${len} exceeds buffer`);
|
|
203
|
+
}
|
|
204
|
+
const value = buf.slice(offset, offset + len);
|
|
205
|
+
list.push({ type, value });
|
|
206
|
+
offset += len;
|
|
207
|
+
}
|
|
208
|
+
return list;
|
|
209
|
+
}
|
|
210
|
+
function decodeTLVs(buf) {
|
|
211
|
+
const map2 = /* @__PURE__ */ new Map();
|
|
212
|
+
let offset = 0;
|
|
213
|
+
let lastType = -1;
|
|
214
|
+
while (offset < buf.length) {
|
|
215
|
+
const { value: type, length: typeLen } = decodeVarint(buf, offset);
|
|
216
|
+
offset += typeLen;
|
|
217
|
+
if (type <= lastType) {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`TLV violation: Unsorted or duplicate type ${type} after ${lastType}`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
lastType = type;
|
|
223
|
+
const { value: len, length: lenLen } = decodeVarint(buf, offset);
|
|
224
|
+
offset += lenLen;
|
|
225
|
+
if (offset + len > buf.length) {
|
|
226
|
+
throw new Error(`TLV violation: Length ${len} exceeds buffer`);
|
|
227
|
+
}
|
|
228
|
+
const value = buf.slice(offset, offset + len);
|
|
229
|
+
map2.set(type, value);
|
|
230
|
+
offset += len;
|
|
231
|
+
}
|
|
232
|
+
return map2;
|
|
233
|
+
}
|
|
234
|
+
function decodeObject(bytes2, depth = 0, limits = { maxDepth: 8, maxItems: 128 }) {
|
|
235
|
+
if (depth > limits.maxDepth) {
|
|
236
|
+
throw new Error("OBJECT_DEPTH_EXCEEDED");
|
|
237
|
+
}
|
|
238
|
+
const map2 = decodeTLVs(bytes2);
|
|
239
|
+
return map2;
|
|
240
|
+
}
|
|
241
|
+
function decodeArray(bytes2, itemType, maxItems = 256) {
|
|
242
|
+
const list = decodeTLVsList(bytes2, maxItems);
|
|
243
|
+
const items = [];
|
|
244
|
+
for (const tlv2 of list) {
|
|
245
|
+
if (tlv2.type !== itemType) {
|
|
246
|
+
throw new Error(`INVALID_ARRAY_ITEM:${tlv2.type}`);
|
|
247
|
+
}
|
|
248
|
+
items.push(tlv2.value);
|
|
249
|
+
}
|
|
250
|
+
return items;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/decorators/dto-schema.util.ts
|
|
254
|
+
function extractDtoSchema(dto) {
|
|
255
|
+
const fieldMetas = Reflect.getOwnMetadata(TLV_FIELDS_KEY, dto) || [];
|
|
256
|
+
if (fieldMetas.length === 0) {
|
|
257
|
+
throw new Error(
|
|
258
|
+
`DTO class ${dto.name} has no @TlvField decorators \u2014 nothing to validate`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
const tagByProp = /* @__PURE__ */ new Map();
|
|
262
|
+
const fields = fieldMetas.map((m) => {
|
|
263
|
+
tagByProp.set(m.property, m.tag);
|
|
264
|
+
return {
|
|
265
|
+
name: m.property,
|
|
266
|
+
tag: m.tag,
|
|
267
|
+
kind: m.options.kind,
|
|
268
|
+
required: m.options.required,
|
|
269
|
+
maxLen: m.options.maxLen,
|
|
270
|
+
max: m.options.max,
|
|
271
|
+
scope: m.options.scope
|
|
272
|
+
};
|
|
273
|
+
});
|
|
274
|
+
const validatorMetas = Reflect.getOwnMetadata(TLV_VALIDATORS_KEY, dto) || [];
|
|
275
|
+
const validators = /* @__PURE__ */ new Map();
|
|
276
|
+
for (const vm of validatorMetas) {
|
|
277
|
+
const tag = tagByProp.get(vm.property);
|
|
278
|
+
if (tag === void 0) {
|
|
279
|
+
throw new Error(
|
|
280
|
+
`@TlvValidate on ${dto.name}.${vm.property} but no @TlvField found for that property`
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
vm.tag = tag;
|
|
284
|
+
validators.set(tag, vm.validators);
|
|
285
|
+
}
|
|
286
|
+
return { fields, validators };
|
|
287
|
+
}
|
|
288
|
+
function buildDtoDecoder(dto) {
|
|
289
|
+
const fieldMetas = Reflect.getOwnMetadata(TLV_FIELDS_KEY, dto) || [];
|
|
290
|
+
if (fieldMetas.length === 0) {
|
|
291
|
+
throw new Error(
|
|
292
|
+
`DTO class ${dto.name} has no @TlvField decorators \u2014 cannot build decoder`
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
const tagMap = /* @__PURE__ */ new Map();
|
|
296
|
+
for (const m of fieldMetas) {
|
|
297
|
+
tagMap.set(m.tag, { property: m.property, kind: m.options.kind });
|
|
298
|
+
}
|
|
299
|
+
return (bodyBytes) => {
|
|
300
|
+
const tlvMap2 = decodeTLVs(new Uint8Array(bodyBytes));
|
|
301
|
+
const result = {};
|
|
302
|
+
for (const [tag, raw] of tlvMap2) {
|
|
303
|
+
const meta = tagMap.get(tag);
|
|
304
|
+
if (!meta) continue;
|
|
305
|
+
switch (meta.kind) {
|
|
306
|
+
case "utf8":
|
|
307
|
+
result[meta.property] = new TextDecoder().decode(raw);
|
|
308
|
+
break;
|
|
309
|
+
case "u64": {
|
|
310
|
+
let n = 0n;
|
|
311
|
+
for (let i = 0; i < raw.length; i++) {
|
|
312
|
+
n = n << 8n | BigInt(raw[i]);
|
|
313
|
+
}
|
|
314
|
+
result[meta.property] = n;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
case "bytes":
|
|
318
|
+
case "bytes16":
|
|
319
|
+
result[meta.property] = raw;
|
|
320
|
+
break;
|
|
321
|
+
case "bool":
|
|
322
|
+
result[meta.property] = raw.length > 0 && raw[0] !== 0;
|
|
323
|
+
break;
|
|
324
|
+
case "obj":
|
|
325
|
+
case "arr":
|
|
326
|
+
result[meta.property] = JSON.parse(new TextDecoder().decode(raw));
|
|
327
|
+
break;
|
|
328
|
+
default:
|
|
329
|
+
result[meta.property] = raw;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return result;
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// src/base/axis-tlv.dto.ts
|
|
337
|
+
var AxisTlvDto = class {
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
// src/base/axis-id.dto.ts
|
|
341
|
+
var AxisIdDto = class extends AxisTlvDto {
|
|
342
|
+
};
|
|
343
|
+
__decorateClass([
|
|
344
|
+
TlvField(1, { kind: "utf8", required: true, maxLen: 128 }),
|
|
345
|
+
TlvMinLen(1, "id must not be empty")
|
|
346
|
+
], AxisIdDto.prototype, "id", 2);
|
|
347
|
+
|
|
348
|
+
// src/base/axis-partial-type.ts
|
|
349
|
+
import "reflect-metadata";
|
|
350
|
+
function AxisPartialType(BaseDto) {
|
|
351
|
+
class PartialDto extends BaseDto {
|
|
352
|
+
}
|
|
353
|
+
const fields = Reflect.getOwnMetadata(TLV_FIELDS_KEY, BaseDto) || [];
|
|
354
|
+
const partialFields = fields.map((f) => ({
|
|
355
|
+
property: f.property,
|
|
356
|
+
tag: f.tag,
|
|
357
|
+
options: { ...f.options, required: false }
|
|
358
|
+
}));
|
|
359
|
+
Reflect.defineMetadata(TLV_FIELDS_KEY, partialFields, PartialDto);
|
|
360
|
+
const validators = Reflect.getOwnMetadata(TLV_VALIDATORS_KEY, BaseDto) || [];
|
|
361
|
+
if (validators.length > 0) {
|
|
362
|
+
Reflect.defineMetadata(TLV_VALIDATORS_KEY, [...validators], PartialDto);
|
|
363
|
+
}
|
|
364
|
+
Object.defineProperty(PartialDto, "name", {
|
|
365
|
+
value: `Partial${BaseDto.name}`
|
|
366
|
+
});
|
|
367
|
+
return PartialDto;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// src/base/axis-response.dto.ts
|
|
371
|
+
var RESPONSE_TAG_ID = 1;
|
|
372
|
+
var RESPONSE_TAG_CREATED_AT = 2;
|
|
373
|
+
var RESPONSE_TAG_UPDATED_AT = 3;
|
|
374
|
+
var RESPONSE_TAG_CREATED_BY = 4;
|
|
375
|
+
var RESPONSE_TAG_UPDATED_BY = 5;
|
|
376
|
+
var AxisResponseDto = class extends AxisTlvDto {
|
|
377
|
+
};
|
|
378
|
+
__decorateClass([
|
|
379
|
+
TlvField(RESPONSE_TAG_ID, { kind: "utf8" })
|
|
380
|
+
], AxisResponseDto.prototype, "id", 2);
|
|
381
|
+
__decorateClass([
|
|
382
|
+
TlvField(RESPONSE_TAG_CREATED_AT, { kind: "u64" })
|
|
383
|
+
], AxisResponseDto.prototype, "created_at", 2);
|
|
384
|
+
__decorateClass([
|
|
385
|
+
TlvField(RESPONSE_TAG_UPDATED_AT, { kind: "u64" })
|
|
386
|
+
], AxisResponseDto.prototype, "updated_at", 2);
|
|
387
|
+
__decorateClass([
|
|
388
|
+
TlvField(RESPONSE_TAG_CREATED_BY, { kind: "utf8" })
|
|
389
|
+
], AxisResponseDto.prototype, "created_by", 2);
|
|
390
|
+
__decorateClass([
|
|
391
|
+
TlvField(RESPONSE_TAG_UPDATED_BY, { kind: "utf8" })
|
|
392
|
+
], AxisResponseDto.prototype, "updated_by", 2);
|
|
393
|
+
|
|
48
394
|
// src/engine/intent.router.ts
|
|
49
395
|
import { Injectable as Injectable2 } from "@nestjs/common";
|
|
50
396
|
var IntentRouter = class {
|
|
@@ -285,139 +631,6 @@ var ERR_BAD_SIGNATURE = "BAD_SIGNATURE";
|
|
|
285
631
|
var ERR_REPLAY_DETECTED = "REPLAY_DETECTED";
|
|
286
632
|
var ERR_CONTRACT_VIOLATION = "CONTRACT_VIOLATION";
|
|
287
633
|
|
|
288
|
-
// src/core/varint.ts
|
|
289
|
-
function encodeVarint(value) {
|
|
290
|
-
if (value < 0) throw new Error("Varint must be unsigned");
|
|
291
|
-
const bytes2 = [];
|
|
292
|
-
while (true) {
|
|
293
|
-
const byte = value & 127;
|
|
294
|
-
value >>>= 7;
|
|
295
|
-
if (value === 0) {
|
|
296
|
-
bytes2.push(byte);
|
|
297
|
-
break;
|
|
298
|
-
}
|
|
299
|
-
bytes2.push(byte | 128);
|
|
300
|
-
}
|
|
301
|
-
return new Uint8Array(bytes2);
|
|
302
|
-
}
|
|
303
|
-
function decodeVarint(buf, offset = 0) {
|
|
304
|
-
let value = 0;
|
|
305
|
-
let shift = 0;
|
|
306
|
-
let length = 0;
|
|
307
|
-
while (true) {
|
|
308
|
-
if (offset + length >= buf.length) {
|
|
309
|
-
throw new Error("Varint decode out of bounds");
|
|
310
|
-
}
|
|
311
|
-
const byte = buf[offset + length];
|
|
312
|
-
value += (byte & 127) * Math.pow(2, shift);
|
|
313
|
-
length++;
|
|
314
|
-
shift += 7;
|
|
315
|
-
if ((byte & 128) === 0) {
|
|
316
|
-
break;
|
|
317
|
-
}
|
|
318
|
-
if (length > 8) throw new Error("Varint too large");
|
|
319
|
-
}
|
|
320
|
-
return { value, length };
|
|
321
|
-
}
|
|
322
|
-
function varintLength(value) {
|
|
323
|
-
if (value < 0) throw new Error("Varint must be unsigned");
|
|
324
|
-
let len = 0;
|
|
325
|
-
do {
|
|
326
|
-
value >>>= 7;
|
|
327
|
-
len++;
|
|
328
|
-
} while (value !== 0);
|
|
329
|
-
return len;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// src/core/tlv.ts
|
|
333
|
-
function encodeTLVs(tlvs) {
|
|
334
|
-
const sorted = [...tlvs].sort((a, b) => a.type - b.type);
|
|
335
|
-
for (let i = 0; i < sorted.length - 1; i++) {
|
|
336
|
-
if (sorted[i].type === sorted[i + 1].type) {
|
|
337
|
-
throw new Error(`Duplicate TLV type: ${sorted[i].type}`);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
let totalSize = 0;
|
|
341
|
-
for (const t of sorted) {
|
|
342
|
-
totalSize += varintLength(t.type);
|
|
343
|
-
totalSize += varintLength(t.value.length);
|
|
344
|
-
totalSize += t.value.length;
|
|
345
|
-
}
|
|
346
|
-
const buf = new Uint8Array(totalSize);
|
|
347
|
-
let offset = 0;
|
|
348
|
-
for (const t of sorted) {
|
|
349
|
-
const typeBytes = encodeVarint(t.type);
|
|
350
|
-
buf.set(typeBytes, offset);
|
|
351
|
-
offset += typeBytes.length;
|
|
352
|
-
const lenBytes = encodeVarint(t.value.length);
|
|
353
|
-
buf.set(lenBytes, offset);
|
|
354
|
-
offset += lenBytes.length;
|
|
355
|
-
buf.set(t.value, offset);
|
|
356
|
-
offset += t.value.length;
|
|
357
|
-
}
|
|
358
|
-
return buf;
|
|
359
|
-
}
|
|
360
|
-
function decodeTLVsList(buf, maxItems = 1024) {
|
|
361
|
-
const list = [];
|
|
362
|
-
let offset = 0;
|
|
363
|
-
while (offset < buf.length) {
|
|
364
|
-
if (list.length >= maxItems) throw new Error("TLV_LIMIT");
|
|
365
|
-
const { value: type, length: typeLen } = decodeVarint(buf, offset);
|
|
366
|
-
offset += typeLen;
|
|
367
|
-
const { value: len, length: lenLen } = decodeVarint(buf, offset);
|
|
368
|
-
offset += lenLen;
|
|
369
|
-
if (offset + len > buf.length) {
|
|
370
|
-
throw new Error(`TLV violation: Length ${len} exceeds buffer`);
|
|
371
|
-
}
|
|
372
|
-
const value = buf.slice(offset, offset + len);
|
|
373
|
-
list.push({ type, value });
|
|
374
|
-
offset += len;
|
|
375
|
-
}
|
|
376
|
-
return list;
|
|
377
|
-
}
|
|
378
|
-
function decodeTLVs(buf) {
|
|
379
|
-
const map2 = /* @__PURE__ */ new Map();
|
|
380
|
-
let offset = 0;
|
|
381
|
-
let lastType = -1;
|
|
382
|
-
while (offset < buf.length) {
|
|
383
|
-
const { value: type, length: typeLen } = decodeVarint(buf, offset);
|
|
384
|
-
offset += typeLen;
|
|
385
|
-
if (type <= lastType) {
|
|
386
|
-
throw new Error(
|
|
387
|
-
`TLV violation: Unsorted or duplicate type ${type} after ${lastType}`
|
|
388
|
-
);
|
|
389
|
-
}
|
|
390
|
-
lastType = type;
|
|
391
|
-
const { value: len, length: lenLen } = decodeVarint(buf, offset);
|
|
392
|
-
offset += lenLen;
|
|
393
|
-
if (offset + len > buf.length) {
|
|
394
|
-
throw new Error(`TLV violation: Length ${len} exceeds buffer`);
|
|
395
|
-
}
|
|
396
|
-
const value = buf.slice(offset, offset + len);
|
|
397
|
-
map2.set(type, value);
|
|
398
|
-
offset += len;
|
|
399
|
-
}
|
|
400
|
-
return map2;
|
|
401
|
-
}
|
|
402
|
-
function decodeObject(bytes2, depth = 0, limits = { maxDepth: 8, maxItems: 128 }) {
|
|
403
|
-
if (depth > limits.maxDepth) {
|
|
404
|
-
throw new Error("OBJECT_DEPTH_EXCEEDED");
|
|
405
|
-
}
|
|
406
|
-
const map2 = decodeTLVs(bytes2);
|
|
407
|
-
return map2;
|
|
408
|
-
}
|
|
409
|
-
function decodeArray(bytes2, itemType, maxItems = 256) {
|
|
410
|
-
const list = decodeTLVsList(bytes2, maxItems);
|
|
411
|
-
const items = [];
|
|
412
|
-
for (const tlv2 of list) {
|
|
413
|
-
if (tlv2.type !== itemType) {
|
|
414
|
-
throw new Error(`INVALID_ARRAY_ITEM:${tlv2.type}`);
|
|
415
|
-
}
|
|
416
|
-
items.push(tlv2.value);
|
|
417
|
-
}
|
|
418
|
-
return items;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
634
|
// src/core/signature.ts
|
|
422
635
|
import * as crypto from "crypto";
|
|
423
636
|
|
|
@@ -1368,10 +1581,10 @@ function tlv(type, value) {
|
|
|
1368
1581
|
]);
|
|
1369
1582
|
}
|
|
1370
1583
|
function buildTLVs(items, opts) {
|
|
1371
|
-
const
|
|
1584
|
+
const allow = opts?.allowDupTypes ?? /* @__PURE__ */ new Set();
|
|
1372
1585
|
const sorted = [...items].sort((a, b) => a.type - b.type);
|
|
1373
1586
|
for (let i = 1; i < sorted.length; i++) {
|
|
1374
|
-
if (sorted[i].type === sorted[i - 1].type && !
|
|
1587
|
+
if (sorted[i].type === sorted[i - 1].type && !allow.has(sorted[i].type)) {
|
|
1375
1588
|
throw new Error(`TLV_DUP_TYPE_${sorted[i].type}`);
|
|
1376
1589
|
}
|
|
1377
1590
|
}
|
|
@@ -2181,425 +2394,6 @@ function isTimestampValid(ts, skewSeconds = 120) {
|
|
|
2181
2394
|
const diff = Math.abs(now - ts);
|
|
2182
2395
|
return diff <= skewSeconds;
|
|
2183
2396
|
}
|
|
2184
|
-
|
|
2185
|
-
// src/nestflow/types.ts
|
|
2186
|
-
var DeviceType = /* @__PURE__ */ ((DeviceType2) => {
|
|
2187
|
-
DeviceType2["MOBILE"] = "mobile";
|
|
2188
|
-
DeviceType2["BROWSER"] = "browser";
|
|
2189
|
-
DeviceType2["CLI"] = "cli";
|
|
2190
|
-
DeviceType2["SERVICE"] = "service";
|
|
2191
|
-
return DeviceType2;
|
|
2192
|
-
})(DeviceType || {});
|
|
2193
|
-
var DeviceTrustLevel = /* @__PURE__ */ ((DeviceTrustLevel2) => {
|
|
2194
|
-
DeviceTrustLevel2["PRIMARY"] = "primary";
|
|
2195
|
-
DeviceTrustLevel2["TRUSTED"] = "trusted";
|
|
2196
|
-
DeviceTrustLevel2["EPHEMERAL"] = "ephemeral";
|
|
2197
|
-
return DeviceTrustLevel2;
|
|
2198
|
-
})(DeviceTrustLevel || {});
|
|
2199
|
-
var DeviceStatus = /* @__PURE__ */ ((DeviceStatus2) => {
|
|
2200
|
-
DeviceStatus2["ACTIVE"] = "active";
|
|
2201
|
-
DeviceStatus2["REVOKED"] = "revoked";
|
|
2202
|
-
DeviceStatus2["SUSPENDED"] = "suspended";
|
|
2203
|
-
return DeviceStatus2;
|
|
2204
|
-
})(DeviceStatus || {});
|
|
2205
|
-
var LoginChallengeStatus = /* @__PURE__ */ ((LoginChallengeStatus3) => {
|
|
2206
|
-
LoginChallengeStatus3["PENDING"] = "pending";
|
|
2207
|
-
LoginChallengeStatus3["SCANNED"] = "scanned";
|
|
2208
|
-
LoginChallengeStatus3["APPROVED"] = "approved";
|
|
2209
|
-
LoginChallengeStatus3["REJECTED"] = "rejected";
|
|
2210
|
-
LoginChallengeStatus3["EXPIRED"] = "expired";
|
|
2211
|
-
return LoginChallengeStatus3;
|
|
2212
|
-
})(LoginChallengeStatus || {});
|
|
2213
|
-
var TickAuthChallengeStatus = /* @__PURE__ */ ((TickAuthChallengeStatus2) => {
|
|
2214
|
-
TickAuthChallengeStatus2["PENDING"] = "pending";
|
|
2215
|
-
TickAuthChallengeStatus2["FULFILLED"] = "fulfilled";
|
|
2216
|
-
TickAuthChallengeStatus2["REJECTED"] = "rejected";
|
|
2217
|
-
TickAuthChallengeStatus2["EXPIRED"] = "expired";
|
|
2218
|
-
return TickAuthChallengeStatus2;
|
|
2219
|
-
})(TickAuthChallengeStatus || {});
|
|
2220
|
-
var NestFlowCapsuleType = /* @__PURE__ */ ((NestFlowCapsuleType2) => {
|
|
2221
|
-
NestFlowCapsuleType2["LOGIN"] = "login";
|
|
2222
|
-
NestFlowCapsuleType2["DEVICE_REGISTRATION"] = "device_registration";
|
|
2223
|
-
NestFlowCapsuleType2["STEP_UP"] = "step_up";
|
|
2224
|
-
NestFlowCapsuleType2["RECOVERY"] = "recovery";
|
|
2225
|
-
return NestFlowCapsuleType2;
|
|
2226
|
-
})(NestFlowCapsuleType || {});
|
|
2227
|
-
var CapsuleStatus = /* @__PURE__ */ ((CapsuleStatus2) => {
|
|
2228
|
-
CapsuleStatus2["ACTIVE"] = "active";
|
|
2229
|
-
CapsuleStatus2["CONSUMED"] = "consumed";
|
|
2230
|
-
CapsuleStatus2["REVOKED"] = "revoked";
|
|
2231
|
-
CapsuleStatus2["EXPIRED"] = "expired";
|
|
2232
|
-
return CapsuleStatus2;
|
|
2233
|
-
})(CapsuleStatus || {});
|
|
2234
|
-
var SessionStatus = /* @__PURE__ */ ((SessionStatus2) => {
|
|
2235
|
-
SessionStatus2["ACTIVE"] = "active";
|
|
2236
|
-
SessionStatus2["EXPIRED"] = "expired";
|
|
2237
|
-
SessionStatus2["REVOKED"] = "revoked";
|
|
2238
|
-
return SessionStatus2;
|
|
2239
|
-
})(SessionStatus || {});
|
|
2240
|
-
var TrustLinkType = /* @__PURE__ */ ((TrustLinkType2) => {
|
|
2241
|
-
TrustLinkType2["LOGIN"] = "login";
|
|
2242
|
-
TrustLinkType2["PROMOTION"] = "promotion";
|
|
2243
|
-
TrustLinkType2["RECOVERY"] = "recovery";
|
|
2244
|
-
return TrustLinkType2;
|
|
2245
|
-
})(TrustLinkType || {});
|
|
2246
|
-
var TrustLinkStatus = /* @__PURE__ */ ((TrustLinkStatus2) => {
|
|
2247
|
-
TrustLinkStatus2["ACTIVE"] = "active";
|
|
2248
|
-
TrustLinkStatus2["REVOKED"] = "revoked";
|
|
2249
|
-
return TrustLinkStatus2;
|
|
2250
|
-
})(TrustLinkStatus || {});
|
|
2251
|
-
var AuthLevel = /* @__PURE__ */ ((AuthLevel2) => {
|
|
2252
|
-
AuthLevel2["SESSION"] = "session";
|
|
2253
|
-
AuthLevel2["SESSION_BROWSER"] = "session_browser";
|
|
2254
|
-
AuthLevel2["STEP_UP"] = "step_up";
|
|
2255
|
-
AuthLevel2["PRIMARY_DEVICE"] = "primary_device";
|
|
2256
|
-
return AuthLevel2;
|
|
2257
|
-
})(AuthLevel || {});
|
|
2258
|
-
|
|
2259
|
-
// src/nestflow/intents.ts
|
|
2260
|
-
var NESTFLOW_INTENTS = {
|
|
2261
|
-
// Auth
|
|
2262
|
-
AUTH_WEB_LOGIN_REQUEST: "auth.web.login.request",
|
|
2263
|
-
AUTH_WEB_LOGIN_SCAN: "auth.web.login.scan",
|
|
2264
|
-
// TickAuth
|
|
2265
|
-
TICKAUTH_CHALLENGE_CREATE: "tickauth.challenge.create",
|
|
2266
|
-
TICKAUTH_CHALLENGE_FULFILL: "tickauth.challenge.fulfill",
|
|
2267
|
-
TICKAUTH_CHALLENGE_REJECT: "tickauth.challenge.reject",
|
|
2268
|
-
// Capsule
|
|
2269
|
-
CAPSULE_ISSUE_LOGIN: "capsule.issue.login",
|
|
2270
|
-
CAPSULE_ISSUE_DEVICE_REGISTRATION: "capsule.issue.device_registration",
|
|
2271
|
-
CAPSULE_ISSUE_STEP_UP: "capsule.issue.step_up",
|
|
2272
|
-
CAPSULE_ISSUE_RECOVERY: "capsule.issue.recovery",
|
|
2273
|
-
// Session
|
|
2274
|
-
SESSION_ACTIVATE: "session.activate",
|
|
2275
|
-
SESSION_REFRESH: "session.refresh",
|
|
2276
|
-
SESSION_LOGOUT: "session.logout",
|
|
2277
|
-
// Device Trust
|
|
2278
|
-
DEVICE_TRUST_REQUEST: "device.trust.request",
|
|
2279
|
-
DEVICE_TRUST_PROMOTE: "device.trust.promote",
|
|
2280
|
-
DEVICE_REVOKE: "device.revoke",
|
|
2281
|
-
DEVICE_LIST: "device.list",
|
|
2282
|
-
DEVICE_RENAME: "device.rename",
|
|
2283
|
-
// Protected Operations
|
|
2284
|
-
FLOW_PUBLISH: "flow.publish",
|
|
2285
|
-
FLOW_DELETE: "flow.delete",
|
|
2286
|
-
NODE_DELETE: "node.delete",
|
|
2287
|
-
SECRET_ROTATE: "secret.rotate",
|
|
2288
|
-
ORG_SECURITY_UPDATE: "org.security.update",
|
|
2289
|
-
PRODUCTION_EXECUTION_APPROVE: "production.execution.approve",
|
|
2290
|
-
// Recovery
|
|
2291
|
-
IDENTITY_RECOVERY_START: "identity.recovery.start",
|
|
2292
|
-
IDENTITY_RECOVERY_COMPLETE: "identity.recovery.complete",
|
|
2293
|
-
PRIMARY_DEVICE_ROTATE: "primary.device.rotate",
|
|
2294
|
-
IDENTITY_LOCK: "identity.lock",
|
|
2295
|
-
IDENTITY_UNLOCK: "identity.unlock"
|
|
2296
|
-
};
|
|
2297
|
-
var NESTFLOW_INTENT_SET = new Set(
|
|
2298
|
-
Object.values(NESTFLOW_INTENTS)
|
|
2299
|
-
);
|
|
2300
|
-
function isNestFlowIntent(intent) {
|
|
2301
|
-
return NESTFLOW_INTENT_SET.has(intent);
|
|
2302
|
-
}
|
|
2303
|
-
|
|
2304
|
-
// src/nestflow/policy-map.ts
|
|
2305
|
-
var NESTFLOW_POLICY_MAP = {
|
|
2306
|
-
// Auth — unauthenticated initiator (session issued after)
|
|
2307
|
-
[NESTFLOW_INTENTS.AUTH_WEB_LOGIN_REQUEST]: "session" /* SESSION */,
|
|
2308
|
-
[NESTFLOW_INTENTS.AUTH_WEB_LOGIN_SCAN]: "primary_device" /* PRIMARY_DEVICE */,
|
|
2309
|
-
// TickAuth — primary device handles challenges
|
|
2310
|
-
[NESTFLOW_INTENTS.TICKAUTH_CHALLENGE_CREATE]: "session" /* SESSION */,
|
|
2311
|
-
[NESTFLOW_INTENTS.TICKAUTH_CHALLENGE_FULFILL]: "primary_device" /* PRIMARY_DEVICE */,
|
|
2312
|
-
[NESTFLOW_INTENTS.TICKAUTH_CHALLENGE_REJECT]: "primary_device" /* PRIMARY_DEVICE */,
|
|
2313
|
-
// Capsule issuance — varies per type
|
|
2314
|
-
[NESTFLOW_INTENTS.CAPSULE_ISSUE_LOGIN]: "primary_device" /* PRIMARY_DEVICE */,
|
|
2315
|
-
[NESTFLOW_INTENTS.CAPSULE_ISSUE_DEVICE_REGISTRATION]: "primary_device" /* PRIMARY_DEVICE */,
|
|
2316
|
-
[NESTFLOW_INTENTS.CAPSULE_ISSUE_STEP_UP]: "primary_device" /* PRIMARY_DEVICE */,
|
|
2317
|
-
[NESTFLOW_INTENTS.CAPSULE_ISSUE_RECOVERY]: "primary_device" /* PRIMARY_DEVICE */,
|
|
2318
|
-
// Session management
|
|
2319
|
-
[NESTFLOW_INTENTS.SESSION_ACTIVATE]: "session" /* SESSION */,
|
|
2320
|
-
[NESTFLOW_INTENTS.SESSION_REFRESH]: "session_browser" /* SESSION_BROWSER */,
|
|
2321
|
-
[NESTFLOW_INTENTS.SESSION_LOGOUT]: "session" /* SESSION */,
|
|
2322
|
-
// Device trust management
|
|
2323
|
-
[NESTFLOW_INTENTS.DEVICE_TRUST_REQUEST]: "session_browser" /* SESSION_BROWSER */,
|
|
2324
|
-
[NESTFLOW_INTENTS.DEVICE_TRUST_PROMOTE]: "step_up" /* STEP_UP */,
|
|
2325
|
-
[NESTFLOW_INTENTS.DEVICE_REVOKE]: "step_up" /* STEP_UP */,
|
|
2326
|
-
[NESTFLOW_INTENTS.DEVICE_LIST]: "session" /* SESSION */,
|
|
2327
|
-
[NESTFLOW_INTENTS.DEVICE_RENAME]: "session_browser" /* SESSION_BROWSER */,
|
|
2328
|
-
// Protected operations — require step-up auth
|
|
2329
|
-
[NESTFLOW_INTENTS.FLOW_PUBLISH]: "session_browser" /* SESSION_BROWSER */,
|
|
2330
|
-
[NESTFLOW_INTENTS.FLOW_DELETE]: "step_up" /* STEP_UP */,
|
|
2331
|
-
[NESTFLOW_INTENTS.NODE_DELETE]: "step_up" /* STEP_UP */,
|
|
2332
|
-
[NESTFLOW_INTENTS.SECRET_ROTATE]: "step_up" /* STEP_UP */,
|
|
2333
|
-
[NESTFLOW_INTENTS.ORG_SECURITY_UPDATE]: "step_up" /* STEP_UP */,
|
|
2334
|
-
[NESTFLOW_INTENTS.PRODUCTION_EXECUTION_APPROVE]: "step_up" /* STEP_UP */,
|
|
2335
|
-
// Recovery — highest privilege
|
|
2336
|
-
[NESTFLOW_INTENTS.IDENTITY_RECOVERY_START]: "primary_device" /* PRIMARY_DEVICE */,
|
|
2337
|
-
[NESTFLOW_INTENTS.IDENTITY_RECOVERY_COMPLETE]: "primary_device" /* PRIMARY_DEVICE */,
|
|
2338
|
-
[NESTFLOW_INTENTS.PRIMARY_DEVICE_ROTATE]: "primary_device" /* PRIMARY_DEVICE */,
|
|
2339
|
-
[NESTFLOW_INTENTS.IDENTITY_LOCK]: "primary_device" /* PRIMARY_DEVICE */,
|
|
2340
|
-
[NESTFLOW_INTENTS.IDENTITY_UNLOCK]: "primary_device" /* PRIMARY_DEVICE */
|
|
2341
|
-
};
|
|
2342
|
-
function getRequiredAuthLevel(intent) {
|
|
2343
|
-
return NESTFLOW_POLICY_MAP[intent];
|
|
2344
|
-
}
|
|
2345
|
-
var AUTH_LEVEL_ORDER = [
|
|
2346
|
-
"session" /* SESSION */,
|
|
2347
|
-
"session_browser" /* SESSION_BROWSER */,
|
|
2348
|
-
"step_up" /* STEP_UP */,
|
|
2349
|
-
"primary_device" /* PRIMARY_DEVICE */
|
|
2350
|
-
];
|
|
2351
|
-
function satisfiesAuthLevel(provided, required) {
|
|
2352
|
-
const providedIdx = AUTH_LEVEL_ORDER.indexOf(provided);
|
|
2353
|
-
const requiredIdx = AUTH_LEVEL_ORDER.indexOf(required);
|
|
2354
|
-
return providedIdx >= requiredIdx;
|
|
2355
|
-
}
|
|
2356
|
-
|
|
2357
|
-
// src/nestflow/guards.ts
|
|
2358
|
-
var allow = () => ({ allowed: true });
|
|
2359
|
-
var deny = (reason) => ({ allowed: false, reason });
|
|
2360
|
-
function checkIntentPolicy(intent, currentAuthLevel) {
|
|
2361
|
-
const required = getRequiredAuthLevel(intent);
|
|
2362
|
-
if (!required) {
|
|
2363
|
-
return allow();
|
|
2364
|
-
}
|
|
2365
|
-
if (satisfiesAuthLevel(currentAuthLevel, required)) {
|
|
2366
|
-
return allow();
|
|
2367
|
-
}
|
|
2368
|
-
return {
|
|
2369
|
-
allowed: false,
|
|
2370
|
-
reason: `Intent '${intent}' requires auth level '${required}', got '${currentAuthLevel}'`,
|
|
2371
|
-
step_up_intent: required === "step_up" /* STEP_UP */ ? intent : void 0
|
|
2372
|
-
};
|
|
2373
|
-
}
|
|
2374
|
-
function checkSession(session) {
|
|
2375
|
-
if (!session) {
|
|
2376
|
-
return deny("No session found");
|
|
2377
|
-
}
|
|
2378
|
-
if (session.status !== "active" /* ACTIVE */) {
|
|
2379
|
-
return deny(`Session status is '${session.status}', expected 'active'`);
|
|
2380
|
-
}
|
|
2381
|
-
if (new Date(session.expires_at).getTime() < Date.now()) {
|
|
2382
|
-
return deny("Session has expired");
|
|
2383
|
-
}
|
|
2384
|
-
return allow();
|
|
2385
|
-
}
|
|
2386
|
-
function checkBrowserProof(proof, expectedNonce) {
|
|
2387
|
-
if (!proof) {
|
|
2388
|
-
return deny("Browser proof-of-possession required but not provided");
|
|
2389
|
-
}
|
|
2390
|
-
if (!proof.server_nonce || !proof.signature || !proof.signature_algorithm) {
|
|
2391
|
-
return deny("Browser proof is missing required fields");
|
|
2392
|
-
}
|
|
2393
|
-
if (proof.server_nonce !== expectedNonce) {
|
|
2394
|
-
return deny("Browser proof nonce does not match expected server nonce");
|
|
2395
|
-
}
|
|
2396
|
-
return allow();
|
|
2397
|
-
}
|
|
2398
|
-
var TRUST_ORDER = [
|
|
2399
|
-
"ephemeral" /* EPHEMERAL */,
|
|
2400
|
-
"trusted" /* TRUSTED */,
|
|
2401
|
-
"primary" /* PRIMARY */
|
|
2402
|
-
];
|
|
2403
|
-
function checkDeviceTrust(device, minimumTrust) {
|
|
2404
|
-
if (!device) {
|
|
2405
|
-
return deny("Device not found");
|
|
2406
|
-
}
|
|
2407
|
-
if (device.status !== "active" /* ACTIVE */) {
|
|
2408
|
-
return deny(`Device status is '${device.status}', expected 'active'`);
|
|
2409
|
-
}
|
|
2410
|
-
const deviceIdx = TRUST_ORDER.indexOf(device.trust_level);
|
|
2411
|
-
const requiredIdx = TRUST_ORDER.indexOf(minimumTrust);
|
|
2412
|
-
if (deviceIdx < requiredIdx) {
|
|
2413
|
-
return deny(
|
|
2414
|
-
`Device trust level '${device.trust_level}' does not meet minimum '${minimumTrust}'`
|
|
2415
|
-
);
|
|
2416
|
-
}
|
|
2417
|
-
return allow();
|
|
2418
|
-
}
|
|
2419
|
-
function checkCapsule(capsule, intent, requestingDeviceUid) {
|
|
2420
|
-
if (!capsule) {
|
|
2421
|
-
return deny("Capsule not found");
|
|
2422
|
-
}
|
|
2423
|
-
if (capsule.status !== "active" /* ACTIVE */) {
|
|
2424
|
-
return deny(`Capsule status is '${capsule.status}', expected 'active'`);
|
|
2425
|
-
}
|
|
2426
|
-
if (new Date(capsule.expires_at).getTime() < Date.now()) {
|
|
2427
|
-
return deny("Capsule has expired");
|
|
2428
|
-
}
|
|
2429
|
-
const intentAllowed = capsule.intents.some((pattern) => {
|
|
2430
|
-
if (pattern === "*") return true;
|
|
2431
|
-
if (pattern === intent) return true;
|
|
2432
|
-
if (pattern.endsWith(".*")) {
|
|
2433
|
-
return intent.startsWith(pattern.slice(0, -1));
|
|
2434
|
-
}
|
|
2435
|
-
return false;
|
|
2436
|
-
});
|
|
2437
|
-
if (!intentAllowed) {
|
|
2438
|
-
return deny(`Capsule does not authorize intent '${intent}'`);
|
|
2439
|
-
}
|
|
2440
|
-
if (capsule.device_uid && requestingDeviceUid && capsule.device_uid !== requestingDeviceUid) {
|
|
2441
|
-
return deny("Capsule is bound to a different device");
|
|
2442
|
-
}
|
|
2443
|
-
return allow();
|
|
2444
|
-
}
|
|
2445
|
-
function checkLoginChallenge(challenge, expectedStatus) {
|
|
2446
|
-
if (!challenge) {
|
|
2447
|
-
return deny("Login challenge not found");
|
|
2448
|
-
}
|
|
2449
|
-
if (new Date(challenge.expires_at).getTime() < Date.now()) {
|
|
2450
|
-
return deny("Login challenge has expired");
|
|
2451
|
-
}
|
|
2452
|
-
if (challenge.status !== expectedStatus) {
|
|
2453
|
-
return deny(
|
|
2454
|
-
`Login challenge status is '${challenge.status}', expected '${expectedStatus}'`
|
|
2455
|
-
);
|
|
2456
|
-
}
|
|
2457
|
-
return allow();
|
|
2458
|
-
}
|
|
2459
|
-
function checkTickAuth(challenge) {
|
|
2460
|
-
if (!challenge) {
|
|
2461
|
-
return deny("TickAuth challenge not found");
|
|
2462
|
-
}
|
|
2463
|
-
if (challenge.status !== "pending" /* PENDING */) {
|
|
2464
|
-
return deny(
|
|
2465
|
-
`TickAuth challenge status is '${challenge.status}', expected 'pending'`
|
|
2466
|
-
);
|
|
2467
|
-
}
|
|
2468
|
-
const now = Date.now();
|
|
2469
|
-
const start = new Date(challenge.tick_window.start).getTime();
|
|
2470
|
-
const end = new Date(challenge.tick_window.end).getTime();
|
|
2471
|
-
if (now < start || now > end) {
|
|
2472
|
-
return deny("TickAuth challenge is outside its tick window");
|
|
2473
|
-
}
|
|
2474
|
-
return allow();
|
|
2475
|
-
}
|
|
2476
|
-
async function checkReplayProtection(nonce, store, windowMs = 5 * 60 * 1e3) {
|
|
2477
|
-
if (!nonce) {
|
|
2478
|
-
return deny("Nonce is required for replay protection");
|
|
2479
|
-
}
|
|
2480
|
-
const seen = await store.has(nonce);
|
|
2481
|
-
if (seen) {
|
|
2482
|
-
return deny("Nonce has already been used (replay detected)");
|
|
2483
|
-
}
|
|
2484
|
-
await store.add(nonce, new Date(Date.now() + windowMs));
|
|
2485
|
-
return allow();
|
|
2486
|
-
}
|
|
2487
|
-
|
|
2488
|
-
// src/nestflow/invariants.ts
|
|
2489
|
-
var LOGIN_CHALLENGE_TRANSITIONS = {
|
|
2490
|
-
["pending" /* PENDING */]: [
|
|
2491
|
-
"scanned" /* SCANNED */,
|
|
2492
|
-
"expired" /* EXPIRED */
|
|
2493
|
-
],
|
|
2494
|
-
["scanned" /* SCANNED */]: [
|
|
2495
|
-
"approved" /* APPROVED */,
|
|
2496
|
-
"rejected" /* REJECTED */,
|
|
2497
|
-
"expired" /* EXPIRED */
|
|
2498
|
-
],
|
|
2499
|
-
["approved" /* APPROVED */]: [],
|
|
2500
|
-
["rejected" /* REJECTED */]: [],
|
|
2501
|
-
["expired" /* EXPIRED */]: []
|
|
2502
|
-
};
|
|
2503
|
-
var TICKAUTH_TRANSITIONS = {
|
|
2504
|
-
["pending" /* PENDING */]: [
|
|
2505
|
-
"fulfilled" /* FULFILLED */,
|
|
2506
|
-
"rejected" /* REJECTED */,
|
|
2507
|
-
"expired" /* EXPIRED */
|
|
2508
|
-
],
|
|
2509
|
-
["fulfilled" /* FULFILLED */]: [],
|
|
2510
|
-
["rejected" /* REJECTED */]: [],
|
|
2511
|
-
["expired" /* EXPIRED */]: []
|
|
2512
|
-
};
|
|
2513
|
-
var CAPSULE_TRANSITIONS = {
|
|
2514
|
-
["active" /* ACTIVE */]: [
|
|
2515
|
-
"consumed" /* CONSUMED */,
|
|
2516
|
-
"revoked" /* REVOKED */,
|
|
2517
|
-
"expired" /* EXPIRED */
|
|
2518
|
-
],
|
|
2519
|
-
["consumed" /* CONSUMED */]: [],
|
|
2520
|
-
["revoked" /* REVOKED */]: [],
|
|
2521
|
-
["expired" /* EXPIRED */]: []
|
|
2522
|
-
};
|
|
2523
|
-
var SESSION_TRANSITIONS = {
|
|
2524
|
-
["active" /* ACTIVE */]: ["expired" /* EXPIRED */, "revoked" /* REVOKED */],
|
|
2525
|
-
["expired" /* EXPIRED */]: [],
|
|
2526
|
-
["revoked" /* REVOKED */]: []
|
|
2527
|
-
};
|
|
2528
|
-
var DEVICE_TRANSITIONS = {
|
|
2529
|
-
["active" /* ACTIVE */]: ["suspended" /* SUSPENDED */, "revoked" /* REVOKED */],
|
|
2530
|
-
["suspended" /* SUSPENDED */]: ["active" /* ACTIVE */, "revoked" /* REVOKED */],
|
|
2531
|
-
["revoked" /* REVOKED */]: []
|
|
2532
|
-
};
|
|
2533
|
-
var TRUST_LINK_TRANSITIONS = {
|
|
2534
|
-
["active" /* ACTIVE */]: ["revoked" /* REVOKED */],
|
|
2535
|
-
["revoked" /* REVOKED */]: []
|
|
2536
|
-
};
|
|
2537
|
-
function checkTransition(entity, transitions, from, to) {
|
|
2538
|
-
const allowed = transitions[from];
|
|
2539
|
-
if (!allowed) {
|
|
2540
|
-
return {
|
|
2541
|
-
valid: false,
|
|
2542
|
-
reason: `${entity}: unknown current state '${from}'`
|
|
2543
|
-
};
|
|
2544
|
-
}
|
|
2545
|
-
if (!allowed.includes(to)) {
|
|
2546
|
-
return {
|
|
2547
|
-
valid: false,
|
|
2548
|
-
reason: `${entity}: invalid transition '${from}' \u2192 '${to}'. Allowed: [${allowed.join(", ")}]`
|
|
2549
|
-
};
|
|
2550
|
-
}
|
|
2551
|
-
return { valid: true };
|
|
2552
|
-
}
|
|
2553
|
-
function validateLoginChallengeTransition(from, to) {
|
|
2554
|
-
return checkTransition(
|
|
2555
|
-
"LoginChallenge",
|
|
2556
|
-
LOGIN_CHALLENGE_TRANSITIONS,
|
|
2557
|
-
from,
|
|
2558
|
-
to
|
|
2559
|
-
);
|
|
2560
|
-
}
|
|
2561
|
-
function validateTickAuthTransition(from, to) {
|
|
2562
|
-
return checkTransition("TickAuthChallenge", TICKAUTH_TRANSITIONS, from, to);
|
|
2563
|
-
}
|
|
2564
|
-
function validateCapsuleTransition(from, to) {
|
|
2565
|
-
return checkTransition("Capsule", CAPSULE_TRANSITIONS, from, to);
|
|
2566
|
-
}
|
|
2567
|
-
function validateSessionTransition(from, to) {
|
|
2568
|
-
return checkTransition("Session", SESSION_TRANSITIONS, from, to);
|
|
2569
|
-
}
|
|
2570
|
-
function validateDeviceTransition(from, to) {
|
|
2571
|
-
return checkTransition("Device", DEVICE_TRANSITIONS, from, to);
|
|
2572
|
-
}
|
|
2573
|
-
function validateTrustLinkTransition(from, to) {
|
|
2574
|
-
return checkTransition("TrustLink", TRUST_LINK_TRANSITIONS, from, to);
|
|
2575
|
-
}
|
|
2576
|
-
function isLoginChallengeTerminal(status) {
|
|
2577
|
-
return [
|
|
2578
|
-
"approved" /* APPROVED */,
|
|
2579
|
-
"rejected" /* REJECTED */,
|
|
2580
|
-
"expired" /* EXPIRED */
|
|
2581
|
-
].includes(status);
|
|
2582
|
-
}
|
|
2583
|
-
function isTickAuthTerminal(status) {
|
|
2584
|
-
return [
|
|
2585
|
-
"fulfilled" /* FULFILLED */,
|
|
2586
|
-
"rejected" /* REJECTED */,
|
|
2587
|
-
"expired" /* EXPIRED */
|
|
2588
|
-
].includes(status);
|
|
2589
|
-
}
|
|
2590
|
-
function isCapsuleTerminal(status) {
|
|
2591
|
-
return [
|
|
2592
|
-
"consumed" /* CONSUMED */,
|
|
2593
|
-
"revoked" /* REVOKED */,
|
|
2594
|
-
"expired" /* EXPIRED */
|
|
2595
|
-
].includes(status);
|
|
2596
|
-
}
|
|
2597
|
-
function isSessionTerminal(status) {
|
|
2598
|
-
return ["expired" /* EXPIRED */, "revoked" /* REVOKED */].includes(status);
|
|
2599
|
-
}
|
|
2600
|
-
function isDeviceTerminal(status) {
|
|
2601
|
-
return status === "revoked" /* REVOKED */;
|
|
2602
|
-
}
|
|
2603
2397
|
export {
|
|
2604
2398
|
ATS1_HDR,
|
|
2605
2399
|
ATS1_SCHEMA,
|
|
@@ -2607,19 +2401,18 @@ export {
|
|
|
2607
2401
|
AXIS_OPCODES,
|
|
2608
2402
|
AXIS_VERSION,
|
|
2609
2403
|
ats1_exports as Ats1Codec,
|
|
2610
|
-
AuthLevel,
|
|
2611
2404
|
AxisFrameZ,
|
|
2405
|
+
AxisIdDto,
|
|
2612
2406
|
T as AxisPacketTags,
|
|
2407
|
+
AxisPartialType,
|
|
2408
|
+
AxisResponseDto,
|
|
2409
|
+
AxisTlvDto,
|
|
2613
2410
|
BodyProfile,
|
|
2614
2411
|
CAPABILITIES,
|
|
2615
|
-
CapsuleStatus,
|
|
2616
2412
|
ContractViolationError,
|
|
2617
2413
|
DEFAULT_CONTRACTS,
|
|
2618
2414
|
DEFAULT_TIMEOUT,
|
|
2619
2415
|
Decision,
|
|
2620
|
-
DeviceStatus,
|
|
2621
|
-
DeviceTrustLevel,
|
|
2622
|
-
DeviceType,
|
|
2623
2416
|
ERR_BAD_SIGNATURE,
|
|
2624
2417
|
ERR_CONTRACT_VIOLATION,
|
|
2625
2418
|
ERR_INVALID_PACKET,
|
|
@@ -2631,6 +2424,7 @@ export {
|
|
|
2631
2424
|
FLAG_HAS_WITNESS,
|
|
2632
2425
|
HANDLER_METADATA_KEY,
|
|
2633
2426
|
Handler,
|
|
2427
|
+
INTENT_METADATA_KEY,
|
|
2634
2428
|
INTENT_REQUIREMENTS,
|
|
2635
2429
|
INTENT_ROUTES_KEY,
|
|
2636
2430
|
INTENT_SENSITIVITY_MAP,
|
|
@@ -2638,7 +2432,6 @@ export {
|
|
|
2638
2432
|
Intent,
|
|
2639
2433
|
IntentRouter,
|
|
2640
2434
|
IntentSensitivity,
|
|
2641
|
-
LoginChallengeStatus,
|
|
2642
2435
|
MAX_BODY_LEN,
|
|
2643
2436
|
MAX_FRAME_LEN,
|
|
2644
2437
|
MAX_HDR_LEN,
|
|
@@ -2653,10 +2446,6 @@ export {
|
|
|
2653
2446
|
NCERT_PUB,
|
|
2654
2447
|
NCERT_SCOPE,
|
|
2655
2448
|
NCERT_SIG,
|
|
2656
|
-
NESTFLOW_INTENTS,
|
|
2657
|
-
NESTFLOW_INTENT_SET,
|
|
2658
|
-
NESTFLOW_POLICY_MAP,
|
|
2659
|
-
NestFlowCapsuleType,
|
|
2660
2449
|
PROOF_CAPABILITIES,
|
|
2661
2450
|
PROOF_CAPSULE,
|
|
2662
2451
|
PROOF_JWT,
|
|
@@ -2665,13 +2454,17 @@ export {
|
|
|
2665
2454
|
PROOF_NONE,
|
|
2666
2455
|
PROOF_WITNESS,
|
|
2667
2456
|
ProofType,
|
|
2457
|
+
RESPONSE_TAG_CREATED_AT,
|
|
2458
|
+
RESPONSE_TAG_CREATED_BY,
|
|
2459
|
+
RESPONSE_TAG_ID,
|
|
2460
|
+
RESPONSE_TAG_UPDATED_AT,
|
|
2461
|
+
RESPONSE_TAG_UPDATED_BY,
|
|
2668
2462
|
RiskDecision,
|
|
2669
2463
|
Schema2002_PasskeyLoginOptionsRes,
|
|
2670
2464
|
Schema2011_PasskeyLoginVerifyReq,
|
|
2671
2465
|
Schema2012_PasskeyLoginVerifyRes,
|
|
2672
2466
|
Schema2021_PasskeyRegisterOptionsReq,
|
|
2673
2467
|
SensorDecisions,
|
|
2674
|
-
SessionStatus,
|
|
2675
2468
|
TLV_ACTOR_ID,
|
|
2676
2469
|
TLV_AUD,
|
|
2677
2470
|
TLV_BODY_ARR,
|
|
@@ -2680,6 +2473,7 @@ export {
|
|
|
2680
2473
|
TLV_EFFECT,
|
|
2681
2474
|
TLV_ERROR_CODE,
|
|
2682
2475
|
TLV_ERROR_MSG,
|
|
2476
|
+
TLV_FIELDS_KEY,
|
|
2683
2477
|
TLV_INDEX,
|
|
2684
2478
|
TLV_INTENT,
|
|
2685
2479
|
TLV_KID,
|
|
@@ -2703,15 +2497,20 @@ export {
|
|
|
2703
2497
|
TLV_TRACE_ID,
|
|
2704
2498
|
TLV_TS,
|
|
2705
2499
|
TLV_UPLOAD_ID,
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2500
|
+
TLV_VALIDATORS_KEY,
|
|
2501
|
+
TlvEnum,
|
|
2502
|
+
TlvField,
|
|
2503
|
+
TlvMinLen,
|
|
2504
|
+
TlvRange,
|
|
2505
|
+
TlvUtf8Pattern,
|
|
2506
|
+
TlvValidate,
|
|
2709
2507
|
axis1SigningBytes,
|
|
2710
2508
|
b64urlDecode,
|
|
2711
2509
|
b64urlDecodeString,
|
|
2712
2510
|
b64urlEncode,
|
|
2713
2511
|
b64urlEncodeString,
|
|
2714
2512
|
buildAts1Hdr,
|
|
2513
|
+
buildDtoDecoder,
|
|
2715
2514
|
buildPacket,
|
|
2716
2515
|
buildReceiptHash,
|
|
2717
2516
|
buildTLVs,
|
|
@@ -2719,14 +2518,6 @@ export {
|
|
|
2719
2518
|
canAccessResource,
|
|
2720
2519
|
canonicalJson,
|
|
2721
2520
|
canonicalJsonExcluding,
|
|
2722
|
-
checkBrowserProof,
|
|
2723
|
-
checkCapsule,
|
|
2724
|
-
checkDeviceTrust,
|
|
2725
|
-
checkIntentPolicy,
|
|
2726
|
-
checkLoginChallenge,
|
|
2727
|
-
checkReplayProtection,
|
|
2728
|
-
checkSession,
|
|
2729
|
-
checkTickAuth,
|
|
2730
2521
|
classifyIntent,
|
|
2731
2522
|
computeReceiptHash,
|
|
2732
2523
|
computeSignaturePayload,
|
|
@@ -2742,18 +2533,12 @@ export {
|
|
|
2742
2533
|
encodeFrame,
|
|
2743
2534
|
encodeTLVs,
|
|
2744
2535
|
encodeVarint,
|
|
2536
|
+
extractDtoSchema,
|
|
2745
2537
|
generateEd25519KeyPair,
|
|
2746
|
-
getRequiredAuthLevel,
|
|
2747
2538
|
getSignTarget,
|
|
2748
2539
|
hasScope,
|
|
2749
2540
|
isAdminOpcode,
|
|
2750
|
-
isCapsuleTerminal,
|
|
2751
|
-
isDeviceTerminal,
|
|
2752
2541
|
isKnownOpcode,
|
|
2753
|
-
isLoginChallengeTerminal,
|
|
2754
|
-
isNestFlowIntent,
|
|
2755
|
-
isSessionTerminal,
|
|
2756
|
-
isTickAuthTerminal,
|
|
2757
2542
|
isTimestampValid,
|
|
2758
2543
|
nonce16,
|
|
2759
2544
|
normalizeSensorDecision,
|
|
@@ -2764,7 +2549,6 @@ export {
|
|
|
2764
2549
|
packPasskeyRegisterOptionsReq,
|
|
2765
2550
|
parseScope,
|
|
2766
2551
|
resolveTimeout,
|
|
2767
|
-
satisfiesAuthLevel,
|
|
2768
2552
|
sensitivityName,
|
|
2769
2553
|
sha256,
|
|
2770
2554
|
signFrame,
|
|
@@ -2774,13 +2558,7 @@ export {
|
|
|
2774
2558
|
unpackPasskeyLoginVerifyReq,
|
|
2775
2559
|
unpackPasskeyRegisterOptionsReq,
|
|
2776
2560
|
utf8,
|
|
2777
|
-
validateCapsuleTransition,
|
|
2778
|
-
validateDeviceTransition,
|
|
2779
2561
|
validateFrameShape,
|
|
2780
|
-
validateLoginChallengeTransition,
|
|
2781
|
-
validateSessionTransition,
|
|
2782
|
-
validateTickAuthTransition,
|
|
2783
|
-
validateTrustLinkTransition,
|
|
2784
2562
|
varintLength,
|
|
2785
2563
|
varintU,
|
|
2786
2564
|
verifyFrameSignature
|