Compare commits
No commits in common. "59fcc15ca6abc99b3a37c0b8231ef0010fe80635" and "5d344f940e61b506d9ffeae9adb0b4b52820a401" have entirely different histories.
59fcc15ca6
...
5d344f940e
5
Makefile
5
Makefile
|
|
@ -122,11 +122,8 @@ pdf-thumbs:
|
|||
# A failing pdftoppm must at least warn: the `find | while` pipeline's
|
||||
# exit status is the last iteration's, so without the `||` a corrupt
|
||||
# PDF would silently ship without a thumbnail.
|
||||
# Walk ALL of static/ (not just papers/): /cv.pdf and /resume.pdf are
|
||||
# the most-linked PDFs on the site and need hover thumbnails too.
|
||||
# pdfjs/ is pruned — the vendored viewer ships sample PDFs.
|
||||
@if command -v pdftoppm >/dev/null 2>&1; then \
|
||||
find static -path static/pdfjs -prune -o -name '*.pdf' -print 2>/dev/null | while read pdf; do \
|
||||
find static/papers -name '*.pdf' 2>/dev/null | while read pdf; do \
|
||||
thumb="$${pdf%.pdf}.thumb"; \
|
||||
if [ ! -f "$${thumb}.png" ] || [ "$$pdf" -nt "$${thumb}.png" ]; then \
|
||||
echo " pdf-thumb $$pdf"; \
|
||||
|
|
|
|||
|
|
@ -33,28 +33,11 @@ resolver_timeout 5s;
|
|||
# (revisions get distinct IDs like 2604.06217v2), so 30d is safe.
|
||||
location /proxy/arxiv/ {
|
||||
set $upstream_arxiv export.arxiv.org;
|
||||
# With a VARIABLE upstream, a URI part on proxy_pass is passed to
|
||||
# the upstream literally — "proxy_pass https://$up/;" sends every
|
||||
# request to the upstream's homepage instead of prefix-stripping.
|
||||
# Strip the prefix explicitly; `break` keeps args intact.
|
||||
rewrite ^/proxy/arxiv/(.*)$ /$1 break;
|
||||
proxy_pass https://$upstream_arxiv;
|
||||
proxy_pass https://$upstream_arxiv/;
|
||||
proxy_set_header Host $upstream_arxiv;
|
||||
proxy_set_header User-Agent "levineuwirth.org popup-proxy (ln@levineuwirth.org)";
|
||||
proxy_ssl_server_name on;
|
||||
|
||||
# Keep the security baseline: the add_header directives below
|
||||
# would otherwise drop it for /proxy/ responses (same pattern
|
||||
# as archive.conf). The upstream's own security headers are hidden
|
||||
# first — browsers honor only the FIRST Strict-Transport-Security
|
||||
# header (RFC 6797 §8.1), so an upstream's short max-age passing
|
||||
# through ahead of ours would downgrade the domain's cached HSTS
|
||||
# policy on every popup fetch.
|
||||
proxy_hide_header Strict-Transport-Security;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
proxy_hide_header X-Frame-Options;
|
||||
include snippets/security-headers.conf;
|
||||
|
||||
proxy_cache popup_proxy;
|
||||
proxy_cache_valid 200 30d;
|
||||
proxy_cache_valid any 5m;
|
||||
|
|
@ -72,26 +55,11 @@ location /proxy/arxiv/ {
|
|||
# change, but rarely; 7d strikes a reasonable balance.
|
||||
location /proxy/archive/ {
|
||||
set $upstream_archive archive.org;
|
||||
# Prefix-strip explicitly — see the arXiv block for why a URI part
|
||||
# on a variable proxy_pass would break this.
|
||||
rewrite ^/proxy/archive/(.*)$ /$1 break;
|
||||
proxy_pass https://$upstream_archive;
|
||||
proxy_pass https://$upstream_archive/;
|
||||
proxy_set_header Host $upstream_archive;
|
||||
proxy_set_header User-Agent "levineuwirth.org popup-proxy (ln@levineuwirth.org)";
|
||||
proxy_ssl_server_name on;
|
||||
|
||||
# Keep the security baseline: the add_header directives below
|
||||
# would otherwise drop it for /proxy/ responses (same pattern
|
||||
# as archive.conf). The upstream's own security headers are hidden
|
||||
# first — browsers honor only the FIRST Strict-Transport-Security
|
||||
# header (RFC 6797 §8.1), so an upstream's short max-age passing
|
||||
# through ahead of ours would downgrade the domain's cached HSTS
|
||||
# policy on every popup fetch.
|
||||
proxy_hide_header Strict-Transport-Security;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
proxy_hide_header X-Frame-Options;
|
||||
include snippets/security-headers.conf;
|
||||
|
||||
proxy_cache popup_proxy;
|
||||
proxy_cache_valid 200 7d;
|
||||
proxy_cache_valid any 5m;
|
||||
|
|
@ -108,10 +76,7 @@ location /proxy/archive/ {
|
|||
# them server-side so popups.js stays focused on rendering.
|
||||
location /proxy/pubmed/ {
|
||||
set $upstream_pubmed eutils.ncbi.nlm.nih.gov;
|
||||
# Prefix-strip explicitly — see the arXiv block for why a URI part
|
||||
# on a variable proxy_pass would break this.
|
||||
rewrite ^/proxy/pubmed/(.*)$ /$1 break;
|
||||
proxy_pass https://$upstream_pubmed;
|
||||
proxy_pass https://$upstream_pubmed/;
|
||||
proxy_set_header Host $upstream_pubmed;
|
||||
proxy_set_header User-Agent "levineuwirth.org popup-proxy (ln@levineuwirth.org)";
|
||||
proxy_ssl_server_name on;
|
||||
|
|
@ -120,18 +85,6 @@ location /proxy/pubmed/ {
|
|||
# caching this is rarely exercised, but the burst guards a hot page.
|
||||
limit_req zone=pubmed burst=3 nodelay;
|
||||
|
||||
# Keep the security baseline: the add_header directives below
|
||||
# would otherwise drop it for /proxy/ responses (same pattern
|
||||
# as archive.conf). The upstream's own security headers are hidden
|
||||
# first — browsers honor only the FIRST Strict-Transport-Security
|
||||
# header (RFC 6797 §8.1), so an upstream's short max-age passing
|
||||
# through ahead of ours would downgrade the domain's cached HSTS
|
||||
# policy on every popup fetch.
|
||||
proxy_hide_header Strict-Transport-Security;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
proxy_hide_header X-Frame-Options;
|
||||
include snippets/security-headers.conf;
|
||||
|
||||
proxy_cache popup_proxy;
|
||||
proxy_cache_valid 200 30d;
|
||||
proxy_cache_valid any 5m;
|
||||
|
|
|
|||
|
|
@ -75,4 +75,4 @@ add_header Permissions-Policy
|
|||
#
|
||||
# To collect violation reports, set up a `report-uri` endpoint and add
|
||||
# `report-uri /csp-report;` (and/or `report-to <group>;`) below.
|
||||
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' 'unsafe-eval' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data: https://*.basemaps.cartocdn.com https://upload.wikimedia.org;font-src 'self' data: https://cdn.jsdelivr.net; connect-src 'self' https://cdn.jsdelivr.net https://*.wikipedia.org https://api.crossref.org https://api.github.com https://openlibrary.org https://api.biorxiv.org https://www.youtube.com https://git.levineuwirth.org; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'; upgrade-insecure-requests" always;
|
||||
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' 'unsafe-eval' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data: https://*.basemaps.cartocdn.com; font-src 'self' data: https://cdn.jsdelivr.net; connect-src 'self' https://cdn.jsdelivr.net https://*.wikipedia.org https://api.crossref.org https://api.github.com https://openlibrary.org https://api.biorxiv.org https://www.youtube.com https://git.levineuwirth.org; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'; upgrade-insecure-requests" always;
|
||||
|
|
|
|||
|
|
@ -55,26 +55,16 @@ brotli off; # we ship pre-compressed sidecars only, no on-the-fly b
|
|||
# instantaneous. Same reasoning applies to fingerprinted fonts and the
|
||||
# locally vendored ML model files.
|
||||
location ^~ /pdfjs/ {
|
||||
# Re-include the security baseline: this location declares its
|
||||
# own add_header, which (per nginx inheritance rules) would
|
||||
# otherwise drop HSTS/nosniff/CSP for everything it serves —
|
||||
# and nosniff matters most on exactly these JS/CSS responses.
|
||||
# Same pattern as archive.conf.
|
||||
include snippets/security-headers.conf;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location ^~ /fonts/ {
|
||||
# Keep the security baseline (see first location above).
|
||||
include snippets/security-headers.conf;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location ^~ /models/ {
|
||||
# Keep the security baseline (see first location above).
|
||||
include snippets/security-headers.conf;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
access_log off;
|
||||
}
|
||||
|
|
@ -84,8 +74,6 @@ location ^~ /models/ {
|
|||
# keeps them responsive to deploys (~1h staleness window for warm clients)
|
||||
# without forcing a fetch on every page navigation.
|
||||
location ~* \.(?:css|js|mjs|woff2?|svg|webp|png|jpg|jpeg|ico)$ {
|
||||
# Keep the security baseline (see first location above).
|
||||
include snippets/security-headers.conf;
|
||||
add_header Cache-Control "public, max-age=3600, must-revalidate" always;
|
||||
access_log off;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,18 +78,6 @@
|
|||
line-height: 1.35;
|
||||
}
|
||||
|
||||
/* Optional lead image (Wikipedia pageimages thumbnail, etc.) — floats
|
||||
beside the title/extract so text wraps around it; contained by the
|
||||
popup's own overflow box. */
|
||||
.popup-image {
|
||||
float: right;
|
||||
max-width: 96px;
|
||||
max-height: 120px;
|
||||
margin: 0 0 0.4rem 0.6rem;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--border-muted);
|
||||
}
|
||||
|
||||
.popup-abstract,
|
||||
.popup-extract {
|
||||
font-size: 0.78rem;
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 192 KiB |
|
|
@ -453,14 +453,6 @@
|
|||
|
||||
var html = '<div class="popup-' + p.name + '">'
|
||||
+ srcHtml(iconKey, p.label);
|
||||
/* Optional lead image (e.g. Wikipedia pageimages thumbnail).
|
||||
https-only: the URL comes from the provider's API response,
|
||||
and anything else (protocol-relative, data:, …) is dropped
|
||||
rather than guessed at. esc() handles attribute safety. */
|
||||
if (fields.image && /^https:\/\//.test(fields.image)) {
|
||||
html += '<img class="popup-image" src="' + esc(fields.image)
|
||||
+ '" alt="" loading="lazy">';
|
||||
}
|
||||
if (fields.tags) html += '<div class="popup-tags">' + esc(fields.tags) + '</div>';
|
||||
html += '<div class="popup-title">' + esc(fields.title) + '</div>';
|
||||
if (authors) html += '<div class="popup-authors">' + esc(authors) + '</div>';
|
||||
|
|
@ -523,14 +515,8 @@
|
|||
var hostMatch = ctx.href.match(/\/\/([a-z0-9-]+)\.wikipedia\.org\//i);
|
||||
var sub = hostMatch ? hostMatch[1].toLowerCase() : 'en';
|
||||
if (sub === 'www') sub = 'en';
|
||||
/* pageimages|extracts in one call: the article's lead
|
||||
image thumbnail rides along with the intro text.
|
||||
Thumbnails come from upload.wikimedia.org — that host
|
||||
must stay in the CSP's img-src. */
|
||||
return 'https://' + sub + '.wikipedia.org/w/api.php'
|
||||
+ '?action=query&prop=extracts%7Cpageimages&exintro=1'
|
||||
+ '&piprop=thumbnail&pithumbsize=320'
|
||||
+ '&format=json&redirects=1'
|
||||
+ '?action=query&prop=extracts&exintro=1&format=json&redirects=1'
|
||||
+ '&titles=' + encodeURIComponent(decodeURIComponent(ctx.match[1]))
|
||||
+ '&origin=*';
|
||||
},
|
||||
|
|
@ -547,21 +533,14 @@
|
|||
});
|
||||
var text = (doc.body.textContent || '').replace(/\s+/g, ' ').trim();
|
||||
if (!text) return null;
|
||||
return {
|
||||
title: page.title,
|
||||
extract: text,
|
||||
image: page.thumbnail && page.thumbnail.source
|
||||
};
|
||||
return { title: page.title, extract: text };
|
||||
}
|
||||
},
|
||||
|
||||
/* arXiv — Atom API (CORS-broken upstream, proxied).
|
||||
ID forms: new-style 2403.12345(v2), and old-style
|
||||
archive/0211159 or archive.SC/0211159 (pre-2007); /pdf/ URLs
|
||||
may carry a trailing .pdf, which stays outside the capture. */
|
||||
/* arXiv — Atom API (CORS-broken upstream, proxied). */
|
||||
{
|
||||
name: 'arxiv', label: 'arXiv',
|
||||
match: /arxiv\.org\/(?:abs|pdf)\/((?:\d{4}\.\d{4,5}|[a-z-]+(?:\.[A-Z]{2})?\/\d{7})(?:v\d+)?)/,
|
||||
match: /arxiv\.org\/(?:abs|pdf)\/(\d{4}\.\d{4,5}(?:v\d+)?)/,
|
||||
fetchType: 'xml',
|
||||
url: function (ctx) {
|
||||
return '/proxy/arxiv/api/query?id_list='
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 270 KiB |
Loading…
Reference in New Issue