From 7d0d303c2a7d7a6a205fc6d340dd32cda8ed8c2a Mon Sep 17 00:00:00 2001 From: Thayol Date: Sun, 13 Sep 2026 08:57:01 +0200 Subject: [PATCH] Rename to uncensored-send --- .gitignore | 2 +- README.md | 8 ++++---- go.mod | 2 +- internal/auth/tokens.go | 2 +- internal/auth/tokens_test.go | 2 +- internal/config/config.go | 2 +- internal/config/config_test.go | 8 ++++---- internal/config/flags.go | 6 +++--- internal/server/admin.go | 2 +- internal/server/cookie.go | 2 +- internal/server/delete.go | 4 ++-- internal/server/download.go | 2 +- internal/server/login.go | 2 +- internal/server/pages.go | 6 +++--- internal/server/ratelimit.go | 2 +- internal/server/server.go | 8 ++++---- internal/server/server_test.go | 8 ++++---- internal/server/upload.go | 6 +++--- main.go | 24 ++++++++++++------------ token.go | 22 +++++++++++----------- web/templates/admin.html | 2 +- 21 files changed, 61 insertions(+), 61 deletions(-) diff --git a/.gitignore b/.gitignore index d8c1e8c..e69e0ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -/send +/uncensored-send /data/ diff --git a/README.md b/README.md index 8d06eab..b21fdfe 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ Built for sharing large binaries with friends so that I don't have to manually m ``` go build -./send token add me --vanity --admin -./send +./uncensored-send token add me --vanity --admin +./uncensored-send ``` Open , click **Log in**, paste the token. That's it. @@ -25,9 +25,9 @@ upload limit. ## Options -**Read `./send --help` rather than this file.** +**Read `./uncensored-send --help` rather than this file.** -Every option also reads from `SEND_`-prefixed environment variables. +Every option also reads from `UNCENSORED_SEND_`-prefixed environment variables. ## Development diff --git a/go.mod b/go.mod index 10d92b9..907998b 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module send +module uncensored-send go 1.25 diff --git a/internal/auth/tokens.go b/internal/auth/tokens.go index d15d965..e734b81 100644 --- a/internal/auth/tokens.go +++ b/internal/auth/tokens.go @@ -18,7 +18,7 @@ import ( "sync" "time" - "send/internal/config" + "uncensored-send/internal/config" ) // tokenFilePerm is deliberately stricter than the rest of the data directory: diff --git a/internal/auth/tokens_test.go b/internal/auth/tokens_test.go index 678c327..a2ed188 100644 --- a/internal/auth/tokens_test.go +++ b/internal/auth/tokens_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "send/internal/config" + "uncensored-send/internal/config" ) func defaults() *config.Config { diff --git a/internal/config/config.go b/internal/config/config.go index 46b6bc2..181183c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -35,7 +35,7 @@ type Config struct { trustedProxyNets []*net.IPNet } -const EnvPrefix = "SEND_" +const EnvPrefix = "UNCENSORED_SEND_" // Register wires every option onto s. Short forms exist only for the options // reached often; everything else is long-only, by design. diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 6918511..e62945c 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -86,7 +86,7 @@ func TestFormatRoundTrips(t *testing.T) { func TestHyphenConvention(t *testing.T) { newSet := func() (*Set, *string) { var listen string - s := NewSet("test", "SEND_TEST_") + s := NewSet("test", "UNCENSORED_SEND_TEST_") s.String(&listen, "listen", "l", "default", "ADDR", "listen address") return s, &listen } @@ -116,9 +116,9 @@ func TestHyphenConvention(t *testing.T) { } func TestEnvFallback(t *testing.T) { - t.Setenv("SEND_TEST_MAX_SIZE", "4GiB") + t.Setenv("UNCENSORED_SEND_TEST_MAX_SIZE", "4GiB") var size int64 - s := NewSet("test", "SEND_TEST_") + s := NewSet("test", "UNCENSORED_SEND_TEST_") s.Size(&size, "max-size", "s", "2GiB", "cap") if err := s.Parse(nil); err != nil { t.Fatal(err) @@ -128,7 +128,7 @@ func TestEnvFallback(t *testing.T) { } // An explicit flag still wins over the environment. - s = NewSet("test", "SEND_TEST_") + s = NewSet("test", "UNCENSORED_SEND_TEST_") s.Size(&size, "max-size", "s", "2GiB", "cap") if err := s.Parse([]string{"--max-size", "1GiB"}); err != nil { t.Fatal(err) diff --git a/internal/config/flags.go b/internal/config/flags.go index ca3cf20..0dfbdc3 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -52,7 +52,7 @@ func (s *Set) note(long, short string) { } } -// envName maps --max-size to SEND_MAX_SIZE. +// envName maps --max-size to UNCENSORED_SEND_MAX_SIZE. func (s *Set) envName(long string) string { return s.envPrefix + strings.ToUpper(strings.ReplaceAll(long, "-", "_")) } @@ -183,7 +183,7 @@ func (s *Set) checkConvention(args []string) error { return nil } -// applyEnv seeds every option from its SEND_-prefixed environment variable. +// applyEnv seeds every option from its UNCENSORED_SEND_-prefixed environment variable. // Called before parsing so an explicit command-line flag always wins. func (s *Set) applyEnv() error { for _, sp := range s.specs { @@ -214,7 +214,7 @@ func (s *Set) Parse(args []string) error { // Changed reports whether an option was given on the command line. // // Values picked up from the environment do not count: a command that acts only -// on the options you actually typed must not quietly act on a SEND_ variable +// on the options you actually typed must not quietly act on a UNCENSORED_SEND_ variable // exported for the server. func (s *Set) Changed(long string) bool { if s.fromEnv[long] { diff --git a/internal/server/admin.go b/internal/server/admin.go index 5419fb2..a4fd6b5 100644 --- a/internal/server/admin.go +++ b/internal/server/admin.go @@ -7,7 +7,7 @@ import ( "slices" "time" - "send/internal/config" + "uncensored-send/internal/config" ) // adminPage is the one view that shows every object, regardless of who diff --git a/internal/server/cookie.go b/internal/server/cookie.go index ed93fc0..5eaa212 100644 --- a/internal/server/cookie.go +++ b/internal/server/cookie.go @@ -14,7 +14,7 @@ import ( // reason to prefer it over localStorage, where any injected script could // exfiltrate the credential. The page never needs to see the value: the server // resolves it and renders who the caller is. -const tokenCookie = "send_token" +const tokenCookie = "uncensored_send_token" // rememberFor is how long a persisted login survives. Tokens are revoked by // deleting them from the token file, so a long window costs nothing. diff --git a/internal/server/delete.go b/internal/server/delete.go index 481c8ed..5d9344f 100644 --- a/internal/server/delete.go +++ b/internal/server/delete.go @@ -4,8 +4,8 @@ import ( "net/http" "strings" - "send/internal/auth" - "send/internal/store" + "uncensored-send/internal/auth" + "uncensored-send/internal/store" ) // handleDelete removes an object early. Three credentials are accepted: the diff --git a/internal/server/download.go b/internal/server/download.go index 70825b3..71c7e61 100644 --- a/internal/server/download.go +++ b/internal/server/download.go @@ -4,7 +4,7 @@ import ( "net/http" "strings" - "send/internal/store" + "uncensored-send/internal/store" ) // downloadCSP is as inert as a policy gets. Combined with the attachment diff --git a/internal/server/login.go b/internal/server/login.go index c29b39e..f500bf9 100644 --- a/internal/server/login.go +++ b/internal/server/login.go @@ -5,7 +5,7 @@ import ( "net/url" "strings" - "send/internal/config" + "uncensored-send/internal/config" ) // loginPage backs both the form and its error redisplay. diff --git a/internal/server/pages.go b/internal/server/pages.go index 441939f..0e6136b 100644 --- a/internal/server/pages.go +++ b/internal/server/pages.go @@ -6,9 +6,9 @@ import ( "net/http" "time" - "send/internal/auth" - "send/internal/config" - "send/internal/store" + "uncensored-send/internal/auth" + "uncensored-send/internal/config" + "uncensored-send/internal/store" ) func writeJSON(w http.ResponseWriter, status int, v any) { diff --git a/internal/server/ratelimit.go b/internal/server/ratelimit.go index 1f449f4..bf7ad90 100644 --- a/internal/server/ratelimit.go +++ b/internal/server/ratelimit.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "send/internal/config" + "uncensored-send/internal/config" ) // limiter is a per-key token bucket. It is deliberately small: there is no diff --git a/internal/server/server.go b/internal/server/server.go index 8529bc9..eb203b8 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -11,10 +11,10 @@ import ( "strings" "time" - "send/internal/auth" - "send/internal/config" - "send/internal/store" - "send/web" + "uncensored-send/internal/auth" + "uncensored-send/internal/config" + "uncensored-send/internal/store" + "uncensored-send/web" ) // Server holds everything the handlers need. It is safe for concurrent use. diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 1c1b492..eca81ce 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -19,9 +19,9 @@ import ( "testing" "time" - "send/internal/auth" - "send/internal/config" - "send/internal/store" + "uncensored-send/internal/auth" + "uncensored-send/internal/config" + "uncensored-send/internal/store" ) // clock is the fixed instant tests start from; s.now is swapped so expiry can @@ -42,7 +42,7 @@ func newHarness(t *testing.T, tweak func(*config.Config)) *harness { dir := t.TempDir() cfg := config.Config{} - fs := config.NewSet("test", "SEND_TEST_") + fs := config.NewSet("test", "UNCENSORED_SEND_TEST_") cfg.Register(fs) if err := fs.Parse(nil); err != nil { t.Fatal(err) diff --git a/internal/server/upload.go b/internal/server/upload.go index 633cb52..137dee9 100644 --- a/internal/server/upload.go +++ b/internal/server/upload.go @@ -10,9 +10,9 @@ import ( "strings" "time" - "send/internal/auth" - "send/internal/config" - "send/internal/store" + "uncensored-send/internal/auth" + "uncensored-send/internal/config" + "uncensored-send/internal/store" ) const ( diff --git a/main.go b/main.go index 121a291..d5db83c 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,4 @@ -// Command send is a small self-hosted file drop: uploads land in a flat data +// Command uncensored-send is a small self-hosted file drop: uploads land in a flat data // directory, expire on their own, and are served back as inert attachments. package main @@ -15,10 +15,10 @@ import ( "syscall" "time" - "send/internal/auth" - "send/internal/config" - "send/internal/server" - "send/internal/store" + "uncensored-send/internal/auth" + "uncensored-send/internal/config" + "uncensored-send/internal/server" + "uncensored-send/internal/store" ) func main() { @@ -26,7 +26,7 @@ func main() { if errors.Is(err, flag.ErrHelp) { os.Exit(0) } - fmt.Fprintln(os.Stderr, "send: "+err.Error()) + fmt.Fprintln(os.Stderr, "uncensored-send: "+err.Error()) os.Exit(1) } } @@ -38,13 +38,13 @@ func run(args []string) error { return serve(args) } -const serveUsage = `send - a small self-hosted file drop +const serveUsage = `uncensored-send - a small self-hosted file drop Usage: - send [options] run the server - send token add [opts] mint a token, printing it once - send token list list tokens - send token rm remove a token + uncensored-send [options] run the server + uncensored-send token add [opts] mint a token, printing it once + uncensored-send token list list tokens + uncensored-send token rm remove a token Options take one hyphen with a single letter (-s) and two with a full word (--max-size). Every option can also be set from the environment. @@ -54,7 +54,7 @@ Options: func serve(args []string) error { var cfg config.Config - fs := config.NewSet("send", config.EnvPrefix) + fs := config.NewSet("uncensored-send", config.EnvPrefix) fs.SetOutput(os.Stderr) cfg.Register(fs) diff --git a/token.go b/token.go index 3975e32..d011559 100644 --- a/token.go +++ b/token.go @@ -12,19 +12,19 @@ import ( "text/tabwriter" "time" - "send/internal/auth" - "send/internal/config" + "uncensored-send/internal/auth" + "uncensored-send/internal/config" ) -const tokenUsage = `send token - manage upload credentials +const tokenUsage = `uncensored-send token - manage upload credentials Usage: - send token add [options] generate a token - send token add --token - read a chosen one from stdin - send token rotate [--token -] replace the secret, keep everything else - send token set [options] change limits and flags in place - send token list [options] - send token rm [options] + uncensored-send token add [options] generate a token + uncensored-send token add --token - read a chosen one from stdin + uncensored-send token rotate [--token -] replace the secret, keep everything else + uncensored-send token set [options] change limits and flags in place + uncensored-send token list [options] + uncensored-send token rm [options] A token grants its own size and lifetime limits. Any limit left unset is inherited from the running server's defaults, so a token with no options @@ -136,7 +136,7 @@ type tokenOptions struct { } func (o *tokenOptions) register() *config.Set { - fs := config.NewSet("send token", config.EnvPrefix) + fs := config.NewSet("uncensored-send token", config.EnvPrefix) fs.String(&o.dataDir, "data", "d", "./data", "DIR", "directory holding the data") fs.String(&o.tokensPath, "tokens", "", "", "FILE", "token file location (default /tokens.json)") fs.String(&o.maxSize, "max-size", "s", "", "SIZE", "per-upload cap for this token; 'unlimited' to remove it") @@ -296,7 +296,7 @@ func tokenSet(file *auth.File, name string, opts tokenOptions, fs *config.Set) e changes = append(changes, fmt.Sprintf("--%s=%t", f.flag, f.value)) } if fs.Changed("token") { - return errors.New("use \"send token rotate\" to change the secret") + return errors.New("use \"uncensored-send token rotate\" to change the secret") } return nil }) diff --git a/web/templates/admin.html b/web/templates/admin.html index ff1a8cc..e51bd85 100644 --- a/web/templates/admin.html +++ b/web/templates/admin.html @@ -52,7 +52,7 @@

Tokens

- Tokens are minted, rotated and revoked with ./send token on the + Tokens are minted, rotated and revoked with ./uncensored-send token on the server. They are deliberately not manageable from here: nothing that hands out credentials should be reachable over the network.