mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2024-09-28 22:37:50 +00:00
Merge branch 'flutter-3' into naiji-dev
This commit is contained in:
commit
d8568fc82f
|
@ -5,8 +5,8 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
|
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||||
|
|
||||||
class HiveConfig {
|
class HiveConfig {
|
||||||
|
@ -25,16 +25,16 @@ class HiveConfig {
|
||||||
await getEncryptedKey(BNames.serverInstallationEncryptionKey));
|
await getEncryptedKey(BNames.serverInstallationEncryptionKey));
|
||||||
|
|
||||||
await Hive.openBox<User>(BNames.usersDeprecated);
|
await Hive.openBox<User>(BNames.usersDeprecated);
|
||||||
await Hive.openBox<User>(BNames.users, encryptionCipher: cipher);
|
await Hive.openBox<User>(BNames.usersBox, encryptionCipher: cipher);
|
||||||
|
|
||||||
Box<User> deprecatedUsers = Hive.box<User>(BNames.usersDeprecated);
|
Box<User> deprecatedUsers = Hive.box<User>(BNames.usersDeprecated);
|
||||||
if (deprecatedUsers.isNotEmpty) {
|
if (deprecatedUsers.isNotEmpty) {
|
||||||
Box<User> users = Hive.box<User>(BNames.users);
|
Box<User> users = Hive.box<User>(BNames.usersBox);
|
||||||
users.addAll(deprecatedUsers.values.toList());
|
users.addAll(deprecatedUsers.values.toList());
|
||||||
deprecatedUsers.clear();
|
deprecatedUsers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
await Hive.openBox(BNames.serverInstallation, encryptionCipher: cipher);
|
await Hive.openBox(BNames.serverInstallationBox, encryptionCipher: cipher);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Uint8List> getEncryptedKey(String encKey) async {
|
static Future<Uint8List> getEncryptedKey(String encKey) async {
|
||||||
|
@ -61,54 +61,54 @@ class BNames {
|
||||||
/// A boolean field of [appSettingsBox] box.
|
/// A boolean field of [appSettingsBox] box.
|
||||||
static String isOnboardingShowing = 'isOnboardingShowing';
|
static String isOnboardingShowing = 'isOnboardingShowing';
|
||||||
|
|
||||||
/// Encryption key to decrypt [serverInstallation] and [users] box.
|
/// Encryption key to decrypt [serverInstallationBox] and [usersBox] box.
|
||||||
static String serverInstallationEncryptionKey = 'key';
|
static String serverInstallationEncryptionKey = 'key';
|
||||||
|
|
||||||
/// Server installation box. Contains server details and provider tokens.
|
/// Server installation box. Contains server details and provider tokens.
|
||||||
static String serverInstallation = 'appConfig';
|
static String serverInstallationBox = 'appConfig';
|
||||||
|
|
||||||
/// A List<String> field of [serverInstallation] box.
|
/// A List<String> field of [serverInstallationBox] box.
|
||||||
static String rootKeys = 'rootKeys';
|
static String rootKeys = 'rootKeys';
|
||||||
|
|
||||||
/// A boolean field of [serverInstallation] box.
|
/// A boolean field of [serverInstallationBox] box.
|
||||||
static String hasFinalChecked = 'hasFinalChecked';
|
static String hasFinalChecked = 'hasFinalChecked';
|
||||||
|
|
||||||
/// A boolean field of [serverInstallation] box.
|
/// A boolean field of [serverInstallationBox] box.
|
||||||
static String isServerStarted = 'isServerStarted';
|
static String isServerStarted = 'isServerStarted';
|
||||||
|
|
||||||
/// A [ServerDomain] field of [serverInstallation] box.
|
/// A [ServerDomain] field of [serverInstallationBox] box.
|
||||||
static String serverDomain = 'cloudFlareDomain';
|
static String serverDomain = 'cloudFlareDomain';
|
||||||
|
|
||||||
/// A String field of [serverInstallation] box.
|
/// A String field of [serverInstallationBox] box.
|
||||||
static String hetznerKey = 'hetznerKey';
|
static String hetznerKey = 'hetznerKey';
|
||||||
|
|
||||||
/// A String field of [serverInstallation] box.
|
/// A String field of [serverInstallationBox] box.
|
||||||
static String cloudFlareKey = 'cloudFlareKey';
|
static String cloudFlareKey = 'cloudFlareKey';
|
||||||
|
|
||||||
/// A [User] field of [serverInstallation] box.
|
/// A [User] field of [serverInstallationBox] box.
|
||||||
static String rootUser = 'rootUser';
|
static String rootUser = 'rootUser';
|
||||||
|
|
||||||
/// A [ServerHostingDetails] field of [serverInstallation] box.
|
/// A [ServerHostingDetails] field of [serverInstallationBox] box.
|
||||||
static String serverDetails = 'hetznerServer';
|
static String serverDetails = 'hetznerServer';
|
||||||
|
|
||||||
/// A [BackblazeCredential] field of [serverInstallation] box.
|
/// A [BackblazeCredential] field of [serverInstallationBox] box.
|
||||||
static String backblazeCredential = 'backblazeKey';
|
static String backblazeCredential = 'backblazeKey';
|
||||||
|
|
||||||
/// A [BackblazeBucket] field of [serverInstallation] box.
|
/// A [BackblazeBucket] field of [serverInstallationBox] box.
|
||||||
static String backblazeBucket = 'backblazeBucket';
|
static String backblazeBucket = 'backblazeBucket';
|
||||||
|
|
||||||
/// A boolean field of [serverInstallation] box.
|
/// A boolean field of [serverInstallationBox] box.
|
||||||
static String isLoading = 'isLoading';
|
static String isLoading = 'isLoading';
|
||||||
|
|
||||||
/// A boolean field of [serverInstallation] box.
|
/// A boolean field of [serverInstallationBox] box.
|
||||||
static String isServerResetedFirstTime = 'isServerResetedFirstTime';
|
static String isServerResetedFirstTime = 'isServerResetedFirstTime';
|
||||||
|
|
||||||
/// A boolean field of [serverInstallation] box.
|
/// A boolean field of [serverInstallationBox] box.
|
||||||
static String isServerResetedSecondTime = 'isServerResetedSecondTime';
|
static String isServerResetedSecondTime = 'isServerResetedSecondTime';
|
||||||
|
|
||||||
/// Deprecated users box as it is unencrypted
|
/// Deprecated users box as it is unencrypted
|
||||||
static String usersDeprecated = 'users';
|
static String usersDeprecated = 'users';
|
||||||
|
|
||||||
/// Box with users
|
/// Box with users
|
||||||
static String users = 'usersEncrypted';
|
static String usersBox = 'usersEncrypted';
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,14 @@ import 'dart:io';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:selfprivacy/config/get_it_config.dart';
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
|
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/api_token.dart';
|
import 'package:selfprivacy/logic/models/json/api_token.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/auto_upgrade_settings.dart';
|
import 'package:selfprivacy/logic/models/json/auto_upgrade_settings.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/json/backup.dart';
|
import 'package:selfprivacy/logic/models/json/backup.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/recovery_token_status.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/json/device_token.dart';
|
import 'package:selfprivacy/logic/models/json/device_token.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/json/recovery_token_status.dart';
|
||||||
import 'package:selfprivacy/logic/models/timezone_settings.dart';
|
import 'package:selfprivacy/logic/models/timezone_settings.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
|
||||||
|
|
||||||
import 'api_map.dart';
|
import 'api_map.dart';
|
||||||
|
|
||||||
|
@ -34,9 +34,13 @@ class ServerApi extends ApiMap {
|
||||||
bool hasLogger;
|
bool hasLogger;
|
||||||
bool isWithToken;
|
bool isWithToken;
|
||||||
String? overrideDomain;
|
String? overrideDomain;
|
||||||
|
String? customToken;
|
||||||
|
|
||||||
ServerApi(
|
ServerApi(
|
||||||
{this.hasLogger = false, this.isWithToken = true, this.overrideDomain});
|
{this.hasLogger = false,
|
||||||
|
this.isWithToken = true,
|
||||||
|
this.overrideDomain,
|
||||||
|
this.customToken});
|
||||||
|
|
||||||
BaseOptions get options {
|
BaseOptions get options {
|
||||||
var options = BaseOptions();
|
var options = BaseOptions();
|
||||||
|
@ -52,7 +56,12 @@ class ServerApi extends ApiMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overrideDomain != null) {
|
if (overrideDomain != null) {
|
||||||
options = BaseOptions(baseUrl: 'https://api.$overrideDomain');
|
options = BaseOptions(
|
||||||
|
baseUrl: 'https://api.$overrideDomain',
|
||||||
|
headers: customToken != null
|
||||||
|
? {'Authorization': 'Bearer $customToken'}
|
||||||
|
: null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:selfprivacy/config/hive_config.dart';
|
import 'package:selfprivacy/config/hive_config.dart';
|
||||||
|
|
||||||
export 'package:provider/provider.dart';
|
export 'package:provider/provider.dart';
|
||||||
|
|
||||||
part 'app_settings_state.dart';
|
part 'app_settings_state.dart';
|
||||||
|
|
|
@ -3,8 +3,8 @@ import 'dart:async';
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
|
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||||
|
|
||||||
import '../server_installation/server_installation_repository.dart';
|
import '../server_installation/server_installation_repository.dart';
|
||||||
|
@ -252,6 +252,59 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
||||||
timer = Timer(delay, work);
|
timer = Timer(delay, work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void submitDomainForAccessRecovery(String domain) async {
|
||||||
|
var serverDomain = ServerDomain(
|
||||||
|
domainName: domain,
|
||||||
|
provider: DnsProvider.Unknown,
|
||||||
|
zoneId: '',
|
||||||
|
);
|
||||||
|
final recoveryCapabilities =
|
||||||
|
await repository.getRecoveryCapabilities(serverDomain);
|
||||||
|
|
||||||
|
emit(ServerInstallationRecovery(
|
||||||
|
serverDomain: serverDomain,
|
||||||
|
recoveryCapabilities: recoveryCapabilities,
|
||||||
|
currentStep: RecoveryStep.Selecting,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tryToRecover(String token, ServerRecoveryMethods method) async {
|
||||||
|
final dataState = this.state as ServerInstallationRecovery;
|
||||||
|
final serverDomain = dataState.serverDomain;
|
||||||
|
if (serverDomain == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Future<ServerHostingDetails> Function(ServerDomain, String)
|
||||||
|
recoveryFunction;
|
||||||
|
switch (method) {
|
||||||
|
case ServerRecoveryMethods.newDeviceKey:
|
||||||
|
recoveryFunction = repository.authorizeByNewDeviceKey;
|
||||||
|
break;
|
||||||
|
case ServerRecoveryMethods.recoveryKey:
|
||||||
|
recoveryFunction = repository.authorizeByRecoveryKey;
|
||||||
|
break;
|
||||||
|
case ServerRecoveryMethods.oldToken:
|
||||||
|
recoveryFunction = repository.authorizeByApiToken;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw Exception('Unknown recovery method');
|
||||||
|
}
|
||||||
|
final serverDetails = await recoveryFunction(
|
||||||
|
serverDomain,
|
||||||
|
token,
|
||||||
|
);
|
||||||
|
emit(dataState.copyWith(
|
||||||
|
serverDetails: serverDetails,
|
||||||
|
currentStep: RecoveryStep.HetznerToken,
|
||||||
|
));
|
||||||
|
} on ServerAuthorizationException {
|
||||||
|
return;
|
||||||
|
} on IpNotFoundException {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void clearAppConfig() {
|
void clearAppConfig() {
|
||||||
closeTimer();
|
closeTimer();
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,42 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:basic_utils/basic_utils.dart';
|
import 'package:basic_utils/basic_utils.dart';
|
||||||
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:pub_semver/pub_semver.dart';
|
||||||
import 'package:selfprivacy/config/get_it_config.dart';
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/config/hive_config.dart';
|
import 'package:selfprivacy/config/hive_config.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/cloudflare.dart';
|
import 'package:selfprivacy/logic/api_maps/cloudflare.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/hetzner.dart';
|
import 'package:selfprivacy/logic/api_maps/hetzner.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/server.dart';
|
import 'package:selfprivacy/logic/api_maps/server.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
|
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/message.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/json/device_token.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/message.dart';
|
||||||
import 'package:selfprivacy/ui/components/action_button/action_button.dart';
|
import 'package:selfprivacy/ui/components/action_button/action_button.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_alert/brand_alert.dart';
|
import 'package:selfprivacy/ui/components/brand_alert/brand_alert.dart';
|
||||||
|
|
||||||
import '../server_installation/server_installation_cubit.dart';
|
import '../server_installation/server_installation_cubit.dart';
|
||||||
|
|
||||||
|
class IpNotFoundException implements Exception {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
IpNotFoundException(this.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServerAuthorizationException implements Exception {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
ServerAuthorizationException(this.message);
|
||||||
|
}
|
||||||
|
|
||||||
class ServerInstallationRepository {
|
class ServerInstallationRepository {
|
||||||
Box box = Hive.box(BNames.serverInstallation);
|
Box box = Hive.box(BNames.serverInstallationBox);
|
||||||
|
|
||||||
Future<ServerInstallationState> load() async {
|
Future<ServerInstallationState> load() async {
|
||||||
final hetznerToken = getIt<ApiConfigModel>().hetznerKey;
|
final hetznerToken = getIt<ApiConfigModel>().hetznerKey;
|
||||||
|
@ -43,7 +61,7 @@ class ServerInstallationRepository {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getIt<ApiConfigModel>().serverDomain?.provider == DnsProvider.Unknown) {
|
if (serverDomain != null && serverDomain.provider == DnsProvider.Unknown) {
|
||||||
return ServerInstallationRecovery(
|
return ServerInstallationRecovery(
|
||||||
hetznerKey: hetznerToken,
|
hetznerKey: hetznerToken,
|
||||||
cloudFlareKey: cloudflareToken,
|
cloudFlareKey: cloudflareToken,
|
||||||
|
@ -52,7 +70,8 @@ class ServerInstallationRepository {
|
||||||
serverDetails: serverDetails,
|
serverDetails: serverDetails,
|
||||||
rootUser: box.get(BNames.rootUser),
|
rootUser: box.get(BNames.rootUser),
|
||||||
currentStep: _getCurrentRecoveryStep(
|
currentStep: _getCurrentRecoveryStep(
|
||||||
hetznerToken, cloudflareToken, serverDomain!, serverDetails),
|
hetznerToken, cloudflareToken, serverDomain, serverDetails),
|
||||||
|
recoveryCapabilities: await getRecoveryCapabilities(serverDomain),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,6 +315,158 @@ class ServerInstallationRepository {
|
||||||
return await hetznerApi.powerOn();
|
return await hetznerApi.powerOn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<ServerRecoveryCapabilities> getRecoveryCapabilities(
|
||||||
|
ServerDomain serverDomain,
|
||||||
|
) async {
|
||||||
|
var serverApi = ServerApi(
|
||||||
|
isWithToken: false,
|
||||||
|
overrideDomain: serverDomain.domainName,
|
||||||
|
);
|
||||||
|
final serverApiVersion = await serverApi.getApiVersion();
|
||||||
|
if (serverApiVersion == null) {
|
||||||
|
return ServerRecoveryCapabilities.none;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final parsedVersion = Version.parse(serverApiVersion);
|
||||||
|
if (parsedVersion.major == 1 && parsedVersion.minor < 2) {
|
||||||
|
return ServerRecoveryCapabilities.legacy;
|
||||||
|
}
|
||||||
|
return ServerRecoveryCapabilities.loginTokens;
|
||||||
|
} on FormatException {
|
||||||
|
return ServerRecoveryCapabilities.none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> getServerIpFromDomain(ServerDomain serverDomain) async {
|
||||||
|
final lookup = await DnsUtils.lookupRecord(
|
||||||
|
serverDomain.domainName, RRecordType.A,
|
||||||
|
provider: DnsApiProvider.CLOUDFLARE);
|
||||||
|
if (lookup == null || lookup.isEmpty) {
|
||||||
|
throw IpNotFoundException('No IP found for domain $serverDomain');
|
||||||
|
}
|
||||||
|
return lookup[0].data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> getDeviceName() async {
|
||||||
|
final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
|
||||||
|
if (kIsWeb) {
|
||||||
|
return await deviceInfo.webBrowserInfo
|
||||||
|
.then((value) => '${value.browserName} ${value.platform}');
|
||||||
|
} else {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
return await deviceInfo.androidInfo
|
||||||
|
.then((value) => '${value.model} ${value.version.release}');
|
||||||
|
} else if (Platform.isIOS) {
|
||||||
|
return await deviceInfo.iosInfo.then((value) =>
|
||||||
|
'${value.utsname.machine} ${value.systemName} ${value.systemVersion}');
|
||||||
|
} else if (Platform.isLinux) {
|
||||||
|
return await deviceInfo.linuxInfo.then((value) => value.prettyName);
|
||||||
|
} else if (Platform.isMacOS) {
|
||||||
|
return await deviceInfo.macOsInfo
|
||||||
|
.then((value) => '${value.hostName} ${value.computerName}');
|
||||||
|
} else if (Platform.isWindows) {
|
||||||
|
return await deviceInfo.windowsInfo.then((value) => value.computerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'Unidentified';
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ServerHostingDetails> authorizeByNewDeviceKey(
|
||||||
|
ServerDomain serverDomain,
|
||||||
|
String newDeviceKey,
|
||||||
|
) async {
|
||||||
|
var serverApi = ServerApi(
|
||||||
|
isWithToken: false,
|
||||||
|
overrideDomain: serverDomain.domainName,
|
||||||
|
);
|
||||||
|
final serverIp = await getServerIpFromDomain(serverDomain);
|
||||||
|
final apiResponse = await serverApi.authorizeDevice(
|
||||||
|
DeviceToken(device: await getDeviceName(), token: newDeviceKey));
|
||||||
|
|
||||||
|
if (apiResponse.isSuccess) {
|
||||||
|
return ServerHostingDetails(
|
||||||
|
apiToken: apiResponse.data,
|
||||||
|
volume: ServerVolume(
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
),
|
||||||
|
provider: ServerProvider.Unknown,
|
||||||
|
id: 0,
|
||||||
|
ip4: serverIp,
|
||||||
|
startTime: null,
|
||||||
|
createTime: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ServerAuthorizationException(
|
||||||
|
apiResponse.errorMessage ?? apiResponse.data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ServerHostingDetails> authorizeByRecoveryKey(
|
||||||
|
ServerDomain serverDomain,
|
||||||
|
String recoveryKey,
|
||||||
|
) async {
|
||||||
|
var serverApi = ServerApi(
|
||||||
|
isWithToken: false,
|
||||||
|
overrideDomain: serverDomain.domainName,
|
||||||
|
);
|
||||||
|
final apiResponse = await serverApi.useRecoveryToken(
|
||||||
|
DeviceToken(device: await getDeviceName(), token: recoveryKey));
|
||||||
|
|
||||||
|
if (apiResponse.isSuccess) {
|
||||||
|
return ServerHostingDetails(
|
||||||
|
apiToken: apiResponse.data,
|
||||||
|
volume: ServerVolume(
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
),
|
||||||
|
provider: ServerProvider.Unknown,
|
||||||
|
id: 0,
|
||||||
|
ip4: '',
|
||||||
|
startTime: null,
|
||||||
|
createTime: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ServerAuthorizationException(
|
||||||
|
apiResponse.errorMessage ?? apiResponse.data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ServerHostingDetails> authorizeByApiToken(
|
||||||
|
ServerDomain serverDomain,
|
||||||
|
String apiToken,
|
||||||
|
) async {
|
||||||
|
var serverApi = ServerApi(
|
||||||
|
isWithToken: false,
|
||||||
|
overrideDomain: serverDomain.domainName,
|
||||||
|
customToken: apiToken,
|
||||||
|
);
|
||||||
|
final deviceAuthKey = await serverApi.createDeviceToken();
|
||||||
|
final apiResponse = await serverApi.authorizeDevice(
|
||||||
|
DeviceToken(device: await getDeviceName(), token: deviceAuthKey.data));
|
||||||
|
|
||||||
|
if (apiResponse.isSuccess) {
|
||||||
|
return ServerHostingDetails(
|
||||||
|
apiToken: apiResponse.data,
|
||||||
|
volume: ServerVolume(
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
),
|
||||||
|
provider: ServerProvider.Unknown,
|
||||||
|
id: 0,
|
||||||
|
ip4: '',
|
||||||
|
startTime: null,
|
||||||
|
createTime: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ServerAuthorizationException(
|
||||||
|
apiResponse.errorMessage ?? apiResponse.data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> saveServerDetails(ServerHostingDetails serverDetails) async {
|
Future<void> saveServerDetails(ServerHostingDetails serverDetails) async {
|
||||||
await getIt<ApiConfigModel>().storeServerDetails(serverDetails);
|
await getIt<ApiConfigModel>().storeServerDetails(serverDetails);
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,8 +265,21 @@ enum RecoveryStep {
|
||||||
BackblazeToken,
|
BackblazeToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ServerRecoveryCapabilities {
|
||||||
|
none,
|
||||||
|
legacy,
|
||||||
|
loginTokens,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ServerRecoveryMethods {
|
||||||
|
newDeviceKey,
|
||||||
|
recoveryKey,
|
||||||
|
oldToken,
|
||||||
|
}
|
||||||
|
|
||||||
class ServerInstallationRecovery extends ServerInstallationState {
|
class ServerInstallationRecovery extends ServerInstallationState {
|
||||||
final RecoveryStep currentStep;
|
final RecoveryStep currentStep;
|
||||||
|
final ServerRecoveryCapabilities recoveryCapabilities;
|
||||||
|
|
||||||
const ServerInstallationRecovery({
|
const ServerInstallationRecovery({
|
||||||
String? hetznerKey,
|
String? hetznerKey,
|
||||||
|
@ -276,6 +289,7 @@ class ServerInstallationRecovery extends ServerInstallationState {
|
||||||
User? rootUser,
|
User? rootUser,
|
||||||
ServerHostingDetails? serverDetails,
|
ServerHostingDetails? serverDetails,
|
||||||
required RecoveryStep this.currentStep,
|
required RecoveryStep this.currentStep,
|
||||||
|
required ServerRecoveryCapabilities this.recoveryCapabilities,
|
||||||
}) : super(
|
}) : super(
|
||||||
hetznerKey: hetznerKey,
|
hetznerKey: hetznerKey,
|
||||||
cloudFlareKey: cloudFlareKey,
|
cloudFlareKey: cloudFlareKey,
|
||||||
|
@ -309,6 +323,7 @@ class ServerInstallationRecovery extends ServerInstallationState {
|
||||||
User? rootUser,
|
User? rootUser,
|
||||||
ServerHostingDetails? serverDetails,
|
ServerHostingDetails? serverDetails,
|
||||||
RecoveryStep? currentStep,
|
RecoveryStep? currentStep,
|
||||||
|
ServerRecoveryCapabilities? recoveryCapabilities,
|
||||||
}) =>
|
}) =>
|
||||||
ServerInstallationRecovery(
|
ServerInstallationRecovery(
|
||||||
hetznerKey: hetznerKey ?? this.hetznerKey,
|
hetznerKey: hetznerKey ?? this.hetznerKey,
|
||||||
|
@ -317,5 +332,7 @@ class ServerInstallationRecovery extends ServerInstallationState {
|
||||||
serverDomain: serverDomain ?? this.serverDomain,
|
serverDomain: serverDomain ?? this.serverDomain,
|
||||||
rootUser: rootUser ?? this.rootUser,
|
rootUser: rootUser ?? this.rootUser,
|
||||||
serverDetails: serverDetails ?? this.serverDetails,
|
serverDetails: serverDetails ?? this.serverDetails,
|
||||||
currentStep: currentStep ?? this.currentStep);
|
currentStep: currentStep ?? this.currentStep,
|
||||||
|
recoveryCapabilities: recoveryCapabilities ?? this.recoveryCapabilities,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
|
||||||
serverInstallationCubit,
|
serverInstallationCubit,
|
||||||
UsersState(
|
UsersState(
|
||||||
<User>[], User(login: 'root'), User(login: 'loading...')));
|
<User>[], User(login: 'root'), User(login: 'loading...')));
|
||||||
Box<User> box = Hive.box<User>(BNames.users);
|
Box<User> box = Hive.box<User>(BNames.usersBox);
|
||||||
Box serverInstallationBox = Hive.box(BNames.serverInstallation);
|
Box serverInstallationBox = Hive.box(BNames.serverInstallationBox);
|
||||||
|
|
||||||
final api = ServerApi();
|
final api = ServerApi();
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@ import 'package:hive/hive.dart';
|
||||||
import 'package:selfprivacy/config/hive_config.dart';
|
import 'package:selfprivacy/config/hive_config.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
|
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
|
||||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
||||||
|
|
||||||
class ApiConfigModel {
|
class ApiConfigModel {
|
||||||
Box _box = Hive.box(BNames.serverInstallation);
|
Box _box = Hive.box(BNames.serverInstallationBox);
|
||||||
|
|
||||||
ServerHostingDetails? get serverDetails => _serverDetails;
|
ServerHostingDetails? get serverDetails => _serverDetails;
|
||||||
String? get hetznerKey => _hetznerKey;
|
String? get hetznerKey => _hetznerKey;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/config/brand_theme.dart';
|
import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
|
||||||
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/models/provider.dart';
|
import 'package:selfprivacy/logic/models/provider.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
|
import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart';
|
import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart';
|
||||||
|
@ -15,7 +15,7 @@ import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
|
||||||
import 'package:selfprivacy/ui/helpers/modals.dart';
|
import 'package:selfprivacy/ui/helpers/modals.dart';
|
||||||
import 'package:selfprivacy/ui/pages/backup_details/backup_details.dart';
|
import 'package:selfprivacy/ui/pages/backup_details/backup_details.dart';
|
||||||
import 'package:selfprivacy/ui/pages/dns_details/dns_details.dart';
|
import 'package:selfprivacy/ui/pages/dns_details/dns_details.dart';
|
||||||
import 'package:selfprivacy/ui/pages/server_details/server_details.dart';
|
import 'package:selfprivacy/ui/pages/server_details/server_details_screen.dart';
|
||||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||||
|
|
||||||
var navigatorKey = GlobalKey<NavigatorState>();
|
var navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
@ -113,7 +113,7 @@ class _Card extends StatelessWidget {
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => BrandBottomSheet(
|
builder: (context) => BrandBottomSheet(
|
||||||
isExpended: true,
|
isExpended: true,
|
||||||
child: ServerDetails(),
|
child: ServerDetailsScreen(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
part of 'server_details.dart';
|
part of 'server_details_screen.dart';
|
||||||
|
|
||||||
class _Chart extends StatelessWidget {
|
class _Chart extends StatelessWidget {
|
||||||
const _Chart({Key? key}) : super(key: key);
|
const _Chart({Key? key}) : super(key: key);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
part of 'server_details.dart';
|
part of 'server_details_screen.dart';
|
||||||
|
|
||||||
class _Header extends StatelessWidget {
|
class _Header extends StatelessWidget {
|
||||||
const _Header({
|
const _Header({
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import 'package:cubit_form/cubit_form.dart';
|
import 'package:cubit_form/cubit_form.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/config/brand_colors.dart';
|
import 'package:selfprivacy/config/brand_colors.dart';
|
||||||
import 'package:selfprivacy/config/brand_theme.dart';
|
import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
|
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
|
||||||
import 'package:selfprivacy/logic/cubit/hetzner_metrics/hetzner_metrics_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/hetzner_metrics/hetzner_metrics_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/models/state_types.dart';
|
import 'package:selfprivacy/logic/models/state_types.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart';
|
import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
|
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
|
||||||
|
@ -14,32 +15,32 @@ import 'package:selfprivacy/ui/components/brand_loader/brand_loader.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_radio_tile/brand_radio_tile.dart';
|
import 'package:selfprivacy/ui/components/brand_radio_tile/brand_radio_tile.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||||
import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart';
|
import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:selfprivacy/ui/components/switch_block/switch_bloc.dart';
|
import 'package:selfprivacy/ui/components/switch_block/switch_bloc.dart';
|
||||||
import 'package:selfprivacy/ui/pages/server_details/time_zone/lang.dart';
|
import 'package:selfprivacy/ui/pages/server_details/time_zone/lang.dart';
|
||||||
|
import 'package:selfprivacy/utils/extensions/duration.dart';
|
||||||
import 'package:selfprivacy/utils/named_font_weight.dart';
|
import 'package:selfprivacy/utils/named_font_weight.dart';
|
||||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||||
import 'package:timezone/timezone.dart';
|
import 'package:timezone/timezone.dart';
|
||||||
|
|
||||||
import 'cpu_chart.dart';
|
import 'cpu_chart.dart';
|
||||||
import 'network_charts.dart';
|
import 'network_charts.dart';
|
||||||
import 'package:selfprivacy/utils/extensions/duration.dart';
|
|
||||||
|
|
||||||
part 'server_settings.dart';
|
|
||||||
part 'text_details.dart';
|
|
||||||
part 'chart.dart';
|
part 'chart.dart';
|
||||||
part 'header.dart';
|
part 'header.dart';
|
||||||
|
part 'server_settings.dart';
|
||||||
|
part 'text_details.dart';
|
||||||
part 'time_zone/time_zone.dart';
|
part 'time_zone/time_zone.dart';
|
||||||
|
|
||||||
var navigatorKey = GlobalKey<NavigatorState>();
|
var navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
class ServerDetails extends StatefulWidget {
|
class ServerDetailsScreen extends StatefulWidget {
|
||||||
const ServerDetails({Key? key}) : super(key: key);
|
const ServerDetailsScreen({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ServerDetailsState createState() => _ServerDetailsState();
|
_ServerDetailsScreenState createState() => _ServerDetailsScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ServerDetailsState extends State<ServerDetails>
|
class _ServerDetailsScreenState extends State<ServerDetailsScreen>
|
||||||
with SingleTickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
late TabController tabController;
|
late TabController tabController;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
part of 'server_details.dart';
|
part of 'server_details_screen.dart';
|
||||||
|
|
||||||
class _ServerSettings extends StatelessWidget {
|
class _ServerSettings extends StatelessWidget {
|
||||||
const _ServerSettings({
|
const _ServerSettings({
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
part of 'server_details.dart';
|
part of 'server_details_screen.dart';
|
||||||
|
|
||||||
class _TextDetails extends StatelessWidget {
|
class _TextDetails extends StatelessWidget {
|
||||||
const _TextDetails({Key? key}) : super(key: key);
|
const _TextDetails({Key? key}) : super(key: key);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
part of '../server_details.dart';
|
part of '../server_details_screen.dart';
|
||||||
|
|
||||||
final List<Location> locations = timeZoneDatabase.locations.values.toList()
|
final List<Location> locations = timeZoneDatabase.locations.values.toList()
|
||||||
..sort((l1, l2) =>
|
..sort((l1, l2) =>
|
||||||
|
|
44
pubspec.lock
44
pubspec.lock
|
@ -218,6 +218,48 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.3"
|
version: "2.2.3"
|
||||||
|
device_info_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: device_info_plus
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.3"
|
||||||
|
device_info_plus_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: device_info_plus_linux
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
device_info_plus_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: device_info_plus_macos
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.3"
|
||||||
|
device_info_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: device_info_plus_platform_interface
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0+1"
|
||||||
|
device_info_plus_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: device_info_plus_web
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
device_info_plus_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: device_info_plus_windows
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
dio:
|
dio:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -750,7 +792,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.2"
|
version: "6.0.2"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: pub_semver
|
name: pub_semver
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
|
|
|
@ -13,6 +13,7 @@ dependencies:
|
||||||
crypt: ^4.2.1
|
crypt: ^4.2.1
|
||||||
cubit_form: ^2.0.1
|
cubit_form: ^2.0.1
|
||||||
cupertino_icons: ^1.0.4
|
cupertino_icons: ^1.0.4
|
||||||
|
device_info_plus: ^3.2.3
|
||||||
dio: ^4.0.4
|
dio: ^4.0.4
|
||||||
dynamic_color: ^1.2.2
|
dynamic_color: ^1.2.2
|
||||||
easy_localization: ^3.0.0
|
easy_localization: ^3.0.0
|
||||||
|
@ -36,6 +37,7 @@ dependencies:
|
||||||
package_info: ^2.0.2
|
package_info: ^2.0.2
|
||||||
pretty_dio_logger: ^1.2.0-beta-1
|
pretty_dio_logger: ^1.2.0-beta-1
|
||||||
provider: ^6.0.2
|
provider: ^6.0.2
|
||||||
|
pub_semver: ^2.1.1
|
||||||
share_plus: ^4.0.4
|
share_plus: ^4.0.4
|
||||||
ssh_key: ^0.7.1
|
ssh_key: ^0.7.1
|
||||||
system_theme: ^2.0.0
|
system_theme: ^2.0.0
|
||||||
|
|
Loading…
Reference in a new issue