Release PR for v0.5.0. Features since v0.4.0: theme-aware scrollbars (#273), editor gutter alignment with wrapped rows (#274), jump to top/bottom buttons (#267), page URL renames to match nav labels (#256), static-width copy feedback (#260), gutter sized to widest line number (#257), gutter pinned during horizontal scroll (#261), widened history URL column (#255), rate limiter hardening (#280), jumpnav mobile fix (#282), /raw attachment streaming fix (#281), README/screenshot refresh.
Release PR for v0.5.0. Features since v0.4.0: theme-aware scrollbars (#273), editor gutter alignment with wrapped rows (#274), jump to top/bottom buttons (#267), page URL renames to match nav labels (#256), static-width copy feedback (#260), gutter sized to widest line number (#257), gutter pinned during horizontal scroll (#261), widened history URL column (#255), rate limiter hardening (#280), jumpnav mobile fix (#282), /raw attachment streaming fix (#281), README/screenshot refresh.
A 250-char multipart filename was accepted and echoed verbatim in
Content-Disposition. SanitizeFilename already truncates; lower the cap
from 255 to 128 so DB rows and header echoes stay bounded (#248).
The paste gutter was pinned to a fixed 3ch width. With box-sizing:
border-box that leaves only ~19px of content after the 10px+10px side
padding, so 2+ digit line numbers overflow right into the code text
(owner-visible from line 10, worst at 100+).
paste-lines.js now sets the gutter width to calc(Nch + 20px), where N is
the digit count of the highest line number, via CSSOM (CSP forbids
inline style attributes). Numbers were already right-aligned; the column
now matches the width of the biggest number. The width is only written
when it changes, so the resize-observer/renumber loop keeps a stable
fixed point.
Fixed-position Top/Bottom pills appear only when content exceeds 2x
viewport height (window scroll on paste view, textarea scroll on /new).
New static/jump.js drives them; markup added to paste.html and new.html.
With wrap on, a logical line occupies several visual rows in the textarea
but the gutter showed one number per logical line, so every number after
the first wrapped line drifted off its text (the paste view fixed this in
#167; the editor gutter did not). Measure the wrapped row count per logical
line with a hidden mirror div sharing the editor's font and wrapping rules,
and render one .gutline block per visual row with the number on the first
row of its logical line. Re-measure on input, wrap toggle and resize.
Verified: gutter scrollHeight == textarea scrollHeight with zero diff at
1400x900 and 375x812, wrap on and off.
- Add code-viewer polish line to the feature list (pinned gutter sized to
the widest number, line wrap, jump buttons, theme-aware scrollbars)
- Extend mobile preview links (editor, dark and light paste views)
- Clarify PALETTE_MAX_ITEM covers can items and file attachments
- Document PALETTE_DEFAULT_DARK in docker-compose.yml so the compose file
really covers every env var
clientIP() keyed rate-limit buckets on the rightmost X-Forwarded-For
entry, assuming traefik appends the real client IP. The deployed ingress
does not rewrite XFF, so rotating the header gave a fresh bucket per
request (pentest H1: 8 creates with rotating XFF -> 6x201).
Now the bucket keys on the actual peer address (RemoteAddr) by default;
every client-supplied IP header is ignored. Deployments whose ingress
overwrites a client-IP header can opt in via PALETTE_TRUSTED_IP_HEADER
(e.g. CF-Connecting-IP behind Cloudflare) to restore per-client limits.
Adds tests: rotating XFF no longer resets the bucket; the trusted header
is honored only when explicitly configured.
The initial refresh() ran before the mobile layout settled (media queries,
fonts, async highlighting) and under-measured the content, leaving #jumpnav
hidden on long pastes at 375x812 until a resize event. Re-check after a
double rAF, on window load, after 300ms, and via a ResizeObserver on
document.body for late content growth. Editor textarea scroller unchanged.
handleRaw only streamed the blob behind an isImageMime gate (#221), so
non-image attachment pastes fell through to empty row.Content and /raw
served 0 bytes. Serve the blob for every attachment mime, passing the
sniffed mime through serveContentType so active-content types (html,
svg, xml) still serve as text/plain per the #34 rule. Regression tests
cover text and html attachments (size, Content-Type, byte equality).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Release PR for v0.5.0. Features since v0.4.0: theme-aware scrollbars (#273), editor gutter alignment with wrapped rows (#274), jump to top/bottom buttons (#267), page URL renames to match nav labels (#256), static-width copy feedback (#260), gutter sized to widest line number (#257), gutter pinned during horizontal scroll (#261), widened history URL column (#255), rate limiter hardening (#280), jumpnav mobile fix (#282), /raw attachment streaming fix (#281), README/screenshot refresh.