fix(extensions): trust only bootstrapped extension ids (#5094)
This commit is contained in:
1 parent
07ed67a793
commit
cb96a5cf39
4 files changed
+75
-29
No files matched your search
+12
-1
@@ -1115,7 +1115,18 @@ def get_extension_config() -> Dict[str, Any]:
|
||||
_EXTENSION_STYLESHEET_URLS_ENV, manifest_stylesheets or None
|
||||
),
|
||||
}
|
||||
runtime_entries = _extension_runtime_entries(manifest, disabled_ids) if manifest is not None else []
|
||||
runtime_entries: List[Dict[str, object]] = []
|
||||
if manifest is not None:
|
||||
extension_state = _manifest_extension_state(manifest, disabled_ids)
|
||||
runtime_entries = [
|
||||
{
|
||||
"id": entry["id"],
|
||||
"name": entry["name"],
|
||||
"storage_owned": entry["storage_owned"],
|
||||
"settings_schema": entry["settings_schema"],
|
||||
}
|
||||
for entry in extension_state["extensions"]
|
||||
]
|
||||
if runtime_entries:
|
||||
config["extensions"] = runtime_entries
|
||||
return config
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
const STORAGE_PREFIX='hermes.ext.storage.';
|
||||
const FIELD_TYPES=new Set(['boolean','string','number','integer','enum']);
|
||||
const schemas=new Map();
|
||||
const trustedExtensions=new Map();
|
||||
let trustedSeeded=false;
|
||||
|
||||
function extensionId(value){
|
||||
return String(value||'').trim();
|
||||
@@ -115,9 +117,28 @@
|
||||
}
|
||||
|
||||
function primeFromStatus(statusPayload){
|
||||
const entries=normalizeSchemas(statusPayload&&statusPayload.extensions);
|
||||
if(!trustedSeeded){
|
||||
trustedExtensions.clear();
|
||||
for(const entry of entries){
|
||||
trustedExtensions.set(entry.id,{
|
||||
id:entry.id,
|
||||
name:entry.name,
|
||||
storage_owned:entry.storage_owned,
|
||||
});
|
||||
}
|
||||
trustedSeeded=true;
|
||||
}
|
||||
schemas.clear();
|
||||
for(const entry of normalizeSchemas(statusPayload&&statusPayload.extensions)){
|
||||
schemas.set(entry.id,entry);
|
||||
for(const entry of entries){
|
||||
const trusted=trustedExtensions.get(entry.id);
|
||||
if(!trusted) continue;
|
||||
schemas.set(entry.id,{
|
||||
id:entry.id,
|
||||
name:entry.name,
|
||||
storage_owned:trusted.storage_owned===true,
|
||||
settings_schema:trusted.storage_owned===true?entry.settings_schema:[],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -238,7 +238,13 @@ def test_extension_manifest_adds_bundled_assets_before_env_urls(tmp_path, monkey
|
||||
"name": "templates",
|
||||
"storage_owned": False,
|
||||
"settings_schema": [],
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "disabled",
|
||||
"name": "disabled",
|
||||
"storage_owned": False,
|
||||
"settings_schema": [],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,26 @@ def test_extension_settings_runtime_normalizes_persists_resets_and_clears():
|
||||
const assert = require('assert');
|
||||
const store = new Map();
|
||||
global.window = {{
|
||||
__HERMES_EXTENSION_CONFIG__: {{
|
||||
extensions: [{{
|
||||
id: 'demo.ext',
|
||||
name: 'Demo',
|
||||
storage_owned: true,
|
||||
settings_schema: [
|
||||
{{key: 'flag', type: 'boolean', default: false}},
|
||||
{{key: 'mode', type: 'enum', options: ['compact', {{value: 'full', label: 'Full'}}], default: 'compact'}},
|
||||
{{key: 'count', type: 'integer', default: 2}},
|
||||
{{key: 'secret', type: 'string', sensitive: true, default: 'x'}},
|
||||
{{key: 'bad', type: 'enum', options: [{{label: 'missing value'}}]}},
|
||||
{{key: 'flag', type: 'boolean', default: true}}
|
||||
]
|
||||
}}, {{
|
||||
id: 'denied.ext',
|
||||
name: 'Denied',
|
||||
storage_owned: false,
|
||||
settings_schema: [{{key: 'flag', type: 'boolean', default: false}}],
|
||||
}}]
|
||||
}},
|
||||
localStorage: {{
|
||||
getItem(key) {{ return store.has(key) ? store.get(key) : null; }},
|
||||
setItem(key, value) {{ store.set(key, String(value)); }},
|
||||
@@ -42,22 +62,6 @@ def test_extension_settings_runtime_normalizes_persists_resets_and_clears():
|
||||
}};
|
||||
eval(fs.readFileSync({str(EXTENSION_SETTINGS_JS)!r}, 'utf8'));
|
||||
|
||||
window.HermesExtensionSettings.primeFromStatus({{
|
||||
extensions: [{{
|
||||
id: 'demo.ext',
|
||||
name: 'Demo',
|
||||
storage_owned: true,
|
||||
settings_schema: [
|
||||
{{key: 'flag', type: 'boolean', default: false}},
|
||||
{{key: 'mode', type: 'enum', options: ['compact', {{value: 'full', label: 'Full'}}], default: 'compact'}},
|
||||
{{key: 'count', type: 'integer', default: 2}},
|
||||
{{key: 'secret', type: 'string', sensitive: true, default: 'x'}},
|
||||
{{key: 'bad', type: 'enum', options: [{{label: 'missing value'}}]}},
|
||||
{{key: 'flag', type: 'boolean', default: true}}
|
||||
]
|
||||
}}]
|
||||
}});
|
||||
|
||||
const settings = window.HermesExtensionSettings.settingsForExtension('demo.ext');
|
||||
assert.deepStrictEqual(settings.schema.map(field => field.key), ['flag', 'mode', 'count']);
|
||||
assert.deepStrictEqual(settings.values, {{flag: false, mode: 'compact', count: 2}});
|
||||
@@ -76,15 +80,6 @@ def test_extension_settings_runtime_normalizes_persists_resets_and_clears():
|
||||
assert.strictEqual(storage.clear(), true);
|
||||
assert.strictEqual(store.has('hermes.ext.storage.demo.ext'), false);
|
||||
|
||||
window.HermesExtensionSettings.primeFromStatus({{
|
||||
extensions: [{{
|
||||
id: 'denied.ext',
|
||||
name: 'Denied',
|
||||
storage_owned: false,
|
||||
settings_schema: [{{key: 'flag', type: 'boolean', default: false}}],
|
||||
}}]
|
||||
}});
|
||||
|
||||
const deniedSettings = window.HermesExtensionSettings.settingsForExtension('denied.ext');
|
||||
assert.strictEqual(deniedSettings.setAll({{flag: true}}).ok, false);
|
||||
assert.strictEqual(store.has('hermes.ext.settings.denied.ext'), false);
|
||||
@@ -92,6 +87,19 @@ def test_extension_settings_runtime_normalizes_persists_resets_and_clears():
|
||||
const deniedStorage = window.HermesExtensionSettings.storageForExtension('denied.ext');
|
||||
assert.strictEqual(deniedStorage.set('note', 'blocked'), false);
|
||||
assert.strictEqual(store.has('hermes.ext.storage.denied.ext'), false);
|
||||
|
||||
window.HermesExtensionSettings.primeFromStatus({{
|
||||
extensions: [{{
|
||||
id: 'unknown.ext',
|
||||
name: 'Unknown',
|
||||
storage_owned: true,
|
||||
settings_schema: [{{key: 'flag', type: 'boolean', default: false}}],
|
||||
}}]
|
||||
}});
|
||||
|
||||
const unknownSettings = window.HermesExtensionSettings.settingsForExtension('unknown.ext');
|
||||
assert.strictEqual(unknownSettings.setAll({{flag: true}}).ok, false);
|
||||
assert.strictEqual(store.has('hermes.ext.settings.unknown.ext'), false);
|
||||
"""
|
||||
)
|
||||
_run_node(script)
|
||||
Reference in new issue
Block a user