diff --git a/README.md b/README.md index c1d5c5b..98277a1 100644 --- a/README.md +++ b/README.md @@ -1,114 +1,128 @@ # noxy is a nostr proxy -noxy receives a [nostr](https://nostr.info/) event id, fetches images and -link previews, and returns the result in a JSON object. the idea is to run -such proxies to reduce IP address leaks and client fingerprinting. +noxy proxies URL preview metadata, images and other media files. +the idea is to run such proxies to reduce IP address leaks and client +fingerprinting. -## API v1 +to limit noxy abuse, it works only with URLs linked to +from [nostr](https://nostr.info/) events. the following nostr event kinds +are currently supported: -over HTTP, noxy exposes a single endpoint accepting a nostr event id and -a relay to fetch the event from: +- 0: `set_metadata`; `picture` URL +- 1: `text_note`; any URL in the `content` +- 40: create channel; `picture` URL +- 41: set channel metadata; `picture` URL +- 42: channel message; any URL in the `content` - GET /api/v1/e/?relay= +## API -the response is an array of objects: +over HTTP, noxy exposes two endpoints: one for meta info of URL preview, +and the other one for file (data) transfer. + +### /meta + +the request has the following form. all parameter values are expected to be +url-encoded. + + GET /meta?id=&relay=&url= + +the parameters are: + +- `id`: nostr event id as described in [NIP-01](https://github.com/nostr-protocol/nips/blob/master/01.md) +- `relay`: a URL of a nostr relay where the event was posted to +- `url`: any URL found in the event text note or the `picture` for structured messages + +noxy fetches HTML at `url`, looks for [OGP](https://ogp.me/) metadata +and responds with a JSON object containing the following keys: ```json -[ - { - "url": "", - "cache": "", - "kind": "media|preview", - "size": 123, - "title": "resource title", - "descr": "resource description" - } -] +{ + "type": "", + "title": "", + "descr": "", + "images": ["", ...] +} ``` -where `url` is the original url found in a nostr event payload and `cache` is the -proxied url or a link preview image. the other fields presence and their values -depend on the `kind` of the resource. +where image URLs are taken from `og:image:secure_url` or `og:image`; the former +is preferred. other fields are copied verbatim from `og:type`, `og:title` +and `og:description`, respectively. future versions may also employ +[oEmbed](https://oembed.com/) and other metadata formats parsing. -for images, videos and audio the `kind` field is `media` and the `size` is the -file size in bytes as stored in cache. if the file size is unknown at the time -of a response, it is 0. +the web page at `url` must be served with `text/html` content type. if the page +contains no or empty OGP metadata, noxy response with 200 OK and blank fields. +otherwise, the response is a 4xx status code. -for link previews, the `kind` field is `preview`, `cache` url points to a link -preview image and the `size` is the preview image size. link preview image, -`title` and `descr` field values are collected using -[the open graph protocol](https://ogp.me/) or [oEmbed](https://oembed.com/). +### /data -some examples follow. +data endpoint request is of the following form. all parameter values are +expected to be url-encoded. -### fetch a pubkey profile picture, event kind 0 + GET /data?id=&relay=&url= +the parameters are: -request example: +- `id`: a nostr event id +- `relay`: a URL of a nostr relay where the event was posted to +- `url`: any URL found either in the event text note, `picture` field for +structured messages, or an `images` array element of a `/meta` endpoint response +produced from the same event id. - GET /api/v1/e/e01ac1cfc5cb68b54183f878261b21ef30a65f5e06a24356cfe3ecdacce14bae?relay=wss%3A%2F%2Frelay.nostr.info +the data endpoint simply streams contents at the `url` to the client +with the same `content-type` as the original. `content-length` may or may +not be present. in the latter case, the response is chunked. -response: +### example: fetch a pubkey profile picture, event kind 0 -```json -[ - { - "url": "https://git.qcode.ch/avatars/5a8071777eba7ebf178143fa650c8012?size=870", - "cache": "https://noxy.example.org/abcdef/abcdef0123456789.png", - "kind": "media", - "size": 279342 - } -] -``` + $ eventid=e01ac1cfc5cb68b54183f878261b21ef30a65f5e06a24356cfe3ecdacce14bae + $ relay=wss://relay.nostr.info + $ url=https://git.qcode.ch/avatars/5a8071777eba7ebf178143fa650c8012?size=870 + $ curl -o /tmp/img "https://noxy.nostr.ch/data?id=$eventid&relay=$relay&url=$url" + $ file /tmp/img + /tmp/img: PNG image data, 290 x 290, 16-bit/color RGB, non-interlaced [event raw data →](https://nostr.com/e/e01ac1cfc5cb68b54183f878261b21ef30a65f5e06a24356cfe3ecdacce14bae) -if a noxy instance is unable to fetch the original, it responds with an empty array: +### example: fetch images from a text note, event kind 1 -```json -[] -``` + $ eventid=d822fdd220d8a74d2f025f331840eec8a640a663f1d3ca3de9f6a74ff0cc61fa + $ relay=wss://relay.damus.io + $ url=https://res.cloudinary.com/eskema/image/upload/v1668636521/osso_vt7qh7.png + $ curl -o /tmp/img "https://noxy.nostr.ch/data?id=$eventid&relay=$relay&url=$url" + $ file /tmp/img + /tmp/img: PNG image data, 800 x 800, 8-bit/color RGB, non-interlaced -### fetch images from a text note, event kind 1 +[event raw data →](https://nostr.com/e/d822fdd220d8a74d2f025f331840eec8a640a663f1d3ca3de9f6a74ff0cc61fa) -request example: +### example: fetch link preview from a text note, event kind 1 - GET /api/v1/e/d822fdd220d8a74d2f025f331840eec8a640a663f1d3ca3de9f6a74ff0cc61fa?relay=wss%3A%2F%2Frelay.damus.io + $ EVENTID=af30dac1d800acc25b87d0d6d0dd33bddf49e7f356556540a6c7722e3cb363fe + $ RELAY=wss://nostr.x1ddos.ch/ + $ URL=https://github.com/fiatjaf/noscl/pull/24 + $ curl "https://noxy.nostr.ch/meta?id=$EVENTID&relay=$RELAY&url=$URL" response: ```json -[ - { - "url": "https://res.cloudinary.com/eskema/image/upload/v1668636521/osso_vt7qh7.png", - "cache": "https://noxy.example.org/fedcba/fedcba9876543210.png", - "kind": "media", - "size": 93241 - } -] +{ + "type": "object", + "title": "publish,message: accept content from stdin by x1ddos · Pull Request #24 · fiatjaf/noscl", + "descr": "if the arg to publish or message command is '-', it is read from stdin.\ncloses #19", + "images": [ + "https://opengraph.githubassets.com/dc27bad9f4d71ea7803c4bd07a9991c0bcb798bbdc451aebc42d222e5d7692c8/fiatjaf/noscl/pull/24" + ] +} ``` -[event raw data →](https://nostr.com/e/d822fdd220d8a74d2f025f331840eec8a640a663f1d3ca3de9f6a74ff0cc61fa) +now, fetch the preview image. note the change from `/meta` to `/data` endpoint: -### fetch link preview from a text note, event kind 1 + $ URL=https://opengraph.githubassets.com/dc27bad9f4d71ea7803c4bd07a9991c0bcb798bbdc451aebc42d222e5d7692c8/fiatjaf/noscl/pull/24 + $ curl -o /tmp/img "https://noxy.nostr.ch/data?id=$EVENTID&relay=$RELAY&url=$URL" + $ file /tmp/img + /tmp/img: PNG image data, 1200 x 600, 8-bit/color RGBA, non-interlaced -request example: +[event raw data →](https://nostr.com/e/af30dac1d800acc25b87d0d6d0dd33bddf49e7f356556540a6c7722e3cb363fe) - GET /api/v1/e/af30dac1d800acc25b87d0d6d0dd33bddf49e7f356556540a6c7722e3cb363fe?relay=wss%3A%2F%2Fnostr.x1ddos.ch%2F -response: -```json -[ - { - "url": "https://github.com/fiatjaf/noscl/pull/24", - "cache": "https://noxy.example.org/beef01/beef0123456789.png", - "kind": "preview", - "size": 110480, - "title": "publish,message: accept content from stdin by x1ddos · Pull Request #24 · fiatjaf/noscl", - "descr": "if the arg to publish or message command is '-', it is read from stdin.\ncloses #19" - } -] -``` -[event raw data →](https://nostr.com/e/af30dac1d800acc25b87d0d6d0dd33bddf49e7f356556540a6c7722e3cb363fe)