Commit Graph
553 Commits
Author SHA1 Message Date
SGavrl a2fd4d1735 fix(js): parse fragments in their insertion context 2026-08-01 15:54:51 +00:00
SGavrl 35fa61032b Merge remote-tracking branch 'origin/main' into maintainer/pr-507-review 2026-08-01 15:50:23 +00:00
SGavrl 907e15d85d perf(js): avoid per-element style sync objects 2026-08-01 15:46:25 +00:00
SGavrl 82aa320084 Merge remote-tracking branch 'origin/main' into maintainer/pr-492-fix 2026-08-01 15:44:40 +00:00
SGavrl 5d7a02041a fix(js): preserve inline styles when cloning 2026-08-01 15:41:45 +00:00
SGavrl c327354911 Merge remote-tracking branch 'origin/main' into maintainer/pr-494-review 2026-08-01 15:40:11 +00:00
SGavrl 16b6a09546 Merge remote-tracking branch 'origin/main' into maintainer/pr-517-tests 2026-08-01 15:37:17 +00:00
SGavrl dbc87e86f9 test(js): cover string timer handlers 2026-08-01 15:37:17 +00:00
SGavrl b5c2f9cc4e Merge branch 'maintainer/pr-508-review' into maintainer/pr-510-review
# Conflicts:
#	crates/obscura-js/src/runtime.rs
2026-08-01 15:30:32 +00:00
SGavrl caf51975bb Merge remote-tracking branch 'origin/main' into maintainer/pr-508-review 2026-08-01 15:28:07 +00:00
SGavrl 3f5dd23778 Merge remote-tracking branch 'origin/main' into maintainer/pr-510-review 2026-08-01 15:28:02 +00:00
SGavrl d93ff517fc fix(js): keep performance clock bounded 2026-08-01 15:20:35 +00:00
h4ckf0r0day 5634386488 Update README.md 2026-08-01 01:06:22 +02:00
SGavrl d66e5ec110 Merge pull request #526 from marcoripa96/native-ca-roots
feat(net): trust platform CA roots alongside bundled webpki roots
2026-07-31 17:44:01 +00:00
SGavrl bb21452f90 Merge pull request #532 from alectimison-maker/fix/dynamic-script-data-urls
fix(js): execute dynamic data URL scripts
2026-07-31 17:43:45 +00:00
SGavrl 0def838088 Merge pull request #523 from stack3mpty/fix/missing-event-constructors-521-522
fix(js): add global PromiseRejectionEvent and StorageEvent constructors
2026-07-31 17:43:25 +00:00
SGavrl f46f741e8c fix(net): load configured CA roots without default cost 2026-07-30 21:57:18 +00:00
SGavrl 0ff1ba0ea9 fix(js): match event constructor semantics 2026-07-30 21:43:33 +00:00
SGavrl f84120591e fix(js): match Chromium data URL handling 2026-07-30 21:40:13 +00:00
alectimison-maker 0c4740a86a fix(js): execute dynamic data URL scripts
Decode JavaScript data URLs inside the serialized classic-script queue so each body runs before its load event advances a nested chain.

Fixes #520.
2026-07-31 04:44:29 +08:00
SGavrl 3a68457c0b Merge pull request #530 from lisa0314/fix/524-react-controlled-inputs
fix(mcp): fill React controlled inputs
2026-07-29 22:24:20 +00:00
h4ckf0r0day 487deac25f Repository of the day README update 2026-07-29 23:18:23 +02:00
lisa0314 6fac7f719a fix(mcp): fill React controlled inputs 2026-07-29 20:19:21 +08:00
SGavrl f153487030 Update README.md 2026-07-29 01:31:08 +02:00
SGavrl 450eaa3b88 Added sponsor logo 2026-07-28 23:27:45 +00:00
Marco Ripamonti 0522831dcc feat(net): trust platform CA roots alongside bundled webpki roots
reqwest was pinned to rustls-tls, so HTTPS only trusted the bundled
webpki roots: SSL_CERT_FILE, SSL_CERT_DIR, and the system CA store were
ignored, and obscura-net exposes no add-CA hook. Deployments behind a
TLS-inspecting egress proxy or an internal CA cannot fetch at all, and a
caching proxy in front of --proxy cannot terminate TLS.

Enable rustls-tls-native-roots alongside rustls-tls. reqwest merges the
two root stores into one, so the default trust surface only grows and
certificate verification is otherwise unchanged: unknown CAs are still
rejected. The stealth (wreq) client has its own TLS stack and is out of
scope here.

Tests: an in-process HTTPS fixture with an rcgen-minted private CA,
served via tokio-rustls (pinned to the ring provider so the test binary
has a single rustls CryptoProvider). With SSL_CERT_FILE pointing at the
CA the fetch succeeds; without it the same fixture is rejected.

Fixes #525.
2026-07-28 15:43:12 +02:00
c.kai 776c915c8c fix(js): add global PromiseRejectionEvent and StorageEvent constructors
Obscura lacked these two standard event constructors on globalThis.
The missing PromiseRejectionEvent caused core-js to misdetect the
environment and override native Promise with a broken polyfill,
breaking Vue application rendering. StorageEvent completes the
localStorage/sessionStorage API surface.

Both are also registered in document.createEvent() for legacy callers.

Fixes #521, fixes #522.
2026-07-27 14:47:48 +08:00
hol"mo"fy 3d39e59c14 Update bootstrap.js 2026-07-26 20:57:02 +08:00
SGavrl e78b5e6026 Merge pull request #516 from h4ckf0r0day/fix/macos-stealth-sdk-506
ci(release): use active macOS SDK for stealth builds
2026-07-26 11:50:20 +00:00
SGavrl 0670e738a0 ci(release): use active macOS SDK for stealth builds 2026-07-26 11:47:15 +00:00
Andrey Mnatsakanov 1fc5a24e98 fix(js): keep the current URL when pushState/replaceState omit url
resolveOrFallback(undefined) returned undefined, so applyVirtual set
__virtualUrl to null and location reverted to the document URL. Per the HTML
spec a missing url keeps the current document URL; return __currentUrl() so the
new history entry captures the current location instead of clearing it.

Fixes #496
2026-07-26 13:30:07 +02:00
Andrey Mnatsakanov a663a15556 fix(js): case-insensitive insertAdjacentHTML that keeps table/select fragments
Two defects: the position keyword was matched case-sensitively with no default
(so 'BeforeEnd' inserted nothing and an invalid position silently no-oped
instead of throwing SyntaxError), and fragments were parsed inside a throwaway
<div>, so context-sensitive children (<tr>, <td>, <option>, …) were dropped.

Lowercase the position and throw SyntaxError on an unknown value; parse via a
table/select-aware wrapMap (chosen from the fragment's leading tag, falling back
to the insertion context) so rows/cells/options survive.

Fixes #495
2026-07-26 13:30:07 +02:00
Andrey Mnatsakanov 499a5ef983 fix(js): coerce non-string primitives in before/after/replaceWith
before(), after() and replaceWith() only converted string arguments to Text
nodes; other primitives (numbers, booleans, null) were passed straight to
insert_before with no _nid, corrupting the call. Route them through the shared
_convertNodes helper (the same path append/prepend use), so every non-node
argument becomes document.createTextNode(String(n)).

Fixes #498
2026-07-26 13:30:07 +02:00
Andrey Mnatsakanov cdab919599 fix(js): make performance.now() monotonic
The old sub-millisecond bump (_sub += 0.1) was uncapped, so after >10 calls in
one millisecond it exceeded 1.0; when the wall clock then ticked over and the
bump reset to 0, now() returned a value below the previous call. Track the last
returned value and never go below it (advance by a tiny epsilon when the clock
has not moved past it).

Fixes #497
2026-07-26 13:30:07 +02:00
Andrey Mnatsakanov 6314ecbf88 fix(js): make setAttributeNS/getAttributeNS/removeAttributeNS namespace-aware
The three NS methods ignored the namespace: setAttributeNS stored the qualified
name against the non-namespaced store and getAttributeNS/removeAttributeNS
looked up by local name only, so a namespaced attribute was not addressable by
(namespace, localName) — getAttributeNS(xlink, 'href') returned null.

Record the namespace on the attribute and add namespace-aware DOM ops that match
by (namespace, localName), where the local name is the attribute name after any
prefix (so both setAttributeNS-created 'xlink:href' and parser-created 'href'
resolve). The non-namespaced getAttribute/serialization paths are untouched, and
getAttributeNS(null, name) still reads plain attributes.

Fixes #503
2026-07-26 13:29:43 +02:00
Andrey Mnatsakanov 72a9c3ced3 fix(dom): honor quirks mode for class/id selector case-sensitivity
set_quirks_mode was a no-op and the selector MatchingContext hardcoded
QuirksMode::NoQuirks, so class/id selectors were always case-sensitive even on
quirks-mode (no-doctype) pages where browsers match .foo / #bar
ASCII-case-insensitively. Store the parser-reported quirks mode on DomTree, pass
it into the selector context, and skip the exact-case #id index fast path in
quirks mode so it falls through to case-insensitive matching.

Fixes #499
2026-07-26 13:29:12 +02:00
Andrey Mnatsakanov 52e110b67c fix(dom): guard DomTree::remove() against OOB and double-free
remove() freed a node and its descendants by directly indexing inner.nodes and
unconditionally pushing each slot onto the free list. An out-of-range id panicked
out-of-bounds, and removing an already-freed node pushed its slot a second time,
so two later allocations could be handed the same NodeId (aliasing/corruption).
Free a slot only when it is currently live, via checked access.

Fixes #500
2026-07-26 13:29:12 +02:00
SGavrl 8078cc3070 Merge pull request #506 from h4ckf0r0day/fix/release-stealth-build-483
ci(release): publish explicit stealth artifacts
2026-07-26 11:21:54 +00:00
SGavrl 19aeb1eddb Merge pull request #505 from h4ckf0r0day/fix/mcp-read-timeout-501
fix(mcp): bound HTTP request read time
2026-07-26 11:21:22 +00:00
SGavrl 78a3e997e7 ci(release): publish explicit stealth artifacts 2026-07-26 11:05:13 +00:00
SGavrl 750ffa62a9 fix(mcp): bound HTTP request read time 2026-07-26 11:05:04 +00:00
SGavrl 6ad8eb9040 Merge pull request #502 from h4ckf0r0day/fix/op-reentrancy-453-v2
fix(js): scope fetch clients to browser contexts
2026-07-26 10:32:16 +00:00
SGavrl ab6fa0e39b fix(js): scope fetch clients to browser contexts 2026-07-26 10:20:25 +00:00
SGavrl 4af658351d Merge pull request #493 from mnaza/fix/mcp-sse-wedge-489
fix(mcp): detach SSE keep-alive so it cannot wedge the HTTP server
2026-07-26 10:18:38 +00:00
SGavrl 08d7b5e254 Merge pull request #485 from ulises2k/fix/svg-parsed-namespace
fix(js,dom): keep parsed SVG in the SVG namespace so href reflects an SVGAnimatedString
2026-07-26 10:18:19 +00:00
SGavrl e023cc87cb Merge pull request #487 from ulises2k/security/quinn-proto-GHSA-4w2j-m93h-cj5j
security(deps): bump quinn-proto 0.11.14 -> 0.11.15 (GHSA-4w2j-m93h-cj5j)
2026-07-26 10:17:59 +00:00
Andrey Mnatsakanov 491ecfb0f1 fix(js): clone nodes structurally instead of via div.innerHTML
cloneNode(true) round-tripped through a throwaway <div>'s innerHTML, so the
HTML fragment parser discarded elements that are not valid children of <div>
(<tr>, <td>, <option>, <tbody>, …) — createElement('tr').cloneNode(true)
returned null — and JS-set inline styles were lost. The shallow path also
re-derived attributes by regex-scraping serialized HTML.

Clone structurally with real DOM APIs: shallow-clone each node via
createElement/createElementNS plus a getAttributeNames() attribute copy (no
parsing context, every attribute preserved), then descend into children with an
explicit stack so a deep subtree cannot overflow the JS stack. Text, Comment,
DocumentFragment and <template> contents are handled.

Fixes #490
2026-07-26 11:09:42 +02:00
Andrey Mnatsakanov ea417bcd11 fix(mcp): detach SSE keep-alive so it cannot wedge the HTTP server
The MCP HTTP server serves connections sequentially on the single
current-thread runtime (the browser session is !Send). The SSE branch
(GET /mcp, Accept: text/event-stream) ran an infinite keep-alive ping loop
inline, so handle_connection never returned and the accept loop never ran
again — one open SSE stream hung every later POST /mcp tool call
indefinitely (functional break + trivial unauthenticated DoS).

The keep-alive carries no browser state and its write half is Send + 'static,
so spawn the ping loop on its own task and return from the handler. POST
handling stays serialized (correct for a single browser session), but a live
SSE stream no longer blocks the accept loop.

Fixes #489
2026-07-26 11:05:57 +02:00
Andrey Mnatsakanov 80803cbec8 fix(js): sync el.style with the style attribute in both directions
CSSStyleDeclaration was backed by an in-memory _props map that was never
bridged to the element's style content attribute. Parsed inline styles were
invisible to el.style.*, setAttribute('style', …) did not update el.style, and
el.style.x = … never reached the attribute or serialization; getComputedStyle
read the same disconnected declaration.

Give the declaration its owner element: lazily pull the style attribute into
_props on read (skipping the reparse when unchanged) and push _props back to the
attribute on every mutation. Owner-less declarations (getComputedStyle fallback,
stylesheet rules) stay purely in-memory, so their behavior is unchanged.

Fixes #488
2026-07-26 11:04:02 +02:00
ulises2k 2ac416c886 security(deps): bump quinn-proto 0.11.14 -> 0.11.15 (GHSA-4w2j-m93h-cj5j)
Fixes remote memory exhaustion in quinn-proto <=0.11.14 (HIGH).
See https://github.com/advisories/GHSA-4w2j-m93h-cj5j

Lockfile-only bump; non-optional deps of 0.11.15 are unchanged vs 0.11.14.
2026-07-26 02:26:06 -03:00