Stage 7a: the locator, its opening and the envelope
lib/src/locator.dart gains the rest of package locator of datekeys-go but
Seal and the data of the extension, with the same checks in the same
order and the same texts:
- Locator: unmarshalLocator, the map of spec 44.1 with the length that
Marshal gives and nothing else, and marshal, its form, its addresses and
key 6 up to the least multiple of 4096 that it fills, as padFor and
PlaintextLength; usable, the addresses that a reader uses.
- openLocator, Open of Go: the profile, then age with the tlock identity
of agewrap, and at most 1 MiB of plaintext, as io.LimitReader: the
chunks after it are neither decrypted nor checked.
- The envelope: restIn, openEnvelope with the size and the SHA-256 of the
rest and of the .dkc, hideRest, and splitEnvelope, the part of
NewEnvelope after its age encryption, which needs the writer of age.
A Locator keeps the types of Go: keys and digests of 32 bytes, and no
negative size or offset. Its errors carry no code, as in Go.
The tests run the cases of locator.json, the padding of every base, 482
plaintexts, Marshal at its limits, 118 openings, the files past 1 MiB, the
envelope, the rests and the split; a part also on Node.js.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
// The locator and the envelope against Go (spec §44.1), from the part of
|
|
|
|
|
// locator_vectors.json that locator_vectors.g.dart holds, so that it runs on
|
|
|
|
|
// the VM and compiled to JavaScript: the padding of every base, plaintexts
|
|
|
|
|
// valid and broken, Marshal at every limit, sealed locators opened with
|
Stage 7a: the data of datekeys.capsule
lib/src/locator.dart gains the data of the extension, as Info, ParseInfo
and Info.Extension of Go, with the same checks in the same order and the
same texts:
- parseCapsuleInfo: the map of spec 44.1 with the note under the rules of
spec 24.1, the canonical DateKey, and a sealed locator that is an age
file with one tlock stanza for its round; every failure is
ERR_EXTENSION_DATA_INVALID and nothing else, so that it makes the
extension unusable and never the .dkk (spec 54).
- CapsuleInfo.toExtension, which reads back what it writes (spec 72), and
CapsuleInfo.openLocator, OpenLocator of Go, with the default registry of
pinned profiles when none is given, as the opening of a capsule takes it.
- checkCapsuleData, the ValidateCapsule of Go's locator.Standard, for
StandardExtensions.
The tests run the extension cases of locator.json with their code, the
writing and the reading of the data, OpenLocator, the registry of
locator.Standard through checkCritical, checkNoncritical and checkWrite,
and the opening of a fixture whose .dkk carries datekeys.capsule, whose
unusable extensions and checks are those of Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
// their release and with others, the envelope, its rest and its split, the
|
|
|
|
|
// data of datekeys.capsule written and read, and the registry of
|
|
|
|
|
// locator.Standard. locator_vm_test.dart runs every case of the files.
|
Stage 7a: the locator, its opening and the envelope
lib/src/locator.dart gains the rest of package locator of datekeys-go but
Seal and the data of the extension, with the same checks in the same
order and the same texts:
- Locator: unmarshalLocator, the map of spec 44.1 with the length that
Marshal gives and nothing else, and marshal, its form, its addresses and
key 6 up to the least multiple of 4096 that it fills, as padFor and
PlaintextLength; usable, the addresses that a reader uses.
- openLocator, Open of Go: the profile, then age with the tlock identity
of agewrap, and at most 1 MiB of plaintext, as io.LimitReader: the
chunks after it are neither decrypted nor checked.
- The envelope: restIn, openEnvelope with the size and the SHA-256 of the
rest and of the .dkc, hideRest, and splitEnvelope, the part of
NewEnvelope after its age encryption, which needs the writer of age.
A Locator keeps the types of Go: keys and digests of 32 bytes, and no
negative size or offset. Its errors carry no code, as in Go.
The tests run the cases of locator.json, the padding of every base, 482
plaintexts, Marshal at its limits, 118 openings, the files past 1 MiB, the
envelope, the rests and the split; a part also on Node.js.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
library;
|
|
|
|
|
|
|
|
|
|
import 'dart:typed_data';
|
|
|
|
|
|
|
|
|
|
import 'package:datekeys/src/bytes.dart';
|
Stage 7a: the data of datekeys.capsule
lib/src/locator.dart gains the data of the extension, as Info, ParseInfo
and Info.Extension of Go, with the same checks in the same order and the
same texts:
- parseCapsuleInfo: the map of spec 44.1 with the note under the rules of
spec 24.1, the canonical DateKey, and a sealed locator that is an age
file with one tlock stanza for its round; every failure is
ERR_EXTENSION_DATA_INVALID and nothing else, so that it makes the
extension unusable and never the .dkk (spec 54).
- CapsuleInfo.toExtension, which reads back what it writes (spec 72), and
CapsuleInfo.openLocator, OpenLocator of Go, with the default registry of
pinned profiles when none is given, as the opening of a capsule takes it.
- checkCapsuleData, the ValidateCapsule of Go's locator.Standard, for
StandardExtensions.
The tests run the extension cases of locator.json with their code, the
writing and the reading of the data, OpenLocator, the registry of
locator.Standard through checkCritical, checkNoncritical and checkWrite,
and the opening of a fixture whose .dkk carries datekeys.capsule, whose
unusable extensions and checks are those of Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
import 'package:datekeys/src/datekey.dart';
|
|
|
|
|
import 'package:datekeys/src/errors.dart';
|
|
|
|
|
import 'package:datekeys/src/extension.dart';
|
Stage 7a: the locator, its opening and the envelope
lib/src/locator.dart gains the rest of package locator of datekeys-go but
Seal and the data of the extension, with the same checks in the same
order and the same texts:
- Locator: unmarshalLocator, the map of spec 44.1 with the length that
Marshal gives and nothing else, and marshal, its form, its addresses and
key 6 up to the least multiple of 4096 that it fills, as padFor and
PlaintextLength; usable, the addresses that a reader uses.
- openLocator, Open of Go: the profile, then age with the tlock identity
of agewrap, and at most 1 MiB of plaintext, as io.LimitReader: the
chunks after it are neither decrypted nor checked.
- The envelope: restIn, openEnvelope with the size and the SHA-256 of the
rest and of the .dkc, hideRest, and splitEnvelope, the part of
NewEnvelope after its age encryption, which needs the writer of age.
A Locator keeps the types of Go: keys and digests of 32 bytes, and no
negative size or offset. Its errors carry no code, as in Go.
The tests run the cases of locator.json, the padding of every base, 482
plaintexts, Marshal at its limits, 118 openings, the files past 1 MiB, the
envelope, the rests and the split; a part also on Node.js.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
import 'package:datekeys/src/locator.dart';
|
|
|
|
|
import 'package:test/test.dart';
|
|
|
|
|
|
|
|
|
|
import 'locator_support.dart';
|
|
|
|
|
import 'vectors/locator_vectors.g.dart';
|
|
|
|
|
|
|
|
|
|
/// The cases of the locator, shared with locator_vm_test.dart, which runs
|
|
|
|
|
/// them on the whole file.
|
|
|
|
|
void locatorCases(Json v) {
|
|
|
|
|
final envelope = v['envelope']! as Json;
|
|
|
|
|
final plainBases = [
|
|
|
|
|
for (final h in v['plaintext_bases']! as List<Object?>)
|
|
|
|
|
fromHex(h! as String),
|
|
|
|
|
];
|
|
|
|
|
final sealedBases = [
|
|
|
|
|
for (final s in (v['sealed_bases']! as List<Object?>).cast<Json>())
|
|
|
|
|
fromHex(s['sealed']! as String),
|
|
|
|
|
];
|
Stage 7a: the data of datekeys.capsule
lib/src/locator.dart gains the data of the extension, as Info, ParseInfo
and Info.Extension of Go, with the same checks in the same order and the
same texts:
- parseCapsuleInfo: the map of spec 44.1 with the note under the rules of
spec 24.1, the canonical DateKey, and a sealed locator that is an age
file with one tlock stanza for its round; every failure is
ERR_EXTENSION_DATA_INVALID and nothing else, so that it makes the
extension unusable and never the .dkk (spec 54).
- CapsuleInfo.toExtension, which reads back what it writes (spec 72), and
CapsuleInfo.openLocator, OpenLocator of Go, with the default registry of
pinned profiles when none is given, as the opening of a capsule takes it.
- checkCapsuleData, the ValidateCapsule of Go's locator.Standard, for
StandardExtensions.
The tests run the extension cases of locator.json with their code, the
writing and the reading of the data, OpenLocator, the registry of
locator.Standard through checkCritical, checkNoncritical and checkWrite,
and the opening of a fixture whose .dkk carries datekeys.capsule, whose
unusable extensions and checks are those of Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
final parseBases = [
|
|
|
|
|
for (final h in v['parse_bases']! as List<Object?>) fromHex(h! as String),
|
|
|
|
|
];
|
|
|
|
|
final datas = [
|
|
|
|
|
for (final h in v['datas']! as List<Object?>) fromHex(h! as String),
|
|
|
|
|
];
|
Stage 7a: the locator, its opening and the envelope
lib/src/locator.dart gains the rest of package locator of datekeys-go but
Seal and the data of the extension, with the same checks in the same
order and the same texts:
- Locator: unmarshalLocator, the map of spec 44.1 with the length that
Marshal gives and nothing else, and marshal, its form, its addresses and
key 6 up to the least multiple of 4096 that it fills, as padFor and
PlaintextLength; usable, the addresses that a reader uses.
- openLocator, Open of Go: the profile, then age with the tlock identity
of agewrap, and at most 1 MiB of plaintext, as io.LimitReader: the
chunks after it are neither decrypted nor checked.
- The envelope: restIn, openEnvelope with the size and the SHA-256 of the
rest and of the .dkc, hideRest, and splitEnvelope, the part of
NewEnvelope after its age encryption, which needs the writer of age.
A Locator keeps the types of Go: keys and digests of 32 bytes, and no
negative size or offset. Its errors carry no code, as in Go.
The tests run the cases of locator.json, the padding of every base, 482
plaintexts, Marshal at its limits, 118 openings, the files past 1 MiB, the
envelope, the rests and the split; a part also on Node.js.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
Locator base({
|
|
|
|
|
List<LocatorAddress>? addresses,
|
|
|
|
|
List<int>? key,
|
|
|
|
|
List<int>? header,
|
|
|
|
|
List<int>? restDigest,
|
|
|
|
|
int? restSize,
|
|
|
|
|
List<int>? capsuleDigest,
|
|
|
|
|
}) => Locator(
|
|
|
|
|
addresses:
|
|
|
|
|
addresses ?? [LocatorAddress('https://ejemplo.org/foto.jpg', 3000)],
|
|
|
|
|
envelopeKey: key ?? fromHex(envelope['key']! as String),
|
|
|
|
|
envelopeHeader: header ?? fromHex(envelope['header']! as String),
|
|
|
|
|
restDigest: restDigest ?? fromHex(envelope['rest_digest']! as String),
|
|
|
|
|
restSize: restSize ?? envelope['rest_size']! as int,
|
|
|
|
|
capsuleDigest:
|
|
|
|
|
capsuleDigest ?? fromHex(envelope['capsule_digest']! as String),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test('locatorPlaintextLength gives the least multiple that key 6 fills, '
|
|
|
|
|
'on every base from -4100 to 16484', () {
|
|
|
|
|
var n = 0;
|
|
|
|
|
for (final r in rows(v, 'padding')) {
|
|
|
|
|
for (var b = r[0]! as int; b <= (r[1]! as int); b++) {
|
|
|
|
|
expect(locatorPlaintextLength(b), r[2], reason: '$b');
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
expect(n, 4100 + 1 + 16484);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('unmarshalLocator reads plaintexts as Unmarshal', () {
|
|
|
|
|
for (final c in rows(v, 'plaintexts')) {
|
|
|
|
|
final b = applyLocatorEdits(plainBases[c[0]! as int], c[1]);
|
|
|
|
|
Locator? l;
|
|
|
|
|
expect(
|
|
|
|
|
errorText(() => l = unmarshalLocator(b)),
|
|
|
|
|
textOf(v, c[2]),
|
|
|
|
|
reason: '${c[1]}',
|
|
|
|
|
);
|
|
|
|
|
if (c[3] != null) {
|
|
|
|
|
expect(summaryOf(l!), expandSummary(c[3]), reason: '${c[1]}');
|
|
|
|
|
// As FuzzUnmarshal of Go: an address that a reader uses passes the
|
|
|
|
|
// rules, and has a host to show.
|
|
|
|
|
for (final a in l!.usable) {
|
|
|
|
|
checkAddressUri(a.uri);
|
|
|
|
|
expect(a.host, isNotEmpty);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('marshal writes the plaintext of Marshal, or its error', () {
|
|
|
|
|
for (final c in rows(v, 'marshal')) {
|
|
|
|
|
final l = base(
|
|
|
|
|
addresses: [
|
|
|
|
|
for (final a in (c[0]! as List<Object?>).cast<List<Object?>>())
|
|
|
|
|
LocatorAddress(uriOf(a[0]), a[1]! as int),
|
|
|
|
|
],
|
|
|
|
|
header: c[1] == null ? null : fromHex(c[1]! as String),
|
|
|
|
|
restSize: c[2]! as int,
|
|
|
|
|
);
|
|
|
|
|
Uint8List? b;
|
|
|
|
|
expect(errorText(() => b = l.marshal()), textOf(v, c[3]), reason: '$c');
|
|
|
|
|
if (b != null) {
|
|
|
|
|
expect([b!.length, sha256Hex(b!)], [c[4], c[5]], reason: '$c');
|
|
|
|
|
// It reads back as it was written.
|
|
|
|
|
expect(summaryOf(unmarshalLocator(b!)), summaryOf(l));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('openLocator opens a sealed locator with the release of its round, '
|
|
|
|
|
'as Open', () {
|
|
|
|
|
for (final c in rows(v, 'open')) {
|
|
|
|
|
final round = c[1]! as int;
|
|
|
|
|
final b = applyLocatorEdits(sealedBases[c[0]! as int], c[4]);
|
|
|
|
|
Locator? l;
|
|
|
|
|
expect(
|
|
|
|
|
errorText(
|
|
|
|
|
() => l = openLocator(
|
|
|
|
|
profileOf(c[3]! as String),
|
|
|
|
|
round,
|
|
|
|
|
openRelease(v, round, c[2]),
|
|
|
|
|
b,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
textOf(v, c[5]),
|
|
|
|
|
reason: '$c',
|
|
|
|
|
);
|
|
|
|
|
if (c[6] != null) {
|
|
|
|
|
expect(summaryOf(l!), expandSummary(c[6]), reason: '$c');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
Stage 7a: the data of datekeys.capsule
lib/src/locator.dart gains the data of the extension, as Info, ParseInfo
and Info.Extension of Go, with the same checks in the same order and the
same texts:
- parseCapsuleInfo: the map of spec 44.1 with the note under the rules of
spec 24.1, the canonical DateKey, and a sealed locator that is an age
file with one tlock stanza for its round; every failure is
ERR_EXTENSION_DATA_INVALID and nothing else, so that it makes the
extension unusable and never the .dkk (spec 54).
- CapsuleInfo.toExtension, which reads back what it writes (spec 72), and
CapsuleInfo.openLocator, OpenLocator of Go, with the default registry of
pinned profiles when none is given, as the opening of a capsule takes it.
- checkCapsuleData, the ValidateCapsule of Go's locator.Standard, for
StandardExtensions.
The tests run the extension cases of locator.json with their code, the
writing and the reading of the data, OpenLocator, the registry of
locator.Standard through checkCritical, checkNoncritical and checkWrite,
and the opening of a fixture whose .dkk carries datekeys.capsule, whose
unusable extensions and checks are those of Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
test('the locator of an extension opens with the default registry, as '
|
|
|
|
|
'OpenLocator', () {
|
|
|
|
|
for (final c in rows(v, 'open_info')) {
|
|
|
|
|
final s = c[2];
|
|
|
|
|
final info = CapsuleInfo(
|
|
|
|
|
dateKey: DateKey(c[0]! as String, c[1]! as int),
|
|
|
|
|
sealed: s == null ? null : sealedBases[s as int],
|
|
|
|
|
);
|
|
|
|
|
Locator? l;
|
|
|
|
|
expect(
|
|
|
|
|
errorText(() => l = info.openLocator(releaseOf(v, c[3]! as int))),
|
|
|
|
|
textOf(v, c[4]),
|
|
|
|
|
reason: '$c',
|
|
|
|
|
);
|
|
|
|
|
if (c[5] != null) expect(summaryOf(l!), expandSummary(c[5]));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
Stage 7a: the locator, its opening and the envelope
lib/src/locator.dart gains the rest of package locator of datekeys-go but
Seal and the data of the extension, with the same checks in the same
order and the same texts:
- Locator: unmarshalLocator, the map of spec 44.1 with the length that
Marshal gives and nothing else, and marshal, its form, its addresses and
key 6 up to the least multiple of 4096 that it fills, as padFor and
PlaintextLength; usable, the addresses that a reader uses.
- openLocator, Open of Go: the profile, then age with the tlock identity
of agewrap, and at most 1 MiB of plaintext, as io.LimitReader: the
chunks after it are neither decrypted nor checked.
- The envelope: restIn, openEnvelope with the size and the SHA-256 of the
rest and of the .dkc, hideRest, and splitEnvelope, the part of
NewEnvelope after its age encryption, which needs the writer of age.
A Locator keeps the types of Go: keys and digests of 32 bytes, and no
negative size or offset. Its errors carry no code, as in Go.
The tests run the cases of locator.json, the padding of every base, 482
plaintexts, Marshal at its limits, 118 openings, the files past 1 MiB, the
envelope, the rests and the split; a part also on Node.js.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
test('openEnvelope checks the rest and the .dkc as OpenEnvelope', () {
|
|
|
|
|
final rest = fromHex(envelope['rest']! as String);
|
|
|
|
|
final header = fromHex(envelope['header']! as String);
|
|
|
|
|
for (final c in rows(v, 'envelopes')) {
|
|
|
|
|
final l = base(
|
|
|
|
|
key: c[1] == '' ? null : fromHex(c[1]! as String),
|
|
|
|
|
header: applyLocatorEdits(header, c[2]),
|
|
|
|
|
restDigest: c[3] == '' ? null : fromHex(c[3]! as String),
|
|
|
|
|
restSize: c[4]! as int,
|
|
|
|
|
capsuleDigest: c[5] == '' ? null : fromHex(c[5]! as String),
|
|
|
|
|
);
|
|
|
|
|
Uint8List? dkc;
|
|
|
|
|
final r = applyLocatorEdits(rest, c[6]);
|
|
|
|
|
expect(
|
|
|
|
|
errorText(() => dkc = l.openEnvelope(r)),
|
|
|
|
|
textOf(v, c[7]),
|
|
|
|
|
reason: '${c[0]}',
|
|
|
|
|
);
|
|
|
|
|
if (dkc != null) {
|
|
|
|
|
expect(sha256Hex(dkc!), c[8]);
|
|
|
|
|
expect(toHex(dkc!), envelope['dkc']);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('restIn reads rest_size bytes from the offset, as RestIn', () {
|
|
|
|
|
final resources = [fromHex(v['rest_in_resource']! as String), Uint8List(0)];
|
|
|
|
|
for (final c in rows(v, 'rest_in')) {
|
|
|
|
|
final l = base(restSize: c[2]! as int);
|
|
|
|
|
Uint8List? r;
|
|
|
|
|
expect(
|
|
|
|
|
errorText(() => r = l.restIn(resources[c[0]! as int], c[1]! as int)),
|
|
|
|
|
textOf(v, c[3]),
|
|
|
|
|
reason: '$c',
|
|
|
|
|
);
|
|
|
|
|
if (r != null) expect(sha256Hex(r!), c[4]);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('hideRest appends the rest, as Hide', () {
|
|
|
|
|
for (final c in rows(v, 'hide')) {
|
|
|
|
|
final (:file, :offset) = hideRest(
|
|
|
|
|
fromHex(c[0]! as String),
|
|
|
|
|
fromHex(c[1]! as String),
|
|
|
|
|
);
|
|
|
|
|
expect([toHex(file), offset], [c[2], c[3]]);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('splitEnvelope splits an age file where NewEnvelope does', () {
|
|
|
|
|
final key = fromHex(envelope['key']! as String);
|
|
|
|
|
final dkc = fromHex(envelope['dkc']! as String);
|
|
|
|
|
for (final c in rows(v, 'split')) {
|
|
|
|
|
final file = fromHex(c[0]! as String);
|
|
|
|
|
({Locator locator, Uint8List rest})? s;
|
|
|
|
|
expect(
|
|
|
|
|
errorText(() => s = splitEnvelope(file, key, dkc)),
|
|
|
|
|
textOf(v, c[1]),
|
|
|
|
|
reason: '$c',
|
|
|
|
|
);
|
|
|
|
|
if (s != null) {
|
|
|
|
|
final end = c[2]! as int;
|
|
|
|
|
expect(toHex(s!.locator.envelopeHeader), toHex(file.sublist(0, end)));
|
|
|
|
|
expect(toHex(s!.rest), toHex(file.sublist(end)));
|
|
|
|
|
expect(s!.locator.addresses, isEmpty);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// The envelope of NewEnvelope: its locator is the one of the vectors.
|
|
|
|
|
final rows0 = rows(v, 'split').first;
|
|
|
|
|
final s = splitEnvelope(fromHex(rows0[0]! as String), key, dkc);
|
|
|
|
|
expect(toHex(s.locator.envelopeHeader), envelope['header']);
|
|
|
|
|
expect(toHex(s.rest), envelope['rest']);
|
|
|
|
|
expect(toHex(s.locator.restDigest), envelope['rest_digest']);
|
|
|
|
|
expect(s.locator.restSize, envelope['rest_size']);
|
|
|
|
|
expect(toHex(s.locator.capsuleDigest), envelope['capsule_digest']);
|
|
|
|
|
expect(s.locator.openEnvelope(s.rest), dkc);
|
|
|
|
|
});
|
Stage 7a: the data of datekeys.capsule
lib/src/locator.dart gains the data of the extension, as Info, ParseInfo
and Info.Extension of Go, with the same checks in the same order and the
same texts:
- parseCapsuleInfo: the map of spec 44.1 with the note under the rules of
spec 24.1, the canonical DateKey, and a sealed locator that is an age
file with one tlock stanza for its round; every failure is
ERR_EXTENSION_DATA_INVALID and nothing else, so that it makes the
extension unusable and never the .dkk (spec 54).
- CapsuleInfo.toExtension, which reads back what it writes (spec 72), and
CapsuleInfo.openLocator, OpenLocator of Go, with the default registry of
pinned profiles when none is given, as the opening of a capsule takes it.
- checkCapsuleData, the ValidateCapsule of Go's locator.Standard, for
StandardExtensions.
The tests run the extension cases of locator.json with their code, the
writing and the reading of the data, OpenLocator, the registry of
locator.Standard through checkCritical, checkNoncritical and checkWrite,
and the opening of a fixture whose .dkk carries datekeys.capsule, whose
unusable extensions and checks are those of Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
|
|
|
|
|
test('toExtension writes the data of datekeys.capsule as Info.Extension', () {
|
|
|
|
|
for (final c in rows(v, 'info')) {
|
|
|
|
|
final sealed = switch (c[3]) {
|
|
|
|
|
null => null,
|
|
|
|
|
final int i => sealedBases[i],
|
|
|
|
|
final String h => fromHex(h),
|
|
|
|
|
final Json z => Uint8List(z['zeros']! as int),
|
|
|
|
|
_ => throw StateError('${c[3]}'),
|
|
|
|
|
};
|
|
|
|
|
final info = CapsuleInfo(
|
|
|
|
|
note: c[0]! as String,
|
|
|
|
|
dateKey: DateKey(c[1]! as String, c[2]! as int),
|
|
|
|
|
sealed: sealed,
|
|
|
|
|
);
|
|
|
|
|
Extension? x;
|
|
|
|
|
expect(
|
|
|
|
|
errorText(() => x = info.toExtension()),
|
|
|
|
|
textOf(v, c[4]),
|
|
|
|
|
reason: '${c.take(3)}',
|
|
|
|
|
);
|
|
|
|
|
if (x != null) {
|
|
|
|
|
expect([x!.id, x!.version], [capsuleExtensionId, 1]);
|
|
|
|
|
expect([x!.data!.length, sha256Hex(x!.data!)], [c[5], c[6]]);
|
|
|
|
|
// A reader reads it back.
|
|
|
|
|
final back = parseCapsuleInfo(x!);
|
|
|
|
|
expect([back.note, back.dateKey], [info.note, info.dateKey]);
|
|
|
|
|
expect(back.sealed, info.sealed);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('parseCapsuleInfo reads the data of datekeys.capsule as ParseInfo, '
|
|
|
|
|
'with ERR_EXTENSION_DATA_INVALID only', () {
|
|
|
|
|
for (final c in rows(v, 'parse')) {
|
|
|
|
|
final b = c[2]! as int;
|
|
|
|
|
final data = b < 0 ? null : applyLocatorEdits(parseBases[b], c[3]);
|
|
|
|
|
CapsuleInfo? info;
|
|
|
|
|
final x = Extension(c[0]! as String, c[1]! as int, data);
|
|
|
|
|
final want = textOf(v, c[4]);
|
|
|
|
|
expect(errorText(() => info = parseCapsuleInfo(x)), want, reason: '$c');
|
|
|
|
|
if (want.isNotEmpty) {
|
|
|
|
|
expect(
|
|
|
|
|
() => parseCapsuleInfo(x),
|
|
|
|
|
throwsA(
|
|
|
|
|
isA<DateKeysException>().having(
|
|
|
|
|
(e) => e.code,
|
|
|
|
|
'code',
|
|
|
|
|
ErrorCode.extensionDataInvalid,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
expect(checkCapsuleData(x), isA<DateKeysException>());
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
expect(checkCapsuleData(x), isNull);
|
|
|
|
|
expect(
|
|
|
|
|
[info!.note, compactDateKey(info!.dateKey), info!.dateKey.round],
|
|
|
|
|
[c[5], c[6], c[7]],
|
|
|
|
|
);
|
|
|
|
|
expect(info!.sealed == null ? null : sha256Hex(info!.sealed!), c[8]);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('the registry of locator.Standard checks the data of datekeys.capsule '
|
|
|
|
|
'in a .dkk, and an encoder only its presence', () {
|
Stage 7a: the default registry checks datekeys.capsule; README, changelog
StandardExtensions checks by default the data of datekeys.capsule with
checkCapsuleData, as locator.Standard of Go: when a .dkk is opened with
it, an extension whose data does not read is unusable, with the text of
Go. With validateCapsule: null it checks only that there is data, as
Go's extension.Standard without ValidateCapsule: the writer of a .dkk
keeps that one, as Go's writer does, and so do the tests of the formats
that compare with extension.Standard. Inspection and opening give Go's
results on every fixture and vector, and the tests of the locator use the
default registry.
lib/datekeys.dart exports locator.dart. The README has the section of
part 7a, its vectors and how the generator makes them; the changelog has
its entry, with its tests and its injected faults.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
// The default registry of the library is locator.Standard of Go, and
|
|
|
|
|
// without ValidateCapsule it is the extension.Standard of Go's writers.
|
|
|
|
|
const std = StandardExtensions();
|
Stage 7a: the data of datekeys.capsule
lib/src/locator.dart gains the data of the extension, as Info, ParseInfo
and Info.Extension of Go, with the same checks in the same order and the
same texts:
- parseCapsuleInfo: the map of spec 44.1 with the note under the rules of
spec 24.1, the canonical DateKey, and a sealed locator that is an age
file with one tlock stanza for its round; every failure is
ERR_EXTENSION_DATA_INVALID and nothing else, so that it makes the
extension unusable and never the .dkk (spec 54).
- CapsuleInfo.toExtension, which reads back what it writes (spec 72), and
CapsuleInfo.openLocator, OpenLocator of Go, with the default registry of
pinned profiles when none is given, as the opening of a capsule takes it.
- checkCapsuleData, the ValidateCapsule of Go's locator.Standard, for
StandardExtensions.
The tests run the extension cases of locator.json with their code, the
writing and the reading of the data, OpenLocator, the registry of
locator.Standard through checkCritical, checkNoncritical and checkWrite,
and the opening of a fixture whose .dkk carries datekeys.capsule, whose
unusable extensions and checks are those of Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
const presence = StandardExtensions(validateCapsule: null);
|
Stage 7a: the default registry checks datekeys.capsule; README, changelog
StandardExtensions checks by default the data of datekeys.capsule with
checkCapsuleData, as locator.Standard of Go: when a .dkk is opened with
it, an extension whose data does not read is unusable, with the text of
Go. With validateCapsule: null it checks only that there is data, as
Go's extension.Standard without ValidateCapsule: the writer of a .dkk
keeps that one, as Go's writer does, and so do the tests of the formats
that compare with extension.Standard. Inspection and opening give Go's
results on every fixture and vector, and the tests of the locator use the
default registry.
lib/datekeys.dart exports locator.dart. The README has the section of
part 7a, its vectors and how the generator makes them; the changelog has
its entry, with its tests and its injected faults.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
expect(std.validateCapsule, checkCapsuleData);
|
Stage 7a: the data of datekeys.capsule
lib/src/locator.dart gains the data of the extension, as Info, ParseInfo
and Info.Extension of Go, with the same checks in the same order and the
same texts:
- parseCapsuleInfo: the map of spec 44.1 with the note under the rules of
spec 24.1, the canonical DateKey, and a sealed locator that is an age
file with one tlock stanza for its round; every failure is
ERR_EXTENSION_DATA_INVALID and nothing else, so that it makes the
extension unusable and never the .dkk (spec 54).
- CapsuleInfo.toExtension, which reads back what it writes (spec 72), and
CapsuleInfo.openLocator, OpenLocator of Go, with the default registry of
pinned profiles when none is given, as the opening of a capsule takes it.
- checkCapsuleData, the ValidateCapsule of Go's locator.Standard, for
StandardExtensions.
The tests run the extension cases of locator.json with their code, the
writing and the reading of the data, OpenLocator, the registry of
locator.Standard through checkCritical, checkNoncritical and checkWrite,
and the opening of a fixture whose .dkk carries datekeys.capsule, whose
unusable extensions and checks are those of Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
for (final c in rows(v, 'registry')) {
|
|
|
|
|
final d = c[2]! as int;
|
|
|
|
|
final x = Extension(
|
|
|
|
|
c[0]! as String,
|
|
|
|
|
c[1]! as int,
|
|
|
|
|
d < 0 ? null : datas[d],
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[
|
|
|
|
|
for (final u in checkNoncritical([x], std, ExtensionObject.accessKey))
|
|
|
|
|
u.error.message,
|
|
|
|
|
],
|
|
|
|
|
[for (final i in c[3]! as List<Object?>) textOf(v, i)],
|
|
|
|
|
reason: '$c',
|
|
|
|
|
);
|
|
|
|
|
final texts = [
|
|
|
|
|
errorText(() => checkCritical([x], std, ExtensionObject.accessKey)),
|
|
|
|
|
errorText(
|
|
|
|
|
() => checkWrite(
|
|
|
|
|
std,
|
|
|
|
|
ExtensionObject.accessKey,
|
|
|
|
|
ExtensionArray.noncritical,
|
|
|
|
|
[x],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
errorText(
|
|
|
|
|
() => checkWrite(
|
|
|
|
|
std,
|
|
|
|
|
ExtensionObject.accessKey,
|
|
|
|
|
ExtensionArray.critical,
|
|
|
|
|
[x],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
errorText(
|
|
|
|
|
() => checkWrite(
|
|
|
|
|
presence,
|
|
|
|
|
ExtensionObject.accessKey,
|
|
|
|
|
ExtensionArray.noncritical,
|
|
|
|
|
[x],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
expect(texts, [for (final i in c.sublist(4)) textOf(v, i)], reason: '$c');
|
|
|
|
|
}
|
|
|
|
|
});
|
Stage 7a: the locator, its opening and the envelope
lib/src/locator.dart gains the rest of package locator of datekeys-go but
Seal and the data of the extension, with the same checks in the same
order and the same texts:
- Locator: unmarshalLocator, the map of spec 44.1 with the length that
Marshal gives and nothing else, and marshal, its form, its addresses and
key 6 up to the least multiple of 4096 that it fills, as padFor and
PlaintextLength; usable, the addresses that a reader uses.
- openLocator, Open of Go: the profile, then age with the tlock identity
of agewrap, and at most 1 MiB of plaintext, as io.LimitReader: the
chunks after it are neither decrypted nor checked.
- The envelope: restIn, openEnvelope with the size and the SHA-256 of the
rest and of the .dkc, hideRest, and splitEnvelope, the part of
NewEnvelope after its age encryption, which needs the writer of age.
A Locator keeps the types of Go: keys and digests of 32 bytes, and no
negative size or offset. Its errors carry no code, as in Go.
The tests run the cases of locator.json, the padding of every base, 482
plaintexts, Marshal at its limits, 118 openings, the files past 1 MiB, the
envelope, the rests and the split; a part also on Node.js.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
final v = decodeJson(locatorVectorsJson);
|
|
|
|
|
group('the part of locator_vectors.json', () => locatorCases(v));
|
|
|
|
|
|
|
|
|
|
test('a Locator has the types of Go: keys and digests of 32 bytes and no '
|
|
|
|
|
'negative size or offset', () {
|
|
|
|
|
final k = Uint8List(32);
|
|
|
|
|
Locator make({int key = 32, int size = 0}) => Locator(
|
|
|
|
|
addresses: const [],
|
|
|
|
|
envelopeKey: Uint8List(key),
|
|
|
|
|
envelopeHeader: [1],
|
|
|
|
|
restDigest: k,
|
|
|
|
|
restSize: size,
|
|
|
|
|
capsuleDigest: k,
|
|
|
|
|
);
|
|
|
|
|
make();
|
|
|
|
|
expect(() => make(key: 31), throwsArgumentError);
|
|
|
|
|
expect(() => make(size: -1), throwsArgumentError);
|
|
|
|
|
expect(() => LocatorAddress('https://a.org/', -1), throwsArgumentError);
|
|
|
|
|
expect(() => make().restIn([1, 2], -1), throwsArgumentError);
|
|
|
|
|
// An envelope without addresses yet does not marshal.
|
|
|
|
|
expect(
|
|
|
|
|
errorText(() => make().marshal()),
|
|
|
|
|
'locator: 0 addresses, not 1 to 8',
|
|
|
|
|
);
|
|
|
|
|
final l = make().withAddresses([LocatorAddress('https://a.org/', 5)]);
|
|
|
|
|
expect(l.addresses.single.offset, 5);
|
|
|
|
|
l.wipe();
|
|
|
|
|
expect(l.envelopeKey, Uint8List(32));
|
|
|
|
|
});
|
|
|
|
|
}
|