Commit Graph
483 Commits
Author SHA1 Message Date
Andrey Mnatsakanov ae33543850 fix(dom): match setAttribute by qualified name, not local name only
Node::set_attribute looked up the existing attribute by local name alone,
while get_attribute and the remove_attribute op both match by qualified
name. A parsed namespaced attribute is stored with a separate prefix
(xlink:href -> prefix="xlink", local="href"), so setAttribute("xlink:href")
never matched it: the update was pushed as a second attribute, getAttribute
kept returning the stale original, and the element serialized xlink:href
twice.

Match set_attribute by qualified_name_eq, consistent with the read/remove
paths, so the update lands in place and no duplicate is created.

Fixes #547
2026-08-04 10:34:04 +02:00
Andrey Mnatsakanov 53295faa59 fix(js): surface a parsererror for malformed XML in DOMParser
DOMParser.parseFromString always HTML-parsed, even for XML mime types, so
malformed XML never produced the <parsererror> element Chrome emits and
error-detection code (doc.querySelector('parsererror')) never triggered. obscura
has no XML parser, so full XML semantics stay out of scope; instead, for XML
mime types run a conservative well-formedness check (tag balance, single root,
terminated comment/CDATA/PI, skipping quoted attribute regions) and, on a clear
error, make the document surface a <parsererror>. The check defaults to
well-formed when ambiguous, so valid XML is never falsely flagged.

Fixes #504
2026-08-04 08:43:45 +02:00
SGavrl f0541f40a4 fix(js): isolate bootstrap declarations (#544) 2026-08-03 16:36:19 +00:00
SGavrl 6a55b63fa6 fix(js): isolate bootstrap declarations 2026-08-03 16:31:30 +00:00
Tamish MhatreandSGavrl 23a8a3111b fix: add missing #[ignore] gate and local fixture for concurrent fetch test (#450)
* fix: add missing #[ignore] gate and local fixture for concurrent fetch test

* fix(test): make fetch fixture nonblocking

---------

Co-authored-by: SGavrl <277843151+SGavrl@users.noreply.github.com>
2026-08-03 16:11:48 +00:00
SGavrl 5912c37c57 Merge pull request #514 from mnaza/fix/attribute-ns-503
fix(js): make setAttributeNS/getAttributeNS/removeAttributeNS namespace-aware
2026-08-03 16:10:58 +00:00
SGavrl 73fe8b91ae test namespace style synchronization 2026-08-03 15:36:52 +00:00
SGavrl 1518ca2a70 Merge remote-tracking branch 'origin/main' into maintainer/pr-514-review
# Conflicts:
#	crates/obscura-js/js/bootstrap.js
2026-08-03 15:35:42 +00:00
SGavrl 42f7fad709 Merge pull request #507 from mnaza/fix/insert-adjacent-html-495
fix(js): case-insensitive insertAdjacentHTML that keeps table/select fragments
2026-08-03 15:33:34 +00:00
SGavrl 62ada5ebb9 Merge pull request #494 from mnaza/fix/clonenode-structural-490
fix(js): clone nodes structurally instead of via div.innerHTML
2026-08-03 15:32:18 +00:00
SGavrl 624b98c7ad Merge pull request #542 from lisa0314/fix/531-scroll-into-view-if-needed
feat(cdp): support DOM.scrollIntoViewIfNeeded
2026-08-03 15:31:59 +00:00
SGavrl becb8816e8 Merge pull request #539 from dgcavalcante-png/fix/stealth-honors-ssl-cert-file
fix(net): honor SSL_CERT_FILE / SSL_CERT_DIR in the stealth client (#525 follow-up)
2026-08-03 15:31:19 +00:00
SGavrl 57cedbf069 Merge pull request #540 from dgcavalcante-png/fix/webidl-globals-non-enumerable
fix(js): expose WebIDL interfaces as non-enumerable, like a real browser
2026-08-03 15:30:45 +00:00
lisa0314 84513d5bcc feat(cdp): support DOM.scrollIntoViewIfNeeded 2026-08-03 14:42:03 +08:00
Diego Cavalcante c7e7c703b7 fix(js): expose WebIDL interfaces as non-enumerable, like a real browser
`bootstrap.js` publishes its DOM interfaces with `globalThis.Node = Node`,
which defaults to `enumerable: true`. A real browser exposes every WebIDL
interface on the global as `enumerable: false`, so the difference is a
one-liner for any script that cares:

    Object.getOwnPropertyDescriptor(window, 'Node').enumerable
    // real Chrome: false     obscura: true

It also means `Object.keys(window)` and `for...in` over the global enumerate
22 names a browser would never list.

The file already has the mechanism for this -- `_preHideInternals()`
pre-declares internal globals with `enumerable: false`, and its own comment
notes that later `globalThis.x = value` assignments only update the value and
leave the descriptor intact. This just adds the WebIDL names to that list, so
no assignment site changes.

Before: 9 of 10 sampled interfaces enumerable. After: 0 of 10, matching Chrome.

Regression: interfaces still callable (`typeof Node === 'function'`),
`instanceof Node` / `instanceof Element` hold, `querySelector` works, Hacker
News still yields 30 results under `--stealth`, snapshot builds clean.

Composes with #537 -- verified with both applied: `var Node` pages run, the
JSF/RichFaces case loads (jQuery/A4J/RichFaces all live), and enumerability
stays at 0/10.
2026-08-02 01:26:42 -03:00
Diego Cavalcante fb42229200 fix(net): honor SSL_CERT_FILE / SSL_CERT_DIR in the stealth client
The #525 fix landed on the reqwest path (`client.rs`: `configured_root_paths()`
-> `add_root_certificate`) but did not cover `wreq_client.rs`. The stealth
client builds its `wreq::Client` without a certificate store, so those
variables are silently ignored whenever `--stealth` is on.

The consequence is inverted: the transport with the best TLS fingerprint is the
only one that cannot reach a host behind a private or incomplete CA chain --
precisely the environments #525 described.

Same binary on current main, same private-CA server, only the flag differs:

  SSL_CERT_FILE=ca.pem obscura           fetch https://127.0.0.1:8443/  -> ok
  SSL_CERT_FILE=ca.pem obscura --stealth fetch https://127.0.0.1:8443/  -> fails

`wreq` already exposes the hook -- `ClientBuilder::tls_cert_store(CertStore)`,
and `CertStore::builder().set_default_paths()` reads both variables. It is
simply never called.

Two constraints, both of which fail silently if got wrong:

* `tls_cert_store`, not `tls_options`. `emulation()` is documented as
  "This will overwrite the existing configuration" and internally calls
  `self.tls_options(emulation.tls_options)`; setting TLS options here would
  discard the Chrome fingerprint, which is the whole point of this client.
  `tls_cert_store` is a separate config field and composes with emulation.
* Opt-in only. Supplying a store REPLACES the webpki roots (see
  `set_cert_store` in `tls/conn/ext.rs`), it does not add to them. Applying it
  unconditionally would break ordinary sites whenever the bundle is
  incomplete. With neither variable set, behaviour is byte-for-byte unchanged.

Verified: with the variable, a private-CA host resolves under --stealth;
without it, the same host still fails; with a deliberately EMPTY bundle,
example.com fails -- which is what proves the store is actually applied rather
than the bundle merely happening to be right.

Refs #538, #525
2026-08-02 01:10:02 -03:00
SGavrl eab2a5eea1 Merge pull request #535 from h4ckf0r0day/fix/492-style-sync
Fix/492 style sync
2026-08-01 19:58:18 +00:00
SGavrl 108e777418 Merge remote-tracking branch 'origin/main' into maintainer/pr-492-fix 2026-08-01 19:51:52 +00:00
SGavrl 4b41d7c746 Merge pull request #534 from h4ckf0r0day/fix/517-string-timers
Fix/517 string timers
2026-08-01 19:51:23 +00:00
SGavrl 037e321a79 Merge remote-tracking branch 'origin/main' into maintainer/pr-517-tests 2026-08-01 19:47:51 +00:00
SGavrl 92576571ef Merge pull request #533 from h4ckf0r0day/fix/509-performance-clock
Fix/509 performance clock
2026-08-01 19:46:49 +00:00
SGavrl 2275d8fea0 Merge remote-tracking branch 'origin/main' into maintainer/pr-509-fix
# Conflicts:
#	crates/obscura-js/src/runtime.rs
2026-08-01 19:39:24 +00:00
SGavrl bbc4980eba Merge pull request #510 from mnaza/fix/childnode-coerce-498
fix(js): coerce non-string primitives in before/after/replaceWith
2026-08-01 17:18:11 +00:00
SGavrl 389de72d1b Merge remote-tracking branch 'origin/main' into maintainer/pr-510-review 2026-08-01 17:14:05 +00:00
SGavrl 31ac297a48 Merge pull request #508 from mnaza/fix/history-preserve-url-496
fix(js): keep the current URL when pushState/replaceState omit url
2026-08-01 17:12:59 +00:00
SGavrl e9f783b3cf Merge pull request #511 from mnaza/fix/quirks-mode-selectors-499
fix(dom): honor quirks mode for class/id selector case-sensitivity
2026-08-01 17:12:44 +00:00
SGavrl ec7334d91b Merge pull request #512 from mnaza/fix/remove-double-free-500
fix(dom): guard DomTree::remove() against OOB and double-free
2026-08-01 17:12:28 +00:00
SGavrl 0428099b0f Merge remote-tracking branch 'origin/main' into maintainer/pr-509-fix 2026-08-01 16:04:37 +00:00
SGavrl 76e5280c32 fix(dom): preserve namespaced attribute qualified names 2026-08-01 16:00:52 +00:00
SGavrl 1e305135e3 Merge remote-tracking branch 'origin/main' into maintainer/pr-514-review 2026-08-01 15:58:03 +00:00
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