Skip to content

feat(uploads): tokenless draft/FILEHOST + origin-based media trust#237

Open
ValwareIRC wants to merge 3 commits into
feat/uploaders-draft-authtokenfrom
feat/tokenless-filehost
Open

feat(uploads): tokenless draft/FILEHOST + origin-based media trust#237
ValwareIRC wants to merge 3 commits into
feat/uploaders-draft-authtokenfrom
feat/tokenless-filehost

Conversation

@ValwareIRC
Copy link
Copy Markdown
Contributor

Summary

Stacked on #219 (the draft/authtoken + obby.world/FILEHOST vendor rename). Adds support for the standard tokenless draft/FILEHOST and fixes filehost media trust to be origin-based.

Base branch is feat/uploaders-draft-authtoken (#219); GitHub will retarget to the default branch once #219 merges.

Tokenless draft/FILEHOST

  • isupport.tsdraft/FILEHOSTserver.fileHosts[] (a space-separated list of upload endpoints; parseIsupport has already un-escaped \x20).
  • mediaUpload.tsuploadFileTokenless() POSTs the file (multipart file field) directly to an advertised endpoint, no auth. Resolves the URL from the spec's Location header, else a JSON {url}/{saved_url} body, else a plain-text URL body (covers girafiles/s.h4ks.com, which returns 200 + {"url":…}).
  • ChatArea — prefer the tokenless endpoint when offered, else the vendor token path; no token mint / policy pre-flight on the tokenless path. canUpload now gates the picker + drag-drop on either mechanism. A server is expected to advertise one mechanism or the other, not both.

Browser uploads to an external host require CORS (Access-Control-Allow-Origin) on that host; native clients are unrestricted.

Media-trust fix

Uploaded files are served from the filehost's domain root, but the trust check matched the full filehost value including its path — so when draft/FILEHOST advertises a path endpoint (e.g. https://host/api/), files at https://host/xyz failed and wouldn't render.

  • isUrlFromFilehost now matches on origin only (path ignored) and accepts a single host or a list.
  • New serverFilehosts(server) folds the tokenless fileHosts in alongside the vendor filehost, threaded through every media/avatar trust site (the old !!server?.filehost && guards short-circuited when only fileHosts was set; one site even used a raw startsWith).

Server companion

draft/FILEHOST is advertised by obbyircd via a new external config directive (ObbyIRCd branch feat/obby-world-filehost):

filehosts {
    host 'https://obby.t3ks.com';        # account-gated -> obby.world/FILEHOST
    external 'https://s.h4ks.com/api/';  # tokenless     -> draft/FILEHOST
}

Tests

  • parseFilehostUploadResponse: Location / JSON {url},{saved_url} / plain-text precedence.
  • Origin-based trust: root file under a /api/ filehost, host lists, serverFilehosts.
  • Full suite green; tsc + vite build clean.

Test plan

  • tsc + build + tests
  • Browser: tokenless upload to s.h4ks.com → URL posted + renders inline
  • Native app: upload (no CORS needed)

Implement the standard IRCv3 draft/FILEHOST: the server advertises a
space-separated list of upload endpoints; the client POSTs the file
directly (multipart 'file' field, no auth) and takes the returned URL.

- isupport.ts: draft/FILEHOST -> server.fileHosts[] (split the already
  \x20-unescaped value, keep http(s) URIs).
- mediaUpload.ts: uploadFileTokenless() -- POST to the endpoint, resolve
  from the Location header (spec), else a JSON {url}/{saved_url} body,
  else a plain-text URL.
- ChatArea: prefer tokenless when offered, else the vendor token path;
  no token mint / policy preflight on the tokenless path. canUpload now
  gates the picker + drag-drop on either filehost mechanism.

Browser uploads to an external host need CORS on that host; native
clients are unrestricted.
Extract parseFilehostUploadResponse from uploadFileTokenless so the
Location-header / JSON-body / plain-text-URL precedence is unit-tested
without XHR mocking.
Uploaded files are served from the filehost's domain root, but the
trust check matched the full filehost value including its path — so when
draft/FILEHOST advertises a path endpoint (e.g. https://host/api/), files
at https://host/xyz failed the check and wouldn't render. Match on origin
only.

Also fold the tokenless draft/FILEHOST list (server.fileHosts) into the
trust set alongside the vendor server.filehost via a new serverFilehosts()
helper, and thread it through every media/avatar trust call site (the old
!!server?.filehost && ... guards short-circuited when only fileHosts was
set). isUrlFromFilehost now accepts a single host or a list.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ccb5ac74-a22a-4313-a027-9ea66cbb79de

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tokenless-filehost

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant