From 79fae03e9b66c4c926337fa67c5a1bdf195298e8 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 12 Jan 2024 18:23:13 +0200 Subject: [PATCH 01/20] fix: overflows use this domain --- .../setup/initializing/domain_picker.dart | 54 ++++++------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/lib/ui/pages/setup/initializing/domain_picker.dart b/lib/ui/pages/setup/initializing/domain_picker.dart index 1d64349c..f9bb83d9 100644 --- a/lib/ui/pages/setup/initializing/domain_picker.dart +++ b/lib/ui/pages/setup/initializing/domain_picker.dart @@ -87,9 +87,13 @@ class _DomainPickerState extends State { }); }, ), - Text( - domain, - style: Theme.of(context).textTheme.bodyLarge, + Expanded( + child: Text( + domain, + style: Theme.of(context).textTheme.bodyLarge, + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), ), ], ), @@ -118,44 +122,20 @@ class _DomainPickerState extends State { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - state.domain, - style: Theme.of(context).textTheme.headlineMedium?.copyWith( - color: Theme.of(context).colorScheme.onBackground, - ), - textAlign: TextAlign.center, + Expanded( + child: Text( + state.domain, + style: Theme.of(context).textTheme.headlineMedium?.copyWith( + color: Theme.of(context).colorScheme.onBackground, + ), + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), ), ], ), ], - if (state is Empty) ...[ - const SizedBox(height: 30), - BrandButton.filled( - onPressed: () => context.read().load(), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon( - Icons.refresh, - color: Colors.white, - ), - const SizedBox(width: 10), - Text( - 'domain.update_list'.tr(), - style: Theme.of(context).textTheme.bodyLarge, - ), - ], - ), - ), - ], - if (state is Loaded) ...[ - const SizedBox(height: 32), - BrandButton.filled( - onPressed: () => - context.read().saveDomain(state.domain), - text: 'initializing.save_domain'.tr(), - ), - ], ], ), ); From 76d93ab7829c248f63cbf94e5fe854eb2aa90286 Mon Sep 17 00:00:00 2001 From: def Date: Thu, 18 Jan 2024 15:31:07 +0200 Subject: [PATCH 02/20] fix: missclicked on "Approve" button --- .../setup/initializing/domain_picker.dart | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/ui/pages/setup/initializing/domain_picker.dart b/lib/ui/pages/setup/initializing/domain_picker.dart index f9bb83d9..1d60ce74 100644 --- a/lib/ui/pages/setup/initializing/domain_picker.dart +++ b/lib/ui/pages/setup/initializing/domain_picker.dart @@ -132,10 +132,38 @@ class _DomainPickerState extends State { overflow: TextOverflow.ellipsis, maxLines: 1, ), - ), + ) ], ), ], + if (state is Empty) ...[ + const SizedBox(height: 30), + BrandButton.filled( + onPressed: () => context.read().load(), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.refresh, + color: Colors.white, + ), + const SizedBox(width: 10), + Text( + 'domain.update_list'.tr(), + style: Theme.of(context).textTheme.bodyLarge, + ), + ], + ), + ), + ], + if (state is Loaded) ...[ + const SizedBox(height: 32), + BrandButton.filled( + onPressed: () => + context.read().saveDomain(state.domain), + text: 'initializing.save_domain'.tr(), + ), + ], ], ), ); From d841f9db440e1ab9c59f720be29fd89f97e4402a Mon Sep 17 00:00:00 2001 From: NaiJi Date: Mon, 15 Jan 2024 12:52:28 +0400 Subject: [PATCH 03/20] feat: Make DNS deletion and creation dynamic - https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/265 --- devtools_options.yaml | 1 + .../cubit/dns_records/dns_records_cubit.dart | 16 +++----- .../server_installation_cubit.dart | 12 +++++- .../server_installation_repository.dart | 27 ++++++++----- .../providers/dns_providers/cloudflare.dart | 33 ++++++++++++---- lib/logic/providers/dns_providers/desec.dart | 30 ++++----------- .../dns_providers/digital_ocean_dns.dart | 38 +++++++++++-------- .../providers/dns_providers/dns_provider.dart | 14 +++---- 8 files changed, 96 insertions(+), 75 deletions(-) create mode 100644 devtools_options.yaml diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 00000000..7e7e7f67 --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1 @@ +extensions: diff --git a/lib/logic/cubit/dns_records/dns_records_cubit.dart b/lib/logic/cubit/dns_records/dns_records_cubit.dart index 7dff72f6..539f36a1 100644 --- a/lib/logic/cubit/dns_records/dns_records_cubit.dart +++ b/lib/logic/cubit/dns_records/dns_records_cubit.dart @@ -168,25 +168,19 @@ class DnsRecordsCubit Future fix() async { emit(state.copyWith(dnsState: DnsRecordsStatus.refreshing)); + final List records = await api.getDnsRecords(); + + /// TODO: Error handling? final ServerDomain? domain = serverInstallationCubit.state.serverDomain; - final String? ipAddress = serverInstallationCubit.state.serverDetails?.ip4; await ProvidersController.currentDnsProvider!.removeDomainRecords( + records: records, domain: domain!, ); await ProvidersController.currentDnsProvider!.createDomainRecords( + records: records, domain: domain, - ip4: ipAddress, ); - final List records = await api.getDnsRecords(); - final DnsRecord? dkimRecord = extractDkimRecord(records); - if (dkimRecord != null) { - await ProvidersController.currentDnsProvider!.setDnsRecord( - dkimRecord, - domain, - ); - } - await load(); } } diff --git a/lib/logic/cubit/server_installation/server_installation_cubit.dart b/lib/logic/cubit/server_installation/server_installation_cubit.dart index 0b5b6eed..fdfd4703 100644 --- a/lib/logic/cubit/server_installation/server_installation_cubit.dart +++ b/lib/logic/cubit/server_installation/server_installation_cubit.dart @@ -264,12 +264,20 @@ class ServerInstallationCubit extends Cubit { final ServerHostingDetails serverDetails, ) async { await repository.saveServerDetails(serverDetails); + + /// TODO: Error handling? await ProvidersController.currentDnsProvider!.removeDomainRecords( - ip4: serverDetails.ip4, + records: getProjectDnsRecords( + state.serverDomain!.domainName, + serverDetails.ip4, + ), domain: state.serverDomain!, ); await ProvidersController.currentDnsProvider!.createDomainRecords( - ip4: serverDetails.ip4, + records: getProjectDnsRecords( + state.serverDomain!.domainName, + serverDetails.ip4, + ), domain: state.serverDomain!, ); diff --git a/lib/logic/cubit/server_installation/server_installation_repository.dart b/lib/logic/cubit/server_installation/server_installation_repository.dart index d69f5b89..36cb8743 100644 --- a/lib/logic/cubit/server_installation/server_installation_repository.dart +++ b/lib/logic/cubit/server_installation/server_installation_repository.dart @@ -558,14 +558,30 @@ class ServerInstallationRepository { } Future deleteServer(final ServerDomain serverDomain) async { + final ServerApi api = ServerApi(); + final dnsRecords = await api.getDnsRecords(); + final GenericResult removalResult = + await ProvidersController.currentDnsProvider!.removeDomainRecords( + domain: serverDomain, + records: dnsRecords, + ); + + if (!removalResult.success) { + getIt().showSnackBar( + 'modals.dns_removal_error'.tr(), + ); + return false; + } + final deletionResult = await ProvidersController.currentServerProvider!.deleteServer( serverDomain.domainName, ); if (!deletionResult.success) { - getIt() - .showSnackBar('modals.server_validators_error'.tr()); + getIt().showSnackBar( + 'modals.server_validators_error'.tr(), + ); return false; } @@ -576,13 +592,6 @@ class ServerInstallationRepository { await box.put(BNames.isLoading, false); await box.put(BNames.serverDetails, null); - final GenericResult removalResult = await ProvidersController - .currentDnsProvider! - .removeDomainRecords(domain: serverDomain); - - if (!removalResult.success) { - getIt().showSnackBar('modals.dns_removal_error'.tr()); - } return true; } diff --git a/lib/logic/providers/dns_providers/cloudflare.dart b/lib/logic/providers/dns_providers/cloudflare.dart index d655cfbb..870a0cb7 100644 --- a/lib/logic/providers/dns_providers/cloudflare.dart +++ b/lib/logic/providers/dns_providers/cloudflare.dart @@ -3,7 +3,6 @@ import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/json/dns_providers/cloudflare_dns_info.dart'; import 'package:selfprivacy/logic/models/json/dns_records.dart'; import 'package:selfprivacy/logic/providers/dns_providers/dns_provider.dart'; -import 'package:selfprivacy/utils/network_utils.dart'; class ApiAdapter { ApiAdapter({ @@ -80,15 +79,14 @@ class CloudflareDnsProvider extends DnsProvider { @override Future> createDomainRecords({ + required final List records, required final ServerDomain domain, - final String? ip4, }) async { final syncZoneIdResult = await syncZoneId(domain.domainName); if (!syncZoneIdResult.success) { return syncZoneIdResult; } - final records = getProjectDnsRecords(domain.domainName, ip4); return _adapter.api().createMultipleDnsRecords( zoneId: _adapter.cachedZoneId, records: records @@ -102,16 +100,17 @@ class CloudflareDnsProvider extends DnsProvider { @override Future> removeDomainRecords({ + required final List records, required final ServerDomain domain, - final String? ip4, }) async { final syncZoneIdResult = await syncZoneId(domain.domainName); if (!syncZoneIdResult.success) { return syncZoneIdResult; } - final result = - await _adapter.api().getDnsRecords(zoneId: _adapter.cachedZoneId); + final result = await _adapter.api().getDnsRecords( + zoneId: _adapter.cachedZoneId, + ); if (result.data.isEmpty || !result.success) { return GenericResult( success: result.success, @@ -121,9 +120,29 @@ class CloudflareDnsProvider extends DnsProvider { ); } + final List selfprivacyRecords = records + .map( + (final record) => CloudflareDnsRecord.fromDnsRecord( + record, + domain.domainName, + ), + ) + .toList(); + + final List cloudflareRecords = result.data; + + /// Remove all records that do not match with SelfPrivacy + cloudflareRecords.removeWhere( + (final oceanRecord) => !selfprivacyRecords.any( + (final selfprivacyRecord) => + selfprivacyRecord.type == oceanRecord.type && + selfprivacyRecord.name == oceanRecord.name, + ), + ); + return _adapter.api().removeSimilarRecords( zoneId: _adapter.cachedZoneId, - records: result.data, + records: cloudflareRecords, ); } diff --git a/lib/logic/providers/dns_providers/desec.dart b/lib/logic/providers/dns_providers/desec.dart index ea139039..188045bf 100644 --- a/lib/logic/providers/dns_providers/desec.dart +++ b/lib/logic/providers/dns_providers/desec.dart @@ -3,7 +3,6 @@ import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/json/dns_providers/desec_dns_info.dart'; import 'package:selfprivacy/logic/models/json/dns_records.dart'; import 'package:selfprivacy/logic/providers/dns_providers/dns_provider.dart'; -import 'package:selfprivacy/utils/network_utils.dart'; class ApiAdapter { ApiAdapter({final bool isWithToken = true}) @@ -75,16 +74,11 @@ class DesecDnsProvider extends DnsProvider { @override Future> createDomainRecords({ + required final List records, required final ServerDomain domain, - final String? ip4, }) async { - final List listDnsRecords = getProjectDnsRecords( - domain.domainName, - ip4, - ); - final List bulkRecords = []; - for (final DnsRecord record in listDnsRecords) { + for (final DnsRecord record in records) { bulkRecords.add(DesecDnsRecord.fromDnsRecord(record, domain.domainName)); } @@ -96,21 +90,19 @@ class DesecDnsProvider extends DnsProvider { @override Future> removeDomainRecords({ + required final List records, required final ServerDomain domain, - final String? ip4, }) async { - final List listDnsRecords = getProjectDnsRecords( - domain.domainName, - ip4, - ); - final List bulkRecords = []; - for (final DnsRecord record in listDnsRecords) { + for (final DnsRecord record in records) { final desecRecord = DesecDnsRecord.fromDnsRecord( record, domain.domainName, ); bulkRecords.add( + /// Yes, it looks weird, but exactly forcing 'records' field + /// to empty array signals deSEC to remove the DNS record completely + /// https://desec.readthedocs.io/en/latest/dns/rrsets.html#deleting-an-rrset DesecDnsRecord( subname: desecRecord.subname, type: desecRecord.type, @@ -119,14 +111,6 @@ class DesecDnsProvider extends DnsProvider { ), ); } - bulkRecords.add( - DesecDnsRecord( - subname: 'selector._domainkey', - type: 'TXT', - ttl: 18000, - records: [], - ), - ); return _adapter.api().removeSimilarRecords( domainName: domain.domainName, diff --git a/lib/logic/providers/dns_providers/digital_ocean_dns.dart b/lib/logic/providers/dns_providers/digital_ocean_dns.dart index e07b63b1..f111c5f3 100644 --- a/lib/logic/providers/dns_providers/digital_ocean_dns.dart +++ b/lib/logic/providers/dns_providers/digital_ocean_dns.dart @@ -3,7 +3,6 @@ import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/json/dns_providers/digital_ocean_dns_info.dart'; import 'package:selfprivacy/logic/models/json/dns_records.dart'; import 'package:selfprivacy/logic/providers/dns_providers/dns_provider.dart'; -import 'package:selfprivacy/utils/network_utils.dart'; class ApiAdapter { ApiAdapter({final bool isWithToken = true}) @@ -75,15 +74,12 @@ class DigitalOceanDnsProvider extends DnsProvider { @override Future> createDomainRecords({ + required final List records, required final ServerDomain domain, - final String? ip4, }) async => _adapter.api().createMultipleDnsRecords( domainName: domain.domainName, - records: getProjectDnsRecords( - domain.domainName, - ip4, - ) + records: records .map( (final e) => DigitalOceanDnsRecord.fromDnsRecord(e, domain.domainName), @@ -93,8 +89,8 @@ class DigitalOceanDnsProvider extends DnsProvider { @override Future> removeDomainRecords({ + required final List records, required final ServerDomain domain, - final String? ip4, }) async { final result = await _adapter.api().getDnsRecords(domain.domainName); if (result.data.isEmpty || !result.success) { @@ -106,17 +102,29 @@ class DigitalOceanDnsProvider extends DnsProvider { ); } - const ignoreType = 'SOA'; - final List filteredRecords = []; - for (final record in result.data) { - if (record.type != ignoreType) { - filteredRecords.add(record); - } - } + final List selfprivacyRecords = records + .map( + (final record) => DigitalOceanDnsRecord.fromDnsRecord( + record, + domain.domainName, + ), + ) + .toList(); + + final List oceanRecords = result.data; + + /// Remove all records that do not match with SelfPrivacy + oceanRecords.removeWhere( + (final oceanRecord) => !selfprivacyRecords.any( + (final selfprivacyRecord) => + selfprivacyRecord.type == oceanRecord.type && + selfprivacyRecord.name == oceanRecord.name, + ), + ); return _adapter.api().removeSimilarRecords( domainName: domain.domainName, - records: filteredRecords, + records: oceanRecords, ); } diff --git a/lib/logic/providers/dns_providers/dns_provider.dart b/lib/logic/providers/dns_providers/dns_provider.dart index 98bd2199..406368b0 100644 --- a/lib/logic/providers/dns_providers/dns_provider.dart +++ b/lib/logic/providers/dns_providers/dns_provider.dart @@ -23,23 +23,21 @@ abstract class DnsProvider { /// Returns list of all available domain entries assigned to the account. Future>> domainList(); - /// Tries to create all main domain records needed - /// for SelfPrivacy to launch on requested domain by ip4. + /// Tries to create domain records + /// by our records list. /// /// Doesn't check for duplication, cleaning has /// to be done beforehand by [removeDomainRecords] Future> createDomainRecords({ + required final List records, required final ServerDomain domain, - final String? ip4, }); - /// Tries to remove all domain records of requested domain by ip4. - /// - /// Will remove all entries, including the ones - /// that weren't created by SelfPrivacy. + /// Tries to remove all records of requested + /// domain that match our records list. Future> removeDomainRecords({ + required final List records, required final ServerDomain domain, - final String? ip4, }); /// Returns list of all [DnsRecord] entries assigned to requested domain. From 39f92f769b013545bca2a0f51866b2efab3ab79c Mon Sep 17 00:00:00 2001 From: NaiJi Date: Mon, 15 Jan 2024 14:31:44 +0400 Subject: [PATCH 04/20] feat: Add selector._domainkey project record - https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/265 --- lib/utils/network_utils.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/utils/network_utils.dart b/lib/utils/network_utils.dart index bfd8a82d..345f62b7 100644 --- a/lib/utils/network_utils.dart +++ b/lib/utils/network_utils.dart @@ -121,6 +121,13 @@ List getProjectDnsRecords( ttl: 18000, ); + final DnsRecord txt3 = DnsRecord( + type: 'TXT', + name: 'selector._domainkey', + content: 'v=DKIM1; k=rsa; p=none', + ttl: 18000, + ); + return [ domainA, apiA, @@ -132,6 +139,7 @@ List getProjectDnsRecords( mx, txt1, txt2, + txt3, vpn, ]; } From 2836ce487058c9c122a2b57a27bb0199a775bac9 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Mon, 15 Jan 2024 14:45:36 +0400 Subject: [PATCH 05/20] fix(cloudflare): Convert MX name from @ to root domain - https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/265 --- .../server_installation/server_installation_cubit.dart | 2 ++ .../models/json/dns_providers/cloudflare_dns_adapter.dart | 6 +++++- lib/utils/network_utils.dart | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/logic/cubit/server_installation/server_installation_cubit.dart b/lib/logic/cubit/server_installation/server_installation_cubit.dart index fdfd4703..95726fb4 100644 --- a/lib/logic/cubit/server_installation/server_installation_cubit.dart +++ b/lib/logic/cubit/server_installation/server_installation_cubit.dart @@ -270,6 +270,7 @@ class ServerInstallationCubit extends Cubit { records: getProjectDnsRecords( state.serverDomain!.domainName, serverDetails.ip4, + false, ), domain: state.serverDomain!, ); @@ -277,6 +278,7 @@ class ServerInstallationCubit extends Cubit { records: getProjectDnsRecords( state.serverDomain!.domainName, serverDetails.ip4, + true, ), domain: state.serverDomain!, ); diff --git a/lib/logic/models/json/dns_providers/cloudflare_dns_adapter.dart b/lib/logic/models/json/dns_providers/cloudflare_dns_adapter.dart index 3a22c89e..8046555c 100644 --- a/lib/logic/models/json/dns_providers/cloudflare_dns_adapter.dart +++ b/lib/logic/models/json/dns_providers/cloudflare_dns_adapter.dart @@ -4,14 +4,18 @@ CloudflareDnsRecord _fromDnsRecord( final DnsRecord dnsRecord, final String rootDomain, ) { + final String type = dnsRecord.type; String name = dnsRecord.name ?? ''; if (name != rootDomain && name != '@') { name = '$name.$rootDomain'; } + if (type == 'MX' && name == '@') { + name = rootDomain; + } return CloudflareDnsRecord( content: dnsRecord.content, name: name, - type: dnsRecord.type, + type: type, zoneName: rootDomain, id: null, ttl: dnsRecord.ttl, diff --git a/lib/utils/network_utils.dart b/lib/utils/network_utils.dart index 345f62b7..a7dc874e 100644 --- a/lib/utils/network_utils.dart +++ b/lib/utils/network_utils.dart @@ -93,6 +93,7 @@ void launchURL(final url) async { List getProjectDnsRecords( final String? domainName, final String? ip4, + final bool isCreating, ) { final DnsRecord domainA = DnsRecord(type: 'A', name: domainName, content: ip4); @@ -139,7 +140,7 @@ List getProjectDnsRecords( mx, txt1, txt2, - txt3, + if (!isCreating) txt3, vpn, ]; } From 40c423437a89eba29b1b7850c3d073c641745a0a Mon Sep 17 00:00:00 2001 From: NaiJi Date: Fri, 19 Jan 2024 17:23:09 +0400 Subject: [PATCH 06/20] refactor: Rename variables and add needed comments - https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/265 --- lib/logic/providers/dns_providers/cloudflare.dart | 6 +++--- lib/utils/network_utils.dart | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/logic/providers/dns_providers/cloudflare.dart b/lib/logic/providers/dns_providers/cloudflare.dart index 870a0cb7..e40292a9 100644 --- a/lib/logic/providers/dns_providers/cloudflare.dart +++ b/lib/logic/providers/dns_providers/cloudflare.dart @@ -133,10 +133,10 @@ class CloudflareDnsProvider extends DnsProvider { /// Remove all records that do not match with SelfPrivacy cloudflareRecords.removeWhere( - (final oceanRecord) => !selfprivacyRecords.any( + (final cloudflareRecord) => !selfprivacyRecords.any( (final selfprivacyRecord) => - selfprivacyRecord.type == oceanRecord.type && - selfprivacyRecord.name == oceanRecord.name, + selfprivacyRecord.type == cloudflareRecord.type && + selfprivacyRecord.name == cloudflareRecord.name, ), ); diff --git a/lib/utils/network_utils.dart b/lib/utils/network_utils.dart index a7dc874e..c155d6a0 100644 --- a/lib/utils/network_utils.dart +++ b/lib/utils/network_utils.dart @@ -122,6 +122,9 @@ List getProjectDnsRecords( ttl: 18000, ); + /// We never create this record! + /// This declaration is only for removal + /// as we need to compare by 'type' and 'name' final DnsRecord txt3 = DnsRecord( type: 'TXT', name: 'selector._domainkey', From 766f44ee1900dca967972c9cc29d339e5fb8553e Mon Sep 17 00:00:00 2001 From: Inex Code Date: Fri, 19 Jan 2024 16:38:07 +0300 Subject: [PATCH 07/20] style: Add missing trailing comma --- lib/ui/pages/setup/initializing/domain_picker.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/pages/setup/initializing/domain_picker.dart b/lib/ui/pages/setup/initializing/domain_picker.dart index 1d60ce74..69e11a8d 100644 --- a/lib/ui/pages/setup/initializing/domain_picker.dart +++ b/lib/ui/pages/setup/initializing/domain_picker.dart @@ -132,7 +132,7 @@ class _DomainPickerState extends State { overflow: TextOverflow.ellipsis, maxLines: 1, ), - ) + ), ], ), ], From e4be60a51b2376656d065939ee13995486adf1d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NaiJi=20=E2=9C=A8?= Date: Fri, 1 Dec 2023 18:13:58 +0000 Subject: [PATCH 08/20] Translated using Weblate (Russian) Currently translated at 100.0% (533 of 533 strings) Translation: SelfPrivacy/SelfPrivacy App Translate-URL: http://weblate.selfprivacy.org/projects/selfprivacy/selfprivacy-app/ru/ --- assets/translations/ru.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 89770fff..ee97773f 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -24,7 +24,7 @@ "username": "Имя пользователя", "loading": "Загрузка…", "later": "Пропустить и настроить потом", - "connect_to_existing": "Подключиться к существующему серверу SelfPrivacy", + "connect_to_existing": "У меня уже есть SelfPrivacy сервер!", "reset": "Сбросить", "details": "Детальная информация", "no_data": "Нет данных", @@ -475,7 +475,7 @@ }, "recovering": { "generic_error": "Ошибка проведения операции, попробуйте ещё раз.", - "recovery_main_header": "Подключение к существующему серверу SelfPrivacy", + "recovery_main_header": "Подключение к существующему серверу", "domain_recovery_description": "Введите домен, по которому вы хотите получить доступ к серверу:", "domain_recover_placeholder": "Домен", "domain_recover_error": "Не удалось найти сервер с таким доменом", From 2ab33144fd9aa1bc0b1c1b1a2008e0e01e1b3c6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NaiJi=20=E2=9C=A8?= Date: Fri, 1 Dec 2023 18:16:04 +0000 Subject: [PATCH 09/20] Translated using Weblate (Spanish) Currently translated at 18.3% (98 of 533 strings) Translation: SelfPrivacy/SelfPrivacy App Translate-URL: http://weblate.selfprivacy.org/projects/selfprivacy/selfprivacy-app/es/ --- assets/translations/es.json | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/assets/translations/es.json b/assets/translations/es.json index ce007fb5..54d11a45 100644 --- a/assets/translations/es.json +++ b/assets/translations/es.json @@ -31,7 +31,7 @@ "remove": "Eliminar", "apply": "Solicitar", "done": "Hecho", - "connect_to_existing": "Conectarse a un servidor de SelfPrivacy existente", + "connect_to_existing": "¡Ya tengo un servidor de SelfPrivacy!", "app_name": "SelfPrivacy", "please_connect": "¡Conecta tu servidor y dominio para sumergirte!", "copied_to_clipboard": "¡Copiado al portapapeles!" @@ -45,7 +45,10 @@ "delete_server_title": "Eliminar servidor", "delete_server_description": "Esto elimina su servidor. Ya no será accesible.", "title": "Ajustes de la aplicación", - "dark_theme_title": "Tema oscuro" + "dark_theme_title": "Tema oscuro", + "system_dark_theme_title": "Tema del sistema", + "system_dark_theme_description": "Utiliza un tema claro u oscuro de la configuración del sistema", + "dangerous_settings": "Configuraciones peligrosas" }, "ssh": { "delete_confirm_question": "¿Está seguro de que desea eliminar la clave SSH?", @@ -57,7 +60,7 @@ "subtitle_without_keys": "Sin llaves", "no_key_name": "Clave sin nombre", "root_title": "Estas son las claves de superusuario", - "input_label": "Clave pública ED25519 o RSA" + "input_label": "Clave pública ED25519, ECDSA o RSA" }, "about_application_page": { "application_version_text": "Versión de la aplicación {}", @@ -92,5 +95,26 @@ }, "about_us_page": { "title": "Sobre nosotros" + }, + "server": { + "reboot_after_upgrade_hint": "Reinicio sin aviso después de aplicar cambios en el servidor", + "card_title": "Servidor", + "description": "Todos sus servicios funcionan aquí", + "general_information": "Información general", + "resource_usage": "Uso de recursos", + "server_timezone": "Zona horaria del servidor", + "select_timezone": "Selecciona zona horaria", + "reboot_after_upgrade": "Reinicia después de actualizar", + "allow_autoupgrade": "Permite la autoactualización", + "allow_autoupgrade_hint": "Ppermite actualizaciones automáticas de paquetes en el servidor" + }, + "resource_chart": { + "month": "Mes", + "out": "Fuera", + "day": "Día", + "hour": "Hora", + "cpu_title": "Uso de CPU", + "network_title": "Uso de la red", + "in": "En" } } From 82fc4c68c21324acad70b129acc3adc8c12ff8aa Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 1 Dec 2023 20:17:54 +0000 Subject: [PATCH 10/20] Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: SelfPrivacy/SelfPrivacy App Markdown: how_hetzner Translate-URL: http://weblate.selfprivacy.org/projects/selfprivacy/selfprivacy-app-markdown-how_hetzner/ --- assets/markdown/how_hetzner-be.md | 42 ++++++++++++++++--------------- assets/markdown/how_hetzner-ru.md | 28 +++++++++++++++------ 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/assets/markdown/how_hetzner-be.md b/assets/markdown/how_hetzner-be.md index 758f6ca0..6f859c18 100644 --- a/assets/markdown/how_hetzner-be.md +++ b/assets/markdown/how_hetzner-be.md @@ -1,21 +1,23 @@ -### Як атрымаць Hetzner API Token -1. Перайдзіце па наступнай [спасылцы](https://console.hetzner.cloud/) і падпішыцеся - у толькі што створаны ўліковы запіс. -2. Увайдзіце ў раней створаны праект. Калі вы яго не стварылі, - тады, калі ласка, працягвайце. -3. Навядзіце курсор мышы на бакавую панэль. Панэль павінна разгарнуцца і паказаць нас - меню. Нас цікавіць апошні — **Security** (значок а ключ). -4. Далей у верхняй частцы інтэрфейсу мы бачым прыблізна - наступнае: **SSH Keys, API Tokens, Certificates, Members.** Вы - патрэбныя **API Tokens**. Націсніце на яго. -5. У правай частцы інтэрфейсу павінна быць **Generate API token** button. Калі вы карыстаецеся мабільнай версіяй вэб-старонкі, у - у правым ніжнім куце вы ўбачыце **red cross**. Націсніце гэтую кнопку. -6. У полі **Description** дайце нашаму токену імя (гэта можа быць любое - імя, якое вам падабаецца. На сутнасць гэта не ўплывае. -7. Пад полем **permissions** мы бачым магчымасць выбару - **дазволы**. Выберыце **Read & Write**. -8. Націсніце **Generate API Token.** -9. Пасля гэтага будзе паказаны наш ключ. Захоўвайце яго ў надзейным месцы, - або ў менеджэры пароляў, што лепш. +### How to get Hetzner API Token +1. Visit the following [link](https://console.hetzner.cloud/) and sign + into newly created account. +2. Enter into previously created project. If you haven't created one, + then please proceed. +3. Hover side panel with mouse cursor. Panel should expand and show us + a menu. We're interested in the last one — **Security** (icon of a + key). +4. Next, in the upper part of an interface, we can see approximately + the following: **SSH Keys, API Tokens, Certificates, Members.** You + need **API Tokens**. Click on it. +5. In the right part of the interface, there should be **Generate API + token** button. If you're using mobile version og a webpage, in the + lower right corner you'll see **red cross**. Push that button. +6. In the **Description** field, give our token a name (this can be any + name that you like. It doesn't influence the essence. +7. Under the **Description** field we can see a possibility to choose + **permissions**. Pick **Read & Write**. +8. Click **Generate API Token.** +9. After that, our key will be shown. Store it in the reliable place, + or in the password manager, which is better. -![Наладжванне маркера Hetzner](рэсурс:assets/images/gifs/Hetzner.gif) +![Hetzner token setup](resource:assets/images/gifs/Hetzner.gif) diff --git a/assets/markdown/how_hetzner-ru.md b/assets/markdown/how_hetzner-ru.md index 94d19c37..6f859c18 100644 --- a/assets/markdown/how_hetzner-ru.md +++ b/assets/markdown/how_hetzner-ru.md @@ -1,9 +1,23 @@ -### Как получить Hetzner API Token -1. Переходим по ссылке https://hetzner.com -2. Заходим в созданный нами проект. Если такового - нет, значит создаём. -3. Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний — Security (с иконкой ключика). -4. Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему. -5. В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же Вы используете мобильную версию сайта, в нижнем правом углу Вы увидите красный плюсик. Нажимаем на эту кнопку. -6. В поле Description, даём нашему токену название (это может быть любое название, которые Вам нравиться. Сути оно не меняет. +### How to get Hetzner API Token +1. Visit the following [link](https://console.hetzner.cloud/) and sign + into newly created account. +2. Enter into previously created project. If you haven't created one, + then please proceed. +3. Hover side panel with mouse cursor. Panel should expand and show us + a menu. We're interested in the last one — **Security** (icon of a + key). +4. Next, in the upper part of an interface, we can see approximately + the following: **SSH Keys, API Tokens, Certificates, Members.** You + need **API Tokens**. Click on it. +5. In the right part of the interface, there should be **Generate API + token** button. If you're using mobile version og a webpage, in the + lower right corner you'll see **red cross**. Push that button. +6. In the **Description** field, give our token a name (this can be any + name that you like. It doesn't influence the essence. +7. Under the **Description** field we can see a possibility to choose + **permissions**. Pick **Read & Write**. +8. Click **Generate API Token.** +9. After that, our key will be shown. Store it in the reliable place, + or in the password manager, which is better. ![Hetzner token setup](resource:assets/images/gifs/Hetzner.gif) From 3c6eefdbbf3b82f20661338e8f61c5687d2c5c07 Mon Sep 17 00:00:00 2001 From: Yaron Date: Tue, 5 Dec 2023 08:46:32 +0000 Subject: [PATCH 11/20] Translated using Weblate (Hebrew) Currently translated at 100.0% (533 of 533 strings) Translation: SelfPrivacy/SelfPrivacy App Translate-URL: http://weblate.selfprivacy.org/projects/selfprivacy/selfprivacy-app/he/ --- assets/translations/he.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/translations/he.json b/assets/translations/he.json index 43b6e3a2..7bb6ce22 100644 --- a/assets/translations/he.json +++ b/assets/translations/he.json @@ -34,7 +34,7 @@ "username": "שם משתמש", "loading": "בטעינה…", "later": "דילוג כדי להגדיר אחר כך", - "connect_to_existing": "התחברות לשרת SelfPrivacy קיים", + "connect_to_existing": "כבר יש לי שרת SelfPrivacy!", "reset": "איפוס", "details": "פרטים", "no_data": "אין נתונים", @@ -480,7 +480,7 @@ "modal_confirmation_ip_valid": "ה־IP זהה לזה שברשומת ה־DNS", "modal_confirmation_ip_invalid": "ה־IP שונה מזה שברשומת ה־DNS", "generic_error": "הפעולה בוטלה, נא לנסות שוב.", - "recovery_main_header": "התחברות לשרת SelfPrivacy קיים", + "recovery_main_header": "התחברות לשרת קיים", "domain_recover_placeholder": "שם התחום שלך", "domain_recover_error": "לא נמצא שרת עם שם תחום כזה", "method_select_description": "נא לבחור שיטת שחזור:", From c8c3ffb4b93320572b709c220fef13ca530c56cb Mon Sep 17 00:00:00 2001 From: Yaron Date: Tue, 9 Jan 2024 09:09:53 +0000 Subject: [PATCH 12/20] Translated using Weblate (Hebrew) Currently translated at 99.2% (534 of 538 strings) Translation: SelfPrivacy/SelfPrivacy App Translate-URL: http://weblate.selfprivacy.org/projects/selfprivacy/selfprivacy-app/he/ --- assets/translations/he.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/translations/he.json b/assets/translations/he.json index 7bb6ce22..5c665b21 100644 --- a/assets/translations/he.json +++ b/assets/translations/he.json @@ -461,7 +461,8 @@ "enter_username_and_password": "נא למלא שם משתמש וסיסמה חזקה", "finish": "הכול מאותחל", "create_master_account": "יצירת חשבון ראשי", - "checks": "בדיקות הושלמו \n{} מתוך {}" + "checks": "בדיקות הושלמו \n{} מתוך {}", + "domain_critical_error": "לא הצלחנו להגיע לשם התחום הזה! נגיעה למידע נוסף…" }, "recovering": { "method_select_other_device": "יש לי גישה דרך מכשיר אחר", From ba3d1b86b7646137f7dd4d283376e8dcaece422e Mon Sep 17 00:00:00 2001 From: Yaron Date: Tue, 9 Jan 2024 20:20:06 +0000 Subject: [PATCH 13/20] Translated using Weblate (Hebrew) Currently translated at 100.0% (538 of 538 strings) Translation: SelfPrivacy/SelfPrivacy App Translate-URL: http://weblate.selfprivacy.org/projects/selfprivacy/selfprivacy-app/he/ --- assets/translations/he.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/assets/translations/he.json b/assets/translations/he.json index 5c665b21..90e4b419 100644 --- a/assets/translations/he.json +++ b/assets/translations/he.json @@ -611,7 +611,11 @@ "use_staging_acme_description": "חל על הקמת שרתים חדשים.", "use_staging_acme": "להשתמש בשרת ACME לבדיקות", "ignore_tls": "לא לאמת אישורי TLS", - "ignore_tls_description": "היישום לא יאמת אישורי RLS בעת התחברות לשרת." + "ignore_tls_description": "היישום לא יאמת אישורי RLS בעת התחברות לשרת.", + "add_root_ssh_key": "הוספת מפתח SSH למשתמש העל (root)", + "allow_ssh_key_at_setup": "לאפשר הגדרת מפתח SSH למשתמש העל (root) במהלך ההתקנה", + "allow_ssh_key_at_setup_description": "כפתור להוספת מפתח יופיע במסך האישור.", + "root_ssh_key_added": "מפתח SSH למשתמש העל (root) הוגדר והוחל" }, "cloud": { "title": "אחסון בענן", From a93844b89c4d3ab4f31192ce1c071345aec6e09c Mon Sep 17 00:00:00 2001 From: Inex Code Date: Wed, 10 Jan 2024 11:41:59 +0000 Subject: [PATCH 14/20] Added translation using Weblate (Estonian) --- assets/translations/et.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 assets/translations/et.json diff --git a/assets/translations/et.json b/assets/translations/et.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/assets/translations/et.json @@ -0,0 +1 @@ +{} From 83fe4fa0f3879356d1e44392ad64770d08ff7c6e Mon Sep 17 00:00:00 2001 From: Inex Code Date: Thu, 18 Jan 2024 23:12:23 +0000 Subject: [PATCH 15/20] Translated using Weblate (Russian) Currently translated at 100.0% (538 of 538 strings) Translation: SelfPrivacy/SelfPrivacy App Translate-URL: http://weblate.selfprivacy.org/projects/selfprivacy/selfprivacy-app/ru/ --- assets/translations/ru.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/assets/translations/ru.json b/assets/translations/ru.json index ee97773f..0b413bdb 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -471,7 +471,8 @@ }, "server_provider_description": "Место, где будут находиться ваши данные и сервисы SelfPrivacy:", "multiple_domains_found": "Найдено несколько доменов", - "multiple_domains_found_text": "Предоставленный токен дает доступ к следующим доменам. Пожалуйста, выберите тот, который вы хотите использовать. Для обеспечения безопасности других доменов следует ограничить доступ этого токена только тем доменом, который вы хотите использовать с SelfPrivacy." + "multiple_domains_found_text": "Предоставленный токен дает доступ к следующим доменам. Пожалуйста, выберите тот, который вы хотите использовать. Для обеспечения безопасности других доменов следует ограничить доступ этого токена только тем доменом, который вы хотите использовать с SelfPrivacy.", + "domain_critical_error": "Не получается подключиться к домену! Нажмите для подробностей…" }, "recovering": { "generic_error": "Ошибка проведения операции, попробуйте ещё раз.", @@ -626,6 +627,10 @@ "cubit_statuses": "Текущий статут кубитов загрузки", "reset_onboarding_description": "Принудить показ приветственного экрана", "ignore_tls_description": "Приложение не будет проверять сертификаты TLS при подключении к серверу.", - "ignore_tls": "Не проверять сертификаты TLS" + "ignore_tls": "Не проверять сертификаты TLS", + "add_root_ssh_key": "Добавить ключ суперпользователя", + "root_ssh_key_added": "SSH ключ суперпользователя задан и будет применён", + "allow_ssh_key_at_setup": "Разрешить задавать SSH ключи суперпользователя во время установки", + "allow_ssh_key_at_setup_description": "Кнопка для добавления ключа появится на экране подтверждения." } } From 954630f5e92b82de6361afac0fc3b17049db6506 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Fri, 19 Jan 2024 13:46:38 +0000 Subject: [PATCH 16/20] Translated using Weblate (Belarusian) Currently translated at 100.0% (2 of 2 strings) Translation: SelfPrivacy/SelfPrivacy App Markdown: how_hetzner Translate-URL: http://weblate.selfprivacy.org/projects/selfprivacy/selfprivacy-app-markdown-how_hetzner/be/ --- assets/markdown/how_hetzner-be.md | 42 +++++++++++++++---------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/assets/markdown/how_hetzner-be.md b/assets/markdown/how_hetzner-be.md index 6f859c18..cf6b2984 100644 --- a/assets/markdown/how_hetzner-be.md +++ b/assets/markdown/how_hetzner-be.md @@ -1,23 +1,21 @@ -### How to get Hetzner API Token -1. Visit the following [link](https://console.hetzner.cloud/) and sign - into newly created account. -2. Enter into previously created project. If you haven't created one, - then please proceed. -3. Hover side panel with mouse cursor. Panel should expand and show us - a menu. We're interested in the last one — **Security** (icon of a - key). -4. Next, in the upper part of an interface, we can see approximately - the following: **SSH Keys, API Tokens, Certificates, Members.** You - need **API Tokens**. Click on it. -5. In the right part of the interface, there should be **Generate API - token** button. If you're using mobile version og a webpage, in the - lower right corner you'll see **red cross**. Push that button. -6. In the **Description** field, give our token a name (this can be any - name that you like. It doesn't influence the essence. -7. Under the **Description** field we can see a possibility to choose - **permissions**. Pick **Read & Write**. -8. Click **Generate API Token.** -9. After that, our key will be shown. Store it in the reliable place, - or in the password manager, which is better. +### Як атрымаць Hetzner API Token +1. Перайдзіце па наступнай [спасылцы](https://console.hetzner.cloud/) і падпішыцеся + у толькі што створаны ўліковы запіс. +2. Увайдзіце ў раней створаны праект. Калі вы яго не стварылі, + тады, калі ласка, працягвайце. +3. Навядзіце курсор мышы на бакавую панэль. Панэль павінна разгарнуцца і паказаць нас + меню. Нас цікавіць апошні — **Security** (значок а ключ). +4. Далей у верхняй частцы інтэрфейсу мы бачым прыблізна + наступнае: **SSH Keys, API Tokens, Certificates, Members.** Вы + патрэбныя **API Tokens**. Націсніце на яго. +5. У правай частцы інтэрфейсу павінна быць **Generate API token** button. Калі вы карыстаецеся мабільнай версіяй вэб-старонкі, у + у правым ніжнім куце вы ўбачыце **чырвоны плюс**. Націсніце гэтую кнопку. +6. У полі **Description** дайце нашаму токену імя (гэта можа быць любое + імя, якое вам падабаецца. На сутнасць гэта не ўплывае. +7. Пад полем **permissions** мы бачым магчымасць выбару + **дазволы**. Выберыце **Read & Write**. +8. Націсніце **Generate API Token.** +9. Пасля гэтага будзе паказаны наш ключ. Захоўвайце яго ў надзейным месцы, + або ў менеджэры пароляў, што лепш. -![Hetzner token setup](resource:assets/images/gifs/Hetzner.gif) +![Наладжванне маркера Hetzner](resource:assets/images/gifs/Hetzner.gif) From 3fb5804b20701d7a5b1836e6da6e0abab6e5e757 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Fri, 19 Jan 2024 13:54:28 +0000 Subject: [PATCH 17/20] Translated using Weblate (Russian) Currently translated at 100.0% (2 of 2 strings) Translation: SelfPrivacy/SelfPrivacy App Markdown: how_hetzner Translate-URL: http://weblate.selfprivacy.org/projects/selfprivacy/selfprivacy-app-markdown-how_hetzner/ru/ --- assets/markdown/how_hetzner-ru.md | 33 +++++++++++-------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/assets/markdown/how_hetzner-ru.md b/assets/markdown/how_hetzner-ru.md index 6f859c18..82bef302 100644 --- a/assets/markdown/how_hetzner-ru.md +++ b/assets/markdown/how_hetzner-ru.md @@ -1,23 +1,12 @@ -### How to get Hetzner API Token -1. Visit the following [link](https://console.hetzner.cloud/) and sign - into newly created account. -2. Enter into previously created project. If you haven't created one, - then please proceed. -3. Hover side panel with mouse cursor. Panel should expand and show us - a menu. We're interested in the last one — **Security** (icon of a - key). -4. Next, in the upper part of an interface, we can see approximately - the following: **SSH Keys, API Tokens, Certificates, Members.** You - need **API Tokens**. Click on it. -5. In the right part of the interface, there should be **Generate API - token** button. If you're using mobile version og a webpage, in the - lower right corner you'll see **red cross**. Push that button. -6. In the **Description** field, give our token a name (this can be any - name that you like. It doesn't influence the essence. -7. Under the **Description** field we can see a possibility to choose - **permissions**. Pick **Read & Write**. -8. Click **Generate API Token.** -9. After that, our key will be shown. Store it in the reliable place, - or in the password manager, which is better. +### Как получить токен API от Hetzner +1. Посетите следующую [ссылку](https://console.hetzner.cloud/) и войдите в свой новый аккаунт. +2. Войдите в ранее созданный проект. Если вы еще не создали его, пожалуйста, сделайте это. +3. Наведите курсор мыши на боковую панель. Панель должна расшириться и показать меню. Нас интересует последний пункт — **Security** (иконка ключа). +4. Далее, в верхней части интерфейса, видим примерно следующее: **SSH Keys, API Tokens, Certificates, Members.** Нужно нажать **API Tokens**. +5. В правой части интерфейса должна быть кнопка **Generate API token**. Если вы используете мобильную версию веб-страницы, в нижнем правом углу вы увидите **красный плюс**. Нажмите на эту кнопку. +6. В поле **Description** дайте вашему токену имя (это может быть любое имя, которое вам нравится). +7. Под полем **Description** мы видим возможность выбрать **permissions**. Выберите **Read & Write**. +8. Нажмите **Generate API Token**. +9. После этого вам будет показан ключ. Храните его в надежном месте, или в менеджере паролей, что еще лучше. -![Hetzner token setup](resource:assets/images/gifs/Hetzner.gif) +![Получение токена Hetzner](resource:assets/images/gifs/Hetzner.gif) From 4e7409ca6d22118d4e380c637c32b8ed1e41b4a0 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Fri, 19 Jan 2024 17:47:45 +0300 Subject: [PATCH 18/20] chore: Bump version to 0.10.0 --- .../android/en-US/changelogs/0.10.0.txt | 69 +++++++++++++++++++ pubspec.yaml | 2 +- 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/0.10.0.txt diff --git a/fastlane/metadata/android/en-US/changelogs/0.10.0.txt b/fastlane/metadata/android/en-US/changelogs/0.10.0.txt new file mode 100644 index 00000000..98140976 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/0.10.0.txt @@ -0,0 +1,69 @@ +### Features + +- **Server installation**: New NixOS version is used during server setup ([#415](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/415)) + - It is also possible to set a root SSH key during server setup. This feature can be activated in developer settings. +- **DNS management**: DNS records creation dynamically gets desired records from the server now ([#424](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/424), resolves [#265](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/265)) +- **UI**: Add the button to copy password on the new user creation screen ([#409](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/409), resolves [#299](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/299)) +- **UI**: Add animation to the recovery key screen ([#410](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/410), resolves [#164](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/164)) +- **Backups**: Bucket name now includes the date of creation ([#403](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/403), resolves [#263](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/263)) +- **UI**: Snapshots List page now shows the button to open the Jobs sheet ([#396](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/396), resolves [#290](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/290)) +- **Server installation**: Implement better domain ownership check during installation ([#394](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/394), resolves [#389](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/389)) +- **UI**: Implement flexible precision formatting for prices ([#387](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/387)) + +### Bug Fixes + +- **UI**: Domain name no longer overflows the screen ([#422](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/422), resolves [#408](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/408)) +- **UI**: Fix overflow of the filled buttons +- **Hetzner**: Filter away ARM architecture from available servers ([#404](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/404), resolves [#402](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/402)) +- **UI**: Add refresh indicator on the 'Devices' screen ([#398](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/398), resolves [#258](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/258) and [#163](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/163)) +- **GraphQL API**: Force DateTime to UTC when timezone naive ([#386](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/386), resolves [#385](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/385)) + +### Other + +- Updated the copyright year ([#417](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/417)) + - Happy new year! +- Upgrade to Flutter 3.16.1 +- Rename the Recovery flow button to prevent user confusion ([#399](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/399), resolves [#346](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/346)) +- **GraphQL API**: Remove and replace deprecated mutations ([#423](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/423), resolves [#418](https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/418)) + +### Translation contributions + +* French + * smtg (12) + +* Spanish + * NaiJi ✨ (35) + +* German + * Marvin F (23) + * User 1234 (30) + +* Hebrew + * Yaron (578) + +* Russian + * def (4) + * NaiJi ✨ (9) + * Inex Code (10) + + +### Translation contributions + +* French + * smtg (12) + +* Spanish + * NaiJi ✨ (35) + +* German + * Marvin F (23) + * User 1234 (30) + +* Hebrew + * Yaron (578) + +* Russian + * def (4) + * NaiJi ✨ (9) + * Inex Code (10) + diff --git a/pubspec.yaml b/pubspec.yaml index 2ae559b0..12a071d1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: selfprivacy description: selfprivacy.org publish_to: 'none' -version: 0.9.1+19 +version: 0.10.0+20 environment: sdk: '>=3.2.1 <4.0.0' From 175e189d5a18732dcdafb625c2c912512bbaf116 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Fri, 19 Jan 2024 17:49:56 +0300 Subject: [PATCH 19/20] chore: Update appimage version --- appimage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appimage.yml b/appimage.yml index 40bcc3c3..9914346f 100644 --- a/appimage.yml +++ b/appimage.yml @@ -10,7 +10,7 @@ AppDir: id: org.selfprivacy.app name: SelfPrivacy icon: org.selfprivacy.app - version: 0.9.1 + version: 0.10.0 exec: selfprivacy exec_args: $@ apt: From bb03bf6a10fa3a5d068db4536a5d198c3e7cae37 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Fri, 19 Jan 2024 17:51:25 +0300 Subject: [PATCH 20/20] chore: Oops, fix the changelog --- .../android/en-US/changelogs/0.10.0.txt | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/fastlane/metadata/android/en-US/changelogs/0.10.0.txt b/fastlane/metadata/android/en-US/changelogs/0.10.0.txt index 98140976..0de2f8df 100644 --- a/fastlane/metadata/android/en-US/changelogs/0.10.0.txt +++ b/fastlane/metadata/android/en-US/changelogs/0.10.0.txt @@ -45,25 +45,3 @@ * def (4) * NaiJi ✨ (9) * Inex Code (10) - - -### Translation contributions - -* French - * smtg (12) - -* Spanish - * NaiJi ✨ (35) - -* German - * Marvin F (23) - * User 1234 (30) - -* Hebrew - * Yaron (578) - -* Russian - * def (4) - * NaiJi ✨ (9) - * Inex Code (10) -