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": {
"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": {
@ -217,7 +224,6 @@
"serviceTurnOff": "Turn off",
"serviceTurnOn": "Turn on",
"jobAdded": "Job added"
},
"validations": {
"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/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,
);

View File

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

View File

@ -90,8 +90,11 @@ class HetznerApi extends ApiMap {
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":[], 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(
'/servers',

View File

@ -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';
@ -90,3 +91,29 @@ class ServerApi extends ApiMap {
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:flutter/cupertino.dart';
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
import 'package:unicons/unicons.dart';
enum InitializingSteps {
setHeznerKey,
@ -22,6 +23,7 @@ enum ServiceTypes {
cloud,
socialNetwork,
git,
vpn,
}
extension ServiceTypesExt on ServiceTypes {
@ -41,6 +43,8 @@ extension ServiceTypesExt on ServiceTypes {
return 'services.social_network.title'.tr();
case ServiceTypes.git:
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();
case ServiceTypes.git:
return 'services.git.subtitle'.tr();
case ServiceTypes.vpn:
return 'services.vpn.subtitle'.tr();
}
}
@ -79,6 +85,10 @@ extension ServiceTypesExt on ServiceTypes {
return BrandIcons.social;
case ServiceTypes.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: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<AppConfigState> {
AppConfigCubit() : super(InitialAppConfigState());
AppConfigCubit(this.servicesCubit) : super(InitialAppConfigState());
final repository = AppConfigRepository();
final ServicesCubit servicesCubit;
Future<void> load() async {
var state = await repository.load();
@ -232,6 +234,7 @@ class AppConfigCubit extends Cubit<AppConfigState> {
if (isServerWorking) {
await repository.saveHasFinalChecked(true);
servicesCubit.allOn();
emit(state.copyWith(
hasFinalChecked: true,
@ -259,12 +262,16 @@ class AppConfigCubit extends Cubit<AppConfigState> {
void clearAppConfig() {
closeTimer();
servicesCubit.allOff();
repository.clearAppConfig();
emit(InitialAppConfigState());
}
Future<void> serverDelete() async {
closeTimer();
servicesCubit.allOff();
if (state.hetznerServer != null) {
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: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:equatable/equatable.dart';
@ -12,10 +13,14 @@ import 'package:easy_localization/easy_localization.dart';
part 'jobs_state.dart';
class JobsCubit extends Cubit<JobsState> {
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 = <Job>[];

View File

@ -1,10 +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<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';
abstract class ServicesState extends Equatable {
const ServicesState();
const switchableServices = [
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
List<Object> get props => [];
List<Object> get props => [
isPasswordManagerEnable,
isCloudEnable,
isGitEnable,
isSocialNetworkEnable,
isVpnEnable
];
}
class ServicesInitial extends ServicesState {}

View File

@ -119,69 +119,72 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
],
),
),
Container(
padding: EdgeInsets.only(top: 20, bottom: 5),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 1, color: BrandColors.dividerColor),
)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: _TextColumn(
title: 'more.settings.5'.tr(),
value: 'more.settings.6'.tr(),
),
),
SizedBox(width: 5),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: BrandColors.red1,
),
child: Text(
'basis.delete'.tr(),
style: TextStyle(
color: BrandColors.white,
fontWeight: NamedFontWeight.demiBold,
),
),
onPressed: () {
showDialog(
context: context,
builder: (_) {
return BrandAlert(
title: 'modals.3'.tr(),
contentText: 'modals.6'.tr(),
acitons: [
ActionButton(
text: 'modals.7'.tr(),
isRed: true,
onPressed: () async {
await context
.read<AppConfigCubit>()
.serverDelete();
Navigator.of(context).pop();
}),
ActionButton(
text: 'basis.cancel'.tr(),
),
],
);
},
);
},
),
],
),
)
// deleteServer(context)
],
),
);
}),
);
}
Widget deleteServer(BuildContext context) {
// todo: need to check
return Container(
padding: EdgeInsets.only(top: 20, bottom: 5),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 1, color: BrandColors.dividerColor),
)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: _TextColumn(
title: 'more.settings.5'.tr(),
value: 'more.settings.6'.tr(),
),
),
SizedBox(width: 5),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: BrandColors.red1,
),
child: Text(
'basis.delete'.tr(),
style: TextStyle(
color: BrandColors.white,
fontWeight: NamedFontWeight.demiBold,
),
),
onPressed: () {
showDialog(
context: context,
builder: (_) {
return BrandAlert(
title: 'modals.3'.tr(),
contentText: 'modals.6'.tr(),
acitons: [
ActionButton(
text: 'modals.7'.tr(),
isRed: true,
onPressed: () async {
await context.read<AppConfigCubit>().serverDelete();
Navigator.of(context).pop();
}),
ActionButton(
text: 'basis.cancel'.tr(),
),
],
);
},
);
},
),
],
),
);
}
}
class _TextColumn extends StatelessWidget {

View File

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

View File

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