From 0050c655964e12e8ed021a0e43c108e7938aabd8 Mon Sep 17 00:00:00 2001 From: Dmitry Verkhoturov Date: Sun, 28 Jan 2024 14:56:49 +0100 Subject: [PATCH] add meaningful error for lack of auth on import, remap and backup Previously, the error printed was just the following: error response "401 Unauthorized", Unauthorized" New error: error response "401 Unauthorized", ensure you have set ADMIN_PASSWD and provided it to the command you're running: Unauthorized --- backend/app/cmd/backup_test.go | 28 ++++++++++++++++++ backend/app/cmd/cmd.go | 3 ++ backend/app/cmd/import_test.go | 42 +++++++++++++++++++++++++++ backend/app/cmd/remap_test.go | 35 ++++++++++++++++++++++ backend/app/rest/api/migrator_test.go | 1 + 5 files changed, 109 insertions(+) diff --git a/backend/app/cmd/backup_test.go b/backend/app/cmd/backup_test.go index 3c32c6a7..471104e4 100644 --- a/backend/app/cmd/backup_test.go +++ b/backend/app/cmd/backup_test.go @@ -1,10 +1,12 @@ package cmd import ( + "encoding/base64" "fmt" "net/http" "net/http/httptest" "os" + "strings" "testing" "github.com/jessevdk/go-flags" @@ -16,6 +18,10 @@ func TestBackup_Execute(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, r.URL.Path, "/api/v1/admin/export") assert.Equal(t, "GET", r.Method) + t.Logf("Authorization header: %+v", r.Header.Get("Authorization")) + auth, err := base64.StdEncoding.DecodeString(strings.Split(r.Header.Get("Authorization"), " ")[1]) + require.NoError(t, err) + assert.Equal(t, "admin:secret", string(auth)) fmt.Fprint(w, "blah\nblah2\n12345678\n") })) defer ts.Close() @@ -34,6 +40,28 @@ func TestBackup_Execute(t *testing.T) { assert.Equal(t, "blah\nblah2\n12345678\n", string(data)) } +func TestBackup_ExecuteNoPassword(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, r.URL.Path, "/api/v1/admin/export") + assert.Equal(t, "GET", r.Method) + t.Logf("Authorization: %+v", r.Header.Get("Authorization")) + auth, err := base64.StdEncoding.DecodeString(strings.Split(r.Header.Get("Authorization"), " ")[1]) + require.NoError(t, err) + require.Equal(t, "admin:", string(auth)) + w.WriteHeader(http.StatusUnauthorized) + fmt.Fprint(w, "Unauthorized") + })) + defer ts.Close() + + cmd := BackupCommand{} + cmd.SetCommon(CommonOpts{RemarkURL: ts.URL}) + p := flags.NewParser(&cmd, flags.Default) + _, err := p.ParseArgs([]string{"--site=remark", "--path=/tmp", "--file={{.SITE}}-test.export"}) + require.NoError(t, err) + err = cmd.Execute(nil) + assert.EqualError(t, err, "error response \"401 Unauthorized\", ensure you have set ADMIN_PASSWD and provided it to the command you're running: Unauthorized") +} + func TestBackup_ExecuteFailedStatus(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, r.URL.Path, "/api/v1/admin/export") diff --git a/backend/app/cmd/cmd.go b/backend/app/cmd/cmd.go index 1f38652e..8c2fbbcd 100644 --- a/backend/app/cmd/cmd.go +++ b/backend/app/cmd/cmd.go @@ -115,6 +115,9 @@ func responseError(resp *http.Response) error { if e != nil { body = []byte("") } + if resp.StatusCode == http.StatusUnauthorized { + return fmt.Errorf("error response %q, ensure you have set ADMIN_PASSWD and provided it to the command you're running: %s", resp.Status, body) + } return fmt.Errorf("error response %q, %s", resp.Status, body) } diff --git a/backend/app/cmd/import_test.go b/backend/app/cmd/import_test.go index 1e69b09c..c608459f 100644 --- a/backend/app/cmd/import_test.go +++ b/backend/app/cmd/import_test.go @@ -1,10 +1,12 @@ package cmd import ( + "encoding/base64" "fmt" "io" "net/http" "net/http/httptest" + "strings" "testing" "time" @@ -18,6 +20,10 @@ func TestImport_Execute(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, r.URL.Path, "/api/v1/admin/import") assert.Equal(t, "POST", r.Method) + t.Logf("Authorization header: %+v", r.Header.Get("Authorization")) + auth, err := base64.StdEncoding.DecodeString(strings.Split(r.Header.Get("Authorization"), " ")[1]) + require.NoError(t, err) + assert.Equal(t, "admin:secret", string(auth)) body, err := io.ReadAll(r.Body) assert.NoError(t, err) assert.Equal(t, "blah\nblah2\n12345678\n", string(body)) @@ -46,6 +52,42 @@ func TestImport_Execute(t *testing.T) { assert.NoError(t, err) } +func TestImport_ExecuteNoPassword(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, r.URL.Path, "/api/v1/admin/import") + assert.Equal(t, "POST", r.Method) + t.Logf("Authorization header: %+v", r.Header.Get("Authorization")) + auth, err := base64.StdEncoding.DecodeString(strings.Split(r.Header.Get("Authorization"), " ")[1]) + require.NoError(t, err) + assert.Equal(t, "admin:", string(auth)) + body, err := io.ReadAll(r.Body) + assert.NoError(t, err) + assert.Equal(t, "blah\nblah2\n12345678\n", string(body)) + + w.WriteHeader(401) + fmt.Fprint(w, "Unauthorized") + })) + defer ts.Close() + + cmd := ImportCommand{} + cmd.SetCommon(CommonOpts{RemarkURL: ts.URL}) + + p := flags.NewParser(&cmd, flags.Default) + _, err := p.ParseArgs([]string{"--site=remark", "--file=testdata/import.txt"}) + require.NoError(t, err) + err = cmd.Execute(nil) + assert.EqualError(t, err, "error response \"401 Unauthorized\", ensure you have set ADMIN_PASSWD and provided it to the command you're running: Unauthorized") + + cmd = ImportCommand{} + cmd.SetCommon(CommonOpts{RemarkURL: ts.URL}) + + p = flags.NewParser(&cmd, flags.Default) + _, err = p.ParseArgs([]string{"--site=remark", "--file=testdata/import.txt.gz"}) + require.NoError(t, err) + err = cmd.Execute(nil) + assert.EqualError(t, err, "error response \"401 Unauthorized\", ensure you have set ADMIN_PASSWD and provided it to the command you're running: Unauthorized") +} + func TestImport_ExecuteFailed(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, r.URL.Path, "/api/v1/admin/import") diff --git a/backend/app/cmd/remap_test.go b/backend/app/cmd/remap_test.go index 22c73294..db5c7b48 100644 --- a/backend/app/cmd/remap_test.go +++ b/backend/app/cmd/remap_test.go @@ -1,9 +1,12 @@ package cmd import ( + "encoding/base64" + "fmt" "io" "net/http" "net/http/httptest" + "strings" "testing" "github.com/jessevdk/go-flags" @@ -16,6 +19,10 @@ func TestRemap_Execute(t *testing.T) { assert.Equal(t, r.URL.Path, "/api/v1/admin/remap") assert.Equal(t, "POST", r.Method) assert.Equal(t, "remark", r.URL.Query().Get("site")) + t.Logf("Authorization header: %+v", r.Header.Get("Authorization")) + auth, err := base64.StdEncoding.DecodeString(strings.Split(r.Header.Get("Authorization"), " ")[1]) + require.NoError(t, err) + assert.Equal(t, "admin:secret", string(auth)) body, err := io.ReadAll(r.Body) assert.NoError(t, err) assert.Equal(t, "http://oldsite.com* https://newsite.com*\nhttp://oldsite.com/from-old-page/1 https://newsite.com/to-new-page/1", string(body)) @@ -33,3 +40,31 @@ func TestRemap_Execute(t *testing.T) { err = cmd.Execute(nil) assert.NoError(t, err) } + +func TestRemap_ExecuteNoPassword(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, r.URL.Path, "/api/v1/admin/remap") + assert.Equal(t, "POST", r.Method) + assert.Equal(t, "remark", r.URL.Query().Get("site")) + t.Logf("Authorization header: %+v", r.Header.Get("Authorization")) + auth, err := base64.StdEncoding.DecodeString(strings.Split(r.Header.Get("Authorization"), " ")[1]) + require.NoError(t, err) + assert.Equal(t, "admin:", string(auth)) + body, err := io.ReadAll(r.Body) + assert.NoError(t, err) + assert.Equal(t, "http://oldsite.com* https://newsite.com*\nhttp://oldsite.com/from-old-page/1 https://newsite.com/to-new-page/1", string(body)) + + w.WriteHeader(401) + fmt.Fprint(w, "Unauthorized") + })) + defer ts.Close() + + cmd := RemapCommand{} + cmd.SetCommon(CommonOpts{RemarkURL: ts.URL}) + + p := flags.NewParser(&cmd, flags.Default) + _, err := p.ParseArgs([]string{"--site=remark", "--file=testdata/remap_urls.txt"}) + require.NoError(t, err) + err = cmd.Execute(nil) + assert.EqualError(t, err, "error response \"401 Unauthorized\", ensure you have set ADMIN_PASSWD and provided it to the command you're running: Unauthorized") +} diff --git a/backend/app/rest/api/migrator_test.go b/backend/app/rest/api/migrator_test.go index 46250878..12ba6e91 100644 --- a/backend/app/rest/api/migrator_test.go +++ b/backend/app/rest/api/migrator_test.go @@ -397,6 +397,7 @@ func TestMigrator_Export(t *testing.T) { req.SetBasicAuth("admin", "password") resp, err = client.Do(req) require.NoError(t, err) + resp.Body.Close() require.Equal(t, http.StatusInternalServerError, resp.StatusCode) require.Equal(t, "application/json", resp.Header.Get("Content-Type"))