From 16671b34064d27ca0d84c0eb128b0ddb5cba574e Mon Sep 17 00:00:00 2001 From: ston1th Date: Fri, 19 Oct 2018 23:08:32 +0200 Subject: [PATCH] some tests and major cleanup --- Makefile | 19 +- go.mod | 1 + pkg/cache/cache_test.go | 50 + pkg/cmd/cmd.go | 15 +- pkg/core/permission.go | 16 - pkg/core/permission_test.go | 81 + pkg/core/pledge.go | 7 + pkg/core/pledge_openbsd.go | 11 + pkg/core/types.go | 3 +- pkg/db/db.go | 13 +- pkg/db/page.go | 9 +- pkg/db/user.go | 6 +- pkg/index/index.go | 10 +- pkg/log/log.go | 23 +- pkg/render/render.go | 39 +- pkg/render/render_test.go | 29 + pkg/server/server.go | 5 +- pkg/server/templates.go | 10 +- pkg/server/xsrf.go | 3 + pkg/server/xsrf_test.go | 31 + pkg/store/boltstore.go | 7 +- pkg/store/boltstore_test.go | 99 + pkg/store/store.go | 12 +- templates.sh | 2 +- templates/custom.css | 4 + templates/index.html | 2 +- templates/page.html | 2 +- templates/pageView.html | 2 +- .../blevesearch/segment/segment_words.go | 38496 ++++----- .../blevesearch/segment/segment_words_prod.go | 71309 +++++++--------- 30 files changed, 49971 insertions(+), 60345 deletions(-) create mode 100644 pkg/cache/cache_test.go create mode 100644 pkg/core/permission_test.go create mode 100644 pkg/core/pledge.go create mode 100644 pkg/core/pledge_openbsd.go create mode 100644 pkg/render/render_test.go create mode 100644 pkg/server/xsrf_test.go create mode 100644 pkg/store/boltstore_test.go diff --git a/Makefile b/Makefile index 88bfea4..34b11ef 100644 --- a/Makefile +++ b/Makefile @@ -10,13 +10,19 @@ all: $(PROGRAM) setup: $(CC) get github.com/client9/misspell +vendor: clean codeqa + CGO_ENABLED=0 $(CC) $(BUILD) -mod=vendor $(LDFLAGS) + $(PROGRAM): clean codeqa CGO_ENABLED=0 $(CC) $(BUILD) $(LDFLAGS) clean: $(CC) clean -x -codeqa: templates gofmt misspell golint +codeqa: generate gofmt misspell golint test + +generate: + $(CC) generate gofmt: gofmt -w . @@ -25,9 +31,14 @@ golint: $(GOPATH)/bin/golint . misspell: + # ignore misspellings from vendor/ $(GOPATH)/bin/misspell -i functionallity,avaliable,HALP,halp,agains,becuase,Christiaan,compatiblity,conjuction,frequence,inital,inot,occurance,overriden,pervious,preceeded,preceeds,precendence,PROPOGATE,reamining,represenation,soley,substract,supression,whcih,preceed * -templates: - $(CC) generate +test: +ifeq ($(shell go env GOARCH), $(shell go env GOHOSTARCH)) + $(CC) test ./... +else + $(info skipping tests of other platforms) +endif -.PHONY: setup build clean templates gofmt misspell golint +.PHONY: setup vendor build clean codeqa generate gofmt golint misspell test diff --git a/go.mod b/go.mod index 43aa597..7bec434 100644 --- a/go.mod +++ b/go.mod @@ -42,4 +42,5 @@ require ( github.com/urfave/cli v1.19.1 github.com/willf/bitset v1.1.9 // indirect golang.org/x/crypto v0.0.0-20161031180806-9477e0b78b9a + golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e ) diff --git a/pkg/cache/cache_test.go b/pkg/cache/cache_test.go new file mode 100644 index 0000000..776a9a1 --- /dev/null +++ b/pkg/cache/cache_test.go @@ -0,0 +1,50 @@ +// Copyright (C) 2018 Marius Schellenberger + +package cache + +import ( + "git.giftfish.de/ston1th/gowiki/pkg/core" + "testing" +) + +func TestCache(t *testing.T) { + title := "test/page" + pages := []*core.Page{ + &core.Page{ + Title: title, + Markdown: "page v1", + }, + &core.Page{ + Title: title, + Markdown: "page v2", + }, + } + c := NewCache() + t.Run("Add", func(t *testing.T) { + c.Add(title, pages[0]) + }) + t.Run("Get", func(t *testing.T) { + p := c.Get(title) + if p.Markdown != pages[0].Markdown { + t.Fail() + } + }) + t.Run("Add", func(t *testing.T) { + c.Add(title, pages[1]) + }) + t.Run("Get", func(t *testing.T) { + p := c.Get(title) + if p.Markdown == pages[0].Markdown { + t.Fail() + } + }) + t.Run("Delete", func(t *testing.T) { + c.Delete(title) + }) + t.Run("Get", func(t *testing.T) { + p := c.Get(title) + if p != nil { + t.Fail() + } + }) +} diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index 3721113..327d9c0 100644 --- a/pkg/cmd/cmd.go +++ b/pkg/cmd/cmd.go @@ -32,6 +32,9 @@ var ( ) func initServer(conf core.Config) (err error) { + if err = core.Pledge("stdio rpath wpath cpath inet fattr flock proc exec id", ""); err != nil { + return + } dropCfg := godrop.Config{ User: conf.User, Group: conf.Group, @@ -47,7 +50,11 @@ func initServer(conf core.Config) (err error) { return } - log.NewLogger(conf.LogFile) + if err = core.Pledge("stdio rpath wpath cpath inet fattr flock", ""); err != nil { + return + } + + log.InitLogger(conf.DataDir, conf.LogFile, conf.Debug) l, err := godrop.GetListener() if err != nil { @@ -89,7 +96,7 @@ func Run(version string) { Action: func(c *cli.Context) error { conf.Version = app.Version if err := initServer(conf); err != nil { - stdlog.Fatal("server: ", err) + stdlog.Fatal(err) } return nil }, @@ -187,7 +194,7 @@ func serverFlags() []cli.Flag { cli.StringFlag{ Name: "log", Value: defLogFile, - Usage: "log file (leave empty for stdout, this only works in combination with -f)", + Usage: "log file (use - for stdout, this only works in combination with -f)", Destination: &conf.LogFile, }, cli.StringFlag{ @@ -208,7 +215,7 @@ func serverFlags() []cli.Flag { cli.BoolFlag{ Name: "debug", Usage: "enable debugging", - Destination: &log.DebugEnabled, + Destination: &conf.Debug, }, } } diff --git a/pkg/core/permission.go b/pkg/core/permission.go index 2303cce..9f00ff8 100644 --- a/pkg/core/permission.go +++ b/pkg/core/permission.go @@ -11,18 +11,6 @@ const ( Private ) -func ParsePerm(p int) Permission { - switch p { - case 1: - return Public - case 2: - return Internal - case 3: - return Private - } - return Invalid -} - func ParsePermString(p string) Permission { switch p { case "1": @@ -51,10 +39,6 @@ func WritePerm(username, section string, p *Page) bool { if section != WikiSection && section != username { return false } - return writePerm(username, p) -} - -func writePerm(username string, p *Page) bool { switch p.Perm { case Public, Internal: if p.Owner == WikiSection { diff --git a/pkg/core/permission_test.go b/pkg/core/permission_test.go new file mode 100644 index 0000000..b60faba --- /dev/null +++ b/pkg/core/permission_test.go @@ -0,0 +1,81 @@ +// Copyright (C) 2018 Marius Schellenberger + +package core + +import ( + "fmt" + "testing" +) + +func TestParsePermString(t *testing.T) { + data := map[string]Permission{ + "": Invalid, + "1": Public, + "2": Internal, + "3": Private, + "123": Invalid, + "test": Invalid, + } + for k, v := range data { + t.Run(k, func(t *testing.T) { + if ParsePermString(k) != v { + t.Fail() + } + }) + } +} + +func TestReadPerm(t *testing.T) { + data := []struct { + Username string + Page *Page + OK bool + }{ + {"", &Page{Perm: Invalid, Owner: "admin"}, false}, + {"", &Page{Perm: Public, Owner: "admin"}, true}, + {"user", &Page{Perm: Public, Owner: "admin"}, true}, + {"", &Page{Perm: Internal, Owner: "admin"}, false}, + {"user", &Page{Perm: Internal, Owner: "admin"}, true}, + {"", &Page{Perm: Private, Owner: "admin"}, false}, + {"user", &Page{Perm: Private, Owner: "admin"}, false}, + {"admin", &Page{Perm: Private, Owner: "admin"}, true}, + } + for i, v := range data { + t.Run(fmt.Sprintf("Read:%d", i), func(t *testing.T) { + if ReadPerm(v.Username, v.Page) != v.OK { + t.Fail() + } + }) + } +} + +func TestWritePerm(t *testing.T) { + data := []struct { + Username string + Section string + Page *Page + OK bool + }{ + {"user", "admin", &Page{Perm: Invalid, Owner: "admin"}, false}, + {"", "user", &Page{Perm: Invalid, Owner: "admin"}, false}, + {"user", "user", &Page{Perm: Invalid, Owner: "user"}, false}, + {"user", "user", &Page{Perm: Public, Owner: "user"}, true}, + {"user", "user", &Page{Perm: Internal, Owner: "user"}, true}, + {"user", "user", &Page{Perm: Private, Owner: "user"}, true}, + {"", WikiSection, &Page{Perm: Invalid, Owner: "admin"}, false}, + {"", WikiSection, &Page{Perm: Public, Owner: "admin"}, false}, + {"", WikiSection, &Page{Perm: Internal, Owner: "admin"}, false}, + {"user", WikiSection, &Page{Perm: Public, Owner: WikiSection}, true}, + {"user", WikiSection, &Page{Perm: Internal, Owner: WikiSection}, true}, + {"", "admin", &Page{Perm: Private, Owner: "admin"}, false}, + {"user", "admin", &Page{Perm: Private, Owner: "admin"}, false}, + {"admin", "admin", &Page{Perm: Private, Owner: "admin"}, true}, + } + for i, v := range data { + t.Run(fmt.Sprintf("Write:%d", i), func(t *testing.T) { + if WritePerm(v.Username, v.Section, v.Page) != v.OK { + t.Fail() + } + }) + } +} diff --git a/pkg/core/pledge.go b/pkg/core/pledge.go new file mode 100644 index 0000000..ecc374a --- /dev/null +++ b/pkg/core/pledge.go @@ -0,0 +1,7 @@ +// Copyright (C) 2018 Marius Schellenberger + +// +build !openbsd + +package core + +func Pledge(promises, execpromises string) error { return nil } diff --git a/pkg/core/pledge_openbsd.go b/pkg/core/pledge_openbsd.go new file mode 100644 index 0000000..5f0ec84 --- /dev/null +++ b/pkg/core/pledge_openbsd.go @@ -0,0 +1,11 @@ +// Copyright (C) 2018 Marius Schellenberger + +// +build openbsd + +package core + +import "golang.org/x/sys/unix" + +func Pledge(promises, execpromises string) error { + return unix.Pledge(promises, execpromises) +} diff --git a/pkg/core/types.go b/pkg/core/types.go index 59ecfd4..98f48fc 100644 --- a/pkg/core/types.go +++ b/pkg/core/types.go @@ -8,7 +8,7 @@ type Page struct { Title string `json:"title"` StoreTitle string `json:"store_title"` Markdown string `json:"markdown"` - PageIndex template.HTML `json:"page_index"` + TOC template.HTML `json:"toc"` HTML template.HTML `json:"html"` Created string `json:"created"` Updated string `json:"updated"` @@ -52,4 +52,5 @@ type Config struct { Secret string Foreground bool SecureCookie bool + Debug bool } diff --git a/pkg/db/db.go b/pkg/db/db.go index 92634ea..b06598b 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -3,13 +3,13 @@ package db import ( - "fmt" "git.giftfish.de/ston1th/gowiki/pkg/cache" "git.giftfish.de/ston1th/gowiki/pkg/core" "git.giftfish.de/ston1th/gowiki/pkg/index" "git.giftfish.de/ston1th/gowiki/pkg/render" "git.giftfish.de/ston1th/gowiki/pkg/store" "io" + "path/filepath" ) const ( @@ -24,24 +24,19 @@ You can customize it how you like.` const blevePath = "bleve" -func dbErr(i interface{}) error { - return fmt.Errorf("db: %s", i) -} - type DB struct { store store.Store cache *cache.Cache Index *index.Index } -func New(datadir string) (db *DB, err error) { +func New(dir string) (db *DB, err error) { db = &DB{cache: cache.NewCache()} - db.Index, err = index.NewIndex(datadir + "/" + blevePath) + db.store, err = store.NewBoltStore(filepath.Join(dir, storeFile), nil) if err != nil { return } - - db.store, err = store.NewBoltStore(storeFile, nil) + db.Index, err = index.NewIndex(filepath.Join(dir, blevePath)) if err != nil { return } diff --git a/pkg/db/page.go b/pkg/db/page.go index fc46be8..fe6cc67 100644 --- a/pkg/db/page.go +++ b/pkg/db/page.go @@ -3,6 +3,7 @@ package db import ( + "errors" "git.giftfish.de/ston1th/gowiki/pkg/core" "git.giftfish.de/ston1th/gowiki/pkg/render" "git.giftfish.de/ston1th/gowiki/pkg/store" @@ -13,10 +14,10 @@ const pagePrefix = "page/" var ( errPageNotFound = store.ErrKeyNotFound - errPermissionDenied = dbErr("permission denied") - errInvalidPermission = dbErr("invalid permission") - errPrivateWikiPage = dbErr("private wiki pages are not allowed") - errDeleteIndexPage = dbErr("index page can not be deleted") + errPermissionDenied = errors.New("db: permission denied") + errInvalidPermission = errors.New("db: invalid permission") + errPrivateWikiPage = errors.New("db: private wiki pages are not allowed") + errDeleteIndexPage = errors.New("db: index page can not be deleted") ) func (db *DB) GetAllPages(username string) (pages core.Pages) { diff --git a/pkg/db/user.go b/pkg/db/user.go index a655112..5a3c1ba 100644 --- a/pkg/db/user.go +++ b/pkg/db/user.go @@ -17,9 +17,9 @@ import ( const userPrefix = "user/" var ( - errUserNotFound = dbErr("user not found") - errUserExists = dbErr("user already exist") - errUserReserved = dbErr("username is reserved") + errUserNotFound = errors.New("db: user not found") + errUserExists = errors.New("db: user already exist") + errUserReserved = errors.New("db: username is reserved") userRe = regexp.MustCompile("[^a-zA-Z0-9]+") ) diff --git a/pkg/index/index.go b/pkg/index/index.go index 677d344..b3c0749 100644 --- a/pkg/index/index.go +++ b/pkg/index/index.go @@ -3,7 +3,7 @@ package index import ( - "fmt" + "errors" "git.giftfish.de/ston1th/gowiki/pkg/core" "github.com/blevesearch/bleve" "html/template" @@ -18,10 +18,6 @@ type indexPage struct { Search string `json:"search"` } -func indexErr(i interface{}) error { - return fmt.Errorf("index: %s", i) -} - type Index struct { i bleve.Index } @@ -32,13 +28,13 @@ func NewIndex(path string) (i *Index, err error) { mapping := bleve.NewIndexMapping() bi, err = bleve.New(path, mapping) if err != nil { - err = indexErr(err) + err = errors.New("index: " + err.Error()) return } } else { bi, err = bleve.Open(path) if err != nil { - err = indexErr(err) + err = errors.New("index: " + err.Error()) return } } diff --git a/pkg/log/log.go b/pkg/log/log.go index 97b99eb..07c25d5 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -5,21 +5,20 @@ package log import ( stdlog "log" "os" + "path/filepath" ) -const debug = "debug: " - var ( - log *stdlog.Logger - DebugEnabled = false + log = stdlog.New(os.Stdout, "", stdlog.LstdFlags) + debug = false ) -func NewLogger(file string) { - if file == "" { - log = stdlog.New(os.Stdout, "", stdlog.LstdFlags) +func InitLogger(dir, file string, debug bool) { + debug = debug + if file == "-" { return } - f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0640) + f, err := os.OpenFile(filepath.Join(dir, file), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0640) if err != nil { stdlog.Fatal(err) } @@ -40,13 +39,13 @@ func Fatal(v ...interface{}) { } func Debug(v ...interface{}) { - if DebugEnabled { - log.Println(append([]interface{}{debug}, v...)) + if debug { + log.Println(append([]interface{}{"debug:"}, v...)) } } func Debugf(fmt string, v ...interface{}) { - if DebugEnabled { - log.Printf(debug+fmt, v...) + if debug { + log.Printf("debug: "+fmt, v...) } } diff --git a/pkg/render/render.go b/pkg/render/render.go index 9be13b4..e74ec61 100644 --- a/pkg/render/render.go +++ b/pkg/render/render.go @@ -30,21 +30,17 @@ var ( func Render(p *core.Page) string { rend := blackfriday.MarkdownCommon([]byte(p.Markdown)) - index, html := buildTOC(string(rend)) + toc, html := buildTOC(string(rend)) html = strings.Replace(html, "", `
`, -1) html = strings.Replace(html, "", `
`, -1) html = strings.Replace(html, "${1}${2}${3}`) @@ -75,17 +71,17 @@ func buildTOC(html string) (string, string) { m[link] = i + 1 newLink := link + strconv.Itoa(i) html = strings.Replace(html, link+`"`, newLink+`"`, 1) - ret += before(hn, k) - ret += `
  • ` + v[2] + "" - ret += after(hn, k) + toc += before(hn, k) + toc += `
  • ` + v[2] + "" + toc += after(hn, k) } - return ret, html + return toc, html } func before(arr [][]string, i int) string { c, _ := strconv.Atoi(arr[i][1]) if c == 1 { - return `
      ` + return `
        ` } return "" } @@ -96,13 +92,14 @@ func after(arr [][]string, i int) string { return closeTag(c-1) + "
      " } n, _ := strconv.Atoi(arr[i+1][1]) - if n == 1 { + switch { + case n == 1: return closeTag(c-n) + "
    " - } else if n < c { + case n < c: return closeTag(c - n) - } else if n > c { + case n > c: return openTag(n - c) - } else if n == c { + case n == c: return "
  • " } return "" @@ -110,11 +107,11 @@ func after(arr [][]string, i int) string { func openTag(j int) (ret string) { for i := 0; i < j; i++ { - ret += `