mirror of
https://github.com/thegeneralist01/archivr
synced 2026-07-22 03:05:32 +02:00
feat: integrate Modal Closer as injected browser script (#27)
Port the modalcloser abx-plugin as a SingleFile --browser-script rather
than a spawned Puppeteer daemon. No external extension download required.
Core behavior (singlefile.rs):
- MODAL_CLOSER_DIALOG_OVERRIDES: main-world <script> bridge (best-effort;
blocked by strict script-src CSP) that overrides window.alert/confirm/
prompt/print, nulls window.onbeforeunload, traps its setter, and wraps
window.addEventListener to no-op 'beforeunload' registrations.
- MODAL_CLOSER_POLLING_SETUP: defines _archivr_mc_run() which runs two
passes on every tick (immediate first run, then setInterval every 500 ms
matching MODALCLOSER_POLL_INTERVAL default):
Pass 1 (best-effort, CSP-sensitive): main-world <script> bridge calls
Bootstrap/jQuery/jQuery UI/SweetAlert teardown APIs.
Pass 2 (always, CSP-immune): isolated-world DOM mutations — Escape-key
dispatch (Radix/Headless UI/Angular Material), backdrop clicks, full
CSS selector hiding for 40+ named consent/overlay vendors, body
scroll-lock reset. Direct DOM mutations need no inline script execution.
- resolve_modal_closer_config(): reads ARCHIVR_MODAL_CLOSER env var
(default true); no external resource required.
- modal_closer_enabled: Option<bool> in CaptureConfig so Default::default()
yields None (follow env var) rather than false.
Schema (database.rs):
- modal_closer_enabled column in auth DB instance_settings (default 1).
- Idempotent ALTER TABLE migration for existing databases.
- get/update_instance_settings updated (SELECT col 6, UPDATE param ?7).
HTTP (routes.rs):
- modal_closer_enabled in CaptureBody and UpdateInstanceSettingsBody.
- Per-capture body overrides global setting which overrides env var.
Frontend:
- SettingsView ExtensionsTab: third ext-card for Modal & Dialog Closer.
- CaptureDialog: per-capture toggle in Advanced Options, state initialized
from server default, included in submitCapture payload.
- api.js: submitCapture forwards modal_closer_enabled to capture body.
Behavior vs original modalcloser daemon:
- Functionally identical on non-strict-CSP pages (the large majority).
- Gap: <script> bridge is subject to page CSP; page.evaluate() is not.
On strict-CSP pages framework teardown and dialog overrides are no-ops;
CSS selector hiding and Escape dispatch (Pass 2) always work.
- Gap: alert/confirm/prompt overridden to instant no-op vs CDP timed
dialog.accept() with 1250 ms delay; irrelevant for archival in practice.
This commit is contained in:
parent
b0d02034ea
commit
278dc928df
10 changed files with 294 additions and 63 deletions
|
|
@ -142,6 +142,8 @@ pub struct InstanceSettings {
|
|||
pub ublock_enabled: bool,
|
||||
/// Global default for cookie-consent banner dismissal via extension during WebPage captures.
|
||||
pub cookie_ext_enabled: bool,
|
||||
/// Global default for modal-closer browser-script behavior during WebPage captures.
|
||||
pub modal_closer_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
|
|
@ -468,7 +470,8 @@ pub fn initialize_auth_schema(conn: &Connection) -> Result<()> {
|
|||
public_archive_submission_enabled INTEGER NOT NULL DEFAULT 0 CHECK (public_archive_submission_enabled IN (0, 1)),
|
||||
default_entry_visibility INTEGER NOT NULL DEFAULT 2,
|
||||
ublock_enabled INTEGER NOT NULL DEFAULT 1 CHECK (ublock_enabled IN (0, 1)),
|
||||
cookie_ext_enabled INTEGER NOT NULL DEFAULT 1 CHECK (cookie_ext_enabled IN (0, 1))
|
||||
cookie_ext_enabled INTEGER NOT NULL DEFAULT 1 CHECK (cookie_ext_enabled IN (0, 1)),
|
||||
modal_closer_enabled INTEGER NOT NULL DEFAULT 1 CHECK (modal_closer_enabled IN (0, 1))
|
||||
);
|
||||
|
||||
INSERT OR IGNORE INTO instance_settings
|
||||
|
|
@ -518,6 +521,11 @@ pub fn initialize_auth_schema(conn: &Connection) -> Result<()> {
|
|||
"ALTER TABLE instance_settings ADD COLUMN cookie_ext_enabled INTEGER NOT NULL DEFAULT 1",
|
||||
[],
|
||||
);
|
||||
// Add modal_closer_enabled column to instance_settings if not present (idempotent migration)
|
||||
let _ = conn.execute(
|
||||
"ALTER TABLE instance_settings ADD COLUMN modal_closer_enabled INTEGER NOT NULL DEFAULT 1",
|
||||
[],
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -745,7 +753,8 @@ pub fn get_instance_settings(conn: &Connection) -> Result<InstanceSettings> {
|
|||
"SELECT public_index_enabled, public_entry_content_enabled,
|
||||
public_archive_submission_enabled, default_entry_visibility,
|
||||
COALESCE(ublock_enabled, 1),
|
||||
COALESCE(cookie_ext_enabled, 1)
|
||||
COALESCE(cookie_ext_enabled, 1),
|
||||
COALESCE(modal_closer_enabled, 1)
|
||||
FROM instance_settings WHERE id = 1",
|
||||
[],
|
||||
|row| {
|
||||
|
|
@ -756,6 +765,7 @@ pub fn get_instance_settings(conn: &Connection) -> Result<InstanceSettings> {
|
|||
default_entry_visibility: row.get::<_, i64>(3)? as u32,
|
||||
ublock_enabled: row.get::<_, i64>(4)? != 0,
|
||||
cookie_ext_enabled: row.get::<_, i64>(5)? != 0,
|
||||
modal_closer_enabled: row.get::<_, i64>(6)? != 0,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
|
@ -770,7 +780,8 @@ pub fn update_instance_settings(conn: &Connection, settings: &InstanceSettings)
|
|||
public_archive_submission_enabled = ?3,
|
||||
default_entry_visibility = ?4,
|
||||
ublock_enabled = ?5,
|
||||
cookie_ext_enabled = ?6
|
||||
cookie_ext_enabled = ?6,
|
||||
modal_closer_enabled = ?7
|
||||
WHERE id = 1",
|
||||
params![
|
||||
settings.public_index_enabled as i64,
|
||||
|
|
@ -779,6 +790,7 @@ pub fn update_instance_settings(conn: &Connection, settings: &InstanceSettings)
|
|||
settings.default_entry_visibility as i64,
|
||||
settings.ublock_enabled as i64,
|
||||
settings.cookie_ext_enabled as i64,
|
||||
settings.modal_closer_enabled as i64,
|
||||
],
|
||||
)?;
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue