107 lines
3.5 KiB
Dart
107 lines
3.5 KiB
Dart
|
|
import 'dart:io';
|
||
|
|
import 'dart:typed_data';
|
||
|
|
|
||
|
|
import 'package:halkyon_content/halkyon_content.dart';
|
||
|
|
import 'package:halkyon_learn_agent/src/agent_home.dart';
|
||
|
|
import 'package:path/path.dart' as p;
|
||
|
|
import 'package:test/test.dart';
|
||
|
|
|
||
|
|
/// Where the agent keeps its token, keys and data (Halkyon's ADR 0044,
|
||
|
|
/// D50): a folder per instance only its user may enter, files only it may
|
||
|
|
/// read, and nothing read that others could have read or changed.
|
||
|
|
void main() {
|
||
|
|
late Directory root;
|
||
|
|
|
||
|
|
setUp(() async {
|
||
|
|
root = await Directory.systemTemp.createTemp('agent_home');
|
||
|
|
addTearDown(() => root.delete(recursive: true));
|
||
|
|
});
|
||
|
|
|
||
|
|
int modeOf(String path) => FileStat.statSync(path).mode & 0x1ff;
|
||
|
|
|
||
|
|
test(
|
||
|
|
'each instance has a folder of its own, its user alone entering it',
|
||
|
|
() async {
|
||
|
|
final learn = await AgentHome.open(
|
||
|
|
root,
|
||
|
|
Uri.parse('https://learn.halkyon.eu/'),
|
||
|
|
);
|
||
|
|
final local = await AgentHome.open(
|
||
|
|
root,
|
||
|
|
Uri.parse('http://localhost:8080'),
|
||
|
|
);
|
||
|
|
|
||
|
|
expect(p.basename(learn.folder.path), 'learn.halkyon.eu');
|
||
|
|
expect(p.basename(local.folder.path), 'localhost_8080');
|
||
|
|
expect(modeOf(learn.folder.path), 0x1c0); // 0700
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
test('the token is kept for its user alone, and read back', () async {
|
||
|
|
final home = await AgentHome.open(root, Uri.parse('https://halkyon.li'));
|
||
|
|
expect(await home.token(), isNull);
|
||
|
|
|
||
|
|
await home.keepToken('hlk_agent_secret\n');
|
||
|
|
|
||
|
|
expect(await home.token(), 'hlk_agent_secret');
|
||
|
|
expect(modeOf(p.join(home.folder.path, 'token')), 0x180); // 0600
|
||
|
|
});
|
||
|
|
|
||
|
|
test(
|
||
|
|
"a token, keys or folder others may read or change isn't read",
|
||
|
|
() async {
|
||
|
|
final home = await AgentHome.open(root, Uri.parse('https://halkyon.li'));
|
||
|
|
await home.keepToken('secret');
|
||
|
|
await Process.run('chmod', ['644', p.join(home.folder.path, 'token')]);
|
||
|
|
|
||
|
|
await expectLater(home.token(), throwsA(isA<AgentHomeRefused>()));
|
||
|
|
|
||
|
|
await Process.run('chmod', ['600', p.join(home.folder.path, 'token')]);
|
||
|
|
await Process.run('chmod', ['755', home.folder.path]);
|
||
|
|
await expectLater(
|
||
|
|
AgentHome.open(root, Uri.parse('https://halkyon.li')),
|
||
|
|
throwsA(isA<AgentHomeRefused>()),
|
||
|
|
);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
test(
|
||
|
|
'the keys are kept for its user alone, and read back as they were',
|
||
|
|
() async {
|
||
|
|
final home = await AgentHome.open(root, Uri.parse('https://halkyon.li'));
|
||
|
|
expect(await home.keys(), isNull);
|
||
|
|
final keys = UnlockedAccountKeys(
|
||
|
|
encryptionPublicKey: Uint8List.fromList(List.filled(32, 1)),
|
||
|
|
encryptionSecretKey: Uint8List.fromList(List.filled(32, 2)),
|
||
|
|
signingPublicKey: Uint8List.fromList(List.filled(32, 3)),
|
||
|
|
signingSecretKey: Uint8List.fromList(List.filled(64, 4)),
|
||
|
|
);
|
||
|
|
|
||
|
|
await home.keepKeys(keys);
|
||
|
|
|
||
|
|
expect(await home.keys(), keys);
|
||
|
|
expect(modeOf(p.join(home.folder.path, 'keys.json')), 0x180);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
test('notes once the register holds its public keys', () async {
|
||
|
|
final home = await AgentHome.open(root, Uri.parse('https://halkyon.li'));
|
||
|
|
expect(await home.keysSet(), isFalse);
|
||
|
|
|
||
|
|
await home.noteKeysSet();
|
||
|
|
|
||
|
|
expect(await home.keysSet(), isTrue);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('an instance is reached over HTTPS, or plain HTTP on this machine '
|
||
|
|
'alone', () async {
|
||
|
|
await expectLater(
|
||
|
|
AgentHome.open(root, Uri.parse('http://halkyon.li')),
|
||
|
|
throwsA(isA<AgentHomeRefused>()),
|
||
|
|
);
|
||
|
|
await expectLater(
|
||
|
|
AgentHome.open(root, Uri.parse('ftp://halkyon.li')),
|
||
|
|
throwsA(isA<AgentHomeRefused>()),
|
||
|
|
);
|
||
|
|
});
|
||
|
|
}
|