test: patrol flows for fetch cancel, rotation and unchanged-key refresh
This commit is contained in:
parent
f7452832ea
commit
fa0809f021
4 changed files with 240 additions and 34 deletions
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import "dart:convert";
|
||||
import "dart:io";
|
||||
import "dart:math";
|
||||
import "dart:typed_data";
|
||||
|
||||
import "package:flutter_test/flutter_test.dart";
|
||||
|
|
@ -11,7 +12,7 @@ import "package:flutter_test/flutter_test.dart";
|
|||
import "package:smol_mail/native/client.dart";
|
||||
import "package:smol_mail/native/ffi.dart";
|
||||
|
||||
const spikeServerKey = "g5ttsssqjq6j37vso3h7otn33zrk6o6r7c6jjm7guxbbijoa5nqq";
|
||||
const spikeServerKey = "wukbhdiwboarbg4pujxstbqi3caveunrruaopbwxr226ga3xv5ga";
|
||||
const spikeServer = "127.0.0.1";
|
||||
const spikePort = 19619;
|
||||
|
||||
|
|
@ -90,7 +91,8 @@ void main() async {
|
|||
// username, so identities must be fresh per run.
|
||||
final aliceMaster =
|
||||
Uint8List.fromList(List.generate(32, (i) => i * 7 + DateTime.now().microsecondsSinceEpoch % 251));
|
||||
final bobMaster = Uint8List.fromList(List.generate(32, (i) => i * 13 + 5));
|
||||
final bobMaster =
|
||||
Uint8List.fromList(List.generate(32, (_) => Random.secure().nextInt(256)));
|
||||
final run = DateTime.now().millisecondsSinceEpoch.toRadixString(36);
|
||||
|
||||
final alice = FumiNative("${dir.path}/alice.db");
|
||||
|
|
@ -124,4 +126,55 @@ void main() async {
|
|||
await alice.close();
|
||||
await bob.close();
|
||||
});
|
||||
|
||||
// sec 7's readability invariant: mail sealed to the pre-rotation key must
|
||||
// still open after a rotation, because the account derives every superseded
|
||||
// key from the master.
|
||||
test("old mail stays readable across a rotation",
|
||||
skip: await spikeUp()
|
||||
? false
|
||||
: "no bunshin on 127.0.0.1:19619", () async {
|
||||
final dir = await Directory.systemTemp.createTemp("native-rotate");
|
||||
// Random masters: bunshin refuses a key already bound under another
|
||||
// username, so identities must be fresh per run.
|
||||
final rng = Random.secure();
|
||||
final aliceMaster =
|
||||
Uint8List.fromList(List.generate(32, (_) => rng.nextInt(256)));
|
||||
final bobMaster =
|
||||
Uint8List.fromList(List.generate(32, (_) => rng.nextInt(256)));
|
||||
final run = DateTime.now().millisecondsSinceEpoch.toRadixString(36);
|
||||
|
||||
final alice = FumiNative("${dir.path}/alice.db");
|
||||
await alice.open();
|
||||
alice.setMaster(aliceMaster);
|
||||
await alice.pinServer(spikeServer, spikeServerKey);
|
||||
await alice.register("a$run@$spikeServer:$spikePort");
|
||||
|
||||
final bob = FumiNative("${dir.path}/bob.db");
|
||||
await bob.open();
|
||||
bob.setMaster(bobMaster);
|
||||
// The onboarding screen zeroes its own master reference on dispose;
|
||||
// whatever holds the master after that must not share that buffer.
|
||||
bobMaster.fillRange(0, 32, 0);
|
||||
await bob.pinServer(spikeServer, spikeServerKey);
|
||||
await bob.register("b$run@$spikeServer:$spikePort");
|
||||
|
||||
await alice.send("b$run@$spikeServer:$spikePort",
|
||||
"before the rotation",
|
||||
subject: "pre-rotation");
|
||||
final summary = await bob.fetch();
|
||||
expect(summary["stored"], 1);
|
||||
final requests = await bob.mail("requests");
|
||||
final preRotationId = requests[0]["id"] as String;
|
||||
final before = await bob.describe(preRotationId);
|
||||
expect(before["subject"], "pre-rotation");
|
||||
|
||||
await bob.rotate();
|
||||
final after = await bob.describe(preRotationId);
|
||||
expect(after["subject"], "pre-rotation",
|
||||
reason: "mail sealed to the superseded key must stay readable");
|
||||
|
||||
await alice.close();
|
||||
await bob.close();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue