some tests and major cleanup
This commit is contained in:
parent
8ef2a2547c
commit
16671b3406
30 changed files with 192057 additions and 202431 deletions
19
Makefile
19
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
|
||||
|
|
|
|||
1
go.mod
1
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
|
||||
)
|
||||
|
|
|
|||
50
pkg/cache/cache_test.go
vendored
Normal file
50
pkg/cache/cache_test.go
vendored
Normal file
|
|
@ -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()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
81
pkg/core/permission_test.go
Normal file
81
pkg/core/permission_test.go
Normal file
|
|
@ -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()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
7
pkg/core/pledge.go
Normal file
7
pkg/core/pledge.go
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright (C) 2018 Marius Schellenberger
|
||||
|
||||
// +build !openbsd
|
||||
|
||||
package core
|
||||
|
||||
func Pledge(promises, execpromises string) error { return nil }
|
||||
11
pkg/core/pledge_openbsd.go
Normal file
11
pkg/core/pledge_openbsd.go
Normal file
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
13
pkg/db/db.go
13
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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]+")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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...)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, "<table>", `<table class="table">`, -1)
|
||||
html = strings.Replace(html, "</h1>", `</h1><hr>`, -1)
|
||||
html = strings.Replace(html, "<a", `<a target="_blank"`, -1)
|
||||
p.PageIndex = template.HTML(index)
|
||||
p.TOC = template.HTML(toc)
|
||||
p.HTML = template.HTML(html)
|
||||
return whiteSpace.ReplaceAllString(string(filter.Filter(rend)), " ")
|
||||
}
|
||||
|
||||
func spaceReplace(s string) string {
|
||||
return whiteSpace.ReplaceAllString(s, "+")
|
||||
}
|
||||
|
||||
func Title(title string) string {
|
||||
return spaceReplace(titleRe.ReplaceAllString(title, ""))
|
||||
return whiteSpace.ReplaceAllString(titleRe.ReplaceAllString(title, ""), "+")
|
||||
}
|
||||
|
||||
func StoreTitle(section, title string) string {
|
||||
|
|
@ -59,7 +55,7 @@ func UnstoreTitle(storeTitle string) (section, title string) {
|
|||
}
|
||||
|
||||
func buildTOC(html string) (string, string) {
|
||||
var ret string
|
||||
var toc string
|
||||
m := make(map[string]int)
|
||||
hn := reIndex.FindAllStringSubmatch(html, -1)
|
||||
html = reHeader.ReplaceAllString(html, `<a id="${2}" class="anchor"></a>${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 += `<li><a href="#` + newLink + `">` + v[2] + "</a>"
|
||||
ret += after(hn, k)
|
||||
toc += before(hn, k)
|
||||
toc += `<li><a href="#` + newLink + `">` + v[2] + "</a>"
|
||||
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 `<ul type="circle">`
|
||||
return `<ul class="toc">`
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
@ -96,13 +92,14 @@ func after(arr [][]string, i int) string {
|
|||
return closeTag(c-1) + "</ul>"
|
||||
}
|
||||
n, _ := strconv.Atoi(arr[i+1][1])
|
||||
if n == 1 {
|
||||
switch {
|
||||
case n == 1:
|
||||
return closeTag(c-n) + "</ul>"
|
||||
} 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 "</li>"
|
||||
}
|
||||
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 += `<ul type="circle"><li>`
|
||||
}
|
||||
if j > 1 {
|
||||
ret = strings.Replace(ret, "circle", "none", j-1)
|
||||
ret += `<ul class="toc"><li>`
|
||||
}
|
||||
//if j > 1 {
|
||||
// ret = strings.Replace(ret, "circle", "none", j-1)
|
||||
//}
|
||||
ret = ret[0 : len(ret)-4]
|
||||
return
|
||||
}
|
||||
|
|
|
|||
29
pkg/render/render_test.go
Normal file
29
pkg/render/render_test.go
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (C) 2018 Marius Schellenberger
|
||||
|
||||
package render
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTitleFunctions(t *testing.T) {
|
||||
section := "section"
|
||||
title := "title"
|
||||
combined := "section/title"
|
||||
t.Run("StoreTitle", func(t *testing.T) {
|
||||
if StoreTitle(section, title) != combined {
|
||||
t.Fail()
|
||||
}
|
||||
})
|
||||
t.Run("UnstoreTitle", func(t *testing.T) {
|
||||
se, ti := UnstoreTitle(combined)
|
||||
if se != section || ti != title {
|
||||
t.Fail()
|
||||
}
|
||||
})
|
||||
t.Run("Title", func(t *testing.T) {
|
||||
if Title("9ßw$%4h4t-8v74 287(G /SV&3[45v}=94#+?)") != "9w4h4t-8v74+287G+SV345v94" {
|
||||
t.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ package server
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/core"
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/db"
|
||||
"git.giftfish.de/ston1th/gowiki/pkg/log"
|
||||
|
|
@ -54,7 +55,7 @@ func NewHTTPServer(l net.Listener, conf core.Config) (srv *HTTPServer) {
|
|||
func (s *HTTPServer) Start() (err error) {
|
||||
s.DB, err = db.New(s.DataDir)
|
||||
if err != nil {
|
||||
return
|
||||
return errors.New("db: " + err.Error())
|
||||
}
|
||||
if s.Secret != "" {
|
||||
s.JWT, err = jwt.New(jwt.DefaultExpiry, s.DB, bytes.NewBufferString(s.Secret))
|
||||
|
|
@ -62,7 +63,7 @@ func (s *HTTPServer) Start() (err error) {
|
|||
s.JWT, err = jwt.New(jwt.DefaultExpiry, s.DB, nil)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
return errors.New("server: " + err.Error())
|
||||
}
|
||||
go func() {
|
||||
log.Println(s.srv.Serve(s.listener))
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ const (
|
|||
<head>
|
||||
<title>GoWiki | {{.Title}}</title>
|
||||
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-NeLmQ7cX66J4MdtgGlG3O/TgvsSyP1b9WbaQtxYZUbQ="></link>
|
||||
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-1LNAeuiM/rtsY1jIgLovUZ7HbYnOCkj3ZyailNA3rFQ="></link>
|
||||
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-/SZfW8eVqFuioMg+QXacvK1Zc3XLtT5LGu9tMle65Jc="></link>
|
||||
</head>
|
||||
<body id="back-to-top">
|
||||
<div class="navbar navbar-expand fixed-top navbar-dark bg-primary">
|
||||
|
|
@ -259,7 +259,7 @@ const (
|
|||
</div>
|
||||
<div class="row mt-5">
|
||||
<div class="col">
|
||||
{{.Data.PageIndex}}
|
||||
{{.Data.TOC}}
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="btn-group float-md-right">
|
||||
|
|
@ -388,7 +388,7 @@ const (
|
|||
</div>
|
||||
<div class="row mt-5">
|
||||
<div class="col">
|
||||
{{.Data.PageIndex}}
|
||||
{{.Data.TOC}}
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="btn-group float-md-right">
|
||||
|
|
@ -680,6 +680,10 @@ h6 {
|
|||
font-family: 'Courier New';
|
||||
font-size: 14;
|
||||
}
|
||||
ul.toc {
|
||||
list-style-type: disc;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
pre {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ func checkXsrf(xsrf string, secret []byte) bool {
|
|||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if len(t) != jwt.KeySize {
|
||||
return false
|
||||
}
|
||||
return subtle.ConstantTimeCompare(secret, xor(t[keySize:], t[:keySize])) == 1
|
||||
}
|
||||
|
||||
|
|
|
|||
31
pkg/server/xsrf_test.go
Normal file
31
pkg/server/xsrf_test.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (C) 2018 Marius Schellenberger
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestXsrf(t *testing.T) {
|
||||
sec := genKey(keySize)
|
||||
if len(sec) != keySize {
|
||||
t.Fatal("len(sec) != keySize")
|
||||
}
|
||||
xsrf := newXsrf(sec)
|
||||
if xsrf == "" {
|
||||
t.Fatal("xsrf is empty")
|
||||
}
|
||||
|
||||
if !checkXsrf(xsrf, sec) {
|
||||
t.Fatal("valid xsrf check failed")
|
||||
}
|
||||
|
||||
if checkXsrf("test", sec) {
|
||||
t.Fatal("invalid xsrf check succeeded")
|
||||
}
|
||||
|
||||
rnd := genKey(keySize)
|
||||
if checkXsrf(xsrf, rnd) {
|
||||
t.Fatal("invalid xsrf check succeeded")
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,10 @@ import (
|
|||
"io"
|
||||
)
|
||||
|
||||
const defaultBoltBucket = "default"
|
||||
const (
|
||||
defaultBoltBucket = "default"
|
||||
fileMode = 0640
|
||||
)
|
||||
|
||||
type BoltStore struct {
|
||||
Marshaler
|
||||
|
|
@ -19,7 +22,7 @@ func NewBoltStore(file string, m Marshaler) (bs *BoltStore, err error) {
|
|||
if m == nil {
|
||||
m = NewGOB()
|
||||
}
|
||||
db, err := bolt.Open(file, 0640, nil)
|
||||
db, err := bolt.Open(file, fileMode, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
99
pkg/store/boltstore_test.go
Normal file
99
pkg/store/boltstore_test.go
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright (C) 2018 Marius Schellenberger
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testData struct {
|
||||
Data string
|
||||
}
|
||||
|
||||
func TestBoltStore(t *testing.T) {
|
||||
data := []testData{
|
||||
{"123"},
|
||||
{"hello"},
|
||||
}
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
bs, err := NewBoltStore(filepath.Join(dir, "bolt.db"), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = bs.Set("key0", data[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = bs.Set("key1", data[1])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Run("GetKey0", func(t *testing.T) {
|
||||
var d testData
|
||||
err := bs.Get("key0", &d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if d != data[0] {
|
||||
t.Error("d is not data[0]")
|
||||
}
|
||||
})
|
||||
t.Run("ForEach", func(t *testing.T) {
|
||||
err := bs.ForEach(func(k string, v []byte) error {
|
||||
if k == "key0" || k == "key1" {
|
||||
return nil
|
||||
}
|
||||
return errors.New("key0 or key1 not found")
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
t.Run("DumpRestore", func(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
err := bs.Dump(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if buf.Len() == 0 {
|
||||
t.Error("no dump written")
|
||||
}
|
||||
err = bs.Restore(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
t.Run("DeleteKey1", func(t *testing.T) {
|
||||
err := bs.Delete("key1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
t.Run("GetKey1", func(t *testing.T) {
|
||||
var d testData
|
||||
err := bs.Get("key1", &d)
|
||||
if err == nil {
|
||||
t.Error("key1 should be deleted")
|
||||
}
|
||||
if d == data[1] {
|
||||
t.Error("d is not data[1]")
|
||||
}
|
||||
})
|
||||
t.Run("Close", func(t *testing.T) {
|
||||
err := bs.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -2,16 +2,12 @@
|
|||
|
||||
package store
|
||||
|
||||
import "fmt"
|
||||
|
||||
func storeErr(i interface{}) error {
|
||||
return fmt.Errorf("store: %s", i)
|
||||
}
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrKeyNotFound = storeErr("key not found")
|
||||
ErrWriterIsNil = storeErr("writer is nil")
|
||||
ErrReaderIsNil = storeErr("reader is nil")
|
||||
ErrKeyNotFound = errors.New("store: key not found")
|
||||
ErrWriterIsNil = errors.New("store: writer is nil")
|
||||
ErrReaderIsNil = errors.New("store: reader is nil")
|
||||
)
|
||||
|
||||
type Store interface {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
# of the templates directory
|
||||
|
||||
templates_go="pkg/server/templates.go"
|
||||
echo "Generating templates.go"
|
||||
echo "Generating ${templates_go}"
|
||||
|
||||
if [ ! -d templates ]; then
|
||||
echo "error: templates directory not found" 1>&2
|
||||
|
|
|
|||
|
|
@ -75,6 +75,10 @@ h6 {
|
|||
font-family: 'Courier New';
|
||||
font-size: 14;
|
||||
}
|
||||
ul.toc {
|
||||
list-style-type: disc;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
pre {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<title>GoWiki | {{.Title}}</title>
|
||||
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-NeLmQ7cX66J4MdtgGlG3O/TgvsSyP1b9WbaQtxYZUbQ="></link>
|
||||
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-1LNAeuiM/rtsY1jIgLovUZ7HbYnOCkj3ZyailNA3rFQ="></link>
|
||||
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-/SZfW8eVqFuioMg+QXacvK1Zc3XLtT5LGu9tMle65Jc="></link>
|
||||
</head>
|
||||
<body id="back-to-top">
|
||||
<div class="navbar navbar-expand fixed-top navbar-dark bg-primary">
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
</div>
|
||||
<div class="row mt-5">
|
||||
<div class="col">
|
||||
{{.Data.PageIndex}}
|
||||
{{.Data.TOC}}
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="btn-group float-md-right">
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
</div>
|
||||
<div class="row mt-5">
|
||||
<div class="col">
|
||||
{{.Data.PageIndex}}
|
||||
{{.Data.TOC}}
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="btn-group float-md-right">
|
||||
|
|
|
|||
38496
vendor/github.com/blevesearch/segment/segment_words.go
generated
vendored
38496
vendor/github.com/blevesearch/segment/segment_words.go
generated
vendored
File diff suppressed because it is too large
Load diff
71309
vendor/github.com/blevesearch/segment/segment_words_prod.go
generated
vendored
71309
vendor/github.com/blevesearch/segment/segment_words_prod.go
generated
vendored
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue