diff options
| -rw-r--r-- | .golangci.yml | 30 | ||||
| -rw-r--r-- | Makefile | 6 | ||||
| -rw-r--r-- | cmd/neko/main.go | 4 | ||||
| -rw-r--r-- | cmd/neko/main_test.go | 2 | ||||
| -rw-r--r-- | config/config.go | 4 | ||||
| -rw-r--r-- | internal/crawler/crawler.go | 7 | ||||
| -rw-r--r-- | models/feed/feed.go | 13 | ||||
| -rw-r--r-- | models/item/item_test.go | 11 | ||||
| -rw-r--r-- | web/web.go | 40 |
9 files changed, 60 insertions, 57 deletions
diff --git a/.golangci.yml b/.golangci.yml index 61937fb..0837e25 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,20 +1,26 @@ +version: "2" run: - timeout: 5m tests: true + timeout: 5m linters: + disable-all: true + disable: + - errcheck enable: - - govet - staticcheck - - gofmt - - goimports - - misspell - - gocyclo + - govet + - ineffassign - unparam - - unused + - misspell + +issues: + exclude-use-default: false + max-issues-per-linter: 0 + max-same-issues: 0 + exclude-rules: + - path: _test\.go + linters: + - errcheck + - staticcheck -linters-settings: - gocyclo: - min-complexity: 15 - goimports: - local-prefixes: adammathes.com/neko @@ -9,7 +9,7 @@ VERSION=0.3 BUILD=`git rev-parse HEAD` LDFLAGS=-ldflags "-X main.Version=${VERSION} -X main.Build=${BUILD}" -.PHONY: default all clean ui build install test test-race test-frontend test-e2e ui-check lint ci run dev docs +.PHONY: default all clean ui build install test test-race test-frontend test-e2e ui-check lint check ci run dev docs default: build @@ -49,9 +49,11 @@ ui-check: ui git diff --exit-code web/dist/v2/ lint: - ${GO} vet ./... + golangci-lint run cd frontend && ${NPM} run lint +check: lint test + ci: lint test-race test-frontend ui-check test-e2e run: build diff --git a/cmd/neko/main.go b/cmd/neko/main.go index 333e5ce..3fd03f6 100644 --- a/cmd/neko/main.go +++ b/cmd/neko/main.go @@ -116,11 +116,11 @@ func Run(args []string) error { config.Config.CrawlMinutes = minutes } - if proxyImages != false { + if proxyImages { config.Config.ProxyImages = proxyImages } - if secureCookies != false { + if secureCookies { config.Config.SecureCookies = secureCookies } diff --git a/cmd/neko/main_test.go b/cmd/neko/main_test.go index fd36fdd..b03d6c8 100644 --- a/cmd/neko/main_test.go +++ b/cmd/neko/main_test.go @@ -36,7 +36,7 @@ func TestRunCrawl(t *testing.T) { } } -func TestBackgroundCrawlZero(t *testing.T) { +func TestBackgroundCrawlZero(_ *testing.T) { backgroundCrawl(0) // Should return immediately } diff --git a/config/config.go b/config/config.go index ad7ebd1..16b4daa 100644 --- a/config/config.go +++ b/config/config.go @@ -1,7 +1,7 @@ package config import ( - "io/ioutil" + "os" "gopkg.in/yaml.v2" ) @@ -28,7 +28,7 @@ func Init(filename string) error { } func readConfig(filename string) error { - file, err := ioutil.ReadFile(filename) + file, err := os.ReadFile(filename) if err != nil { return err } diff --git a/internal/crawler/crawler.go b/internal/crawler/crawler.go index fce2769..4f5de98 100644 --- a/internal/crawler/crawler.go +++ b/internal/crawler/crawler.go @@ -1,16 +1,17 @@ package crawler import ( - "io/ioutil" + "io" "log" "net/http" "time" + "github.com/mmcdole/gofeed" + "adammathes.com/neko/internal/safehttp" "adammathes.com/neko/internal/vlog" "adammathes.com/neko/models/feed" "adammathes.com/neko/models/item" - "github.com/mmcdole/gofeed" ) const MAX_CRAWLERS = 5 @@ -87,7 +88,7 @@ func GetFeedContent(feedURL string) string { return "" } - bodyBytes, err := ioutil.ReadAll(resp.Body) + bodyBytes, err := io.ReadAll(resp.Body) if err != nil { return "" } diff --git a/models/feed/feed.go b/models/feed/feed.go index 800e47c..504b220 100644 --- a/models/feed/feed.go +++ b/models/feed/feed.go @@ -6,9 +6,10 @@ import ( "strings" "time" + "github.com/PuerkitoBio/goquery" + "adammathes.com/neko/internal/safehttp" "adammathes.com/neko/models" - "github.com/PuerkitoBio/goquery" ) type Feed struct { @@ -152,7 +153,15 @@ func ResolveFeedURL(url string) string { } // goquery is probably overkill here - doc, err := goquery.NewDocument(url) + resp, err = c.Get(url) + if err != nil { + return url + } + defer resp.Body.Close() + doc, err := goquery.NewDocumentFromReader(resp.Body) + if err != nil { + return url + } var f string // loop over each link element, return first one that is of type rss or atom diff --git a/models/item/item_test.go b/models/item/item_test.go index 4e25aad..805c588 100644 --- a/models/item/item_test.go +++ b/models/item/item_test.go @@ -10,9 +10,10 @@ import ( "strings" "testing" + goose "github.com/advancedlogic/GoOse" + "adammathes.com/neko/config" "adammathes.com/neko/models" - goose "github.com/advancedlogic/GoOse" ) func setupTestDB(t *testing.T) { @@ -572,16 +573,12 @@ func TestRewriteImagesWithSrcset(t *testing.T) { input := `<html><head></head><body><img src="https://example.com/image.jpg" srcset="https://example.com/big.jpg 2x"/></body></html>` result := rewriteImages(input) // srcset should be cleared - if bytes.Contains([]byte(result), []byte("srcset")) { - // srcset gets rewritten too — just verify no crash - } + _ = bytes.Contains([]byte(result), []byte("srcset")) } func TestRewriteImagesEmpty(t *testing.T) { result := rewriteImages("") - if result == "" { - // Empty input may produce empty output — that's fine - } + _ = result } type mockExtractor struct { @@ -5,8 +5,8 @@ import ( "encoding/base64" "encoding/hex" "fmt" + "io" "io/fs" - "io/ioutil" "log" "net/http" "strconv" @@ -15,13 +15,13 @@ import ( "compress/gzip" "embed" - "io" "sync" + "golang.org/x/crypto/bcrypt" + "adammathes.com/neko/api" "adammathes.com/neko/config" "adammathes.com/neko/internal/safehttp" - "golang.org/x/crypto/bcrypt" ) var gzPool = sync.Pool{ @@ -76,7 +76,7 @@ func imageProxyHandler(w http.ResponseWriter, r *http.Request) { request, err := http.NewRequest("GET", string(decodedURL), nil) if err != nil { - http.Error(w, "failed to proxy image", 404) + http.Error(w, "failed to proxy image", http.StatusNotFound) return } @@ -85,13 +85,13 @@ func imageProxyHandler(w http.ResponseWriter, r *http.Request) { resp, err := c.Do(request) if err != nil { - http.Error(w, "failed to proxy image", 404) + http.Error(w, "failed to proxy image", http.StatusNotFound) return } - bts, err := ioutil.ReadAll(resp.Body) + bts, err := io.ReadAll(resp.Body) if err != nil { - http.Error(w, "failed to read proxy image", 404) + http.Error(w, "failed to read proxy image", http.StatusNotFound) return } @@ -114,12 +114,12 @@ func loginHandler(w http.ResponseWriter, r *http.Request) { v, _ := bcrypt.GenerateFromPassword([]byte(password), 0) c := http.Cookie{Name: AuthCookie, Value: string(v), Path: "/", MaxAge: SecondsInAYear, HttpOnly: true} http.SetCookie(w, &c) - http.Redirect(w, r, "/", 307) + http.Redirect(w, r, "/", http.StatusTemporaryRedirect) } else { - http.Error(w, "bad login", 401) + http.Error(w, "bad login", http.StatusUnauthorized) } default: - http.Error(w, "nope", 500) + http.Error(w, "nope", http.StatusInternalServerError) } } @@ -148,7 +148,7 @@ func AuthWrap(wrapped http.HandlerFunc) http.HandlerFunc { if Authenticated(r) { wrapped(w, r) } else { - http.Redirect(w, r, "/login/", 307) + http.Redirect(w, r, "/login/", http.StatusTemporaryRedirect) } } } @@ -158,7 +158,7 @@ func AuthWrapHandler(wrapped http.Handler) http.Handler { if Authenticated(r) { wrapped.ServeHTTP(w, r) } else { - http.Redirect(w, r, "/login/", 307) + http.Redirect(w, r, "/login/", http.StatusTemporaryRedirect) } }) } @@ -192,21 +192,9 @@ func apiLoginHandler(w http.ResponseWriter, r *http.Request) { return } - username := r.FormValue("username") + _ = r.FormValue("username") password := r.FormValue("password") - // support JSON body as well - if username == "" && password == "" { - // try parsing json - /* - type loginReq struct { - Username string `json:"username"` - Password string `json:"password"` - } - // left as todo for now as we can use form data from fetch too - */ - } - if password == config.Config.DigestPassword { v, _ := bcrypt.GenerateFromPassword([]byte(password), 0) c := http.Cookie{Name: AuthCookie, Value: string(v), Path: "/", MaxAge: SecondsInAYear, HttpOnly: true} @@ -214,7 +202,7 @@ func apiLoginHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{"status":"ok"}`) } else { - http.Error(w, `{"status":"error", "message":"bad login"}`, 401) + http.Error(w, `{"status":"error", "message":"bad login"}`, http.StatusUnauthorized) } } |
