From 7c67223ea05857bad77d7863f6b84cf45b349819 Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Mon, 27 Jul 2026 06:21:11 +0300 Subject: [PATCH] fix(theme): default remote install to kDebugMode for localhost policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #399 — release builds no longer allow localhost/private IPs via ThemeRemoteInstallService constructor default. --- .../theme/theme_remote_install_service.dart | 3 ++- .../theme_remote_install_service_test.dart | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/core/theme/theme_remote_install_service.dart b/lib/core/theme/theme_remote_install_service.dart index 061c27c3..fa958c89 100644 --- a/lib/core/theme/theme_remote_install_service.dart +++ b/lib/core/theme/theme_remote_install_service.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:crypto/crypto.dart'; +import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:path/path.dart' as p; @@ -27,7 +28,7 @@ class ThemeRemoteInstallService { this._registry, { Future Function(Uri uri)? httpGet, Duration timeout = const Duration(seconds: 30), - bool allowLocalhostInDebug = true, + bool allowLocalhostInDebug = kDebugMode, }) : _httpGet = httpGet ?? _defaultHttpGet, _timeout = timeout, _allowLocalhostInDebug = allowLocalhostInDebug; diff --git a/test/core/theme/theme_remote_install_service_test.dart b/test/core/theme/theme_remote_install_service_test.dart index 04adc8b6..ad80b0cb 100644 --- a/test/core/theme/theme_remote_install_service_test.dart +++ b/test/core/theme/theme_remote_install_service_test.dart @@ -164,6 +164,32 @@ void main() { expect(result, isA()); }); + test('rejects localhost URLs when release policy is enforced', () async { + final service = ThemeRemoteInstallService( + registry, + allowLocalhostInDebug: false, + ); + final result = await service.installFromUrl( + 'https://127.0.0.1/theme.json', + ); + expect(result, isA()); + expect( + (result as ThemeDefinitionImportFailure).message, + contains('Only public HTTPS theme URLs are allowed'), + ); + }); + + test('rejects private IPv4 URLs when release policy is enforced', () async { + final service = ThemeRemoteInstallService( + registry, + allowLocalhostInDebug: false, + ); + final result = await service.installFromUrl( + 'https://192.168.1.10/theme.json', + ); + expect(result, isA()); + }); + test('reuses existing file when remote content hash matches', () async { final raw = await File('test/fixtures/themes/querya_custom_dark.json') .readAsString();