@@ -3,6 +3,7 @@ import 'dart:convert';
33import 'dart:io' ;
44import 'package:archive/archive.dart' ;
55import 'package:crypto/crypto.dart' ;
6+ import 'package:flutter/foundation.dart' ;
67import 'package:http/http.dart' as http;
78import 'package:path/path.dart' as p;
89import 'package:querya_desktop/core/extensions/extension_support.dart' ;
@@ -11,6 +12,7 @@ import 'package:querya_desktop/core/extensions/sandbox/sandbox_policy.dart';
1112import 'package:querya_desktop/core/extensions/local_extension_registry.dart' ;
1213import 'package:querya_desktop/core/extensions/models/extension_manifest.dart' ;
1314import 'package:querya_desktop/core/extensions/models/extension_type.dart' ;
15+ import 'marketplace_download_policy.dart' ;
1416import 'marketplace_repository.dart' ;
1517
1618/// HTTP implementation of [MarketplaceRepository] connecting to MarketApi backend.
@@ -21,13 +23,46 @@ class HttpMarketplaceRepository implements MarketplaceRepository {
2123 HttpMarketplaceRepository ({
2224 this .baseUrl = 'http://localhost:8000/api/v1' ,
2325 http.Client ? client,
24- }) : _client = client ?? http.Client ();
26+ Iterable <String > extraTrustedDownloadHosts = const [],
27+ bool allowLocalhostInDebug = kDebugMode,
28+ }) : _client = client ?? http.Client (),
29+ _allowLocalhostInDebug = allowLocalhostInDebug,
30+ _trustedDownloadHosts = MarketplaceDownloadPolicy .trustedHostsFor (
31+ apiBaseUrl: baseUrl,
32+ extraTrustedHosts: extraTrustedDownloadHosts,
33+ ) {
34+ _validateApiBaseUrl ();
35+ }
2536
2637 final String baseUrl;
2738 final http.Client _client;
39+ final bool _allowLocalhostInDebug;
40+ final Set <String > _trustedDownloadHosts;
41+
42+ void _validateApiBaseUrl () {
43+ if (! MarketplaceDownloadPolicy .isAllowedApiBaseUrl (
44+ baseUrl,
45+ allowLocalhostInDebug: _allowLocalhostInDebug,
46+ )) {
47+ throw MarketplaceException (
48+ 'Marketplace API base URL is not allowed: $baseUrl ' ,
49+ );
50+ }
51+ }
52+
53+ void _validateDownloadUrl (Uri uri) {
54+ if (! MarketplaceDownloadPolicy .isAllowedDownloadUrl (
55+ uri,
56+ trustedHosts: _trustedDownloadHosts,
57+ allowLocalhostInDebug: _allowLocalhostInDebug,
58+ )) {
59+ throw MarketplaceException ('Download URL is not allowed: $uri ' );
60+ }
61+ }
2862
2963 @override
3064 Future <List <ExtensionManifest >> getTrending ({ExtensionType ? type}) async {
65+ _validateApiBaseUrl ();
3166 final uri = Uri .parse ('$baseUrl /extensions/trending' ).replace (
3267 queryParameters: type != null ? {'type' : type.value} : null ,
3368 );
@@ -41,6 +76,7 @@ class HttpMarketplaceRepository implements MarketplaceRepository {
4176
4277 @override
4378 Future <List <ExtensionManifest >> search (String query, {ExtensionType ? type}) async {
79+ _validateApiBaseUrl ();
4480 final uri = Uri .parse ('$baseUrl /extensions/search' ).replace (
4581 queryParameters: {
4682 'q' : query.trim (),
@@ -61,6 +97,7 @@ class HttpMarketplaceRepository implements MarketplaceRepository {
6197 if (uri == null ) {
6298 throw MarketplaceException ('Invalid download URL: $url ' );
6399 }
100+ _validateDownloadUrl (uri);
64101
65102 final request = http.Request ('GET' , uri);
66103 final response = await _client.send (request).timeout (const Duration (seconds: 30 ));
0 commit comments