master
Kherel 2021-08-29 15:54:28 +02:00
parent 94a0e22b15
commit 84e9259ec2
14 changed files with 288 additions and 74 deletions

16
.editorconfig Normal file
View File

@ -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

View File

@ -147,6 +147,13 @@
"bottom_sheet": { "bottom_sheet": {
"1": "You can connect and create a new user here:" "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": { "users": {
@ -217,7 +224,6 @@
"serviceTurnOff": "Turn off", "serviceTurnOff": "Turn off",
"serviceTurnOn": "Turn on", "serviceTurnOn": "Turn on",
"jobAdded": "Job added" "jobAdded": "Job added"
}, },
"validations": { "validations": {
"required": "Required", "required": "Required",

View File

@ -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/app_config/app_config_cubit.dart';
import 'package:selfprivacy/logic/cubit/jobs/jobs_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/providers/providers_cubit.dart';
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart'; import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
class BlocAndProviderConfig extends StatelessWidget { class BlocAndProviderConfig extends StatelessWidget {
@ -13,11 +14,9 @@ class BlocAndProviderConfig extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// var platformBrightness =
// SchedulerBinding.instance.window.platformBrightness;
// var isDark = platformBrightness == Brightness.dark;
var isDark = false; var isDark = false;
var usersCubit = UsersCubit(); var usersCubit = UsersCubit();
var servicesCubit = ServicesCubit();
return MultiProvider( return MultiProvider(
providers: [ providers: [
BlocProvider( BlocProvider(
@ -28,11 +27,17 @@ class BlocAndProviderConfig extends StatelessWidget {
), ),
BlocProvider( BlocProvider(
lazy: false, lazy: false,
create: (_) => AppConfigCubit()..load(), create: (_) => AppConfigCubit(servicesCubit)..load(),
), ),
BlocProvider(create: (_) => ProvidersCubit()), BlocProvider(create: (_) => ProvidersCubit()),
BlocProvider(create: (_) => usersCubit..load(), lazy: false), 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, child: child,
); );

View File

@ -20,6 +20,7 @@ class HiveConfig {
await Hive.openBox(BNames.appSettings); await Hive.openBox(BNames.appSettings);
await Hive.openBox<User>(BNames.users); await Hive.openBox<User>(BNames.users);
await Hive.openBox(BNames.servicesState);
var cipher = HiveAesCipher(await getEncriptedKey()); var cipher = HiveAesCipher(await getEncriptedKey());
await Hive.openBox(BNames.appConfig, encryptionCipher: cipher); await Hive.openBox(BNames.appConfig, encryptionCipher: cipher);
@ -45,6 +46,7 @@ class BNames {
static String users = 'users'; static String users = 'users';
static String appSettings = 'appSettings'; static String appSettings = 'appSettings';
static String servicesState = 'servicesState';
static String key = 'key'; static String key = 'key';

View File

@ -90,8 +90,11 @@ class HetznerApi extends ApiMap {
var dbPassword = StringGenerators.dbPassword(); var dbPassword = StringGenerators.dbPassword();
var dbId = dbCreateResponse.data['volume']['id']; 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( var data = jsonDecode(
'''{"name":"$domainName","server_type":"cx11","start_after_create":false,"image":"ubuntu-20.04", "volumes":[$dbId], "networks":[], ssh_keys:[kherel], "user_data":"#cloud-config\\nruncmd:\\n- curl https://git.selfprivacy.org/ilchub/selfprivacy-nixos-infect/raw/branch/development/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"}'''); '''{"name":"$domainName","server_type":"cx11","start_after_create":false,"image":"ubuntu-20.04", "volumes":[$dbId], "networks":[], "ssh_keys":["kherel"], "user_data":"#cloud-config\\nruncmd:\\n- curl https://git.selfprivacy.org/ilchub/selfprivacy-nixos-infect/raw/branch/development/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( Response serverCreateResponse = await client.post(
'/servers', '/servers',

View File

@ -3,6 +3,7 @@ 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/models/user.dart'; import 'package:selfprivacy/logic/models/user.dart';
import 'api_map.dart'; import 'api_map.dart';
@ -90,3 +91,29 @@ class ServerApi extends ApiMap {
return res; return res;
} }
} }
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');
}
}
}

View File

@ -1,6 +1,7 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
import 'package:unicons/unicons.dart';
enum InitializingSteps { enum InitializingSteps {
setHeznerKey, setHeznerKey,
@ -22,6 +23,7 @@ enum ServiceTypes {
cloud, cloud,
socialNetwork, socialNetwork,
git, git,
vpn,
} }
extension ServiceTypesExt on ServiceTypes { extension ServiceTypesExt on ServiceTypes {
@ -41,6 +43,8 @@ extension ServiceTypesExt on ServiceTypes {
return 'services.social_network.title'.tr(); return 'services.social_network.title'.tr();
case ServiceTypes.git: case ServiceTypes.git:
return 'services.git.title'.tr(); return 'services.git.title'.tr();
case ServiceTypes.vpn:
return 'services.vpn.title'.tr();
} }
} }
@ -60,6 +64,8 @@ extension ServiceTypesExt on ServiceTypes {
return 'services.social_network.subtitle'.tr(); return 'services.social_network.subtitle'.tr();
case ServiceTypes.git: case ServiceTypes.git:
return 'services.git.subtitle'.tr(); return 'services.git.subtitle'.tr();
case ServiceTypes.vpn:
return 'services.vpn.subtitle'.tr();
} }
} }
@ -79,6 +85,10 @@ extension ServiceTypesExt on ServiceTypes {
return BrandIcons.social; return BrandIcons.social;
case ServiceTypes.git: case ServiceTypes.git:
return BrandIcons.git; return BrandIcons.git;
case ServiceTypes.vpn:
return UniconsLine.cloud_lock;
} }
} }
String get txt => this.toString().split('.')[1];
} }

View File

@ -2,6 +2,7 @@ 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/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/models/backblaze_credential.dart'; import 'package:selfprivacy/logic/models/backblaze_credential.dart';
import 'package:selfprivacy/logic/models/cloudflare_domain.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 /// c. if server is okay set that fully checked
class AppConfigCubit extends Cubit<AppConfigState> { class AppConfigCubit extends Cubit<AppConfigState> {
AppConfigCubit() : super(InitialAppConfigState()); AppConfigCubit(this.servicesCubit) : super(InitialAppConfigState());
final repository = AppConfigRepository(); final repository = AppConfigRepository();
final ServicesCubit servicesCubit;
Future<void> load() async { Future<void> load() async {
var state = await repository.load(); var state = await repository.load();
@ -232,6 +234,7 @@ class AppConfigCubit extends Cubit<AppConfigState> {
if (isServerWorking) { if (isServerWorking) {
await repository.saveHasFinalChecked(true); await repository.saveHasFinalChecked(true);
servicesCubit.allOn();
emit(state.copyWith( emit(state.copyWith(
hasFinalChecked: true, hasFinalChecked: true,
@ -259,12 +262,16 @@ class AppConfigCubit extends Cubit<AppConfigState> {
void clearAppConfig() { void clearAppConfig() {
closeTimer(); closeTimer();
servicesCubit.allOff();
repository.clearAppConfig(); repository.clearAppConfig();
emit(InitialAppConfigState()); emit(InitialAppConfigState());
} }
Future<void> serverDelete() async { Future<void> serverDelete() async {
closeTimer(); closeTimer();
servicesCubit.allOff();
if (state.hetznerServer != null) { if (state.hetznerServer != null) {
await repository.deleteServer(state.cloudFlareDomain!); await repository.deleteServer(state.cloudFlareDomain!);
} }

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/server.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/cubit/users/users_cubit.dart';
import 'package:selfprivacy/logic/models/jobs/job.dart'; import 'package:selfprivacy/logic/models/jobs/job.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
@ -12,10 +13,14 @@ import 'package:easy_localization/easy_localization.dart';
part 'jobs_state.dart'; part 'jobs_state.dart';
class JobsCubit extends Cubit<JobsState> { class JobsCubit extends Cubit<JobsState> {
JobsCubit(this.usersCubit) : super(JobsStateEmpty()); JobsCubit({
required this.usersCubit,
required this.servicesCubit,
}) : super(JobsStateEmpty());
final api = ServerApi(); final api = ServerApi();
final UsersCubit usersCubit; final UsersCubit usersCubit;
final ServicesCubit servicesCubit;
void addJob(Job job) { void addJob(Job job) {
var newJobsList = <Job>[]; var newJobsList = <Job>[];

View File

@ -1,10 +1,63 @@
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.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'; part 'services_state.dart';
class ServicesCubit extends Cubit<ServicesState> { class ServicesCubit extends Cubit<ServicesState> {
ServicesCubit() : super(ServicesInitial()); 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<ServiceTypes> list) {
for (final service in list) {
box.put(service.txt, false);
}
emit(state.disableList(list));
}
void turnOnist(List<ServiceTypes> list) {
for (final service in list) {
box.put(service.txt, true);
}
emit(state.enableList(list));
}
} }

View File

@ -1,10 +1,84 @@
part of 'services_cubit.dart'; part of 'services_cubit.dart';
abstract class ServicesState extends Equatable { const switchableServices = [
const ServicesState(); ServiceTypes.passwordManager,
ServiceTypes.cloud,
ServiceTypes.socialNetwork,
ServiceTypes.git,
ServiceTypes.vpn,
];
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<ServiceTypes> 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<ServiceTypes> 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 @override
List<Object> get props => []; List<Object> get props => [
isPasswordManagerEnable,
isCloudEnable,
isGitEnable,
isSocialNetworkEnable,
isVpnEnable
];
} }
class ServicesInitial extends ServicesState {}

View File

@ -119,7 +119,17 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
], ],
), ),
), ),
Container( // deleteServer(context)
],
),
);
}),
);
}
Widget deleteServer(BuildContext context) {
// todo: need to check
return Container(
padding: EdgeInsets.only(top: 20, bottom: 5), padding: EdgeInsets.only(top: 20, bottom: 5),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(
@ -159,9 +169,7 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
text: 'modals.7'.tr(), text: 'modals.7'.tr(),
isRed: true, isRed: true,
onPressed: () async { onPressed: () async {
await context await context.read<AppConfigCubit>().serverDelete();
.read<AppConfigCubit>()
.serverDelete();
Navigator.of(context).pop(); Navigator.of(context).pop();
}), }),
ActionButton( ActionButton(
@ -175,11 +183,6 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
), ),
], ],
), ),
)
],
),
);
}),
); );
} }
} }

View File

@ -301,6 +301,10 @@ class _ServiceDetails extends StatelessWidget {
], ],
)); ));
break; break;
case ServiceTypes.vpn:
child = Text(
'services.vpn.bottom_sheet.1'.tr(),
);
} }
return Dialog( return Dialog(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(

View File

@ -24,7 +24,6 @@ dependencies:
get_it: ^7.2.0 get_it: ^7.2.0
hive: ^2.0.0 hive: ^2.0.0
hive_flutter: ^1.0.0 hive_flutter: ^1.0.0
ionicons: ^0.1.2
json_annotation: ^4.0.0 json_annotation: ^4.0.0
modal_bottom_sheet: ^2.0.0 modal_bottom_sheet: ^2.0.0
nanoid: ^1.0.0 nanoid: ^1.0.0