1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
Freenet shell smoke-test fixture
<!--
This page is published as a Freenet website contract and loaded inside the
shell's sandboxed iframe by the Playwright smoke tests
(crates/core/tests/playwright/tests/shell.spec.ts).
It deliberately does NOT include the shell bridge, the WebSocket shim, or the
navigation interceptor: the freenet node injects those into the served HTML
(see crates/core/src/server/path_handlers.rs::sandbox_content_body). The
point of the test is to exercise that injected code against a real browser,
so the fixture only provides the DOM the injected code acts on.
Stable element ids are the test contract — keep them in sync with
shell.spec.ts.
-->
Freenet shell fixture
<!--
Cross-origin link WITH an explicit new-window target. The interceptor must
leave this to the browser: the shell iframe carries
`allow-popups-to-escape-sandbox`, so the native popup is a real top-level
document with a proper Origin (freenet/river#208's null-origin CORS breakage
came from the popup INHERITING the sandbox, which no longer happens). Routing
it through the shell instead is what broke Firefox, whose popup blocker
refuses `window.open` from a `message` handler.
example.com is a reserved documentation domain (RFC 2606); the tests stub the
route so no real network request is made.
-->
External cross-origin link
<!--
Cross-origin link with NO target. Left native it would navigate the app frame
itself to a foreign origin, which the shell's `frame-src 'self'` refuses — the
click would silently do nothing. The interceptor must open a tab for it, from
inside the click handler where the user gesture is live.
-->
External cross-origin link, no target
<!--
Cross-origin link with `target="_top"`. `_top` names an ANCESTOR context, not
a new one, and the sandbox forbids navigating it — so "any non-`_self` target
is a new-window activation, hand it to the browser" makes this a silently dead
click. It must be classified like an untargeted cross-origin link and opened
in a tab.
-->
External cross-origin link, target=_top
<!--
Same-origin link with an explicit new-window target. This is the #5087 case:
every cross-CONTRACT link is same-ORIGIN, so this is what a thumbnail or
cross-app link looks like. It must open natively as a real top-level tab that
loads the shell (previously it either produced a blank sandbox-inheriting tab,
or — once routed through `open_url` — nothing at all in Firefox).
-->
In-contract page 2, new tab
<!--
Same-origin, in-contract link. The interceptor must turn this into a
`navigate` postMessage so the shell performs an in-place iframe hop instead
of a full reload. The href is relative so it resolves under this contract's
web prefix regardless of the contract key.
-->
In-contract page 2
<!--
Download link. The interceptor must NOT intercept links carrying a
`download` attribute; `handleAnchorClick` early-returns on `download`
(path_handlers.rs:2013), so no open_url / navigate postMessage is sent and
the link keeps its native (download) behaviour.
The href is SAME-ORIGIN (a data URL would be skipped earlier by the
javascript:/data: protocol check at path_handlers.rs:2011, which would NOT
isolate the `download` guard). Without the `download` attribute this exact
same-origin link would be intercepted as a `navigate` (see #same-origin-link);
the `download` attribute is what makes the early-return fire instead, so the
absence of a `navigate` postMessage on click is attributable to the
`download` guard specifically. The test reads `#download-link` directly and
does not rely on what the browser does natively after the early-return.
-->
Download
<!--
Programmatic open. A contract calling window.open() from its own JS never
touches the anchor interceptor, so it is the path that relies purely on
`allow-popups-to-escape-sandbox` to produce a real top-level tab. Before
#5100 an override forwarded it to the shell (#4645); now it is native.
-->
window.open()
<!--
The #3818 escape, played out by a hostile contract. `allow-popups-to-escape-sandbox`
means a popup this frame opens is top-level with NO sandboxing flags, and an
`about:blank` popup inherits this frame's origin — so the contract can script
it and, from there, re-embed its own bytes in a nested frame that inherits no
sandboxing either. If the server does not sandbox contract content itself,
that frame runs at the node's real origin.
-->
escape
<!-- Result sink the Playwright tests read via page.evaluate. -->
pending