feat(useragent): added connection info setup screen
This commit is contained in:
56
useragent/lib/features/arbiter_url.dart
Normal file
56
useragent/lib/features/arbiter_url.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class ArbiterUrl {
|
||||
const ArbiterUrl({
|
||||
required this.host,
|
||||
required this.port,
|
||||
required this.caCert,
|
||||
this.bootstrapToken,
|
||||
});
|
||||
|
||||
final String host;
|
||||
final int port;
|
||||
final List<int> caCert;
|
||||
final String? bootstrapToken;
|
||||
|
||||
static const _scheme = 'arbiter';
|
||||
static const _certQueryKey = 'cert';
|
||||
static const _bootstrapTokenQueryKey = 'bootstrap_token';
|
||||
|
||||
static ArbiterUrl parse(String value) {
|
||||
final uri = Uri.tryParse(value);
|
||||
if (uri == null || uri.scheme != _scheme) {
|
||||
throw const FormatException("Invalid URL scheme, expected 'arbiter://'");
|
||||
}
|
||||
|
||||
if (uri.host.isEmpty) {
|
||||
throw const FormatException('Missing host in URL');
|
||||
}
|
||||
|
||||
if (!uri.hasPort) {
|
||||
throw const FormatException('Missing port in URL');
|
||||
}
|
||||
|
||||
final cert = uri.queryParameters[_certQueryKey];
|
||||
if (cert == null || cert.isEmpty) {
|
||||
throw const FormatException("Missing 'cert' query parameter in URL");
|
||||
}
|
||||
|
||||
final decodedCert = _decodeCert(cert);
|
||||
|
||||
return ArbiterUrl(
|
||||
host: uri.host,
|
||||
port: uri.port,
|
||||
caCert: decodedCert,
|
||||
bootstrapToken: uri.queryParameters[_bootstrapTokenQueryKey],
|
||||
);
|
||||
}
|
||||
|
||||
static List<int> _decodeCert(String cert) {
|
||||
try {
|
||||
return base64Url.decode(base64Url.normalize(cert));
|
||||
} on FormatException catch (error) {
|
||||
throw FormatException("Invalid base64 in 'cert' query parameter: ${error.message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
3
useragent/lib/features/connection/connection.dart
Normal file
3
useragent/lib/features/connection/connection.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
class Connection {}
|
||||
@@ -1,6 +1,3 @@
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
enum KeyAlgorithm {
|
||||
rsa, ecdsa, ed25519
|
||||
}
|
||||
@@ -16,4 +13,4 @@ abstract class KeyHandle {
|
||||
abstract class KeyManager {
|
||||
Future<KeyHandle?> get();
|
||||
Future<KeyHandle> create();
|
||||
}
|
||||
}
|
||||
|
||||
67
useragent/lib/features/server_info_storage.dart
Normal file
67
useragent/lib/features/server_info_storage.dart
Normal file
@@ -0,0 +1,67 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
||||
class StoredServerInfo {
|
||||
const StoredServerInfo({
|
||||
required this.address,
|
||||
required this.port,
|
||||
required this.caCertFingerprint,
|
||||
});
|
||||
|
||||
final String address;
|
||||
final int port;
|
||||
final String caCertFingerprint;
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'address': address,
|
||||
'port': port,
|
||||
'caCertFingerprint': caCertFingerprint,
|
||||
};
|
||||
|
||||
factory StoredServerInfo.fromJson(Map<String, dynamic> json) {
|
||||
return StoredServerInfo(
|
||||
address: json['address'] as String,
|
||||
port: json['port'] as int,
|
||||
caCertFingerprint: json['caCertFingerprint'] as String,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ServerInfoStorage {
|
||||
Future<StoredServerInfo?> load();
|
||||
Future<void> save(StoredServerInfo serverInfo);
|
||||
Future<void> clear();
|
||||
}
|
||||
|
||||
class SecureServerInfoStorage implements ServerInfoStorage {
|
||||
static const _storageKey = 'server_info';
|
||||
|
||||
const SecureServerInfoStorage();
|
||||
|
||||
static const _storage = FlutterSecureStorage();
|
||||
|
||||
@override
|
||||
Future<StoredServerInfo?> load() async {
|
||||
final rawValue = await _storage.read(key: _storageKey);
|
||||
if (rawValue == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final decoded = jsonDecode(rawValue) as Map<String, dynamic>;
|
||||
return StoredServerInfo.fromJson(decoded);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> save(StoredServerInfo serverInfo) {
|
||||
return _storage.write(
|
||||
key: _storageKey,
|
||||
value: jsonEncode(serverInfo.toJson()),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> clear() {
|
||||
return _storage.delete(key: _storageKey);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user