115 lines
5.6 KiB
Dart
115 lines
5.6 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:jj_mkvmaker/core/ftp.dart';
|
|
import 'package:jj_mkvmaker/core/remote_fs.dart';
|
|
import 'package:jj_mkvmaker/core/secret_gate.dart';
|
|
import 'package:jj_mkvmaker/core/sftp.dart';
|
|
import 'package:jj_mkvmaker/core/smb.dart';
|
|
import 'package:jj_mkvmaker/core/webdav.dart';
|
|
|
|
/// modular_sync #6 F11 약속: 원격 등록 4벌 · 마스터 문 4벌을 한 몸통 (RemoteRegistry · requireSecretGate) 으로.
|
|
/// ① 다시 접속하는 바뀜은 예전과 같게: 지움 · 비밀이 아닌 칸 (주소 · 사용자 …) · 비밀 값 (SFTP 는 키 · 키 암호까지)
|
|
/// ② 문 (보안): 비밀 값이 있는데 마스터 확인 없이 열리는 길이 없음 - 거절이면 연결 전에 DavLockedException, 비밀 값이 없으면 묻지 않음
|
|
void main() {
|
|
tearDown(() {
|
|
SecretGate.check = null;
|
|
DavRegistry.configure(const []);
|
|
SftpRegistry.configure(const []);
|
|
SmbRegistry.configure(const []);
|
|
FtpRegistry.configure(const []);
|
|
SmbRegistry.requireSecure = false;
|
|
});
|
|
|
|
/// 등록 하나의 규칙: 같으면 같은 클라이언트 · [changes] 마다 새 클라이언트 · 지우면 [missing] 오류
|
|
void rules<S>(String name, S base, List<S> changes, void Function(List<S>) configure, RemoteClient Function(String) client,
|
|
Matcher missing) {
|
|
test('$name: 같으면 같은 클라이언트 · 바뀌면 새로 · 지우면 설정 없음', () {
|
|
configure([base]);
|
|
final first = client('x');
|
|
configure([base]);
|
|
expect(identical(client('x'), first), isTrue, reason: '그대로면 다시 접속하지 않음');
|
|
var prev = first;
|
|
for (final (i, c) in changes.indexed) {
|
|
configure([base]);
|
|
prev = client('x');
|
|
configure([c]);
|
|
expect(identical(client('x'), prev), isFalse, reason: '바뀜 $i 이면 새 클라이언트');
|
|
}
|
|
configure(const []);
|
|
expect(() => client('x'), throwsA(missing));
|
|
});
|
|
}
|
|
|
|
const dav = DavServer(id: 'x', name: 'n', url: 'http://127.0.0.1:1/dav', user: 'u', password: 'p');
|
|
rules<DavServer>('WebDAV', dav, [dav.copyWith(url: 'http://127.0.0.1:2/dav'), dav.copyWith(user: 'v'), dav.copyWith(password: 'q'),
|
|
dav.copyWith(insecure: true)], DavRegistry.configure, DavRegistry.client, isA<DavException>());
|
|
|
|
const sftp = SftpServer(id: 'x', name: 'n', host: '127.0.0.1', port: 1, user: 'u', password: 'p', privateKey: 'k', keyPassphrase: 'kp');
|
|
rules<SftpServer>('SFTP', sftp, [sftp.copyWith(host: 'h2'), sftp.copyWith(user: 'v'), sftp.copyWith(password: 'q'),
|
|
sftp.copyWith(privateKey: 'k2'), sftp.copyWith(keyPassphrase: 'kp2')], SftpRegistry.configure, SftpRegistry.client, isA<SftpException>());
|
|
|
|
const smb = SmbServer(id: 'x', name: 'n', host: '127.0.0.1', port: 1, share: 's', user: 'u', password: 'p');
|
|
rules<SmbServer>('SMB', smb, [smb.copyWith(host: 'h2'), smb.copyWith(share: 't'), smb.copyWith(user: 'v'), smb.copyWith(password: 'q')],
|
|
SmbRegistry.configure, SmbRegistry.client, isA<SmbException>());
|
|
|
|
const ftp = FtpServer(id: 'x', name: 'n', host: '127.0.0.1', port: 1, user: 'u', password: 'p', security: 'none');
|
|
rules<FtpServer>('FTP', ftp, [ftp.copyWith(host: 'h2'), ftp.copyWith(user: 'v'), ftp.copyWith(password: 'q'), ftp.copyWith(security: 'explicit')],
|
|
FtpRegistry.configure, FtpRegistry.client, isA<FtpException>());
|
|
|
|
test('SMB: 서명 · 암호화 필수를 바꾸면 열린 연결을 버림', () {
|
|
SmbRegistry.configure(const [smb]);
|
|
final first = SmbRegistry.client('x');
|
|
SmbRegistry.requireSecure = true;
|
|
expect(identical(SmbRegistry.client('x'), first), isFalse);
|
|
});
|
|
|
|
test('문: 비밀 값이 있으면 4종 모두 마스터 확인을 지나야 함 - 거절이면 연결 전에 DavLockedException', () async {
|
|
var asked = 0;
|
|
SecretGate.check = (_) async {
|
|
asked++;
|
|
return false;
|
|
};
|
|
final clients = <RemoteClient>[DavClient(dav), SftpRemote(sftp), SmbRemote(smb), FtpRemote(ftp)];
|
|
for (final c in clients) {
|
|
await expectLater(c.list('/'), throwsA(isA<DavLockedException>()), reason: '${c.runtimeType}');
|
|
c.close();
|
|
}
|
|
expect(asked, clients.length, reason: '서버마다 물었음');
|
|
// SFTP 는 개인 키만 있어도 비밀 값
|
|
final keyOnly = SftpRemote(const SftpServer(id: 'y', name: 'n', host: '127.0.0.1', port: 1, user: 'u', privateKey: 'k'));
|
|
await expectLater(keyOnly.list('/'), throwsA(isA<DavLockedException>()));
|
|
keyOnly.close();
|
|
});
|
|
|
|
test('문: 비밀 값이 없으면 묻지 않는다 (막히는 것은 마스터가 아니라 그 서버의 까닭)', () async {
|
|
var asked = 0;
|
|
SecretGate.check = (_) async {
|
|
asked++;
|
|
return false;
|
|
};
|
|
for (final c in <RemoteClient>[
|
|
DavClient(const DavServer(id: 'z', name: 'n', url: 'http://127.0.0.1:1/dav')),
|
|
SftpRemote(const SftpServer(id: 'z', name: 'n', host: '127.0.0.1', port: 1, user: 'u')),
|
|
FtpRemote(const FtpServer(id: 'z', name: 'n', host: '127.0.0.1', port: 1, security: 'none')),
|
|
]) {
|
|
await expectLater(c.list('/'), throwsA(isNot(isA<DavLockedException>())), reason: '${c.runtimeType}');
|
|
c.close();
|
|
}
|
|
expect(asked, 0);
|
|
});
|
|
|
|
test('SecretGate.passIf: 비밀 값이 있을 때만 묻고 그 답을 따름 · 없으면 묻지 않고 지나감 · force 를 넘김', () async {
|
|
final asked = <bool>[];
|
|
var answer = false;
|
|
SecretGate.check = (force) async {
|
|
asked.add(force);
|
|
return answer;
|
|
};
|
|
expect(await SecretGate.passIf(false), isTrue);
|
|
expect(asked, isEmpty);
|
|
expect(await SecretGate.passIf(true), isFalse);
|
|
answer = true;
|
|
expect(await SecretGate.passIf(true, force: true), isTrue);
|
|
expect(asked, [false, true]);
|
|
});
|
|
}
|