From 9dc65f0de79f14776e576bd8b0403a5d6d02a979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9=20Vulquin?= Date: Mon, 27 Nov 2023 19:49:15 +0100 Subject: [PATCH 1/3] make remote host a real url this means you can do things like prefix-based reverse-proxying and reverse-proxying in general, actually --- src/cli.go | 30 ++++++++++++++++++++---------- src/sqlite_persistance.go | 27 ++++++++++++++------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/cli.go b/src/cli.go index a588af7..0f43533 100644 --- a/src/cli.go +++ b/src/cli.go @@ -159,9 +159,9 @@ func GetApp() cli.App { config_show := cli.NewCommand("show", "print current config"). WithAction(func(args []string, options map[string]string) int { p := getPersistance(options) - remote := p.State.RemoteHostname - if remote == "" { - remote = "(None)" + remote := "(None)" + if p.State.RemoteURL != nil { + remote = p.State.RemoteURL.Host } fmt.Printf("Encryption Key: \t%v\n", p.State.Key) @@ -232,10 +232,14 @@ func GetApp() cli.App { url, err := url.ParseRequestURI(host) if err != nil { - p.State.RemoteHostname = "http://" + host - } else { - p.State.RemoteHostname = url.String() + fmt.Println("Invalid url:", err.Error()) + return 2 + } + if !strings.HasPrefix(url.Scheme, "http") { + url.Scheme = "https" + fmt.Printf("Warning: only http(s) in URLs is supported, defaulting to https: %s\n", url) } + p.State.RemoteURL = url err = p.CommitState() if err != nil { @@ -266,7 +270,11 @@ func GetApp() cli.App { logger.Fatal("Key not found.") } - fmt.Println(p.State.RemoteHostname + "/get?q=" + entry.UrlToken) + u, _ := p.State.RemoteURL.Parse("get") // this should never fail + q := u.Query() + q.Set("q", entry.UrlToken) + u.RawQuery = q.Encode() + fmt.Println(u) return 0 }) qr := cli.NewCommand("qr", "print shareable qr code of entry to console"). @@ -289,9 +297,11 @@ func GetApp() cli.App { logger.Fatal("Key not found.") } - url := p.State.RemoteHostname + "/get?q=" + entry.UrlToken - - qrcode.QRCode(url, qrcode.BrightBlack, qrcode.BrightWhite, qr.Low) + url, _ := p.State.RemoteURL.Parse("get") // this should never fail + q := url.Query() + q.Set("q", entry.UrlToken) + url.RawQuery = q.Encode() + qrcode.QRCode(url.String(), qrcode.BrightBlack, qrcode.BrightWhite, qr.Low) return 0 }) diff --git a/src/sqlite_persistance.go b/src/sqlite_persistance.go index 6111ecc..2c1c13a 100644 --- a/src/sqlite_persistance.go +++ b/src/sqlite_persistance.go @@ -17,16 +17,17 @@ import ( "modernc.org/mathutil" _ "modernc.org/sqlite" "net/http" + "net/url" "os" ) type SqliteState struct { - Counter uint64 - Pid uint32 - Key string - RemoteHostname string - RemoteCounter uint64 - SchemaVersion uint32 + Counter uint64 + Pid uint32 + Key string + RemoteURL *url.URL + RemoteCounter uint64 + SchemaVersion uint32 } type SqlitePersistance struct { @@ -36,7 +37,7 @@ type SqlitePersistance struct { } func (p *SqlitePersistance) GetRemoteUpdates() (err error) { - if p.State.RemoteHostname == "" { + if p.State.RemoteURL == nil { return nil } request, err := json.Marshal(UpdateRequest{ProcessID: p.State.Pid, Counter: p.State.RemoteCounter}) @@ -49,7 +50,8 @@ func (p *SqlitePersistance) GetRemoteUpdates() (err error) { return err } - resp, err := http.Post(p.State.RemoteHostname+"/pull", "application/json", bytes.NewReader(request)) + pull, _ := p.State.RemoteURL.Parse("pull") // this should never fail + resp, err := http.Post(pull.String(), "application/json", bytes.NewReader(request)) if err != nil { return err } @@ -81,9 +83,7 @@ func (p *SqlitePersistance) GetRemoteUpdates() (err error) { func (p *SqlitePersistance) Push() error { // push changes to remote - - host := p.State.RemoteHostname - if host == "" { + if p.State.RemoteURL == nil { return nil } updates, err := p.GetUpdates(UpdateRequest{Counter: p.State.RemoteCounter, ProcessID: ReservedProcessID}) @@ -99,7 +99,8 @@ func (p *SqlitePersistance) Push() error { panic(err) } - resp, err := http.DefaultClient.Post(host+"/push", "application/json", bytes.NewReader(payload)) + push, _ := p.State.RemoteURL.Parse("push") // this should never fail + resp, err := http.DefaultClient.Post(push.String(), "application/json", bytes.NewReader(payload)) if err != nil || resp.StatusCode != 200 { return fmt.Errorf("Error posting update to server: %v", err) } else { @@ -173,7 +174,7 @@ func NewSqlitePersistance(path string) (*SqlitePersistance, error) { } else { // init DB _, err := db.Exec(` - create table if not exists entries (key, value, timestamp, pid, counter, urltoken); + create table if not exists entries (key, value, timestamp, pid, counter, urltoken); create table if not exists state (state);`) if err != nil { From da866d5b9d0c1ffb4aa82be183afa53f71a54f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9=20Vulquin?= Date: Tue, 28 Nov 2023 10:12:16 +0100 Subject: [PATCH 2/3] panic on (typically impossible) errors --- src/sqlite_persistance.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sqlite_persistance.go b/src/sqlite_persistance.go index 2c1c13a..6af4f94 100644 --- a/src/sqlite_persistance.go +++ b/src/sqlite_persistance.go @@ -50,7 +50,10 @@ func (p *SqlitePersistance) GetRemoteUpdates() (err error) { return err } - pull, _ := p.State.RemoteURL.Parse("pull") // this should never fail + pull, err := p.State.RemoteURL.Parse("pull") + if err != nil { + panic(err) + } resp, err := http.Post(pull.String(), "application/json", bytes.NewReader(request)) if err != nil { return err @@ -99,7 +102,10 @@ func (p *SqlitePersistance) Push() error { panic(err) } - push, _ := p.State.RemoteURL.Parse("push") // this should never fail + push, err := p.State.RemoteURL.Parse("push") + if err != nil { + panic(err) + } resp, err := http.DefaultClient.Post(push.String(), "application/json", bytes.NewReader(payload)) if err != nil || resp.StatusCode != 200 { return fmt.Errorf("Error posting update to server: %v", err) From f07090f144044970035143a330a9a229f28fb15c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9=20Vulquin?= Date: Tue, 28 Nov 2023 10:23:35 +0100 Subject: [PATCH 3/3] improve url parsing unsetting the remote is much more trivial now, for instance --- src/cli.go | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/cli.go b/src/cli.go index 0f43533..4235e12 100644 --- a/src/cli.go +++ b/src/cli.go @@ -231,15 +231,26 @@ func GetApp() cli.App { p := getPersistance(options) url, err := url.ParseRequestURI(host) - if err != nil { - fmt.Println("Invalid url:", err.Error()) - return 2 - } - if !strings.HasPrefix(url.Scheme, "http") { - url.Scheme = "https" - fmt.Printf("Warning: only http(s) in URLs is supported, defaulting to https: %s\n", url) + if err == nil { + // url parsed fine, use it + // ensure it's http(s) + if !strings.HasPrefix(url.Scheme, "http") { + url.Scheme = "https" + fmt.Println("Warning: only http(s) in URLs is supported, defaulting to https: ", url) + } + // ensure there's a terminal / + // note that this doesn't handle the escaped path or the raw path + if url.Path != "" && !strings.HasSuffix(url.Path, "/") { + url.Path += "/" + } + p.State.RemoteURL = url + } else { + // only warn if the user isn't intentionally unsetting the remote + if host != "" { + fmt.Println("Invalid url, unsetting remote: ", err.Error()) + } + p.State.RemoteURL = url } - p.State.RemoteURL = url err = p.CommitState() if err != nil {