Skip to content

Commit a2c8779

Browse files
committed
refactor(cdn): improve secret management and artifact handling in CdnDefinitionProvider
- Enhanced the _applySecretsFromRoot method to ensure runtime secrets are cleared when no artifacts are present. - Updated secret retrieval logic to prioritize asset environment variables and handle dotenv initialization more robustly. - Removed redundant calls to _applySecretsFromRoot in manifest processing to streamline the workflow. - Introduced a flag to track successful fetching of encrypted manifests, improving error handling during HTTP requests.
1 parent 4266918 commit a2c8779

1 file changed

Lines changed: 28 additions & 9 deletions

File tree

modules/ensemble/lib/framework/definition_providers/cdn_provider.dart

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,22 @@ class CdnDefinitionProvider extends DefinitionProvider {
144144

145145
void _applySecretsFromRoot(Map<String, dynamic> root) {
146146
final artifacts = _asMap(root['artifacts']);
147-
if (artifacts == null) return;
147+
if (artifacts == null) {
148+
// No artifacts -> ensure runtime secrets can't linger.
149+
if (_runtimeSecrets.isNotEmpty) {
150+
_assetEnv?.removeWhere((k, _) => _runtimeSecrets.containsKey(k));
151+
_runtimeSecrets.clear();
152+
}
153+
return;
154+
}
148155

149156
// Per requirement: artifacts.secrets is a flat key/value mapping.
150157
final rawSecrets = _asMap(artifacts['secrets']);
158+
// Always replace runtime secrets on refresh so deleted keys don't linger.
159+
if (_runtimeSecrets.isNotEmpty) {
160+
_assetEnv?.removeWhere((k, _) => _runtimeSecrets.containsKey(k));
161+
_runtimeSecrets.clear();
162+
}
151163
if (rawSecrets == null || rawSecrets.isEmpty) return;
152164

153165
rawSecrets.forEach((k, v) {
@@ -212,7 +224,6 @@ class CdnDefinitionProvider extends DefinitionProvider {
212224
if (cachedManifest != null && cachedManifest.isNotEmpty) {
213225
try {
214226
final root = _decodeManifestRoot(cachedManifest);
215-
_applySecretsFromRoot(root);
216227
_rebuildFromRoot(root);
217228
} catch (e) {
218229
// Clear invalid cache
@@ -280,13 +291,20 @@ class CdnDefinitionProvider extends DefinitionProvider {
280291
}
281292

282293
bool _hasEncryptionKey() {
283-
final key = (_assetEnv ?? const {})['ENSEMBLE_ENCRYPTION_KEY'] ??
284-
dotenv.env['ENSEMBLE_ENCRYPTION_KEY'];
285-
return key != null && key.trim().isNotEmpty;
294+
final fromAssets = (_assetEnv ?? const {})['ENSEMBLE_ENCRYPTION_KEY'];
295+
if (fromAssets != null && fromAssets.trim().isNotEmpty) return true;
296+
297+
if (!dotenv.isInitialized) return false;
298+
final fromDotenv = dotenv.env['ENSEMBLE_ENCRYPTION_KEY'];
299+
return fromDotenv != null && fromDotenv.trim().isNotEmpty;
286300
}
287301

288302
String? _getSecret(String name) {
289-
return (_assetEnv ?? const {})[name] ?? dotenv.env[name];
303+
final fromAssets = (_assetEnv ?? const {})[name];
304+
if (fromAssets != null) return fromAssets;
305+
306+
if (!dotenv.isInitialized) return null;
307+
return dotenv.env[name];
290308
}
291309

292310
static Uint8List _b64UrlDecode(String input) {
@@ -461,7 +479,6 @@ class CdnDefinitionProvider extends DefinitionProvider {
461479
final newEtag = fetched['etag'] as String?;
462480
final root = _decodeManifestRoot(jsonString);
463481

464-
_applySecretsFromRoot(root);
465482
_rebuildFromRoot(root);
466483
await _refreshTranslationsAtRuntime();
467484
_etag = newEtag ?? _etag;
@@ -510,7 +527,6 @@ class CdnDefinitionProvider extends DefinitionProvider {
510527
_etag = fetched['etag'] as String?;
511528

512529
final root = _decodeManifestRoot(jsonString);
513-
_applySecretsFromRoot(root);
514530
_rebuildFromRoot(root);
515531

516532
// Save to persistent cache
@@ -567,6 +583,7 @@ class CdnDefinitionProvider extends DefinitionProvider {
567583
}
568584

569585
http.Response resp;
586+
var fetchedEncrypted = false;
570587
if (shouldUseEncrypted) {
571588
final encryptedHeaders = Map<String, String>.from(headers);
572589
final manifestKey = _getSecret('ENSEMBLE_MANIFEST_KEY');
@@ -575,6 +592,7 @@ class CdnDefinitionProvider extends DefinitionProvider {
575592
}
576593

577594
resp = await http.get(encryptedUri, headers: encryptedHeaders);
595+
fetchedEncrypted = resp.statusCode != 404;
578596
// If encrypted manifest doesn't exist for this app, fall back to plain.
579597
if (resp.statusCode == 404) {
580598
resp = await http.get(plainUri, headers: headers);
@@ -597,7 +615,7 @@ class CdnDefinitionProvider extends DefinitionProvider {
597615
String jsonString = decodedBody;
598616

599617
// If we fetched the encrypted-manifest endpoint successfully, decrypt it.
600-
if (shouldUseEncrypted && resp.request?.url == encryptedUri) {
618+
if (shouldUseEncrypted && fetchedEncrypted) {
601619
jsonString = _decryptEncryptedManifestEnvelope(decodedBody);
602620
}
603621
if (jsonString.isEmpty) return null;
@@ -634,6 +652,7 @@ class CdnDefinitionProvider extends DefinitionProvider {
634652
_themeMapping = null;
635653
_defaultLocale = null;
636654
_appConfig = null;
655+
_applySecretsFromRoot(root);
637656

638657
final artifacts = _asMap(root['artifacts']);
639658
if (artifacts == null) return;

0 commit comments

Comments
 (0)