fdroid
Kherel 2021-01-21 22:01:42 +01:00
parent 7de50dd237
commit 80213abf9b
14 changed files with 262 additions and 57 deletions

View File

@ -10,6 +10,8 @@ PODS:
- Flutter
- url_launcher (0.0.1):
- Flutter
- wakelock (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
@ -18,6 +20,7 @@ DEPENDENCIES:
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
- wakelock (from `.symlinks/plugins/wakelock/ios`)
EXTERNAL SOURCES:
Flutter:
@ -32,6 +35,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/shared_preferences/ios"
url_launcher:
:path: ".symlinks/plugins/url_launcher/ios"
wakelock:
:path: ".symlinks/plugins/wakelock/ios"
SPEC CHECKSUMS:
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
@ -40,6 +45,7 @@ SPEC CHECKSUMS:
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
wakelock: bfc7955c418d0db797614075aabbc58a39ab5107
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c

View File

@ -47,7 +47,9 @@ class BNames {
static String hetznerKey = 'hetznerKey';
static String cloudFlareKey = 'cloudFlareKey';
static String rootUser = 'rootUser';
static String hetznerServer = 'server';
static String hetznerServer = 'hetznerServer';
static String isDkimSetted = 'isDkimSetted';
static String isDnsChecked = 'isDnsChecked';
static String serverInitStart = 'serverInitStart';
static String isServerStarted = 'isServerStarted';
}

View File

@ -1,14 +1,26 @@
import 'dart:developer';
import 'dart:io';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/get_it/console.dart';
import 'package:selfprivacy/logic/models/message.dart';
abstract class ApiMap {
ApiMap() {
var client = Dio()..interceptors.add(ConsoleInterceptor());
(client.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(HttpClient client) {
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
return client;
};
loggedClient = client;
}
String rootAddress;
// Dio client = Dio();
Dio loggedClient = Dio()..interceptors.add(ConsoleInterceptor());
Dio loggedClient;
void close() {
loggedClient.close();
@ -45,7 +57,7 @@ class ConsoleInterceptor extends InterceptorsWrapper {
@override
Future onError(DioError err) async {
var response = err.response;
log(err.toString());
addMessage(
Message.warn(
text:

View File

@ -7,7 +7,8 @@ import 'package:selfprivacy/logic/models/dns_records.dart';
class CloudflareApi extends ApiMap {
CloudflareApi([String token]) {
if (token != null) {
loggedClient.options = BaseOptions(headers: {'Authorization': 'Bearer $token'});
loggedClient.options =
BaseOptions(headers: {'Authorization': 'Bearer $token'});
}
}
@ -116,12 +117,18 @@ class CloudflareApi extends ApiMap {
await Future.wait(allFutures);
}
// createSDKIM(String dkim) {
// var txt3 = DnsRecords(
// type: 'TXT',
// name: 'selector._domainkey',
// content: dkim,
// ttl: 18000,
// );
// }
setDkim(String dkimRecordString, String domainZoneId) {
var txt3 = DnsRecords(
type: 'TXT',
name: 'selector._domainkey',
content: dkimRecordString,
ttl: 18000,
);
var url = '$rootAddress/zones/$domainZoneId/dns_records';
loggedClient.post(
url,
data: txt3.toJson(),
);
}
}

View File

@ -1,12 +1,47 @@
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'api_map.dart';
class ServerApi extends ApiMap {
ServerApi([String token]) {
if (token != null) {
loggedClient.options =
BaseOptions(headers: {'Authorization': 'Bearer $token'});
ServerApi(String domainName) {
loggedClient.options = BaseOptions(
baseUrl: 'https://api.$domainName',
);
}
Future<bool> isHttpServerWorking() async {
bool res;
Response response;
try {
response = await loggedClient.get('/serviceStatus');
res = response.statusCode == HttpStatus.ok;
} catch (e) {
res = false;
}
return res;
}
Future<String> getDkim(String domainName) async {
var response = await loggedClient.get(
'/getDKIM',
options: Options(responseType: ResponseType.plain),
);
return _decodeAndCutData(response.data, domainName);
}
}
String _decodeAndCutData(String text, String domainName) {
var decodedTextString = text.substring(1, text.length - 1);
var stringToBase64 = utf8.fuse(base64);
return stringToBase64
.decode(decodedTextString)
.replaceAll("selector._domainkey IN TXT ( ", "")
.replaceAll("\"\n \"", "")
.replaceAll(' ) ; ----- DKIM key selector for $domainName\n', '');
}

View File

@ -1,5 +1,8 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import 'package:selfprivacy/logic/models/cloudflare_domain.dart';
import 'package:selfprivacy/logic/models/server_details.dart';
@ -9,6 +12,18 @@ import 'app_config_repository.dart';
part 'app_config_state.dart';
/// initializeing steps: |setHetznerKey
/// 1. Hetzner key |setCloudFlare
/// 2. Cloudflare key |setCloudflareKey
/// 3. Set Domain address |setDomain
/// 4. Set Root user name password |setRootUser
/// 5. Set Create server ans set DNS-Records |createServerAndSetDnsRecords
/// (without start)
/// 6. ChecksAndSets:
/// 6.1 checkDnsAndStartServer |checkDnsAndStartServer
/// 6.2 setDkim |setDkim
/// (checkServer + getDkim + Set DKIM)
class AppConfigCubit extends Cubit<AppConfigState> {
AppConfigCubit() : super(InitialAppConfigState());
@ -29,7 +44,7 @@ class AppConfigCubit extends Cubit<AppConfigState> {
emit(state.copyWith(hetznerKey: hetznerKey));
}
void setCloudFlare(String cloudFlareKey) {
void setCloudflareKey(String cloudFlareKey) {
repository.saveCloudFlare(cloudFlareKey);
emit(state.copyWith(cloudFlareKey: cloudFlareKey));
}
@ -44,7 +59,30 @@ class AppConfigCubit extends Cubit<AppConfigState> {
emit(state.copyWith(rootUser: rootUser));
}
Future<void> checkDns() async {
void setDkim() async {
var callBack = () async {
var isServerWorking = await repository.isHttpServerWorking(
state.cloudFlareDomain.domainName,
);
if (!isServerWorking) {
var last = DateTime.now();
print(last);
emit(state.copyWith(lastServerStatusCheckTime: last));
return;
}
await repository.setDkim(
state.cloudFlareDomain.domainName,
state.cloudFlareKey,
state.cloudFlareDomain.zoneId,
);
emit(state.copyWith(isDkimSetted: true));
};
_tryOrAddError(state, callBack);
}
void checkDnsAndStartServer() async {
var ip4 = state.hetznerServer.ip4;
var domainName = state.cloudFlareDomain.domainName;
@ -58,7 +96,8 @@ class AppConfigCubit extends Cubit<AppConfigState> {
repository.saveServerDetails(server);
emit(
state.copyWith(
isDnsCheckedAndServerStarted: true,
isDnsChecked: true,
isServerStarted: true,
isLoading: false,
hetznerServer: server,
),
@ -68,30 +107,39 @@ class AppConfigCubit extends Cubit<AppConfigState> {
}
}
void createServer() async {
emit(state.copyWith(isLoading: true));
try {
void createServerAndSetDnsRecords() async {
var callback = () async {
var serverDetails = await repository.createServer(
state.hetznerKey,
state.rootUser,
state.cloudFlareDomain.domainName,
);
await repository.createDnsRecords(
state.cloudFlareKey,
serverDetails.ip4,
state.cloudFlareDomain,
);
// await repository.createDnsRecords(
// state.cloudFlareKey,
// serverDetails.ip4,
// state.cloudFlareDomain,
// );
emit(state.copyWith(
isLoading: false,
hetznerServer: serverDetails,
));
};
_tryOrAddError(state, callback);
}
FutureOr<void> _tryOrAddError(
AppConfigState state,
AsyncCallback callback,
) async {
emit(state.copyWith(isLoading: true));
try {
await callback();
} catch (e) {
addError(e);
emit(state.copyWith(isLoading: false));
emit(state);
}
}
}

View File

@ -2,6 +2,7 @@ import 'package:hive/hive.dart';
import 'package:selfprivacy/config/hive_config.dart';
import 'package:selfprivacy/logic/api_maps/cloudflare.dart';
import 'package:selfprivacy/logic/api_maps/hetzner.dart';
import 'package:selfprivacy/logic/api_maps/server.dart';
import 'package:selfprivacy/logic/models/cloudflare_domain.dart';
import 'package:selfprivacy/logic/models/server_details.dart';
import 'package:selfprivacy/logic/models/user.dart';
@ -21,7 +22,9 @@ class AppConfigRepository {
cloudFlareDomain: box.get(BNames.cloudFlareDomain),
rootUser: box.get(BNames.rootUser),
hetznerServer: box.get(BNames.hetznerServer),
isDnsCheckedAndServerStarted: box.get(BNames.isDnsChecked),
isServerStarted: box.get(BNames.isServerStarted, defaultValue: false),
isDnsChecked: box.get(BNames.isDnsChecked, defaultValue: false),
isDkimSetted: box.get(BNames.isDkimSetted, defaultValue: false),
);
}
@ -52,6 +55,7 @@ class AppConfigRepository {
var hetznerApi = HetznerApi(hetznerKey);
var serverDetails = await hetznerApi.startServer(server: hetznerServer);
hetznerApi.close();
box.put(BNames.isServerStarted, true);
return serverDetails;
}
@ -92,6 +96,8 @@ class AppConfigRepository {
}
}
box.put(BNames.isDnsChecked, true);
return true;
}
@ -117,14 +123,36 @@ class AppConfigRepository {
String ip4,
CloudFlareDomain cloudFlareDomain,
) async {
var cloudflareApi = CloudflareApi(cloudFlareKey);
await cloudflareApi.createMultipleDnsRecords(
ip4: ip4,
cloudFlareDomain: cloudFlareDomain,
);
cloudflareApi.close();
}
Future<bool> isHttpServerWorking(String domainName) async {
var api = ServerApi(domainName);
var isHttpServerWorking = await api.isHttpServerWorking();
print('isHttpServerWorking: $isHttpServerWorking');
api.close();
return isHttpServerWorking;
}
Future<void> setDkim(
String domainName,
String cloudFlareKey,
String zoneId,
) async {
var api = ServerApi(domainName);
var dkimRecordString = await api.getDkim(domainName);
var cloudflareApi = CloudflareApi(cloudFlareKey);
await cloudflareApi.setDkim(dkimRecordString, zoneId);
box.put(BNames.isDkimSetted, true);
cloudflareApi.close();
}
}

View File

@ -7,10 +7,12 @@ class AppConfigState extends Equatable {
this.cloudFlareDomain,
this.rootUser,
this.hetznerServer,
this.isDnsCheckedAndServerStarted = false,
this.isLoading = false,
this.error,
this.lastDnsCheckTime,
this.lastServerStatusCheckTime,
this.isDnsChecked = false,
this.isServerStarted = false,
this.isDkimSetted = false,
});
@ -25,6 +27,7 @@ class AppConfigState extends Equatable {
isLoading,
error,
lastDnsCheckTime,
lastServerStatusCheckTime,
isDkimSetted,
];
@ -33,10 +36,11 @@ class AppConfigState extends Equatable {
final CloudFlareDomain cloudFlareDomain;
final User rootUser;
final HetznerServerDetails hetznerServer;
final bool isDnsCheckedAndServerStarted;
final bool isDkimSetted;
final bool isServerStarted;
final bool isDnsChecked;
final DateTime lastDnsCheckTime;
final DateTime lastServerStatusCheckTime;
final bool isLoading;
final Exception error;
@ -46,11 +50,13 @@ class AppConfigState extends Equatable {
CloudFlareDomain cloudFlareDomain,
User rootUser,
HetznerServerDetails hetznerServer,
bool isDnsCheckedAndServerStarted,
bool isLoading,
Exception error,
DateTime lastDnsCheckTime,
DateTime lastServerStatusCheckTime,
bool isDkimSetted,
bool isServerStarted,
bool isDnsChecked,
}) =>
AppConfigState(
hetznerKey: hetznerKey ?? this.hetznerKey,
@ -58,12 +64,14 @@ class AppConfigState extends Equatable {
cloudFlareDomain: cloudFlareDomain ?? this.cloudFlareDomain,
rootUser: rootUser ?? this.rootUser,
hetznerServer: hetznerServer ?? this.hetznerServer,
isDnsCheckedAndServerStarted:
isDnsCheckedAndServerStarted ?? this.isDnsCheckedAndServerStarted,
isServerStarted: isServerStarted ?? this.isServerStarted,
isDnsChecked: isDnsChecked ?? this.isDnsChecked,
isLoading: isLoading ?? this.isLoading,
error: error ?? this.error,
lastDnsCheckTime: lastDnsCheckTime ?? this.lastDnsCheckTime,
isDkimSetted: isDkimSetted,
lastServerStatusCheckTime:
lastServerStatusCheckTime ?? this.lastServerStatusCheckTime,
isDkimSetted: isDkimSetted ?? this.isDkimSetted,
);
bool get isHetznerFilled => hetznerKey != null;
@ -73,6 +81,8 @@ class AppConfigState extends Equatable {
bool get isServerFilled => hetznerServer != null;
bool get hasFinalChecked => isDnsCheckedAndServerStarted && isDkimSetted;
bool get isDnsCheckedAndServerStarted => isDnsChecked && isServerStarted;
bool get isFullyInitilized => _fulfilementList.every((el) => el);
int get progress => _fulfilementList.where((el) => el).length;

View File

@ -25,7 +25,7 @@ class CloudFlareFormCubit extends FormCubit {
@override
FutureOr<void> onSubmit() async {
initializingCubit.setCloudFlare(apiKey.state.value);
initializingCubit.setCloudflareKey(apiKey.state.value);
}
final AppConfigCubit initializingCubit;

View File

@ -18,12 +18,12 @@ class HetznerServerDetails {
@HiveField(1)
final int id;
@HiveField(2)
final DateTime startTime;
@HiveField(3)
final DateTime createTime;
@HiveField(2)
final DateTime startTime;
HetznerServerDetails copyWith({DateTime startTime}) {
return HetznerServerDetails(
startTime: startTime ?? this.startTime,

View File

@ -19,8 +19,8 @@ class HetznerServerDetailsAdapter extends TypeAdapter<HetznerServerDetails> {
return HetznerServerDetails(
ip4: fields[0] as String,
id: fields[1] as int,
createTime: fields[3] as DateTime,
startTime: fields[2] as DateTime,
createTime: fields[3] as DateTime,
);
}

View File

@ -0,0 +1,55 @@
import 'package:flutter/foundation.dart';
class ServerStatus {
final StatusTypes http;
final StatusTypes imap;
final StatusTypes smtp;
ServerStatus({
@required this.http,
this.imap = StatusTypes.nodata,
this.smtp = StatusTypes.nodata,
});
ServerStatus fromJson(Map<String, dynamic> json) {
return ServerStatus(
http: statusTypeFromNumber(json['http']),
imap: statusTypeFromNumber(json['imap']),
smtp: statusTypeFromNumber(json['smtp']),
);
}
}
StatusTypes statusTypeFromNumber(int number) {
if (number == 0) {
return StatusTypes.ok;
} else if (number == 1) {
return StatusTypes.error;
} else if (number == 2) {
return StatusTypes.wrongArgument;
} else if (number == 3) {
return StatusTypes.wrongFunction;
} else if (number == 4) {
return StatusTypes.noRights;
} else if (number == 5) {
return StatusTypes.notInstalled;
} else if (number == 6) {
return StatusTypes.notConfigured;
} else if (number == 7) {
return StatusTypes.off;
} else {
throw Exception('wrong status');
}
}
enum StatusTypes {
ok,
error,
wrongArgument,
wrongFunction,
noRights,
notInstalled,
notConfigured,
off,
nodata,
}

View File

@ -73,7 +73,8 @@ class _BrandTimerState extends State<BrandTimer> {
String _durationToString(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitSeconds = twoDigits(60 - duration.inSeconds.remainder(60));
String twoDigitSeconds =
twoDigits(widget.duration.inSeconds - duration.inSeconds.remainder(60));
return "$twoDigitSeconds cек";
}

View File

@ -270,7 +270,8 @@ class InitializingPage extends StatelessWidget {
BrandText.body2('Создать сервер'),
Spacer(),
BrandButton.rised(
onPressed: isLoading ? null : appConfigCubit.createServer,
onPressed:
isLoading ? null : appConfigCubit.createServerAndSetDnsRecords,
title: isLoading ? 'loading' : 'Создать сервер',
),
Spacer(flex: 2),
@ -285,7 +286,7 @@ class InitializingPage extends StatelessWidget {
Widget _stepCheck(AppConfigCubit appConfigCubit) {
var state = appConfigCubit.state;
var isDnsChecked = appConfigCubit.state.isDnsCheckedAndServerStarted;
var isDnsChecked = state.isDnsCheckedAndServerStarted;
return Builder(builder: (context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -303,19 +304,19 @@ class InitializingPage extends StatelessWidget {
BrandText.body2('До следующей проверки: '),
isDnsChecked
? BrandTimer(
startDateTime:
state.lastDnsCheckTime ?? state.hetznerServer.createTime,
startDateTime: state.lastServerStatusCheckTime ??
state.hetznerServer.startTime,
duration: Duration(minutes: 1),
callback: () {
appConfigCubit.checkDns();
appConfigCubit.setDkim();
},
)
: BrandTimer(
startDateTime:
state.lastDnsCheckTime ?? state.hetznerServer.createTime,
startDateTime: state.lastDnsCheckTime ??
state.hetznerServer.createTime,
duration: Duration(minutes: 1),
callback: () {
appConfigCubit.checkDns();
appConfigCubit.checkDnsAndStartServer();
},
)
],