documentation comments for all the commands and bech32 pointers
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
// Package pointers is a set of basic nip-19 data types for generating bech32
|
||||
// encoded nostr entities.
|
||||
package pointers
|
||||
|
||||
import (
|
||||
|
||||
2
cmd/doc.go
Normal file
2
cmd/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package cmd contains the executable applications of the realy suite.
|
||||
package cmd
|
||||
196
cmd/jurl/main.go
196
cmd/jurl/main.go
@@ -1,196 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
realy_lol "realy.lol"
|
||||
"realy.lol/httpauth"
|
||||
"realy.lol/lol"
|
||||
"realy.lol/sha256"
|
||||
)
|
||||
|
||||
const issuer = "NOSTR_PUBLIC_KEY"
|
||||
const secEnv = "NOSTR_JWT_SECRET"
|
||||
|
||||
var userAgent = fmt.Sprintf("nurl/%s", realy_lol.Version)
|
||||
|
||||
func fail(format string, a ...any) {
|
||||
_, _ = fmt.Fprintf(os.Stderr, format+"\n", a...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
lol.SetLogLevel("trace")
|
||||
if len(os.Args) > 1 && os.Args[1] == "help" {
|
||||
fmt.Printf(`jurl help:
|
||||
|
||||
for nostr http using JWT HTTP authentication:
|
||||
|
||||
jurl <url> <file>
|
||||
|
||||
if no file is given, the request will be processed as a HTTP GET
|
||||
(if relevant there can be request parameters)
|
||||
|
||||
* JWT secret will be expected in the environment variable "%s" -
|
||||
if absent, will not be added to the header
|
||||
|
||||
* the "issuer" key, the nostr public key associated with the JWT public
|
||||
key must also be available at %s or authorization will fail
|
||||
|
||||
Endpoint is assumed to not require it if absent. an error will be returned
|
||||
if it was needed; if the relay does not have a kind 13004 event binding the
|
||||
JWT public key to a nostr public key then it will also fail
|
||||
|
||||
output will be rendered to stdout
|
||||
|
||||
* note this tool is designed to generate momentary authorizations, if you have
|
||||
an unexpired JWT token you can just add it with the
|
||||
|
||||
"Authorization: Bearer <token>"
|
||||
|
||||
as an additional HTTP header field if you have it to any other HTTP request
|
||||
tool, such as "curl", by using "nostrjwt bearer" command
|
||||
|
||||
`, secEnv, issuer)
|
||||
os.Exit(0)
|
||||
}
|
||||
if len(os.Args) < 2 {
|
||||
fail(`error: nurl requires minimum 1 arg: <url>
|
||||
|
||||
signing nsec (in bech32 format) is expected to be found in %s environment variable.
|
||||
|
||||
use "help" to get usage information
|
||||
`, secEnv)
|
||||
}
|
||||
if len(os.Args) < 2 {
|
||||
fail(`error: nurl requires minimum 1 arg: <url>
|
||||
|
||||
signing JWT secret is expected to be found in %s environment variable.
|
||||
|
||||
use "help" to get usage information
|
||||
`, secEnv)
|
||||
}
|
||||
var err error
|
||||
var ur *url.URL
|
||||
if ur, err = url.Parse(os.Args[1]); chk.E(err) {
|
||||
fail("invalid URL: `%s` error: `%s`", os.Args[2], err.Error())
|
||||
}
|
||||
jwtSec := os.Getenv(secEnv)
|
||||
bearer := os.Getenv(issuer)
|
||||
if jwtSec == "" {
|
||||
log.I.F("no key found in environment variable %s", secEnv)
|
||||
} else {
|
||||
var jskb []byte
|
||||
if jskb, err = base64.URLEncoding.DecodeString(jwtSec); chk.E(err) {
|
||||
fail(err.Error())
|
||||
}
|
||||
var sec *ecdsa.PrivateKey
|
||||
if sec, err = x509.ParseECPrivateKey(jskb); chk.E(err) {
|
||||
fail(err.Error())
|
||||
}
|
||||
var claims []byte
|
||||
// generate claim
|
||||
if claims, err = httpauth.GenerateJWTClaims(bearer, ur.String()); chk.E(err) {
|
||||
fail(err.Error())
|
||||
}
|
||||
if bearer, err = httpauth.SignJWTtoken(claims, sec); chk.E(err) {
|
||||
fail(err.Error())
|
||||
}
|
||||
}
|
||||
if len(os.Args) == 2 {
|
||||
if err = Get(ur, bearer); chk.E(err) {
|
||||
fail(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
if err = Post(os.Args[2], ur, bearer); chk.E(err) {
|
||||
fail(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func Get(ur *url.URL, bearer string) (err error) {
|
||||
var r *http.Request
|
||||
if r, err = http.NewRequest("GET", ur.String(), nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
r.Header.Add("User-Agent", userAgent)
|
||||
if bearer != "" {
|
||||
r.Header.Add("Authorization", "Authorization "+bearer)
|
||||
}
|
||||
client := &http.Client{
|
||||
CheckRedirect: func(req *http.Request,
|
||||
via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
}
|
||||
var res *http.Response
|
||||
if res, err = client.Do(r); chk.E(err) {
|
||||
err = errorf.E("request failed: %w", err)
|
||||
return
|
||||
}
|
||||
if _, err = io.Copy(os.Stdout, res.Body); chk.E(err) {
|
||||
res.Body.Close()
|
||||
return
|
||||
}
|
||||
res.Body.Close()
|
||||
return
|
||||
}
|
||||
|
||||
func Post(filePath string, ur *url.URL, bearer string) (err error) {
|
||||
var contentLength int64
|
||||
var payload io.ReadCloser
|
||||
var b []byte
|
||||
if b, err = os.ReadFile(filePath); chk.E(err) {
|
||||
fail(err.Error())
|
||||
}
|
||||
H := sha256.Sum256(b)
|
||||
_ = H
|
||||
var fi os.FileInfo
|
||||
if fi, err = os.Stat(filePath); chk.E(err) {
|
||||
return
|
||||
}
|
||||
contentLength = fi.Size()
|
||||
if payload, err = os.Open(filePath); chk.E(err) {
|
||||
return
|
||||
}
|
||||
log.I.F("opened file %s", filePath)
|
||||
var r *http.Request
|
||||
r = &http.Request{
|
||||
Method: "POST",
|
||||
URL: ur,
|
||||
Proto: "HTTP/1.1",
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 1,
|
||||
Header: make(http.Header),
|
||||
Body: payload,
|
||||
ContentLength: contentLength,
|
||||
Host: ur.Host,
|
||||
}
|
||||
r.Header.Add("User-Agent", userAgent)
|
||||
r.Header.Add("Authorization", "Bearer "+bearer)
|
||||
r.Header.Add("Accept", "application/nostr+json")
|
||||
r.GetBody = func() (rc io.ReadCloser, err error) {
|
||||
rc = payload
|
||||
return
|
||||
}
|
||||
// log.I.S(r)
|
||||
client := &http.Client{}
|
||||
var res *http.Response
|
||||
if res, err = client.Do(r); chk.E(err) {
|
||||
return
|
||||
}
|
||||
// log.I.S(res)
|
||||
defer res.Body.Close()
|
||||
if io.Copy(os.Stdout, res.Body); chk.E(err) {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"realy.lol/lol"
|
||||
)
|
||||
|
||||
var (
|
||||
log, chk, errorf = lol.Main.Log, lol.Main.Check, lol.Main.Errorf
|
||||
equals = bytes.Equal
|
||||
)
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package buf implements a simple concurrent safe buffer pool for raw bytes.
|
||||
package buf
|
||||
|
||||
import "sync"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package hsts implements a HTTP handler that enforces HSTS.
|
||||
package hsts
|
||||
|
||||
import "net/http"
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package reverse is a copy of httputil.NewSingleHostReverseProxy with addition
|
||||
// of "X-Forwarded-Proto" header.
|
||||
package reverse
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package tcpkeepalive implements a net.TCPListener with a singleton set period
|
||||
// for a default 3 minute keep-aline.
|
||||
package tcpkeepalive
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package timeout provides a simple extension of a net.TCPConn with a
|
||||
// configurable read/write deadline.
|
||||
package timeout
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Package util provides some helpers for lerproxy, a tool to convert maps of
|
||||
// strings to slices of the same strings, and a helper to avoid putting two / in
|
||||
// a URL.
|
||||
package util
|
||||
|
||||
import "strings"
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Package main is a tool for generating new JWT key pairs and a kind 13004 JWT
|
||||
// delegation event that allows authentication against a pubkey while using
|
||||
// non-nostr-native tools such as cURL and Postman and minimalistic HTTP browser
|
||||
// implementations as found in some e-book readers.
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Package main is a simple implementation of a cURL like tool that can do
|
||||
// simple GET/POST operations on a HTTP server that understands NIP-98
|
||||
// authentication, with the signing key found in an environment variable.
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package app implements the realy nostr relay with a simple follow/mute list authentication scheme and the new HTTP REST based protocol.
|
||||
package app
|
||||
|
||||
import (
|
||||
@@ -1,3 +1,6 @@
|
||||
// Package main is a nostr relay with a simple follow/mute list authentication
|
||||
// scheme and the new HTTP REST based protocol. Configuration is via environment
|
||||
// variables or an optional .env file.
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package main is a simple nostr key miner that uses the fast bitcoin secp256k1
|
||||
// C library to derive npubs with specified prefix/infix/suffix strings present.
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
Reference in New Issue
Block a user