diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..80a3e35b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,16 @@
+# editorconfig.org
+root = true
+
+[*]
+indent_size = 2
+indent_style = space
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.dart]
+max_line_length = 150
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/assets/translations/en.json b/assets/translations/en.json
index 0b9b3f5e..42178a89 100644
--- a/assets/translations/en.json
+++ b/assets/translations/en.json
@@ -26,7 +26,8 @@
"details": "Details",
"no_data": "No data",
"wait": "Wait",
- "remove": "Remove"
+ "remove": "Remove",
+ "apply": "Apply"
},
"more": {
"_comment": "'More' tab",
@@ -34,6 +35,9 @@
"about_project": "About us",
"about_app": "About application",
"onboarding": "Onboarding",
+ "create_ssh_key": "Create ssh key",
+ "generate_key": "Generate key",
+ "generate_key_text": "You can generate ssh key",
"console": "Console",
"about_app_page": {
"text": "Application version v.{}"
@@ -147,6 +151,13 @@
"bottom_sheet": {
"1": "You can connect and create a new user here:"
}
+ },
+ "vpn": {
+ "title": "VPN Server",
+ "subtitle": "Private VPN server",
+ "bottom_sheet": {
+ "1": "Openconnect VPN Server. Engine for secure and scalable VPN infrastructure"
+ }
}
},
"users": {
@@ -212,7 +223,12 @@
"_comment": "Jobs list",
"title": "Jobs list",
"start": "Start",
- "empty": "No jobs"
+ "empty": "No jobs",
+ "createUser": "Create",
+ "serviceTurnOff": "Turn off",
+ "serviceTurnOn": "Turn on",
+ "jobAdded": "Job added",
+ "runJobs": "Run jobs"
},
"validations": {
"required": "Required",
@@ -222,4 +238,4 @@
"length": "Length is [] shoud be {}",
"user_alredy_exist": "Already exists"
}
-}
\ No newline at end of file
+}
diff --git a/assets/translations/ru.json b/assets/translations/ru.json
index bc89ab19..ac731421 100644
--- a/assets/translations/ru.json
+++ b/assets/translations/ru.json
@@ -26,7 +26,8 @@
"details": "Детальная информация",
"no_data": "Нет данных",
"wait": "Ожидайте",
- "remove": "Удалить"
+ "remove": "Удалить",
+ "apply": "Подать"
},
"more": {
"_comment": "вкладка еще",
@@ -35,6 +36,9 @@
"about_app": "О приложении",
"onboarding": "Приветствие",
"console": "Консоль",
+ "create_ssh_key": "Создать ssh ключ",
+ "generate_key": "Сгенерировать ключ",
+ "generate_key_text": "Вы сможете сгенерировать ключ",
"about_app_page": {
"text": "Версия приложения: v.{}"
},
@@ -212,7 +216,12 @@
"_comment": "Jobs list",
"title": "Задачи",
"start": "Начать выполенение",
- "empty": "Пусто"
+ "empty": "Пусто",
+ "createUser": "Создать запись",
+ "serviceTurnOff": "Остановить",
+ "serviceTurnOn": "Запустить",
+ "jobAdded": "Задача добавленна",
+ "runJobs": "Запустите задачи"
},
"validations": {
"required": "обязательное поле",
@@ -222,4 +231,4 @@
"length": "Длина строки [] должна быть {}",
"user_alredy_exist": "Имя уже используется"
}
-}
\ No newline at end of file
+}
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 6b4c0f78..f2872cf4 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 8.0
+ 9.0
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 285337b4..373cec68 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -44,7 +44,7 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/wakelock/ios"
SPEC CHECKSUMS:
- Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
+ Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
diff --git a/ios/build/Pods.build/Release-iphonesimulator/Flutter.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/Flutter.build/dgph
new file mode 100644
index 00000000..0c4ca337
Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/Flutter.build/dgph differ
diff --git a/ios/build/Pods.build/Release-iphonesimulator/Pods-Runner.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/Pods-Runner.build/dgph
new file mode 100644
index 00000000..0c4ca337
Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/Pods-Runner.build/dgph differ
diff --git a/ios/build/Pods.build/Release-iphonesimulator/flutter_secure_storage.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/flutter_secure_storage.build/dgph
new file mode 100644
index 00000000..0c4ca337
Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/flutter_secure_storage.build/dgph differ
diff --git a/ios/build/Pods.build/Release-iphonesimulator/package_info.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/package_info.build/dgph
new file mode 100644
index 00000000..0c4ca337
Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/package_info.build/dgph differ
diff --git a/ios/build/Pods.build/Release-iphonesimulator/path_provider.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/path_provider.build/dgph
new file mode 100644
index 00000000..0c4ca337
Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/path_provider.build/dgph differ
diff --git a/ios/build/Pods.build/Release-iphonesimulator/share_plus.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/share_plus.build/dgph
new file mode 100644
index 00000000..0c4ca337
Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/share_plus.build/dgph differ
diff --git a/ios/build/Pods.build/Release-iphonesimulator/shared_preferences.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/shared_preferences.build/dgph
new file mode 100644
index 00000000..0c4ca337
Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/shared_preferences.build/dgph differ
diff --git a/ios/build/Pods.build/Release-iphonesimulator/url_launcher.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/url_launcher.build/dgph
new file mode 100644
index 00000000..0c4ca337
Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/url_launcher.build/dgph differ
diff --git a/ios/build/Pods.build/Release-iphonesimulator/wakelock.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/wakelock.build/dgph
new file mode 100644
index 00000000..0c4ca337
Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/wakelock.build/dgph differ
diff --git a/lib/config/bloc_config.dart b/lib/config/bloc_config.dart
index 5fe71380..bc59e531 100644
--- a/lib/config/bloc_config.dart
+++ b/lib/config/bloc_config.dart
@@ -4,6 +4,7 @@ import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart';
+import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
class BlocAndProviderConfig extends StatelessWidget {
@@ -13,11 +14,9 @@ class BlocAndProviderConfig extends StatelessWidget {
@override
Widget build(BuildContext context) {
- // var platformBrightness =
- // SchedulerBinding.instance.window.platformBrightness;
- // var isDark = platformBrightness == Brightness.dark;
var isDark = false;
var usersCubit = UsersCubit();
+ var servicesCubit = ServicesCubit();
return MultiProvider(
providers: [
BlocProvider(
@@ -28,11 +27,17 @@ class BlocAndProviderConfig extends StatelessWidget {
),
BlocProvider(
lazy: false,
- create: (_) => AppConfigCubit()..load(),
+ create: (_) => AppConfigCubit(servicesCubit)..load(),
),
BlocProvider(create: (_) => ProvidersCubit()),
BlocProvider(create: (_) => usersCubit..load(), lazy: false),
- BlocProvider(create: (_) => JobsCubit(usersCubit)),
+ BlocProvider(create: (_) => servicesCubit..load(), lazy: false),
+ BlocProvider(
+ create: (_) => JobsCubit(
+ usersCubit: usersCubit,
+ servicesCubit: servicesCubit,
+ ),
+ ),
],
child: child,
);
diff --git a/lib/config/get_it_config.dart b/lib/config/get_it_config.dart
index 3f01e6d3..99b61cc8 100644
--- a/lib/config/get_it_config.dart
+++ b/lib/config/get_it_config.dart
@@ -2,6 +2,7 @@ import 'package:get_it/get_it.dart';
import 'package:selfprivacy/logic/get_it/api_config.dart';
import 'package:selfprivacy/logic/get_it/console.dart';
import 'package:selfprivacy/logic/get_it/navigation.dart';
+import 'package:selfprivacy/logic/get_it/ssh_helper.dart';
import 'package:selfprivacy/logic/get_it/timer.dart';
export 'package:selfprivacy/logic/get_it/api_config.dart';
@@ -9,7 +10,6 @@ export 'package:selfprivacy/logic/get_it/console.dart';
export 'package:selfprivacy/logic/get_it/navigation.dart';
export 'package:selfprivacy/logic/get_it/timer.dart';
-
final getIt = GetIt.instance;
Future getItSetup() async {
@@ -17,6 +17,7 @@ Future getItSetup() async {
getIt.registerSingleton(ConsoleModel());
getIt.registerSingleton(TimerModel());
+ getIt.registerSingleton(SSHModel()..init());
getIt.registerSingleton(ApiConfigModel()..init());
await getIt.allReady();
diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart
index e704b50c..be47b879 100644
--- a/lib/config/hive_config.dart
+++ b/lib/config/hive_config.dart
@@ -20,22 +20,23 @@ class HiveConfig {
await Hive.openBox(BNames.appSettings);
await Hive.openBox(BNames.users);
+ await Hive.openBox(BNames.servicesState);
- var cipher = HiveAesCipher(await getEncriptedKey());
-
+ var cipher = HiveAesCipher(await getEncriptedKey(BNames.key));
await Hive.openBox(BNames.appConfig, encryptionCipher: cipher);
+ var sshCipher = HiveAesCipher(await getEncriptedKey(BNames.sshEnckey));
+ await Hive.openBox(BNames.sshConfig, encryptionCipher: sshCipher);
}
- static Future getEncriptedKey() async {
- final FlutterSecureStorage secureStorage = FlutterSecureStorage();
- var containsEncryptionKey =
- await secureStorage.containsKey(key: BNames.key);
- if (!containsEncryptionKey) {
+ static Future getEncriptedKey(String encKey) async {
+ final secureStorage = FlutterSecureStorage();
+ var hasEncryptionKey = await secureStorage.containsKey(key: encKey);
+ if (!hasEncryptionKey) {
var key = Hive.generateSecureKey();
- await secureStorage.write(key: BNames.key, value: base64UrlEncode(key));
+ await secureStorage.write(key: encKey, value: base64UrlEncode(key));
}
- String? string = await secureStorage.read(key: BNames.key);
+ String? string = await secureStorage.read(key: encKey);
return base64Url.decode(string!);
}
}
@@ -47,8 +48,10 @@ class BNames {
static String users = 'users';
static String appSettings = 'appSettings';
+ static String servicesState = 'servicesState';
static String key = 'key';
+ static String sshEnckey = 'sshEngkey';
static String cloudFlareDomain = 'cloudFlareDomain';
static String hetznerKey = 'hetznerKey';
@@ -61,4 +64,7 @@ class BNames {
static String isLoading = 'isLoading';
static String isServerResetedFirstTime = 'isServerResetedFirstTime';
static String isServerResetedSecondTime = 'isServerResetedSecondTime';
+ static String sshConfig = 'sshConfig';
+ static String sshPrivateKey = "sshPrivateKey";
+ static String sshPublicKey = "sshPublicKey";
}
diff --git a/lib/logic/api_maps/hetzner.dart b/lib/logic/api_maps/hetzner.dart
index 037db18c..2b714aad 100644
--- a/lib/logic/api_maps/hetzner.dart
+++ b/lib/logic/api_maps/hetzner.dart
@@ -7,7 +7,7 @@ import 'package:selfprivacy/logic/api_maps/api_map.dart';
import 'package:selfprivacy/logic/models/hetzner_server_info.dart';
import 'package:selfprivacy/logic/models/server_details.dart';
import 'package:selfprivacy/logic/models/user.dart';
-import 'package:selfprivacy/utils/password_generator2.dart';
+import 'package:selfprivacy/utils/password_generator.dart';
class HetznerApi extends ApiMap {
bool hasLoger;
@@ -73,30 +73,28 @@ class HetznerApi extends ApiMap {
required User rootUser,
required String domainName,
}) async {
- var dbPassword = getRandomString(40);
-
- const chars =
- 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
-
- var dbStorageName = getRandomString(6, chars);
var client = await getClient();
Response dbCreateResponse = await client.post(
'/volumes',
data: {
"size": 10,
- "name": dbStorageName,
+ "name": StringGenerators.dbStorageName(),
"labels": {"labelkey": "value"},
"location": "fsn1",
"automount": false,
"format": "ext4"
},
);
+
+ var dbPassword = StringGenerators.dbPassword();
var dbId = dbCreateResponse.data['volume']['id'];
+ /// add ssh key when you need it: e.g. "ssh_keys":["kherel"]
+ /// check the branch name, it could be "development" or "master".
+
var data = jsonDecode(
- '''{"name":"$domainName","server_type":"cx11","start_after_create":false,"image":"ubuntu-20.04", "volumes":[$dbId], "networks":[], "user_data":"#cloud-config\\nruncmd:\\n- curl https://git.selfprivacy.org/ilchub/selfprivacy-nixos-infect/raw/branch/master/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-21.05 DOMAIN=$domainName LUSER=${rootUser.login} PASSWORD=${rootUser.password} HASHED_PASSWORD=${rootUser.hashPassword.hash} SALT=${rootUser.hashPassword.salt} CF_TOKEN=$cloudFlareKey DB_PASSWORD=$dbPassword bash 2>&1 | tee /tmp/infect.log","labels":{},"automount":true, "location": "fsn1"}'''
- );
+ '''{"name":"$domainName","server_type":"cx11","start_after_create":false,"image":"ubuntu-20.04", "volumes":[$dbId], "networks":[], "user_data":"#cloud-config\\nruncmd:\\n- curl https://git.selfprivacy.org/ilchub/selfprivacy-nixos-infect/raw/branch/master/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-21.05 DOMAIN=$domainName LUSER=${rootUser.login} PASSWORD=${rootUser.password} CF_TOKEN=$cloudFlareKey DB_PASSWORD=$dbPassword bash 2>&1 | tee /tmp/infect.log","labels":{},"automount":true, "location": "fsn1"}''');
Response serverCreateResponse = await client.post(
'/servers',
diff --git a/lib/logic/api_maps/server.dart b/lib/logic/api_maps/server.dart
index aae49538..6e5686f6 100644
--- a/lib/logic/api_maps/server.dart
+++ b/lib/logic/api_maps/server.dart
@@ -3,6 +3,7 @@ import 'dart:io';
import 'package:dio/dio.dart';
import 'package:selfprivacy/config/get_it_config.dart';
+import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/models/user.dart';
import 'api_map.dart';
@@ -89,4 +90,44 @@ class ServerApi extends ApiMap {
close(client);
return res;
}
+
+ Future switchService(ServiceTypes type, bool needToTurnOn) async {
+ var client = await getClient();
+ client.post('/services/${type.url}/${needToTurnOn ? 'enable' : 'disable'}');
+ client.close();
+ }
+
+ Future sendSsh(String ssh) async {
+ var client = await getClient();
+ client.post(
+ '/services/ssh/enable',
+ data: {"public_key": ssh},
+ );
+ client.close();
+ }
+}
+
+extension UrlServerExt on ServiceTypes {
+ String get url {
+ switch (this) {
+ // case ServiceTypes.mail:
+ // return ''; // cannot be swithch off
+ // case ServiceTypes.messenger:
+ // return ''; // external service
+ // case ServiceTypes.video:
+ // return ''; // jeetsu meet not working
+ case ServiceTypes.passwordManager:
+ return 'bitwarden';
+ case ServiceTypes.cloud:
+ return 'nextcloud';
+ case ServiceTypes.socialNetwork:
+ return 'pleroma';
+ case ServiceTypes.git:
+ return 'gitea';
+ case ServiceTypes.vpn:
+ return 'ocserv';
+ default:
+ throw Exception('wrong state');
+ }
+ }
}
diff --git a/lib/logic/common_enum/common_enum.dart b/lib/logic/common_enum/common_enum.dart
index 912c4cb6..e3d81309 100644
--- a/lib/logic/common_enum/common_enum.dart
+++ b/lib/logic/common_enum/common_enum.dart
@@ -1,3 +1,8 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:ionicons/ionicons.dart';
+import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
+
enum InitializingSteps {
setHeznerKey,
setCloudFlareKey,
@@ -10,3 +15,80 @@ enum InitializingSteps {
}
enum Period { hour, day, month }
+enum ServiceTypes {
+ mail,
+ messenger,
+ passwordManager,
+ video,
+ cloud,
+ socialNetwork,
+ git,
+ vpn,
+}
+
+extension ServiceTypesExt on ServiceTypes {
+ String get title {
+ switch (this) {
+ case ServiceTypes.mail:
+ return 'services.mail.title'.tr();
+ case ServiceTypes.messenger:
+ return 'services.messenger.title'.tr();
+ case ServiceTypes.passwordManager:
+ return 'services.password_manager.title'.tr();
+ case ServiceTypes.video:
+ return 'services.video.title'.tr();
+ case ServiceTypes.cloud:
+ return 'services.cloud.title'.tr();
+ case ServiceTypes.socialNetwork:
+ return 'services.social_network.title'.tr();
+ case ServiceTypes.git:
+ return 'services.git.title'.tr();
+ case ServiceTypes.vpn:
+ return 'services.vpn.title'.tr();
+ }
+ }
+
+ String get subtitle {
+ switch (this) {
+ case ServiceTypes.mail:
+ return 'services.mail.subtitle'.tr();
+ case ServiceTypes.messenger:
+ return 'services.messenger.subtitle'.tr();
+ case ServiceTypes.passwordManager:
+ return 'services.password_manager.subtitle'.tr();
+ case ServiceTypes.video:
+ return 'services.video.subtitle'.tr();
+ case ServiceTypes.cloud:
+ return 'services.cloud.subtitle'.tr();
+ case ServiceTypes.socialNetwork:
+ return 'services.social_network.subtitle'.tr();
+ case ServiceTypes.git:
+ return 'services.git.subtitle'.tr();
+ case ServiceTypes.vpn:
+ return 'services.vpn.subtitle'.tr();
+ }
+ }
+
+ IconData get icon {
+ switch (this) {
+ case ServiceTypes.mail:
+ return BrandIcons.envelope;
+ case ServiceTypes.messenger:
+ return BrandIcons.messanger;
+ case ServiceTypes.passwordManager:
+ return BrandIcons.key;
+ case ServiceTypes.video:
+ return BrandIcons.webcam;
+ case ServiceTypes.cloud:
+ return BrandIcons.upload;
+ case ServiceTypes.socialNetwork:
+ return BrandIcons.social;
+ case ServiceTypes.git:
+ return BrandIcons.git;
+ case ServiceTypes.vpn:
+ return Ionicons.shield_checkmark_outline;
+ }
+ }
+
+ String get txt => this.toString().split('.')[1];
+}
diff --git a/lib/logic/cubit/app_config/app_config_cubit.dart b/lib/logic/cubit/app_config/app_config_cubit.dart
index d8b8f36e..e86cead1 100644
--- a/lib/logic/cubit/app_config/app_config_cubit.dart
+++ b/lib/logic/cubit/app_config/app_config_cubit.dart
@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
+import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/models/backblaze_credential.dart';
import 'package:selfprivacy/logic/models/cloudflare_domain.dart';
@@ -43,9 +44,10 @@ part 'app_config_state.dart';
/// c. if server is okay set that fully checked
class AppConfigCubit extends Cubit {
- AppConfigCubit() : super(InitialAppConfigState());
+ AppConfigCubit(this.servicesCubit) : super(InitialAppConfigState());
final repository = AppConfigRepository();
+ final ServicesCubit servicesCubit;
Future load() async {
var state = await repository.load();
@@ -232,6 +234,7 @@ class AppConfigCubit extends Cubit {
if (isServerWorking) {
await repository.saveHasFinalChecked(true);
+ servicesCubit.allOn();
emit(state.copyWith(
hasFinalChecked: true,
@@ -259,12 +262,16 @@ class AppConfigCubit extends Cubit {
void clearAppConfig() {
closeTimer();
+ servicesCubit.allOff();
+
repository.clearAppConfig();
emit(InitialAppConfigState());
}
Future serverDelete() async {
closeTimer();
+ servicesCubit.allOff();
+
if (state.hetznerServer != null) {
await repository.deleteServer(state.cloudFlareDomain!);
}
diff --git a/lib/logic/cubit/forms/user/user_form_cubit.dart b/lib/logic/cubit/forms/user/user_form_cubit.dart
index a30b90f8..dd4d2bcf 100644
--- a/lib/logic/cubit/forms/user/user_form_cubit.dart
+++ b/lib/logic/cubit/forms/user/user_form_cubit.dart
@@ -2,10 +2,10 @@ import 'dart:async';
import 'package:cubit_form/cubit_form.dart';
import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
-import 'package:selfprivacy/logic/models/jobs/job.dart';
+import 'package:selfprivacy/logic/models/job.dart';
import 'package:selfprivacy/logic/models/user.dart';
-import 'package:selfprivacy/utils/password_generator.dart';
import 'package:easy_localization/easy_localization.dart';
+import 'package:selfprivacy/utils/password_generator.dart';
class UserFormCubit extends FormCubit {
UserFormCubit({
@@ -32,7 +32,7 @@ class UserFormCubit extends FormCubit {
);
password = FieldCubit(
- initalValue: isEdit ? user!.password : genPass(),
+ initalValue: isEdit ? user!.password : StringGenerators.userPassword(),
validations: [
RequiredStringValidation('validations.required'.tr()),
ValidationModel((s) => passwordRegExp.hasMatch(s),
@@ -56,7 +56,7 @@ class UserFormCubit extends FormCubit {
late FieldCubit password;
void genNewPassword() {
- password.externalSetValue(genPass());
+ password.externalSetValue(StringGenerators.userPassword());
}
final JobsCubit jobsCubit;
diff --git a/lib/logic/cubit/jobs/jobs_cubit.dart b/lib/logic/cubit/jobs/jobs_cubit.dart
index aebe2ddd..d9d902a9 100644
--- a/lib/logic/cubit/jobs/jobs_cubit.dart
+++ b/lib/logic/cubit/jobs/jobs_cubit.dart
@@ -1,19 +1,27 @@
+import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/server.dart';
+import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
-import 'package:selfprivacy/logic/models/jobs/job.dart';
+import 'package:selfprivacy/logic/get_it/ssh_helper.dart';
+import 'package:selfprivacy/logic/models/job.dart';
import 'package:equatable/equatable.dart';
import 'package:selfprivacy/logic/models/user.dart';
export 'package:provider/provider.dart';
+import 'package:easy_localization/easy_localization.dart';
part 'jobs_state.dart';
class JobsCubit extends Cubit {
- JobsCubit(this.usersCubit) : super(JobsStateEmpty());
+ JobsCubit({
+ required this.usersCubit,
+ required this.servicesCubit,
+ }) : super(JobsStateEmpty());
final api = ServerApi();
final UsersCubit usersCubit;
+ final ServicesCubit servicesCubit;
void addJob(Job job) {
var newJobsList = [];
@@ -21,6 +29,10 @@ class JobsCubit extends Cubit {
newJobsList.addAll((state as JobsStateWithJobs).jobList);
}
newJobsList.add(job);
+ getIt().showSnackBar(SnackBar(
+ content: Text('jobs.jobAdded'.tr()),
+ duration: const Duration(seconds: 2),
+ ));
emit(JobsStateWithJobs(newJobsList));
}
@@ -29,16 +41,63 @@ class JobsCubit extends Cubit {
emit(newState);
}
+ void createOrRemoveServiceToggleJob(ServiceToggleJob job) {
+ var newJobsList = [];
+ if (state is JobsStateWithJobs) {
+ newJobsList.addAll((state as JobsStateWithJobs).jobList);
+ }
+ var needToRemoveJob =
+ newJobsList.any((el) => el is ServiceToggleJob && el.type == job.type);
+ if (needToRemoveJob) {
+ var removingJob = newJobsList
+ .firstWhere(((el) => el is ServiceToggleJob && el.type == job.type));
+ removeJob(removingJob.id);
+ } else {
+ newJobsList.add(job);
+ getIt().showSnackBar(SnackBar(
+ content: Text('jobs.jobAdded'.tr()),
+ duration: const Duration(seconds: 2),
+ ));
+ emit(JobsStateWithJobs(newJobsList));
+ }
+ }
+
+ void createShhJobIfNotExist(CreateSSHKeyJob job) {
+ var newJobsList = [];
+ if (state is JobsStateWithJobs) {
+ newJobsList.addAll((state as JobsStateWithJobs).jobList);
+ }
+ var isExistInJobList = newJobsList.any((el) => el is CreateSSHKeyJob);
+ if (!isExistInJobList) {
+ newJobsList.add(job);
+ getIt().showSnackBar(SnackBar(
+ content: Text('jobs.jobAdded'.tr()),
+ duration: const Duration(seconds: 2),
+ ));
+ emit(JobsStateWithJobs(newJobsList));
+ }
+ }
+
Future applyAll() async {
if (state is JobsStateWithJobs) {
var jobs = (state as JobsStateWithJobs).jobList;
emit(JobsStateLoading());
-
var newUsers = [];
for (var job in jobs) {
if (job is CreateUserJob) {
newUsers.add(job.user);
await api.createUser(job.user);
+ } else if (job is ServiceToggleJob) {
+ await api.switchService(job.type, job.needToTurnOn);
+ if (job.needToTurnOn) {
+ servicesCubit.turnOnist([job.type]);
+ } else {
+ servicesCubit.turnOffList([job.type]);
+ }
+ }
+ if (job is CreateSSHKeyJob) {
+ await getIt().generateKeys();
+ api.sendSsh(getIt().savedPubKey!);
}
}
diff --git a/lib/logic/cubit/services/services_cubit.dart b/lib/logic/cubit/services/services_cubit.dart
new file mode 100644
index 00000000..c5fb6cf3
--- /dev/null
+++ b/lib/logic/cubit/services/services_cubit.dart
@@ -0,0 +1,63 @@
+import 'package:bloc/bloc.dart';
+import 'package:equatable/equatable.dart';
+import 'package:hive/hive.dart';
+import 'package:selfprivacy/config/hive_config.dart';
+import 'package:selfprivacy/logic/common_enum/common_enum.dart';
+
+part 'services_state.dart';
+
+class ServicesCubit extends Cubit {
+ ServicesCubit() : super(ServicesState.allOff());
+
+ Box box = Hive.box(BNames.servicesState);
+
+ void load() {
+ emit(
+ ServicesState(
+ isPasswordManagerEnable:
+ box.get(ServiceTypes.passwordManager.txt, defaultValue: false),
+ isCloudEnable: box.get(ServiceTypes.cloud.txt, defaultValue: false),
+ isGitEnable: box.get(ServiceTypes.git.txt, defaultValue: false),
+ isSocialNetworkEnable:
+ box.get(ServiceTypes.socialNetwork.txt, defaultValue: false),
+ isVpnEnable: box.get(ServiceTypes.vpn.txt, defaultValue: false),
+ ),
+ );
+ }
+
+ void allOn() {
+ box.put(ServiceTypes.passwordManager.txt, true);
+ box.put(ServiceTypes.cloud.txt, true);
+ box.put(ServiceTypes.git.txt, true);
+ box.put(ServiceTypes.socialNetwork.txt, true);
+ box.put(ServiceTypes.vpn.txt, true);
+
+ emit(ServicesState.allOn());
+ }
+
+ void allOff() {
+ box.put(ServiceTypes.passwordManager.txt, false);
+ box.put(ServiceTypes.cloud.txt, false);
+ box.put(ServiceTypes.git.txt, false);
+ box.put(ServiceTypes.socialNetwork.txt, false);
+ box.put(ServiceTypes.vpn.txt, false);
+
+ emit(ServicesState.allOff());
+ }
+
+ void turnOffList(List list) {
+ for (final service in list) {
+ box.put(service.txt, false);
+ }
+
+ emit(state.disableList(list));
+ }
+
+ void turnOnist(List list) {
+ for (final service in list) {
+ box.put(service.txt, true);
+ }
+
+ emit(state.enableList(list));
+ }
+}
diff --git a/lib/logic/cubit/services/services_state.dart b/lib/logic/cubit/services/services_state.dart
new file mode 100644
index 00000000..a41b5a59
--- /dev/null
+++ b/lib/logic/cubit/services/services_state.dart
@@ -0,0 +1,93 @@
+part of 'services_cubit.dart';
+
+class ServicesState extends Equatable {
+ const ServicesState({
+ required this.isPasswordManagerEnable,
+ required this.isCloudEnable,
+ required this.isGitEnable,
+ required this.isSocialNetworkEnable,
+ required this.isVpnEnable,
+ });
+
+ final bool isPasswordManagerEnable;
+ final bool isCloudEnable;
+ final bool isGitEnable;
+ final bool isSocialNetworkEnable;
+ final bool isVpnEnable;
+
+ factory ServicesState.allOff() => ServicesState(
+ isPasswordManagerEnable: false,
+ isCloudEnable: false,
+ isGitEnable: false,
+ isSocialNetworkEnable: false,
+ isVpnEnable: false,
+ );
+ factory ServicesState.allOn() => ServicesState(
+ isPasswordManagerEnable: true,
+ isCloudEnable: true,
+ isGitEnable: true,
+ isSocialNetworkEnable: true,
+ isVpnEnable: true,
+ );
+
+ ServicesState enableList(
+ List list,
+ ) =>
+ ServicesState(
+ isPasswordManagerEnable: list.contains(ServiceTypes.passwordManager)
+ ? true
+ : isPasswordManagerEnable,
+ isCloudEnable: list.contains(ServiceTypes.cloud) ? true : isCloudEnable,
+ isGitEnable:
+ list.contains(ServiceTypes.git) ? true : isPasswordManagerEnable,
+ isSocialNetworkEnable: list.contains(ServiceTypes.socialNetwork)
+ ? true
+ : isPasswordManagerEnable,
+ isVpnEnable:
+ list.contains(ServiceTypes.vpn) ? true : isPasswordManagerEnable,
+ );
+
+ ServicesState disableList(
+ List list,
+ ) =>
+ ServicesState(
+ isPasswordManagerEnable: list.contains(ServiceTypes.passwordManager)
+ ? false
+ : isPasswordManagerEnable,
+ isCloudEnable:
+ list.contains(ServiceTypes.cloud) ? false : isCloudEnable,
+ isGitEnable:
+ list.contains(ServiceTypes.git) ? false : isPasswordManagerEnable,
+ isSocialNetworkEnable: list.contains(ServiceTypes.socialNetwork)
+ ? false
+ : isPasswordManagerEnable,
+ isVpnEnable:
+ list.contains(ServiceTypes.vpn) ? false : isPasswordManagerEnable,
+ );
+
+ @override
+ List