From 07e48ce318404e023e50af1bf7368d6af53ec9d7 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Wed, 6 Mar 2024 18:03:16 +0530 Subject: [PATCH 01/12] Add an action within OnboardingPage to access developer settings --- auth/lib/l10n/arb/app_en.arb | 4 +- auth/lib/onboarding/view/onboarding_page.dart | 216 ++++++++++-------- 2 files changed, 123 insertions(+), 97 deletions(-) diff --git a/auth/lib/l10n/arb/app_en.arb b/auth/lib/l10n/arb/app_en.arb index 9ac0c98992..b6b8ba7d4c 100644 --- a/auth/lib/l10n/arb/app_en.arb +++ b/auth/lib/l10n/arb/app_en.arb @@ -408,5 +408,7 @@ "hearUsExplanation": "We don't track app installs. It'd help if you told us where you found us!", "waitingForBrowserRequest": "Waiting for browser request...", "launchPasskeyUrlAgain": "Launch passkey URL again", - "passkey": "Passkey" + "passkey": "Passkey", + "developerMode":"Developer mode", + "developerModeWarning":"Are you sure that you want to enter Developer mode?" } \ No newline at end of file diff --git a/auth/lib/onboarding/view/onboarding_page.dart b/auth/lib/onboarding/view/onboarding_page.dart index 78bf4e589d..3c5e8e020b 100644 --- a/auth/lib/onboarding/view/onboarding_page.dart +++ b/auth/lib/onboarding/view/onboarding_page.dart @@ -33,8 +33,12 @@ class OnboardingPage extends StatefulWidget { } class _OnboardingPageState extends State { + static const kDeveloperModeTapCountThreshold = 7; + late StreamSubscription _triggerLogoutEvent; + int _developerModeTapCount = 0; + @override void initState() { _triggerLogoutEvent = @@ -56,114 +60,134 @@ class _OnboardingPageState extends State { final l10n = context.l10n; return Scaffold( body: SafeArea( - child: Center( - child: SingleChildScrollView( - child: Padding( - padding: - const EdgeInsets.symmetric(vertical: 40.0, horizontal: 40), - child: Column( - children: [ - Column( - children: [ - kDebugMode - ? GestureDetector( - child: const Align( - alignment: Alignment.topRight, - child: Text("Lang"), - ), - onTap: () async { - final locale = await getLocale(); - routeToPage( - context, - LanguageSelectorPage( - appSupportedLocales, - (locale) async { - await setLocale(locale); - App.setLocale(context, locale); - }, - locale, + child: GestureDetector( + onTap: () async { + _developerModeTapCount++; + if (_developerModeTapCount >= kDeveloperModeTapCountThreshold) { + _developerModeTapCount = 0; + final result = await showChoiceDialog( + context, + title: l10n.developerMode, + firstButtonLabel: l10n.yes, + body: l10n.developerModeWarning, + isDismissible: false, + ); + if (result?.action == ButtonAction.first) { + // TODO: Navigate to developer mode page + } + } + }, + child: Center( + child: SingleChildScrollView( + child: Padding( + padding: + const EdgeInsets.symmetric(vertical: 40.0, horizontal: 40), + child: Column( + children: [ + Column( + children: [ + kDebugMode + ? GestureDetector( + child: const Align( + alignment: Alignment.topRight, + child: Text("Lang"), + ), + onTap: () async { + final locale = await getLocale(); + routeToPage( + context, + LanguageSelectorPage( + appSupportedLocales, + (locale) async { + await setLocale(locale); + App.setLocale(context, locale); + }, + locale, + ), + ).then((value) { + setState(() {}); + }); + }, + ) + : const SizedBox(), + Image.asset( + "assets/sheild-front-gradient.png", + width: 200, + height: 200, + ), + const SizedBox(height: 12), + const Text( + "ente", + style: TextStyle( + fontWeight: FontWeight.bold, + fontFamily: 'Montserrat', + fontSize: 42, + ), + ), + const SizedBox(height: 4), + Text( + "Authenticator", + style: Theme.of(context).textTheme.headlineMedium, + ), + const SizedBox(height: 32), + Text( + l10n.onBoardingBody, + textAlign: TextAlign.center, + style: + Theme.of(context).textTheme.titleLarge!.copyWith( + color: Colors.white38, ), - ).then((value) { - setState(() {}); - }); - }, - ) - : const SizedBox(), - Image.asset( - "assets/sheild-front-gradient.png", - width: 200, - height: 200, - ), - const SizedBox(height: 12), - const Text( - "ente", - style: TextStyle( - fontWeight: FontWeight.bold, - fontFamily: 'Montserrat', - fontSize: 42, ), + ], + ), + const SizedBox(height: 100), + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 20), + child: GradientButton( + onTap: _navigateToSignUpPage, + text: l10n.newUser, ), - const SizedBox(height: 4), - Text( - "Authenticator", - style: Theme.of(context).textTheme.headlineMedium, - ), - const SizedBox(height: 32), - Text( - l10n.onBoardingBody, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleLarge!.copyWith( - color: Colors.white38, + ), + const SizedBox(height: 4), + Container( + width: double.infinity, + padding: const EdgeInsets.fromLTRB(20, 12, 20, 0), + child: Hero( + tag: "log_in", + child: ElevatedButton( + style: Theme.of(context) + .colorScheme + .optionalActionButtonStyle, + onPressed: _navigateToSignInPage, + child: Text( + l10n.existingUser, + style: const TextStyle( + color: Colors.black, // same for both themes ), - ), - ], - ), - const SizedBox(height: 100), - Container( - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 20), - child: GradientButton( - onTap: _navigateToSignUpPage, - text: l10n.newUser, - ), - ), - const SizedBox(height: 4), - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(20, 12, 20, 0), - child: Hero( - tag: "log_in", - child: ElevatedButton( - style: Theme.of(context) - .colorScheme - .optionalActionButtonStyle, - onPressed: _navigateToSignInPage, - child: Text( - l10n.existingUser, - style: const TextStyle( - color: Colors.black, // same for both themes ), ), ), ), - ), - const SizedBox(height: 4), - Container( - width: double.infinity, - padding: const EdgeInsets.only(top: 20, bottom: 20), - child: GestureDetector( - onTap: _optForOfflineMode, - child: Center( - child: Text( - l10n.useOffline, - style: body.copyWith( - color: Theme.of(context).colorScheme.mutedTextColor, + const SizedBox(height: 4), + Container( + width: double.infinity, + padding: const EdgeInsets.only(top: 20, bottom: 20), + child: GestureDetector( + onTap: _optForOfflineMode, + child: Center( + child: Text( + l10n.useOffline, + style: body.copyWith( + color: + Theme.of(context).colorScheme.mutedTextColor, + ), ), ), ), ), - ), - ], + ], + ), ), ), ), From b893affbfacb54fc569eba139612c84df7462ac0 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Wed, 6 Mar 2024 18:35:38 +0530 Subject: [PATCH 02/12] Add DeveloperSettingsPage --- auth/lib/l10n/arb/app_en.arb | 5 +- auth/lib/onboarding/view/onboarding_page.dart | 9 ++- .../ui/settings/developer_settings_page.dart | 70 +++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 auth/lib/ui/settings/developer_settings_page.dart diff --git a/auth/lib/l10n/arb/app_en.arb b/auth/lib/l10n/arb/app_en.arb index b6b8ba7d4c..66f2b2fdf6 100644 --- a/auth/lib/l10n/arb/app_en.arb +++ b/auth/lib/l10n/arb/app_en.arb @@ -410,5 +410,8 @@ "launchPasskeyUrlAgain": "Launch passkey URL again", "passkey": "Passkey", "developerMode":"Developer mode", - "developerModeWarning":"Are you sure that you want to enter Developer mode?" + "developerModeWarning":"Are you sure that you want to modify Developer settings?", + "developerSettings": "Developer settings", + "invalidURL": "Invalid URL", + "invalidURLMessage": "Sorry, the URL you entered is invalid. Please enter a valid URL and try again." } \ No newline at end of file diff --git a/auth/lib/onboarding/view/onboarding_page.dart b/auth/lib/onboarding/view/onboarding_page.dart index 3c5e8e020b..97b6f698c4 100644 --- a/auth/lib/onboarding/view/onboarding_page.dart +++ b/auth/lib/onboarding/view/onboarding_page.dart @@ -17,6 +17,7 @@ import 'package:ente_auth/ui/common/gradient_button.dart'; import 'package:ente_auth/ui/components/buttons/button_widget.dart'; import 'package:ente_auth/ui/components/models/button_result.dart'; import 'package:ente_auth/ui/home_page.dart'; +import 'package:ente_auth/ui/settings/developer_settings_page.dart'; import 'package:ente_auth/ui/settings/language_picker.dart'; import 'package:ente_auth/utils/dialog_util.dart'; import 'package:ente_auth/utils/navigation_util.dart'; @@ -73,7 +74,13 @@ class _OnboardingPageState extends State { isDismissible: false, ); if (result?.action == ButtonAction.first) { - // TODO: Navigate to developer mode page + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) { + return const DeveloperSettingsPage(); + }, + ), + ); } } }, diff --git a/auth/lib/ui/settings/developer_settings_page.dart b/auth/lib/ui/settings/developer_settings_page.dart new file mode 100644 index 0000000000..9efe113d15 --- /dev/null +++ b/auth/lib/ui/settings/developer_settings_page.dart @@ -0,0 +1,70 @@ +import 'package:ente_auth/l10n/l10n.dart'; +import 'package:ente_auth/ui/common/gradient_button.dart'; +import 'package:ente_auth/utils/dialog_util.dart'; +import 'package:flutter/material.dart'; +import 'package:logging/logging.dart'; + +class DeveloperSettingsPage extends StatefulWidget { + const DeveloperSettingsPage({super.key}); + + @override + _DeveloperSettingsPageState createState() => _DeveloperSettingsPageState(); +} + +class _DeveloperSettingsPageState extends State { + final _logger = Logger('DeveloperSettingsPage'); + final _urlController = TextEditingController(); + + @override + void dispose() { + _urlController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(context.l10n.developerSettings), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + TextField( + controller: _urlController, + decoration: const InputDecoration( + labelText: 'Server Endpoint', + hintText: 'https://api.ente.io:443', + ), + autofocus: true, + ), + const SizedBox(height: 40), + GradientButton( + onTap: () { + String url = _urlController.text; + _logger.info("Entered endpoint: " + url); + try { + final uri = Uri.parse(url); + if ((uri.scheme == "http" || uri.scheme == "https") && + (uri.hasPort || !uri.hasPort)) { + // TODO: Save the URL + } else { + throw const FormatException(); + } + } catch (e) { + showErrorDialog( + context, + context.l10n.invalidURL, + context.l10n.invalidURLMessage, + ); + } + }, + text: context.l10n.saveAction, + ), + ], + ), + ), + ); + } +} From 690f90d29692802339292c0005d03ee07ca61166 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Wed, 6 Mar 2024 20:00:07 +0530 Subject: [PATCH 03/12] Remove unused method --- auth/lib/store/user_store.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/auth/lib/store/user_store.dart b/auth/lib/store/user_store.dart index 20f3ead72b..b191d169d8 100644 --- a/auth/lib/store/user_store.dart +++ b/auth/lib/store/user_store.dart @@ -7,10 +7,6 @@ class UserStore { late SharedPreferences _preferences; static final UserStore instance = UserStore._privateConstructor(); - static const endpoint = String.fromEnvironment( - "endpoint", - defaultValue: "https://api.ente.io", - ); Future init() async { _preferences = await SharedPreferences.getInstance(); From 3593ee49310fb3dec395161f7d49c1f99a3b8e99 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Wed, 6 Mar 2024 20:32:56 +0530 Subject: [PATCH 04/12] Update the endpoint in configuration --- auth/lib/core/configuration.dart | 9 ++++++++- auth/lib/events/endpoint_updated_event.dart | 3 +++ auth/lib/l10n/arb/app_en.arb | 3 ++- .../ui/settings/developer_settings_page.dart | 18 ++++++++++++------ 4 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 auth/lib/events/endpoint_updated_event.dart diff --git a/auth/lib/core/configuration.dart b/auth/lib/core/configuration.dart index 3e6540af65..da3ad9ebf8 100644 --- a/auth/lib/core/configuration.dart +++ b/auth/lib/core/configuration.dart @@ -6,6 +6,7 @@ import 'dart:typed_data'; import 'package:bip39/bip39.dart' as bip39; import 'package:ente_auth/core/constants.dart'; import 'package:ente_auth/core/event_bus.dart'; +import 'package:ente_auth/events/endpoint_updated_event.dart'; import 'package:ente_auth/events/signed_in_event.dart'; import 'package:ente_auth/events/signed_out_event.dart'; import 'package:ente_auth/models/key_attributes.dart'; @@ -42,6 +43,7 @@ class Configuration { static const userIDKey = "user_id"; static const hasMigratedSecureStorageKey = "has_migrated_secure_storage"; static const hasOptedForOfflineModeKey = "has_opted_for_offline_mode"; + static const endPointKey = "endpoint"; final List onlineSecureKeys = [ keyKey, secretKeyKey, @@ -317,7 +319,12 @@ class Configuration { } String getHttpEndpoint() { - return endpoint; + return _preferences.getString(endPointKey) ?? endpoint; + } + + Future setHttpEndpoint(String endpoint) async { + await _preferences.setString(endPointKey, endpoint); + Bus.instance.fire(EndpointUpdatedEvent()); } String? getToken() { diff --git a/auth/lib/events/endpoint_updated_event.dart b/auth/lib/events/endpoint_updated_event.dart new file mode 100644 index 0000000000..0a9915479a --- /dev/null +++ b/auth/lib/events/endpoint_updated_event.dart @@ -0,0 +1,3 @@ +import 'package:ente_auth/events/event.dart'; + +class EndpointUpdatedEvent extends Event {} diff --git a/auth/lib/l10n/arb/app_en.arb b/auth/lib/l10n/arb/app_en.arb index 66f2b2fdf6..e3037fee43 100644 --- a/auth/lib/l10n/arb/app_en.arb +++ b/auth/lib/l10n/arb/app_en.arb @@ -413,5 +413,6 @@ "developerModeWarning":"Are you sure that you want to modify Developer settings?", "developerSettings": "Developer settings", "invalidURL": "Invalid URL", - "invalidURLMessage": "Sorry, the URL you entered is invalid. Please enter a valid URL and try again." + "invalidURLMessage": "Sorry, the URL you entered is invalid. Please enter a valid URL and try again.", + "endpointUpdatedMessage": "Endpoint updated successfully" } \ No newline at end of file diff --git a/auth/lib/ui/settings/developer_settings_page.dart b/auth/lib/ui/settings/developer_settings_page.dart index 9efe113d15..0b11a30c13 100644 --- a/auth/lib/ui/settings/developer_settings_page.dart +++ b/auth/lib/ui/settings/developer_settings_page.dart @@ -1,6 +1,8 @@ +import 'package:ente_auth/core/configuration.dart'; import 'package:ente_auth/l10n/l10n.dart'; import 'package:ente_auth/ui/common/gradient_button.dart'; import 'package:ente_auth/utils/dialog_util.dart'; +import 'package:ente_auth/utils/toast_util.dart'; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; @@ -23,6 +25,9 @@ class _DeveloperSettingsPageState extends State { @override Widget build(BuildContext context) { + _logger.info( + "Current endpoint is: " + Configuration.instance.getHttpEndpoint(), + ); return Scaffold( appBar: AppBar( title: Text(context.l10n.developerSettings), @@ -33,22 +38,23 @@ class _DeveloperSettingsPageState extends State { children: [ TextField( controller: _urlController, - decoration: const InputDecoration( + decoration: InputDecoration( labelText: 'Server Endpoint', - hintText: 'https://api.ente.io:443', + hintText: Configuration.instance.getHttpEndpoint(), ), autofocus: true, ), const SizedBox(height: 40), GradientButton( - onTap: () { + onTap: () async { String url = _urlController.text; _logger.info("Entered endpoint: " + url); try { final uri = Uri.parse(url); - if ((uri.scheme == "http" || uri.scheme == "https") && - (uri.hasPort || !uri.hasPort)) { - // TODO: Save the URL + if ((uri.scheme == "http" || uri.scheme == "https")) { + await Configuration.instance.setHttpEndpoint(url); + showToast(context, context.l10n.endpointUpdatedMessage); + Navigator.of(context).pop(); } else { throw const FormatException(); } From a45129b75bb75c672ac99c52c97bf35c0b865776 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Wed, 6 Mar 2024 20:33:18 +0530 Subject: [PATCH 05/12] Make sure Network uses the latest network configuration --- auth/lib/core/network.dart | 49 ++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/auth/lib/core/network.dart b/auth/lib/core/network.dart index b9fba1cd8c..1942fcbb83 100644 --- a/auth/lib/core/network.dart +++ b/auth/lib/core/network.dart @@ -2,28 +2,24 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:ente_auth/core/configuration.dart'; -import 'package:ente_auth/core/constants.dart'; +import 'package:ente_auth/core/event_bus.dart'; +import 'package:ente_auth/events/endpoint_updated_event.dart'; import 'package:fk_user_agent/fk_user_agent.dart'; import 'package:flutter/foundation.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:uuid/uuid.dart'; int kConnectTimeout = 15000; class Network { - // apiEndpoint points to the Ente server's API endpoint - static const apiEndpoint = String.fromEnvironment( - "endpoint", - defaultValue: kDefaultProductionEndpoint, - ); late Dio _dio; late Dio _enteDio; Future init() async { await FkUserAgent.init(); final packageInfo = await PackageInfo.fromPlatform(); - final preferences = await SharedPreferences.getInstance(); + final endpoint = Configuration.instance.getHttpEndpoint(); + _dio = Dio( BaseOptions( connectTimeout: kConnectTimeout, @@ -34,10 +30,10 @@ class Network { }, ), ); - _dio.interceptors.add(RequestIdInterceptor()); + _enteDio = Dio( BaseOptions( - baseUrl: apiEndpoint, + baseUrl: endpoint, connectTimeout: kConnectTimeout, headers: { HttpHeaders.userAgentHeader: FkUserAgent.userAgent, @@ -46,7 +42,13 @@ class Network { }, ), ); - _enteDio.interceptors.add(EnteRequestInterceptor(preferences, apiEndpoint)); + _setupInterceptors(endpoint); + + Bus.instance.on().listen((event) { + final endpoint = Configuration.instance.getHttpEndpoint(); + _enteDio.options.baseUrl = endpoint; + _setupInterceptors(endpoint); + }); } Network._privateConstructor(); @@ -55,34 +57,41 @@ class Network { Dio getDio() => _dio; Dio get enteDio => _enteDio; + + void _setupInterceptors(String endpoint) { + _dio.interceptors.clear(); + _dio.interceptors.add(RequestIdInterceptor()); + + _enteDio.interceptors.clear(); + _enteDio.interceptors.add(EnteRequestInterceptor(endpoint)); + } } class RequestIdInterceptor extends Interceptor { @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { - // ignore: prefer_const_constructors - options.headers.putIfAbsent("x-request-id", () => Uuid().v4().toString()); + options.headers + .putIfAbsent("x-request-id", () => const Uuid().v4().toString()); return super.onRequest(options, handler); } } class EnteRequestInterceptor extends Interceptor { - final SharedPreferences _preferences; - final String enteEndpoint; + final String endpoint; - EnteRequestInterceptor(this._preferences, this.enteEndpoint); + EnteRequestInterceptor(this.endpoint); @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { if (kDebugMode) { assert( - options.baseUrl == enteEndpoint, + options.baseUrl == endpoint, "interceptor should only be used for API endpoint", ); } - // ignore: prefer_const_constructors - options.headers.putIfAbsent("x-request-id", () => Uuid().v4().toString()); - final String? tokenValue = _preferences.getString(Configuration.tokenKey); + options.headers + .putIfAbsent("x-request-id", () => const Uuid().v4().toString()); + final String? tokenValue = Configuration.instance.getToken(); if (tokenValue != null) { options.headers.putIfAbsent("X-Auth-Token", () => tokenValue); } From 07b496be4c2f0becb78b39c59e3b78695f975e0c Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Wed, 6 Mar 2024 20:33:47 +0530 Subject: [PATCH 06/12] Ensure the AuthenticatorGateway does not cache a stale endpoint --- auth/lib/gateway/authenticator.dart | 64 +++++--------------- auth/lib/services/authenticator_service.dart | 10 +-- 2 files changed, 20 insertions(+), 54 deletions(-) diff --git a/auth/lib/gateway/authenticator.dart b/auth/lib/gateway/authenticator.dart index 1ea1bee328..ee19c79b0d 100644 --- a/auth/lib/gateway/authenticator.dart +++ b/auth/lib/gateway/authenticator.dart @@ -1,43 +1,29 @@ import 'package:dio/dio.dart'; -import 'package:ente_auth/core/configuration.dart'; import 'package:ente_auth/core/errors.dart'; +import 'package:ente_auth/core/network.dart'; import 'package:ente_auth/models/authenticator/auth_entity.dart'; import 'package:ente_auth/models/authenticator/auth_key.dart'; class AuthenticatorGateway { - final Dio _dio; - final Configuration _config; - late String _basedEndpoint; + late Dio _enteDio; - AuthenticatorGateway(this._dio, this._config) { - _basedEndpoint = _config.getHttpEndpoint() + "/authenticator"; + AuthenticatorGateway() { + _enteDio = Network.instance.enteDio; } Future createKey(String encKey, String header) async { - await _dio.post( - _basedEndpoint + "/key", + await _enteDio.post( + "/authenticator/key", data: { "encryptedKey": encKey, "header": header, }, - options: Options( - headers: { - "X-Auth-Token": _config.getToken(), - }, - ), ); } Future getKey() async { try { - final response = await _dio.get( - _basedEndpoint + "/key", - options: Options( - headers: { - "X-Auth-Token": _config.getToken(), - }, - ), - ); + final response = await _enteDio.get("/authenticator/key"); return AuthKey.fromMap(response.data); } on DioError catch (e) { if (e.response != null && (e.response!.statusCode ?? 0) == 404) { @@ -51,17 +37,12 @@ class AuthenticatorGateway { } Future createEntity(String encryptedData, String header) async { - final response = await _dio.post( - _basedEndpoint + "/entity", + final response = await _enteDio.post( + "/authenticator/entity", data: { "encryptedData": encryptedData, "header": header, }, - options: Options( - headers: { - "X-Auth-Token": _config.getToken(), - }, - ), ); return AuthEntity.fromMap(response.data); } @@ -71,50 +52,35 @@ class AuthenticatorGateway { String encryptedData, String header, ) async { - await _dio.put( - _basedEndpoint + "/entity", + await _enteDio.put( + "/authenticator/entity", data: { "id": id, "encryptedData": encryptedData, "header": header, }, - options: Options( - headers: { - "X-Auth-Token": _config.getToken(), - }, - ), ); } Future deleteEntity( String id, ) async { - await _dio.delete( - _basedEndpoint + "/entity", + await _enteDio.delete( + "/authenticator/entity", queryParameters: { "id": id, }, - options: Options( - headers: { - "X-Auth-Token": _config.getToken(), - }, - ), ); } Future> getDiff(int sinceTime, {int limit = 500}) async { try { - final response = await _dio.get( - _basedEndpoint + "/entity/diff", + final response = await _enteDio.get( + "/authenticator/entity/diff", queryParameters: { "sinceTime": sinceTime, "limit": limit, }, - options: Options( - headers: { - "X-Auth-Token": _config.getToken(), - }, - ), ); final List authEntities = []; final diff = response.data["diff"] as List; diff --git a/auth/lib/services/authenticator_service.dart b/auth/lib/services/authenticator_service.dart index cdc9a4fb31..12e8b52e0b 100644 --- a/auth/lib/services/authenticator_service.dart +++ b/auth/lib/services/authenticator_service.dart @@ -5,7 +5,6 @@ import 'dart:math'; import 'package:ente_auth/core/configuration.dart'; import 'package:ente_auth/core/errors.dart'; import 'package:ente_auth/core/event_bus.dart'; -import 'package:ente_auth/core/network.dart'; import 'package:ente_auth/events/codes_updated_event.dart'; import 'package:ente_auth/events/signed_in_event.dart'; import 'package:ente_auth/events/trigger_logout_event.dart'; @@ -26,6 +25,7 @@ enum AccountMode { online, offline, } + extension on AccountMode { bool get isOnline => this == AccountMode.online; bool get isOffline => this == AccountMode.offline; @@ -56,7 +56,7 @@ class AuthenticatorService { _prefs = await SharedPreferences.getInstance(); _db = AuthenticatorDB.instance; _offlineDb = OfflineAuthenticatorDB.instance; - _gateway = AuthenticatorGateway(Network.instance.getDio(), _config); + _gateway = AuthenticatorGateway(); if (Configuration.instance.hasConfiguredAccount()) { unawaited(onlineSync()); } @@ -154,7 +154,7 @@ class AuthenticatorService { } else { debugPrint("Skipping delete since account mode is offline"); } - if(accountMode.isOnline) { + if (accountMode.isOnline) { await _db.deleteByIDs(generatedIDs: [genID]); } else { await _offlineDb.deleteByIDs(generatedIDs: [genID]); @@ -163,7 +163,7 @@ class AuthenticatorService { Future onlineSync() async { try { - if(getAccountMode().isOffline) { + if (getAccountMode().isOffline) { debugPrint("Skipping sync since account mode is offline"); return false; } @@ -253,7 +253,7 @@ class AuthenticatorService { } Future getOrCreateAuthDataKey(AccountMode mode) async { - if(mode.isOffline) { + if (mode.isOffline) { return _config.getOfflineSecretKey()!; } if (_config.getAuthSecretKey() != null) { From 7ca217f7532a82549094c7357b0acf3d66aa71ab Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Wed, 6 Mar 2024 20:34:01 +0530 Subject: [PATCH 07/12] Update iOS project files --- auth/macos/Runner.xcodeproj/project.pbxproj | 2 +- .../Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/auth/macos/Runner.xcodeproj/project.pbxproj b/auth/macos/Runner.xcodeproj/project.pbxproj index 6d9ed401f4..cbd8b2c8a3 100644 --- a/auth/macos/Runner.xcodeproj/project.pbxproj +++ b/auth/macos/Runner.xcodeproj/project.pbxproj @@ -203,7 +203,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { diff --git a/auth/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/auth/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 3fc3ba1d45..38ba92a69c 100644 --- a/auth/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/auth/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Date: Wed, 6 Mar 2024 20:47:52 +0530 Subject: [PATCH 08/12] Extract string --- auth/lib/l10n/arb/app_en.arb | 1 + auth/lib/ui/settings/developer_settings_page.dart | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/auth/lib/l10n/arb/app_en.arb b/auth/lib/l10n/arb/app_en.arb index e3037fee43..d01e657b4a 100644 --- a/auth/lib/l10n/arb/app_en.arb +++ b/auth/lib/l10n/arb/app_en.arb @@ -412,6 +412,7 @@ "developerMode":"Developer mode", "developerModeWarning":"Are you sure that you want to modify Developer settings?", "developerSettings": "Developer settings", + "serverEndpoint": "Server endpoint", "invalidURL": "Invalid URL", "invalidURLMessage": "Sorry, the URL you entered is invalid. Please enter a valid URL and try again.", "endpointUpdatedMessage": "Endpoint updated successfully" diff --git a/auth/lib/ui/settings/developer_settings_page.dart b/auth/lib/ui/settings/developer_settings_page.dart index 0b11a30c13..4b4a763974 100644 --- a/auth/lib/ui/settings/developer_settings_page.dart +++ b/auth/lib/ui/settings/developer_settings_page.dart @@ -39,7 +39,7 @@ class _DeveloperSettingsPageState extends State { TextField( controller: _urlController, decoration: InputDecoration( - labelText: 'Server Endpoint', + labelText: context.l10n.serverEndpoint, hintText: Configuration.instance.getHttpEndpoint(), ), autofocus: true, From 7bb65af482f2ee60fcfc9cd4e899e65348191a9b Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 7 Mar 2024 12:51:18 +0530 Subject: [PATCH 09/12] /ping to validate the endpoint --- auth/lib/l10n/arb/app_en.arb | 7 +++---- auth/lib/onboarding/view/onboarding_page.dart | 4 ++-- .../ui/settings/developer_settings_page.dart | 17 +++++++++++++++-- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/auth/lib/l10n/arb/app_en.arb b/auth/lib/l10n/arb/app_en.arb index d01e657b4a..9f5674d853 100644 --- a/auth/lib/l10n/arb/app_en.arb +++ b/auth/lib/l10n/arb/app_en.arb @@ -409,11 +409,10 @@ "waitingForBrowserRequest": "Waiting for browser request...", "launchPasskeyUrlAgain": "Launch passkey URL again", "passkey": "Passkey", - "developerMode":"Developer mode", - "developerModeWarning":"Are you sure that you want to modify Developer settings?", + "developerSettingsWarning":"Are you sure that you want to modify Developer settings?", "developerSettings": "Developer settings", "serverEndpoint": "Server endpoint", - "invalidURL": "Invalid URL", - "invalidURLMessage": "Sorry, the URL you entered is invalid. Please enter a valid URL and try again.", + "invalidEndpoint": "Invalid endpoint", + "invalidEndpointMessage": "Sorry, the endpoint you entered is invalid. Please enter a valid endpoint and try again.", "endpointUpdatedMessage": "Endpoint updated successfully" } \ No newline at end of file diff --git a/auth/lib/onboarding/view/onboarding_page.dart b/auth/lib/onboarding/view/onboarding_page.dart index 97b6f698c4..d8c359ecc4 100644 --- a/auth/lib/onboarding/view/onboarding_page.dart +++ b/auth/lib/onboarding/view/onboarding_page.dart @@ -68,9 +68,9 @@ class _OnboardingPageState extends State { _developerModeTapCount = 0; final result = await showChoiceDialog( context, - title: l10n.developerMode, + title: l10n.developerSettings, firstButtonLabel: l10n.yes, - body: l10n.developerModeWarning, + body: l10n.developerSettingsWarning, isDismissible: false, ); if (result?.action == ButtonAction.first) { diff --git a/auth/lib/ui/settings/developer_settings_page.dart b/auth/lib/ui/settings/developer_settings_page.dart index 4b4a763974..1f263e5e9d 100644 --- a/auth/lib/ui/settings/developer_settings_page.dart +++ b/auth/lib/ui/settings/developer_settings_page.dart @@ -1,3 +1,4 @@ +import 'package:dio/dio.dart'; import 'package:ente_auth/core/configuration.dart'; import 'package:ente_auth/l10n/l10n.dart'; import 'package:ente_auth/ui/common/gradient_button.dart'; @@ -52,6 +53,7 @@ class _DeveloperSettingsPageState extends State { try { final uri = Uri.parse(url); if ((uri.scheme == "http" || uri.scheme == "https")) { + await _ping(url); await Configuration.instance.setHttpEndpoint(url); showToast(context, context.l10n.endpointUpdatedMessage); Navigator.of(context).pop(); @@ -61,8 +63,8 @@ class _DeveloperSettingsPageState extends State { } catch (e) { showErrorDialog( context, - context.l10n.invalidURL, - context.l10n.invalidURLMessage, + context.l10n.invalidEndpoint, + context.l10n.invalidEndpointMessage, ); } }, @@ -73,4 +75,15 @@ class _DeveloperSettingsPageState extends State { ), ); } + + Future _ping(String endpoint) async { + try { + final response = await Dio().get(endpoint + '/ping'); + if (response.data['message'] != 'pong') { + throw Exception('Invalid response'); + } + } catch (e) { + throw Exception('Error occurred: $e'); + } + } } From 293246ce924662c589e6aeeec35252ea0b4e03dd Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 7 Mar 2024 13:10:24 +0530 Subject: [PATCH 10/12] Show configured endpoint on OnboardingPage --- auth/lib/l10n/arb/app_en.arb | 3 ++- auth/lib/onboarding/view/onboarding_page.dart | 26 ++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/auth/lib/l10n/arb/app_en.arb b/auth/lib/l10n/arb/app_en.arb index 9f5674d853..9528a2fc41 100644 --- a/auth/lib/l10n/arb/app_en.arb +++ b/auth/lib/l10n/arb/app_en.arb @@ -414,5 +414,6 @@ "serverEndpoint": "Server endpoint", "invalidEndpoint": "Invalid endpoint", "invalidEndpointMessage": "Sorry, the endpoint you entered is invalid. Please enter a valid endpoint and try again.", - "endpointUpdatedMessage": "Endpoint updated successfully" + "endpointUpdatedMessage": "Endpoint updated successfully", + "customEndpoint": "Connecting to {endpoint}" } \ No newline at end of file diff --git a/auth/lib/onboarding/view/onboarding_page.dart b/auth/lib/onboarding/view/onboarding_page.dart index d8c359ecc4..4d7ca79985 100644 --- a/auth/lib/onboarding/view/onboarding_page.dart +++ b/auth/lib/onboarding/view/onboarding_page.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:ente_auth/app/view/app.dart'; import 'package:ente_auth/core/configuration.dart'; +import 'package:ente_auth/core/constants.dart'; import 'package:ente_auth/core/event_bus.dart'; import 'package:ente_auth/ente_theme_data.dart'; import 'package:ente_auth/events/trigger_logout_event.dart'; @@ -74,13 +75,14 @@ class _OnboardingPageState extends State { isDismissible: false, ); if (result?.action == ButtonAction.first) { - Navigator.of(context).push( + await Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) { return const DeveloperSettingsPage(); }, ), ); + setState(() {}); } } }, @@ -193,6 +195,28 @@ class _OnboardingPageState extends State { ), ), ), + Configuration.instance.getHttpEndpoint() == + kDefaultProductionEndpoint + ? const SizedBox.shrink() + : Container( + width: double.infinity, + padding: const EdgeInsets.only(top: 20, bottom: 20), + child: GestureDetector( + onTap: _optForOfflineMode, + child: Center( + child: Text( + context.l10n.customEndpoint( + Configuration.instance.getHttpEndpoint(), + ), + style: body.copyWith( + color: Theme.of(context) + .colorScheme + .subTextColor, + ), + ), + ), + ), + ), ], ), ), From b9078eadc0f2fa025a0d52eb176ad6094759cd51 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 7 Mar 2024 13:19:26 +0530 Subject: [PATCH 11/12] Show custom endpoint within Settings --- auth/lib/l10n/arb/app_en.arb | 2 +- .../settings/developer_settings_widget.dart | 27 +++++++++++++++++++ auth/lib/ui/settings_page.dart | 2 ++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 auth/lib/ui/settings/developer_settings_widget.dart diff --git a/auth/lib/l10n/arb/app_en.arb b/auth/lib/l10n/arb/app_en.arb index 9528a2fc41..d67473d823 100644 --- a/auth/lib/l10n/arb/app_en.arb +++ b/auth/lib/l10n/arb/app_en.arb @@ -415,5 +415,5 @@ "invalidEndpoint": "Invalid endpoint", "invalidEndpointMessage": "Sorry, the endpoint you entered is invalid. Please enter a valid endpoint and try again.", "endpointUpdatedMessage": "Endpoint updated successfully", - "customEndpoint": "Connecting to {endpoint}" + "customEndpoint": "Connected to {endpoint}" } \ No newline at end of file diff --git a/auth/lib/ui/settings/developer_settings_widget.dart b/auth/lib/ui/settings/developer_settings_widget.dart new file mode 100644 index 0000000000..0fb32301ca --- /dev/null +++ b/auth/lib/ui/settings/developer_settings_widget.dart @@ -0,0 +1,27 @@ +import 'package:ente_auth/core/configuration.dart'; +import 'package:ente_auth/core/constants.dart'; +import 'package:ente_auth/l10n/l10n.dart'; +import 'package:flutter/material.dart'; + +class DeveloperSettingsWidget extends StatelessWidget { + const DeveloperSettingsWidget({super.key}); + + @override + Widget build(BuildContext context) { + final endpoint = Configuration.instance.getHttpEndpoint(); + if (endpoint != kDefaultProductionEndpoint) { + final endpointURI = Uri.parse(endpoint); + return Padding( + padding: const EdgeInsets.only(bottom: 20), + child: Text( + context.l10n.customEndpoint( + endpointURI.host + ":" + endpointURI.port.toString(), + ), + style: Theme.of(context).textTheme.bodySmall, + ), + ); + } else { + return const SizedBox.shrink(); + } + } +} diff --git a/auth/lib/ui/settings_page.dart b/auth/lib/ui/settings_page.dart index e5df8fcc31..cfe5ba874f 100644 --- a/auth/lib/ui/settings_page.dart +++ b/auth/lib/ui/settings_page.dart @@ -16,6 +16,7 @@ import 'package:ente_auth/ui/settings/account_section_widget.dart'; import 'package:ente_auth/ui/settings/app_version_widget.dart'; import 'package:ente_auth/ui/settings/data/data_section_widget.dart'; import 'package:ente_auth/ui/settings/data/export_widget.dart'; +import 'package:ente_auth/ui/settings/developer_settings_widget.dart'; import 'package:ente_auth/ui/settings/general_section_widget.dart'; import 'package:ente_auth/ui/settings/security_section_widget.dart'; import 'package:ente_auth/ui/settings/social_section_widget.dart'; @@ -149,6 +150,7 @@ class SettingsPage extends StatelessWidget { sectionSpacing, const AboutSectionWidget(), const AppVersionWidget(), + const DeveloperSettingsWidget(), const SupportDevWidget(), const Padding( padding: EdgeInsets.only(bottom: 60), From fe0697fccb7e36a3d8b4676ec5e83328befe71ea Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 7 Mar 2024 13:22:13 +0530 Subject: [PATCH 12/12] Reuse existing widget to render the custom endpoint (if any) --- auth/lib/onboarding/view/onboarding_page.dart | 25 ++----------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/auth/lib/onboarding/view/onboarding_page.dart b/auth/lib/onboarding/view/onboarding_page.dart index 4d7ca79985..7ae5ede1c1 100644 --- a/auth/lib/onboarding/view/onboarding_page.dart +++ b/auth/lib/onboarding/view/onboarding_page.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:ente_auth/app/view/app.dart'; import 'package:ente_auth/core/configuration.dart'; -import 'package:ente_auth/core/constants.dart'; import 'package:ente_auth/core/event_bus.dart'; import 'package:ente_auth/ente_theme_data.dart'; import 'package:ente_auth/events/trigger_logout_event.dart'; @@ -19,6 +18,7 @@ import 'package:ente_auth/ui/components/buttons/button_widget.dart'; import 'package:ente_auth/ui/components/models/button_result.dart'; import 'package:ente_auth/ui/home_page.dart'; import 'package:ente_auth/ui/settings/developer_settings_page.dart'; +import 'package:ente_auth/ui/settings/developer_settings_widget.dart'; import 'package:ente_auth/ui/settings/language_picker.dart'; import 'package:ente_auth/utils/dialog_util.dart'; import 'package:ente_auth/utils/navigation_util.dart'; @@ -195,28 +195,7 @@ class _OnboardingPageState extends State { ), ), ), - Configuration.instance.getHttpEndpoint() == - kDefaultProductionEndpoint - ? const SizedBox.shrink() - : Container( - width: double.infinity, - padding: const EdgeInsets.only(top: 20, bottom: 20), - child: GestureDetector( - onTap: _optForOfflineMode, - child: Center( - child: Text( - context.l10n.customEndpoint( - Configuration.instance.getHttpEndpoint(), - ), - style: body.copyWith( - color: Theme.of(context) - .colorScheme - .subTextColor, - ), - ), - ), - ), - ), + const DeveloperSettingsWidget(), ], ), ),