Commit Graph

11 Commits

Author SHA1 Message Date
Xavier Roche
e2a57d6c07 WebHTTrack settings pages interpolate values into double-quoted attributes unescaped (#1013)
* WebHTTrack settings pages interpolate values into double-quoted attributes unescaped

#988 escaped the templates' element bodies and event handlers but left
attribute values alone, because cat_html_escaped() keeps the double quote
raw on purpose: the tooltips are written title='${html:LANG_x}'. The
settings pages put about seventy values inside double-quoted attributes,
where a " opens a new attribute.

Add a fourth interpolation mode, attr:, escaping < > & ' " as entities and
nothing else, and point the 230 double-quoted attribute positions at it.
file.html's file:// href stays on the html-urlescaped mode, which now emits
%22 for the quote the way unquoted: already did, and step2.html's in-script
literal moves to js:. Test 185 now requires attr: in a double-quoted
attribute and js: inside a script block; 217 drives hostile values through
three templates and a translation.

Closes #989

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

* Close the two attribute sites the template sweep could not reach

The liststr: format builds its own <option value="..."> in C, so no
template edit covers it, and it escaped with the helper that leaves the
double quote raw. Its values are the project directory names and the
Category= line of each project's winprofile.ini, both of which can hold
a quote.

The save side kept hex-decoding a backslash plus two hex digits, so a
path typed as C:\ab displayed correctly but was written to ~/.httrack.ini
as C: plus byte 0xAB. The ini writer has no inverse for that escape; the
one caller that needs it is a template literal (${test:proxytype:\3A//}),
so the decode now applies only there.

Test 185 classified attributes with a regex that missed a spaced =, an
unquoted or single-quoted value, a template outside html/server/*.html,
and an output-mode region the file never closes; the counting floors it
asserted also survived a count-preserving rewrite. It now walks tags,
asserts the property on every site it classifies, and proves it can see
each of those forms on a synthetic template first.

Test 217 gains a Latin-1 byte in a translation, the POST-render-POST
round trip, and the two fixes above.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

* Trim the comments the last commit added

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

---------

Signed-off-by: Xavier Roche <roche@httrack.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 08:20:14 +00:00
Xavier Roche
2945f0a5e4 The WebHTTrack progress panel renders crawled URLs into HTML and JavaScript unescaped (#988)
* Escape crawled URLs in the WebHTTrack progress panel

refresh.html interpolated ${info.state}, ${info.name} and ${info.file} as
raw HTML and ${info.url_sav} into a single-quoted JS literal, so a link
path holding < > or ' ran as script in the panel origin. Point them at
htsserver.c's html: and js: modes, and sweep the other templates for the
same shape. Widen 185's scan to any unescaped handler or element-body
interpolation, and add 186 to probe the rendered panel during a crawl.

Closes #973

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

* Pin the panel's name column in the escaping test

186 asserted only on the leaf of the crawled path, so info.name could go
back to raw and still pass: 185 cannot see it either, because ${unquoted:}
sits in the directive regex it skips. The link now carries metacharacters
in a directory component too, short enough to survive the engine's 40-char
elision of that column, and the poll breaks on either form so the positive
control stays honest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

* Make test 186 executable, like its siblings

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

* Re-arm the output mode that ${do:end-if} clears

${do:end-if} sets outputmode to 0 rather than restoring what it replaced
(htsserver.c), so the if-not-empty block partway down step4.html's command
textarea drops the ${do:output-mode:html} armed above it, and the 17
${unquoted:} settings below render raw. Posting maxtime or url2 as
A</textarea><img src=x onerror=alert(1)>B breaks out of the textarea.
finished.html's <pre> has the same shape; those two are the only ones.

--sitemap-url moves from html: to arg: like its quoted siblings, since
cat_html_escaped() escapes neither " nor \.

Test 185 had unquoted: on its directive skip list, which is how all 17
sailed past it, and now also rejects an html: value on the command line.
Test 83 reads back the escaped forms at runtime.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

---------

Signed-off-by: Xavier Roche <roche@httrack.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 19:42:37 +00:00
Xavier Roche
73c99ac3a0 Tooltip JavaScript breaks on any translation containing an apostrophe (#967)
* Tooltip JavaScript breaks on any translation containing an apostrophe

The onMouseOver handlers interpolate through ${html:...}, which escapes
for HTML text. The browser decodes an attribute value before compiling
it as JavaScript, so &#39; arrives as a bare quote and closes the string
literal; a translation carrying a double quote ends the attribute
outright. Add a js: template mode escaping for both layers and move all
304 handler sites onto it.

Closes #864

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

* Close the step2.html and title-attribute gaps in the js: escaping test

The static check could not match ${html:html:...}, the very shape it was
added to catch, and the runtime probe only fetched option1.html: reverting
all eight step2.html handlers left the test green. Nothing asserted that a
title= attribute stays on html: outside option1.html either.

Walk every server template instead, pairing each ${...} with the attribute
holding it, and fetch step2.html as well. Also feed the fixture a newline
and a tab, which had no coverage.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

* Emit the backslash as \x5c so a DBCS trail byte cannot swallow it

shift-jis, BIG5 and gb2312 all accept 0x5c as a trail byte, and those are
the declared charsets of three shipped lang files, so the browser really
does run a DBCS decoder over the page. An orphan lead byte followed by the
emitted \\ pair decodes as one glyph plus a stray backslash, which escapes
whatever comes next. Emitting every escape as a \xNN group leaves the
decoder nothing to pair with: the only bytes cat_js_escaped adds are '\',
'x' and hex digits.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

---------

Signed-off-by: Xavier Roche <roche@httrack.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 12:25:36 +00:00
Xavier Roche
8168aa3a45 The masthead wordmark is a 400x34 GIF that blurs on any hi-DPI screen (#916)
* The masthead wordmark is a 400x34 GIF that blurs on any hi-DPI screen

Replaces it with an outlined SVG across the 38 documentation and WebHTTrack
pages that carry it. The original was set in Futura, so the lockup was refitted
in Jost*, the closest free Futura revival, taking weight from the measured stem
thickness, size from the cap heights and tracking by least squares against the
glyph positions in the old bitmap.

tests/82 now asserts that every image a GUI page names is actually served.

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

* Point the shared chrome generator at the new wordmark

The masthead of the 13 generated pages comes from tools/doc-chrome.py, so
editing the pages alone left the generator disagreeing with its own output and
--check red.

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

---------

Signed-off-by: Xavier Roche <xroche@gmail.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 19:17:01 +02:00
Xavier Roche
2382ca3aa0 Refresh the documentation copyright year to 1998-2026 (#647)
Bumps the copyright year in the html/ documentation footers (and the inline notice in contact.html) from 2007 to 1998-2026. Footer text only, no content changes; fcguide.html (Fred Cohen, upstream) is left untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-07-21 18:43:10 +02:00
Xavier Roche
ed05faaaa8 Add native title tooltips to the webhttrack option pages (#594)
The web GUI carried per-control help via onMouseOver="info(...)", which
only wrote window.status. Browsers stopped honoring scripted window.status
writes years ago, so those hints render nowhere.

Emit each hint as a native title='...' attribute alongside the existing
handler, reusing the same ${html:LANG_*} string. Single-quoted so the
filter's ' -> &#39; (and <>&) escaping keeps the attribute well-formed; a
literal " is harmless inside single quotes. The window.status calls stay
(inert) to keep the diff to added attributes.

The webhttrack smoke test now also fetches an option page and requires a
rendered title=' tooltip.

Signed-off-by: Xavier Roche <roche@httrack.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 22:26:53 +02:00
Xavier Roche
d50b6ec569 Fixed permissions 2015-03-14 14:04:17 +01:00
Xavier Roche
9b5c6cf86e Fixed webhttrack incompatibility with Chrome
* closes:#53

Also fixed HTML-escaping issues inside webhttrack

Rationale: The webhttrack script made the wrong assumption that once the "browse" command returned, it meant the user killed the navigation window, and it had to kill the server itself. However, modern browsers tend to "attach" to an existing session (creating a new tab, for example, within an existing window), causing the browsing command to return immediately, thus causing the server to be killed immediately by the webhttrack script. I have rewritten the logic behind, and now the server is able to kill himself if the parent script dies, AND if the browsing client did not make any activity for two minutes. The "activity" can be any browser/refreshed page, or the internal "ping" iframe (which pings the server every 30 seconds). With this model, we *should* be compatible with old browsers, and modern ones.
2014-10-15 19:17:29 +00:00
Xavier Roche
660b569b09 httrack 3.41.2 2012-03-19 12:59:03 +00:00
Xavier Roche
844ecc3707 httrack 3.33.16 2012-03-19 12:55:42 +00:00
Xavier Roche
25adbdabb4 httrack 3.30.1 2012-03-19 12:51:31 +00:00