forked from SelfPrivacy/selfprivacy.org.app
Compare commits
3 Commits
master
...
f6508dfcad
Author | SHA1 | Date |
---|---|---|
Inex Code | f6508dfcad | |
Inex Code | 0bc3d9f31c | |
Inex Code | 88d5dbf010 |
|
@ -154,6 +154,27 @@ class CloudflareApi extends ApiMap {
|
|||
];
|
||||
}
|
||||
|
||||
Future<void> setDkim(
|
||||
String dkimRecordString, CloudFlareDomain cloudFlareDomain) async {
|
||||
final domainZoneId = cloudFlareDomain.zoneId;
|
||||
final url = '$rootAddress/zones/$domainZoneId/dns_records';
|
||||
|
||||
final dkimRecord = DnsRecords(
|
||||
type: 'TXT',
|
||||
name: 'selector._domainkey',
|
||||
content: dkimRecordString,
|
||||
ttl: 18000,
|
||||
);
|
||||
|
||||
var client = await getClient();
|
||||
await client.post(
|
||||
url,
|
||||
data: dkimRecord.toJson(),
|
||||
);
|
||||
|
||||
client.close();
|
||||
}
|
||||
|
||||
Future<List<String>> domainList() async {
|
||||
var url = '$rootAddress/zones?per_page=50';
|
||||
var client = await getClient();
|
||||
|
|
|
@ -115,19 +115,49 @@ class HetznerApi extends ApiMap {
|
|||
final apiToken = StringGenerators.apiToken();
|
||||
|
||||
// Replace all non-alphanumeric characters with an underscore
|
||||
final hostname = domainName.split('.')[0].replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
|
||||
var hostname =
|
||||
domainName.split('.')[0].replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
|
||||
// if hostname ends with -, remove it
|
||||
if (hostname.endsWith('-')) {
|
||||
hostname = hostname.substring(0, hostname.length - 1);
|
||||
}
|
||||
// if hostname starts with -, remove it
|
||||
if (hostname.startsWith('-')) {
|
||||
hostname = hostname.substring(1);
|
||||
}
|
||||
// if hostname is empty, use default
|
||||
if (hostname.isEmpty) {
|
||||
hostname = 'selfprivacy-server';
|
||||
}
|
||||
|
||||
print("hostname: $hostname");
|
||||
|
||||
/// add ssh key when you need it: e.g. "ssh_keys":["kherel"]
|
||||
/// check the branch name, it could be "development" or "master".
|
||||
///
|
||||
final userdataString = "#cloud-config\\nruncmd:\\n- curl https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-infect/raw/branch/master/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-21.05 DOMAIN='$domainName' LUSER='${escapeQuotes(rootUser.login)}' PASSWORD='${escapeQuotes(rootUser.password)}' CF_TOKEN=$cloudFlareKey DB_PASSWORD=${escapeQuotes(dbPassword)} API_TOKEN=$apiToken HOSTNAME=${escapeQuotes(hostname)} bash 2>&1 | tee /tmp/infect.log";
|
||||
print(userdataString);
|
||||
|
||||
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/SelfPrivacy/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 API_TOKEN=$apiToken HOSTNAME=$hostname bash 2>&1 | tee /tmp/infect.log","labels":{},"automount":true, "location": "fsn1"}''');
|
||||
final data = {
|
||||
"name": hostname,
|
||||
"server_type": "cx11",
|
||||
"start_after_create": false,
|
||||
"image": "ubuntu-20.04",
|
||||
"volumes": [dbId],
|
||||
"networks": [],
|
||||
"user_data": userdataString,
|
||||
"labels": {},
|
||||
"automount": true,
|
||||
"location": "fsn1"
|
||||
};
|
||||
print("Decoded data: $data");
|
||||
|
||||
Response serverCreateResponse = await client.post(
|
||||
'/servers',
|
||||
data: data,
|
||||
);
|
||||
|
||||
print(serverCreateResponse.data);
|
||||
client.close();
|
||||
return HetznerServerDetails(
|
||||
id: serverCreateResponse.data['server']['id'],
|
||||
|
@ -226,3 +256,11 @@ class HetznerApi extends ApiMap {
|
|||
close(client);
|
||||
}
|
||||
}
|
||||
|
||||
String escapeQuotes(String str) {
|
||||
// replace all single quotes with escaped single quotes for bash strong quotes (i.e. '\'' )
|
||||
print("Escaping single quotes for bash: $str");
|
||||
print("Escaping result: ${str.replaceAll(RegExp(r"'"), "'\\''")}");
|
||||
// also escape all double quotes for json
|
||||
return str.replaceAll(RegExp(r"'"), "'\\''");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
|
@ -236,6 +237,21 @@ class ServerApi extends ApiMap {
|
|||
client.close();
|
||||
return response.statusCode == HttpStatus.ok;
|
||||
}
|
||||
|
||||
Future<String> getDkim() async {
|
||||
var client = await getClient();
|
||||
Response response = await client.get('/services/mailserver/dkim');
|
||||
client.close();
|
||||
|
||||
// if got 404 raise exception
|
||||
if (response.statusCode == HttpStatus.notFound) {
|
||||
throw Exception('No DKIM key found');
|
||||
}
|
||||
|
||||
final base64toString = utf8.fuse(base64);
|
||||
|
||||
return base64toString.decode(response.data).split('(')[1].split(')')[0];
|
||||
}
|
||||
}
|
||||
|
||||
extension UrlServerExt on ServiceTypes {
|
||||
|
|
|
@ -239,6 +239,7 @@ class AppConfigCubit extends Cubit<AppConfigState> {
|
|||
var isServerWorking = await repository.isHttpServerWorking();
|
||||
|
||||
if (isServerWorking) {
|
||||
await repository.createDkimRecord(state.cloudFlareDomain!);
|
||||
await repository.saveHasFinalChecked(true);
|
||||
|
||||
emit(state.finish());
|
||||
|
|
|
@ -189,9 +189,23 @@ class AppConfigRepository {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> createDkimRecord(CloudFlareDomain cloudFlareDomain) async {
|
||||
var cloudflareApi = CloudflareApi();
|
||||
var api = ServerApi();
|
||||
|
||||
var dkimRecordString = await api.getDkim();
|
||||
|
||||
await cloudflareApi.setDkim(dkimRecordString, cloudFlareDomain);
|
||||
}
|
||||
|
||||
Future<bool> isHttpServerWorking() async {
|
||||
var api = ServerApi();
|
||||
var isHttpServerWorking = await api.isHttpServerWorking();
|
||||
try {
|
||||
await api.getDkim();
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return isHttpServerWorking;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,8 +85,8 @@ class BackupsCubit extends AppConfigDependendCubit<BackupsState> {
|
|||
|
||||
Future<void> createBucket() async {
|
||||
emit(state.copyWith(preventActions: true));
|
||||
final domain =
|
||||
appConfigCubit.state.cloudFlareDomain!.domainName.replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
|
||||
final domain = appConfigCubit.state.cloudFlareDomain!.domainName
|
||||
.replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
|
||||
final serverId = appConfigCubit.state.hetznerServer!.id;
|
||||
var bucketName = 'selfprivacy-$domain-$serverId';
|
||||
// If bucket name is too long, shorten it
|
||||
|
|
Loading…
Reference in New Issue