94 lines
3.5 KiB
Dart
94 lines
3.5 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:pj_supermarket_cloud/common/utils/app/file_access.dart';
|
|
|
|
void main() {
|
|
final vectors =
|
|
jsonDecode(File('test-vectors/file-access.json').readAsStringSync())
|
|
as List;
|
|
for (final v in vectors) {
|
|
test('shared Java/TypeScript vector: ${v['fileName']}', () {
|
|
expect(fileAccessCanonical(v['fileName'], v['appId'], v['kid'], v['ts']),
|
|
v['canonical']);
|
|
expect(
|
|
fileAccessSignature(
|
|
v['fileName'], v['appId'], v['kid'], v['ts'], v['key']),
|
|
v['sign']);
|
|
});
|
|
}
|
|
test(
|
|
'sign only owned files; cache identity survives expiry and old APK URLs keep their suffix',
|
|
() {
|
|
var now = DateTime.fromMillisecondsSinceEpoch(1793232000000);
|
|
final client = FileAccessClient(
|
|
baseUrl: 'https://files.example/api',
|
|
appId: 'mini',
|
|
kid: 'v1',
|
|
key: vectors[0]['key'],
|
|
now: () => now);
|
|
final signed = client.url('/admin/sys-file/oss/file?fileName=a.jpg');
|
|
expect(Uri.parse(signed).queryParameters['sign'], vectors[0]['sign']);
|
|
expect(client.url(signed), signed);
|
|
now = now.add(const Duration(minutes: 26));
|
|
final next = client.url(signed);
|
|
expect(next, isNot(signed));
|
|
expect(client.original(next), client.original(signed));
|
|
expect(
|
|
client.url('installer.apk').endsWith('fileName=installer.apk'), isTrue);
|
|
const external =
|
|
'https://other.example/admin/sys-file/oss/file?fileName=a.jpg';
|
|
expect(client.url(external), external);
|
|
const url =
|
|
'https://files.example/api/admin/sys-file/oss/file?fileName=a&fileName=b';
|
|
expect(() => client.url(url), throwsFormatException);
|
|
});
|
|
test(
|
|
'URL names decode once and clock recovery changes only the transport URL',
|
|
() {
|
|
final client = FileAccessClient(
|
|
baseUrl: 'https://files.example/api',
|
|
appId: 'mini',
|
|
kid: 'v1',
|
|
key: vectors[0]['key'],
|
|
now: () => DateTime.fromMillisecondsSinceEpoch(1793318400000));
|
|
const raw = '/admin/sys-file/oss/file?fileName=literal%252Fname.png';
|
|
final before = client.original(raw);
|
|
client.synchronize(1793232000000, 1800, 0);
|
|
final signed = Uri.parse(client.url(raw));
|
|
expect(signed.queryParameters['fileName'], 'literal%2Fname.png');
|
|
expect(signed.queryParameters['ts'], '1793232000');
|
|
expect(client.original(signed.toString()), before);
|
|
});
|
|
test('local resources, deployment prefixes and stable cache keys', () {
|
|
final client = FileAccessClient(
|
|
baseUrl: 'https://files.example',
|
|
appId: 'flutter',
|
|
kid: 'v1',
|
|
key: vectors[0]['key']);
|
|
expect(
|
|
Uri.parse(client.url('/api/admin/sys-file/oss/file?fileName=a.jpg'))
|
|
.path,
|
|
'/admin/sys-file/oss/file');
|
|
for (final local in [
|
|
'/data/user/0/cache/a.jpg',
|
|
'assets/logo.png',
|
|
'/static/a.png',
|
|
'file:///tmp/a.png',
|
|
'data:image/png;base64,AA=='
|
|
]) {
|
|
expect(client.url(local), local);
|
|
}
|
|
const source = '/admin/sys-file/oss/file?fileName=a.jpg&width=20';
|
|
expect(client.original(client.url(source)), client.original(source));
|
|
final prefix = FileAccessClient(
|
|
baseUrl: 'https://files.example/gateway/api',
|
|
appId: 'flutter',
|
|
kid: 'v1',
|
|
key: vectors[0]['key']);
|
|
expect(
|
|
Uri.parse(prefix.url('/admin/sys-file/oss/file?fileName=a.jpg')).path,
|
|
'/gateway/api/admin/sys-file/oss/file');
|
|
});
|
|
}
|