mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-01 19:21:34 -07:00
fix(anime): harden the extension bridge against untrusted repos and hangs
Addresses CodeRabbit review feedback on the Anime Browser: - reject repository package/apk names that are not plain identifiers, and verify the install target resolves inside the extensions directory - count mpv's %n% option escape in UTF-8 bytes, and escape backslashes in header values so a trailing one cannot eat the list separator - key the bridge extension-id cache by APK content, so an in-place upgrade re-uploads instead of running the previous build - bound every bridge, release-listing, and download request with a timeout - enforce the APK size limit while streaming rather than after buffering - read APK bytes on demand instead of holding a base64 copy per extension for the lifetime of the browser - serialize preference mutations and write the file atomically - handle the sidecar spawn error event, and wait for the child to exit in stop() before returning - report a failed Anime Browser bootstrap instead of showing the starting banner forever - keep the preferences panel's save confirmation and in-flight multi-select edits by re-rendering only on a structural schema change
This commit is contained in:
+18
-11
@@ -488,18 +488,25 @@ api.onBridgeState(renderBridgeState);
|
||||
|
||||
void (async () => {
|
||||
renderBridgeState({ stage: 'idle', progress: null, message: null });
|
||||
const state = await api.ensureBridge();
|
||||
renderBridgeState(state);
|
||||
try {
|
||||
const state = await api.ensureBridge();
|
||||
renderBridgeState(state);
|
||||
|
||||
const snapshot = await api.getSnapshot();
|
||||
renderSources(snapshot.sources, snapshot.selectedSourceId);
|
||||
const snapshot = await api.getSnapshot();
|
||||
renderSources(snapshot.sources, snapshot.selectedSourceId);
|
||||
|
||||
if (state.stage === 'ready' && snapshot.sources.length > 0) {
|
||||
searchInput.focus();
|
||||
await runSearch('');
|
||||
} else if (state.stage === 'ready') {
|
||||
setStatus(state.message ?? 'No extensions installed.', 'error');
|
||||
} else {
|
||||
setStatus(state.message ?? 'The extension bridge is not available.', 'error');
|
||||
if (state.stage === 'ready' && snapshot.sources.length > 0) {
|
||||
searchInput.focus();
|
||||
await runSearch('');
|
||||
} else if (state.stage === 'ready') {
|
||||
setStatus(state.message ?? 'No extensions installed.', 'error');
|
||||
} else {
|
||||
setStatus(state.message ?? 'The extension bridge is not available.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
// Without this the window keeps the "starting" banner up forever, with the
|
||||
// search box disabled and nothing saying why.
|
||||
renderBridgeState({ stage: 'failed', progress: null, message: describe(error) });
|
||||
setStatus(describe(error), 'error');
|
||||
}
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user