|
|
|
# noxy is a nostr proxy
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
- 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`
|
|
|
|
|
|
|
|
## API
|
|
|
|
|
|
|
|
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=<nostr-event-id>&relay=<relay-uri>&url=<original-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
|
|
|
|
{
|
|
|
|
"type": "<OGP type>",
|
|
|
|
"title": "<OGP title>",
|
|
|
|
"descr": "<OGP description>",
|
|
|
|
"images": ["<URL>", ...]
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
### /data
|
|
|
|
|
|
|
|
data endpoint request is of the following form. all parameter values are
|
|
|
|
expected to be url-encoded.
|
|
|
|
|
|
|
|
GET /data?id=<nostr-event-id>&relay=<relay-uri>&url=<file-url>
|
|
|
|
|
|
|
|
the parameters are:
|
|
|
|
|
|
|
|
- `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.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
### example: fetch a pubkey profile picture, event kind 0
|
|
|
|
|
|
|
|
$ 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)
|
|
|
|
|
|
|
|
### example: fetch images from a text note, event kind 1
|
|
|
|
|
|
|
|
$ 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
|
|
|
|
|
|
|
|
[event raw data →](https://nostr.com/e/d822fdd220d8a74d2f025f331840eec8a640a663f1d3ca3de9f6a74ff0cc61fa)
|
|
|
|
|
|
|
|
### example: fetch link preview from a text note, event kind 1
|
|
|
|
|
|
|
|
$ 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
|
|
|
|
{
|
|
|
|
"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"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
now, fetch the preview image. note the change from `/meta` to `/data` endpoint:
|
|
|
|
|
|
|
|
$ 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
|
|
|
|
|
|
|
|
[event raw data →](https://nostr.com/e/af30dac1d800acc25b87d0d6d0dd33bddf49e7f356556540a6c7722e3cb363fe)
|
|
|
|
|
|
|
|
## development
|
|
|
|
|
|
|
|
the binary's entry point is [cmd/noxy/main.go](cmd/noxy/main.go).
|
|
|
|
it imports packages in the root of the repo. the actual proxy is implemented
|
|
|
|
by `Noxer` in [noxy.go](noxy.go).
|
|
|
|
|
|
|
|
running the server locally:
|
|
|
|
|
|
|
|
mkdir cache
|
|
|
|
go run ./cmd/noxy -cachedir $PWD/cache
|
|
|
|
|
|
|
|
before sending a patch, make sure the code is passing tests:
|
|
|
|
|
|
|
|
go test -race
|
|
|
|
|
|
|
|
files are formatted:
|
|
|
|
|
|
|
|
go fmt ./...
|
|
|
|
|
|
|
|
and the go module file is updated:
|
|
|
|
|
|
|
|
go mod tidy
|
|
|
|
|
|
|
|
## release
|
|
|
|
|
|
|
|
a release binary is built using the following script.
|
|
|
|
it produces `noxy` executable in the root of the repo.
|
|
|
|
|
|
|
|
./tools/release.sh
|
|
|
|
|
|
|
|
before making a new release, you'll probably want to create a new git tag.
|
|
|
|
the tag is used as the noxy version, also printed when `-V` flag is specified.
|