diff --git a/.gitignore b/.gitignore
index bd54b44..a4694b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
gowiki
tmp
run.sh
+TODO.txt
diff --git a/Makefile b/Makefile
index 3131911..8950a7c 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,6 @@ PROGRAM=gowiki
all: $(PROGRAM)
setup:
- $(CC) get github.com/tools/godep
$(CC) get github.com/client9/misspell
$(PROGRAM): clean codeqa
@@ -26,7 +25,7 @@ golint:
$(GOPATH)/bin/golint .
misspell:
- $(GOPATH)/bin/misspell **/*
+ $(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 *
templates:
$(CC) generate
diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go
index 97db392..b4bb16f 100644
--- a/pkg/cmd/cmd.go
+++ b/pkg/cmd/cmd.go
@@ -13,7 +13,6 @@ import (
"syscall"
"time"
- "git.giftfish.de/ston1th/gowiki/pkg/db"
"git.giftfish.de/ston1th/gowiki/pkg/log"
"git.giftfish.de/ston1th/gowiki/pkg/server"
)
@@ -29,7 +28,7 @@ const (
defRunGroup = "wiki"
)
-func server(conf serverConfig) (err error) {
+func initServer(conf serverConfig) (err error) {
dropCfg := godrop.Config{
User: conf.User,
Group: conf.Group,
@@ -52,7 +51,7 @@ func server(conf serverConfig) (err error) {
return
}
- srv := server.NewHTTPServer(l, conf.Version, conf.SecureCookie)
+ srv := server.NewHTTPServer(l, conf.Version, conf.DataDir+"/"+blevePath, conf.SecureCookie)
err = srv.Start()
if err != nil {
return
@@ -92,7 +91,7 @@ func Run(version string) {
Flags: defaultFlags(serverFlags()),
Action: func(c *cli.Context) error {
conf.Version = app.Version
- if err := server(conf); err != nil {
+ if err := initServer(conf); err != nil {
stdlog.Fatal("server: ", err)
}
return nil
@@ -106,9 +105,10 @@ func Run(version string) {
if err := os.Chdir(conf.DataDir); err != nil {
stdlog.Fatal("dump: ", err)
}
- if err := db.Dump(blevePath, verbose); err != nil {
- stdlog.Fatal("dump: ", err)
- }
+ //TODO
+ //if err := db.Dump(blevePath, verbose); err != nil {
+ // stdlog.Fatal("dump: ", err)
+ //}
return nil
},
},
@@ -120,9 +120,10 @@ func Run(version string) {
if err := os.Chdir(conf.DataDir); err != nil {
stdlog.Fatal("restore: ", err)
}
- if err := db.Restore(blevePath, verbose); err != nil {
- stdlog.Fatal("restore: ", err)
- }
+ //TODO
+ //if err := db.Restore(blevePath, verbose); err != nil {
+ // stdlog.Fatal("restore: ", err)
+ //}
return nil
},
},
diff --git a/pkg/core/const.go b/pkg/core/const.go
new file mode 100644
index 0000000..5b1fc86
--- /dev/null
+++ b/pkg/core/const.go
@@ -0,0 +1,8 @@
+package core
+
+const (
+ IndexPage = "Index"
+ WikiSection = "wiki"
+
+ IndexURI = WikiSection + "/" + IndexPage
+)
diff --git a/pkg/core/permission.go b/pkg/core/permission.go
index 8c9953a..93efd48 100644
--- a/pkg/core/permission.go
+++ b/pkg/core/permission.go
@@ -21,6 +21,18 @@ func ParsePerm(p int) Permission {
return Invalid
}
+func ParsePermString(p string) Permission {
+ switch p {
+ case "1":
+ return Public
+ case "2":
+ return Internal
+ case "3":
+ return Private
+ }
+ return Invalid
+}
+
func ReadPerm(username string, p *Page) bool {
switch p.Perm {
case Public:
@@ -33,7 +45,14 @@ func ReadPerm(username string, p *Page) bool {
return false
}
-func WritePerm(username string, p *Page) bool {
+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 == "" {
diff --git a/pkg/core/types.go b/pkg/core/types.go
index 4a17c8f..fc50391 100644
--- a/pkg/core/types.go
+++ b/pkg/core/types.go
@@ -3,21 +3,22 @@ package core
import "html/template"
type Page struct {
- Title string `json:"title"`
- Markdown string `json:"markdown"`
- Index template.HTML `json:"index"`
- Text template.HTML `json:"text"`
- Created string `json:"created"`
- Updated string `json:"updated"`
- Owner string `json:"owner"`
- Perm Permission `json:"perm"`
+ Title string `json:"title"`
+ StoreTitle string `json:"store_title"`
+ Markdown string `json:"markdown"`
+ PageIndex template.HTML `json:"page_index"`
+ HTML template.HTML `json:"html"`
+ Created string `json:"created"`
+ Updated string `json:"updated"`
+ Owner string `json:"owner"`
+ Perm Permission `json:"perm"`
}
-type Result struct {
- Title string
- StoreTitle string
- Text string
-}
+type Pages []Page
+
+func (p Pages) Len() int { return len(p) }
+func (p Pages) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p Pages) Less(i, j int) bool { return p[i].StoreTitle < p[j].StoreTitle }
type User struct {
Username string
@@ -25,3 +26,15 @@ type User struct {
Admin bool
Locked int
}
+
+type Users []User
+
+func (u Users) Len() int { return len(u) }
+func (u Users) Swap(i, j int) { u[i], u[j] = u[j], u[i] }
+func (u Users) Less(i, j int) bool { return u[i].Username < u[j].Username }
+
+type Result struct {
+ Title string
+ StoreTitle string
+ Text string
+}
diff --git a/pkg/db/db.go b/pkg/db/db.go
index 21b97de..90cfd83 100644
--- a/pkg/db/db.go
+++ b/pkg/db/db.go
@@ -8,7 +8,6 @@ import (
"git.giftfish.de/ston1th/gowiki/pkg/core"
"git.giftfish.de/ston1th/gowiki/pkg/index"
"git.giftfish.de/ston1th/gowiki/pkg/store"
- "git.giftfish.de/ston1th/gowiki/pkg/util"
)
const (
@@ -17,11 +16,9 @@ const (
usersFile = "users.db"
pagesFile = "pages.db"
bcryptCost = 13
- indexName = "Index"
welcome = `# Welcome to GoWiki
This is the [Index](/wiki/Index) page.
You can customize it how you like.`
- wikiSection = "wiki"
)
/*const (
@@ -40,12 +37,13 @@ type DB struct {
Index *index.Index
}
-func NewDB(indexPath string) (db *DB, err error) {
+func New(indexPath string) (db *DB, err error) {
db = &DB{cache: cache.NewCache()}
- db.Index, err = index.NewIndex(indexPath)
- if err != nil {
- return
- }
+ //TODO
+ //db.Index, err = index.NewIndex(indexPath)
+ //if err != nil {
+ // return
+ //}
db.users, err = store.NewBoltStore(usersFile, nil)
if err != nil {
@@ -66,11 +64,9 @@ func NewDB(indexPath string) (db *DB, err error) {
if err != nil {
return
}
- if _, err = db.pageExists(util.StoreTitle(wikiSection, indexName), defUser); err != nil {
- _, err = db.CreatePage(indexName, wikiSection, welcome, defUser, core.Public)
- if err != nil {
- return
- }
+ _, err = db.CreatePage(core.IndexPage, core.WikiSection, welcome, defUser, core.Public)
+ if err != nil && err != store.ErrKeyNotFound {
+ return
}
return
}
@@ -84,5 +80,7 @@ func (db *DB) Close() error {
if err != nil {
return err
}
- return db.Index.Close()
+ return nil
+ //TODO
+ //return db.Index.Close()
}
diff --git a/pkg/db/helper.go b/pkg/db/helper.go
index ae0cd11..e2dc880 100644
--- a/pkg/db/helper.go
+++ b/pkg/db/helper.go
@@ -5,6 +5,26 @@ import (
"time"
)
+var reservedUsers = []string{
+ "all",
+ "login",
+ "logout",
+ "new",
+ "search",
+ "user",
+ "view",
+ "wiki",
+}
+
+func reservedUser(username string) bool {
+ for _, v := range reservedUsers {
+ if username == v {
+ return true
+ }
+ }
+ return false
+}
+
func validatePassword(pw string) (b []byte) {
b = []byte(pw)
if len(pw) <= 56 {
diff --git a/pkg/db/page.go b/pkg/db/page.go
index 7b0d400..f8ce39b 100644
--- a/pkg/db/page.go
+++ b/pkg/db/page.go
@@ -5,20 +5,38 @@ import (
"git.giftfish.de/ston1th/gowiki/pkg/render"
"git.giftfish.de/ston1th/gowiki/pkg/store"
"git.giftfish.de/ston1th/gowiki/pkg/util"
+ "sort"
)
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")
)
+func (db *DB) GetAllPages(username string) (pages core.Pages) {
+ db.pages.ForEach(func(title string, _ []byte) error {
+ if title == core.IndexURI {
+ return nil
+ }
+ p, err := db.GetPage(title, username)
+ if err == nil {
+ pages = append(pages, *p)
+ }
+ return nil
+ })
+ sort.Sort(pages)
+ return
+}
+
func (db *DB) GetPage(title, username string) (p *core.Page, err error) {
p = db.cache.Get(title)
if p == nil {
- p = new(core.Page)
- err = db.pages.Get(title, p)
+ p, err = db.getPage(title, username)
db.cache.Add(title, p)
+ return
}
if !core.ReadPerm(username, p) {
err = errPageNotFound
@@ -26,7 +44,7 @@ func (db *DB) GetPage(title, username string) (p *core.Page, err error) {
return
}
-func (db *DB) pageExists(title, username string) (p *core.Page, err error) {
+func (db *DB) getPage(title, username string) (p *core.Page, err error) {
p = new(core.Page)
err = db.pages.Get(title, p)
if err != nil {
@@ -43,78 +61,98 @@ func (db *DB) CreatePage(title, section, markdown, username string, p core.Permi
err = errInvalidPermission
return
}
- if section == wikiSection && p == core.Private {
+ if section == core.WikiSection && p == core.Private {
err = errPrivateWikiPage
return
}
st := util.StoreTitle(section, title)
- if _, err = db.pageExists(st, username); err != nil {
+ if _, err = db.getPage(st, username); err != nil && err != store.ErrKeyNotFound {
return
}
page = &core.Page{
- Title: title,
- Markdown: markdown,
- Created: created(username),
- Owner: username,
- Perm: p,
+ Title: title,
+ StoreTitle: st,
+ Markdown: markdown,
+ Created: created(username),
+ Owner: username,
+ Perm: p,
}
- search := render.Render(page)
+ //search := render.Render(page)
+ render.Render(page)
err = db.pages.Set(st, page)
if err != nil {
return
}
- err = db.Index.Add(title, st, search)
- if err != nil {
- return
- }
+ //TODO
+ //err = db.Index.Add(title, st, search)
+ //if err != nil {
+ // return
+ //}
db.cache.Add(st, page)
return
}
-func (db *DB) UpdatePage(title, section, markdown, username string, perm int) (page *core.Page, err error) {
- p := core.ParsePerm(perm)
+func (db *DB) UpdatePage(title, section, markdown, username string, p core.Permission) (err error) {
if p == core.Invalid {
err = errInvalidPermission
return
}
- if section == wikiSection && p == core.Private {
+ if section == core.WikiSection && p == core.Private {
err = errPrivateWikiPage
return
}
st := util.StoreTitle(section, title)
- page, err = db.pageExists(st, username)
+ page, err := db.getPage(st, username)
if err != nil {
return
}
+ if !core.WritePerm(username, section, page) {
+ return errPermissionDenied
+ }
page.Markdown = markdown
page.Updated = created(username)
page.Perm = p
- search := render.Render(page)
+ //TODO
+ //search := render.Render(page)
+ render.Render(page)
err = db.pages.Set(st, page)
if err != nil {
return
}
- err = db.Index.Add(title, st, search)
- if err != nil {
- return
- }
+ //TODO
+ //err = db.Index.Add(title, st, search)
+ //if err != nil {
+ // return
+ //}
db.cache.Add(st, page)
return
}
func (db *DB) DeletePage(title, section, username string) (err error) {
- st := util.StoreTitle(section, title)
- if _, err = db.pageExists(st, username); err != nil {
+ var page *core.Page
+ if section == core.WikiSection && title == core.IndexPage {
+ err = errDeleteIndexPage
return
}
+ st := util.StoreTitle(section, title)
+ if page, err = db.getPage(st, username); err != nil {
+ return
+ }
+ if !core.WritePerm(username, section, page) {
+ return errPermissionDenied
+ }
+
if err = db.pages.Delete(st); err != nil {
return
}
- return db.Index.Delete(st)
+ db.cache.Delete(st)
+ return nil
+ //TODO
+ //return db.Index.Delete(st)
}
diff --git a/pkg/db/user.go b/pkg/db/user.go
index b4a66f2..28f3502 100644
--- a/pkg/db/user.go
+++ b/pkg/db/user.go
@@ -4,19 +4,24 @@ import (
"errors"
"git.giftfish.de/ston1th/gowiki/pkg/core"
"golang.org/x/crypto/bcrypt"
+ "sort"
)
var (
errUserNotFound = dbErr("user not found")
errUserExists = dbErr("user already exist")
+ errUserReserved = dbErr("username is reserved")
)
-func (db *DB) GetUsers() (users []core.User, err error) {
- // TODO
- /*users, err = db.DumpUsers()
- for i := range users {
- users[i].Password = ""
- }*/
+func (db *DB) GetUsers() (users core.Users, err error) {
+ db.users.ForEach(func(username string, _ []byte) error {
+ u, err := db.GetUser(username)
+ if err == nil {
+ users = append(users, u)
+ }
+ return nil
+ })
+ sort.Sort(users)
return
}
@@ -81,6 +86,9 @@ func (bs *BoltStore) RestoreUsers(users []User) error {
}*/
func (db *DB) CreateUser(username, password string, admin bool) error {
+ if reservedUser(username) {
+ return errUserReserved
+ }
if err := db.UserExists(username); err == nil {
return errUserExists
}
diff --git a/pkg/index/index.go b/pkg/index/index.go
index 5a24a38..fb44231 100644
--- a/pkg/index/index.go
+++ b/pkg/index/index.go
@@ -8,7 +8,6 @@ import (
"git.giftfish.de/ston1th/gowiki/pkg/core"
"github.com/blevesearch/bleve"
- // "github.com/blevesearch/bleve/document"
)
const (
diff --git a/pkg/render/render.go b/pkg/render/render.go
index b4a822b..d52a106 100644
--- a/pkg/render/render.go
+++ b/pkg/render/render.go
@@ -10,14 +10,14 @@ import (
"git.giftfish.de/ston1th/gowiki/pkg/core"
"github.com/blevesearch/bleve/analysis"
- htmlFilter "github.com/blevesearch/bleve/analysis/char_filters/html_char_filter"
+ "github.com/blevesearch/bleve/analysis/char/html"
"github.com/russross/blackfriday"
)
var filter = makeFilter()
func makeFilter() analysis.CharFilter {
- f, _ := htmlFilter.CharFilterConstructor(nil, nil)
+ f, _ := html.CharFilterConstructor(nil, nil)
return f
}
@@ -35,8 +35,8 @@ func Render(p *core.Page) string {
html = strings.Replace(html, "
", ``, -1)
html = strings.Replace(html, "", `
`, -1)
html = strings.Replace(html, " 0 && uri[0] != '/' {
+ uri = "/" + uri
+ }
log.Printf("%s %s %s %d %s\n", c.Request.RemoteAddr, c.Request.Method, c.Request.URL, code, uri)
http.Redirect(c.Response, c.Request, uri, code)
}
@@ -146,9 +161,8 @@ func (c *Context) FormSlice(name string) []string {
return c.Request.PostForm[name]
}
-func (c *Context) Form(name string) (ret string) {
- ret = c.Request.PostFormValue(name)
- return
+func (c *Context) Form(name string) string {
+ return c.Request.PostFormValue(name)
}
func (c *Context) Var(name string) (ret string) {
@@ -156,6 +170,7 @@ func (c *Context) Var(name string) (ret string) {
return
}
+// TODO remove f
// CheckToken validates the xsrf token
func (c *Context) CheckXsrf(f func()) (ok bool) {
ok = checkXsrf(c.Form("token"), c.Token.RawSig()[:keySize])
@@ -171,7 +186,27 @@ func (c *Context) CheckXsrf(f func()) (ok bool) {
}
func (c *Context) LoggedOn() (ok bool) {
- _, ok = c.Token.Claims["user"]
+ _, ok = c.Token.Claims.Get(userClaim)
+ return
+}
+
+func newCookie(value string, maxAge int) (cookie *http.Cookie) {
+ cookie = &http.Cookie{
+ Name: cookieName,
+ Value: value,
+ Path: "/",
+ MaxAge: maxAge,
+ //TODO make secure configurable
+ Secure: false,
+ HttpOnly: true,
+ SameSite: http.SameSiteStrictMode,
+ }
+ if maxAge > 0 {
+ d := time.Duration(maxAge) * time.Second
+ cookie.Expires = time.Now().Add(d)
+ } else if maxAge < 0 {
+ cookie.Expires = time.Unix(1, 0)
+ }
return
}
@@ -182,28 +217,15 @@ func (c *Context) SetCookie(claims map[string]interface{}) {
return
}
c.Token = *t
- http.SetCookie(c.Response, &http.Cookie{
- Name: cookieName,
- Value: t.Sig(),
- MaxAge: 3600 * 12,
- Secure: true,
- HttpOnly: true,
- SameSite: http.SameSiteStrictMode,
- })
+ http.SetCookie(c.Response, newCookie(c.Token.String(), int(jwt.DefaultExpiry.Seconds())))
}
-func (c *Context) GetUser() string {
- if ret, ok := c.Token.Claims["user"].(string); ok {
- return ret
- }
- return ""
+func (c *Context) User() string {
+ return c.Token.Claims.GetString(userClaim)
}
-func (c *Context) GetAdmin() bool {
- if ret, ok := c.Token.Claims["admin"].(bool); ok {
- return ret
- }
- return false
+func (c *Context) Admin() bool {
+ return c.Token.Claims.GetBool(adminClaim)
}
type ctxHandler func(*Context)
diff --git a/pkg/server/handler.go b/pkg/server/handler.go
index 6d60cca..9ec70a5 100644
--- a/pkg/server/handler.go
+++ b/pkg/server/handler.go
@@ -5,7 +5,8 @@ package server
import (
"git.giftfish.de/ston1th/gowiki/pkg/core"
"git.giftfish.de/ston1th/gowiki/pkg/log"
- "html/template"
+ "git.giftfish.de/ston1th/gowiki/pkg/util"
+ "git.giftfish.de/ston1th/jwt"
"net/http"
"time"
)
@@ -20,7 +21,7 @@ func (nf *notFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func adminAuthHandler(h ctxHandler) ctxHandler {
return func(ctx *Context) {
- if ctx.GetAdmin() {
+ if ctx.Admin() {
h(ctx)
return
}
@@ -30,11 +31,11 @@ func adminAuthHandler(h ctxHandler) ctxHandler {
func userAuthHandler(h ctxHandler) ctxHandler {
return func(ctx *Context) {
- if ctx.GetAdmin() {
+ if ctx.Admin() {
h(ctx)
return
}
- if ctx.GetUser() == ctx.Var("user") {
+ if ctx.User() == ctx.Var("user") {
h(ctx)
return
}
@@ -68,12 +69,12 @@ func staticHandler(ctx *Context) {
}
func indexHandler(ctx *Context) {
- ctx.Redirect("/wiki/Index", 302)
+ ctx.Redirect(core.IndexURI, 302)
}
func loginHandler(ctx *Context) {
if ctx.LoggedOn() {
- ctx.Redirect("/wiki/Index", 302)
+ ctx.Redirect(core.IndexURI, 302)
return
}
ctx.Template("loginHandler")
@@ -87,11 +88,10 @@ func loginHandler(ctx *Context) {
case "POST":
user := ctx.Form("user")
password := ctx.Form("password")
- submit := ctx.Form("submit")
if !ctx.CheckXsrf(nil) {
return
}
- if user == "" || password == "" || submit != "Login" {
+ if user == "" || password == "" {
ctx.Data.Msg = "wrong inputs"
ctx.Exec()
return
@@ -102,8 +102,8 @@ func loginHandler(ctx *Context) {
ctx.Exec()
return
}
- ctx.SetCookie(map[string]interface{}{"username": u.Username, "admin": u.Admin})
- ctx.Redirect("/wiki/Index", 302)
+ ctx.SetCookie(map[string]interface{}{userClaim: u.Username, adminClaim: u.Admin})
+ ctx.Redirect(core.IndexURI, 302)
}
}
@@ -118,15 +118,9 @@ func searchHandler(ctx *Context) {
ctx.Exec()
case "POST":
search := ctx.Form("search")
- submit := ctx.Form("submit")
if !ctx.CheckXsrf(nil) {
return
}
- if submit != "Search" {
- ctx.Data.Msg = "wrong inputs"
- ctx.Exec()
- return
- }
res, err := ctx.Srv.DB.Index.Search(search)
if err != nil {
@@ -135,7 +129,7 @@ func searchHandler(ctx *Context) {
return
}
ctx.Data.Search = search
- ctx.Data.Data = template.HTML(res)
+ ctx.Data.Data = res
ctx.Exec()
}
}
@@ -143,167 +137,213 @@ func searchHandler(ctx *Context) {
func allHandler(ctx *Context) {
ctx.Template("allHandler")
ctx.Data = webData{
- Title: "All Articles",
- BodyTitle: "All Articles",
- Admin: ctx.GetAdmin(),
+ Title: "All Pages",
+ BodyTitle: "All Pages",
+ Admin: ctx.Admin(),
}
- all, err := ctx.Srv.DB.Index.GetAll(!ctx.LoggedOn())
- if err != nil {
- ctx.Data.Msg = err.Error()
- }
- ctx.Data.Data = all
+ ctx.Data.Data = ctx.Srv.DB.GetAllPages(ctx.User())
ctx.Exec()
}
-func wikiNewHandler(ctx *Context) {
- ctx.Template("wikiNewHandler")
- ctx.Data = webData{Title: "New Article"}
+func pageNewHandler(ctx *Context) {
+ ctx.Template("pageNewHandler")
+ ctx.Data = webData{Title: "New Page"}
switch ctx.Method() {
case "GET":
ctx.Exec()
case "POST":
+ section := ctx.Form("section")
title := ctx.Form("title")
- text := ctx.Form("text")
- public := ctx.Form("public")
- pub := false
- if public == "0" {
- pub = true
- }
- submit := ctx.Form("submit")
+ markdown := ctx.Form("markdown")
+ perm := ctx.Form("perm")
p := core.Page{
- Title: title,
- MD: text,
+ Title: title,
+ Markdown: markdown,
}
ctx.Data.Data = p
if !ctx.CheckXsrf(nil) {
return
}
- if submit != "Submit" {
- ctx.Data.Msg = "wrong inputs"
- ctx.Exec()
- return
+ if section != core.WikiSection {
+ section = ctx.User()
}
- newTitle, err := ctx.Srv.DB.Index.Index(title, text, ctx.GetUser(), pub)
+ page, err := ctx.Srv.DB.CreatePage(title, section, markdown, ctx.User(), core.ParsePermString(perm))
if err != nil {
ctx.Data.Msg = err.Error()
ctx.Exec()
return
}
- ctx.Redirect("/wiki/"+newTitle, 302)
+ ctx.Redirect(page.StoreTitle, 302)
}
}
-func wikiHandler(ctx *Context) {
- if ctx.T == nil {
- ctx.Template("wikiHandler")
- }
+func pageHandler(ctx *Context) {
ctx.Data = webData{
- Admin: ctx.GetAdmin(),
+ Admin: ctx.Admin(),
}
+ section := ctx.Var("section")
title := ctx.Var("title")
- art, err := ctx.Srv.DB.Index.Get(!ctx.LoggedOn(), title)
+ user := ctx.User()
+ if key := ctx.Var("key"); key != "" {
+ t, err := jwt.DecodeToken(key)
+ if err != nil {
+ log.Println("DecodeToken:", err)
+ ctx.NotFound()
+ return
+ }
+ if err = ctx.Srv.JWT.Verify(t); err != nil {
+ log.Println("VerifyToken:", err)
+ ctx.NotFound()
+ return
+ }
+ user = t.Claims.GetString(sharedClaim)
+ section = t.Claims.GetString(sectionClaim)
+ title = t.Claims.GetString(titleClaim)
+ ctx.Data.Key = key
+ if ctx.T == nil {
+ ctx.Template("pageViewHandler")
+ }
+ } else {
+ if ctx.T == nil {
+ ctx.Template("pageHandler")
+ }
+ }
+ page, err := ctx.Srv.DB.GetPage(util.StoreTitle(section, title), user)
if err != nil {
+ log.Println(err)
ctx.NotFound()
return
}
- art.LinkTitle = title
- ctx.Data.Data = art
- ctx.Data.Title = art.Title
- ctx.Data.BodyTitle = art.Title
+ ctx.Data.Data = page
+ ctx.Data.Title = page.Title
+ ctx.Data.BodyTitle = page.Title
ctx.Exec()
}
-func wikiMDHandler(f ctxHandler) ctxHandler {
+func pageMDHandler(f ctxHandler) ctxHandler {
return func(ctx *Context) {
- ctx.Template("wikiMDHandler")
+ ctx.Template("pageMDHandler")
f(ctx)
}
}
-func wikiEditHandler(ctx *Context) {
- ctx.Template("wikiEditHandler")
+// TODO add share token blacklisting
+func pageShareHandler(ctx *Context) {
+ ctx.Template("pageShareHandler")
ctx.Data = webData{}
+ section := ctx.Var("section")
title := ctx.Var("title")
+ user := ctx.User()
+ st := util.StoreTitle(section, title)
+ page, err := ctx.Srv.DB.GetPage(st, user)
+ if err != nil {
+ ctx.NotFound()
+ return
+ }
+ t := jwt.NewToken(map[string]interface{}{
+ sharedClaim: user,
+ sectionClaim: section,
+ titleClaim: title,
+ jwt.ExpClaim: jwt.NewExp(time.Hour * 24),
+ }, nil)
+
+ if err = ctx.Srv.JWT.Sign(t); err != nil {
+ log.Println("SignToken:", err)
+ ctx.NotFound()
+ return
+ }
+ /* TODO
+ host := ctx.Request.Header.Get("X-Forwarded-For")
+ if host == "" {
+ ctx.Request.Host
+ }
+ ctx.Data.Data = "https://" + host + "/view/" + t.String()
+ */
+ ctx.Data.Key = t.String()
+ ctx.Data.Data = st
+ ctx.Data.Title = page.Title
+ ctx.Data.BodyTitle = page.Title
+ ctx.Exec()
+}
+
+func pageEditHandler(ctx *Context) {
+ ctx.Template("pageEditHandler")
+ ctx.Data = webData{}
+ section := ctx.Var("section")
+ title := ctx.Var("title")
+ page, err := ctx.Srv.DB.GetPage(util.StoreTitle(section, title), ctx.User())
+ if err != nil {
+ ctx.NotFound()
+ return
+ }
switch ctx.Method() {
case "GET":
- art, err := ctx.Srv.DB.Index.Get(!ctx.LoggedOn(), title)
- if err != nil {
- ctx.NotFound()
- return
- }
- art.LinkTitle = title
- ctx.Data.Data = art
- ctx.Data.Title = art.Title
- ctx.Data.BodyTitle = art.Title
+ ctx.Data.Data = page
+ ctx.Data.Title = page.Title
+ ctx.Data.BodyTitle = page.Title
ctx.Exec()
case "POST":
- ftitle := ctx.Form("title")
- text := ctx.Form("text")
- public := ctx.Form("public")
- pub := false
- if public == "0" {
- pub = true
- }
- submit := ctx.Form("submit")
+ storeTitle := ctx.Form("store_title")
+ section, title = util.UnstoreTitle(storeTitle)
+ markdown := ctx.Form("markdown")
+ perm := core.ParsePermString(ctx.Form("perm"))
ctx.Data.Data = core.Page{
- Title: ftitle,
- LinkTitle: title,
- MD: text,
- Public: pub,
+ Title: page.Title,
+ StoreTitle: storeTitle,
+ Markdown: markdown,
+ Perm: perm,
}
- ctx.Data.Title = ftitle
- ctx.Data.BodyTitle = ftitle
+ ctx.Data.Title = page.Title
+ ctx.Data.BodyTitle = page.Title
if !ctx.CheckXsrf(nil) {
return
}
- if submit != "Submit" {
- ctx.Data.Msg = "wrong inputs"
- ctx.Exec()
- return
- }
- err := ctx.Srv.DB.Index.Update(title, text, ctx.GetUser(), pub)
+ err = ctx.Srv.DB.UpdatePage(title, section, markdown, ctx.User(), perm)
if err != nil {
ctx.Data.Msg = err.Error()
ctx.Exec()
return
}
- ctx.Srv.Editors.Remove(title)
- ctx.Redirect("/wiki/"+title, 302)
+ ctx.Redirect("/"+page.StoreTitle, 302)
}
}
-func wikiDelHandler(ctx *Context) {
+func pageDelHandler(ctx *Context) {
+ section := ctx.Var("section")
title := ctx.Var("title")
- submit := ctx.Form("submit")
- f := func() {
- ctx.Redirect("/wiki/"+title, 302)
+ st := util.StoreTitle(section, title)
+ ctx.Template("pageDelHandler")
+ ctx.Data.Data = st
+ ctx.Data.Title = title
+ ctx.Data.BodyTitle = title
+ switch ctx.Method() {
+ case "GET":
+ ctx.Exec()
+ case "POST":
+ if !ctx.CheckXsrf(nil) {
+ return
+ }
+ if err := ctx.Srv.DB.DeletePage(title, section, ctx.User()); err != nil {
+ ctx.Data.Msg = err.Error()
+ ctx.Exec()
+ return
+ }
+ ctx.Redirect(core.IndexURI, 302)
}
- if !ctx.CheckXsrf(f) {
- return
- }
- if submit != "Delete" {
- f()
- return
- }
- if err := ctx.Srv.Index.Delete(title); err != nil {
- log.Println("delete:", err)
- f()
- }
- ctx.Redirect("/wiki/Index", 302)
}
-func usersHandler(ctx *Context) {
+func userHandler(ctx *Context) {
if !ctx.LoggedOn() {
ctx.NotFound()
return
}
- ctx.Template("usersHandler")
+ ctx.Template("userHandler")
ctx.Data = webData{
Title: "Users",
BodyTitle: "Users",
- User: ctx.GetUser(),
+ User: ctx.User(),
}
- us, err := ctx.Srv.BS.GetUsers()
+ us, err := ctx.Srv.DB.GetUsers()
if err != nil {
ctx.Data.Msg = err.Error()
}
@@ -329,21 +369,20 @@ func userNewHandler(ctx *Context) {
if admin == "0" {
adm = true
}
- submit := ctx.Form("submit")
if !ctx.CheckXsrf(nil) {
return
}
- if user == "" || password == "" || password != repeat || submit != "Submit" {
+ if user == "" || password == "" || password != repeat {
ctx.Data.Msg = "wrong inputs"
ctx.Exec()
return
}
- if err := ctx.Srv.BS.CreateUser(user, password, adm); err != nil {
+ if err := ctx.Srv.DB.CreateUser(user, password, adm); err != nil {
ctx.Data.Msg = err.Error()
ctx.Exec()
return
}
- ctx.Redirect("/users", 302)
+ ctx.Redirect("/user", 302)
}
}
@@ -355,7 +394,7 @@ func userEditHandler(ctx *Context) {
}
switch ctx.Method() {
case "GET":
- u, err := ctx.Srv.BS.GetUserWithoutPassword(ctx.Var("user"))
+ u, err := ctx.Srv.DB.GetUserWithoutPassword(ctx.Var("user"))
if err != nil {
ctx.Data.Msg = err.Error()
ctx.Exec()
@@ -372,42 +411,41 @@ func userEditHandler(ctx *Context) {
if admin == "0" {
adm = true
}
- submit := ctx.Form("submit")
if !ctx.CheckXsrf(nil) {
return
}
- if user == "" || password != repeat || submit != "Submit" {
+ if user == "" || password != repeat {
ctx.Data.Msg = "wrong inputs"
ctx.Exec()
return
}
- if ctx.GetAdmin() {
- if err := ctx.Srv.BS.AdminUpdateUser(user, password, adm); err != nil {
+ if ctx.Admin() {
+ if err := ctx.Srv.DB.AdminUpdateUser(user, password, adm); err != nil {
ctx.Data.Msg = err.Error()
ctx.Exec()
return
}
} else {
- if user == ctx.GetUser() {
- if err := ctx.Srv.BS.UpdateUserPassword(user, password); err != nil {
+ if user == ctx.User() {
+ if err := ctx.Srv.DB.UpdateUserPassword(user, password); err != nil {
ctx.Data.Msg = err.Error()
ctx.Exec()
return
}
- ctx.Redirect("/wiki/Index", 302)
+ ctx.Redirect(core.IndexURI, 302)
return
}
}
- ctx.Redirect("/users", 302)
+ ctx.Redirect("/user", 302)
}
}
func userUnlockHandler(ctx *Context) {
user := ctx.Var("user")
- if err := ctx.Srv.BS.UnlockUser(user); err != nil {
+ if err := ctx.Srv.DB.UnlockUser(user); err != nil {
log.Println("unlock:", err)
}
- ctx.Redirect("/users", 302)
+ ctx.Redirect("/user", 302)
}
func userDelHandler(ctx *Context) {
@@ -418,7 +456,7 @@ func userDelHandler(ctx *Context) {
}
switch ctx.Method() {
case "GET":
- user, err := ctx.Srv.BS.GetUserWithoutPassword(ctx.Var("user"))
+ user, err := ctx.Srv.DB.GetUserWithoutPassword(ctx.Var("user"))
if err != nil {
ctx.Data.Msg = err.Error()
ctx.Exec()
@@ -427,14 +465,14 @@ func userDelHandler(ctx *Context) {
ctx.Data.Data = user
ctx.Exec()
case "POST":
- if err := ctx.Srv.BS.DeleteUser(ctx.Var("user")); err != nil {
+ if err := ctx.Srv.DB.DeleteUser(ctx.Var("user")); err != nil {
log.Println("delete:", err)
}
- ctx.Redirect("/users", 302)
+ ctx.Redirect("/user", 302)
}
}
func logoutHandler(ctx *Context) {
ctx.SetCookie(nil)
- ctx.Redirect("/wiki/Index", 302)
+ ctx.Redirect(core.IndexURI, 302)
}
diff --git a/pkg/server/routes.go b/pkg/server/routes.go
index 9b3ebac..fdb8c0e 100644
--- a/pkg/server/routes.go
+++ b/pkg/server/routes.go
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 Marius Schellenberger
+// Copyright (C) 2018 Marius Schellenberger
package server
@@ -37,7 +37,7 @@ var routes = []route{
{
"/new",
authHandler(
- wikiNewHandler),
+ pageNewHandler),
[]string{"GET", "POST"},
},
{
@@ -46,55 +46,11 @@ var routes = []route{
[]string{"GET"},
},
{
- "/wiki/{title:[a-zA-Z0-9+-]+$}",
- wikiHandler,
- []string{"GET"},
- },
- {
- "/wiki/{title:[a-zA-Z0-9+-]+}/md",
- wikiMDHandler(
- wikiHandler),
- []string{"GET"},
- },
- {
- "/wiki/{title:[a-zA-Z0-9+-]+}/edit",
- authHandler(
- wikiEditHandler),
- []string{"GET", "POST"},
- },
- {
- "/wiki/{title:[a-zA-Z0-9+-]+}/del",
- authHandler(
- wikiDelHandler),
- []string{"POST"},
- },
- {
- "/users",
+ "/user",
adminAuthHandler(
- usersHandler),
+ userHandler),
[]string{"GET"},
},
- {
- "/users/{user:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+$}",
- wikiHandler,
- []string{"GET"},
- },
- {
- "/users/{user:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}/md",
- wikiMDHandler(
- wikiHandler),
- []string{"GET"},
- },
- {
- "/users/{user:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}/edit",
- wikiEditHandler,
- []string{"GET", "POST"},
- },
- {
- "/users/{user:[a-zA-Z0-9]+}/{title:[a-zA-Z0-9+-]+}/del",
- wikiDelHandler,
- []string{"POST"},
- },
{
"/user/new",
adminAuthHandler(
@@ -124,4 +80,43 @@ var routes = []route{
logoutHandler,
[]string{"GET", "POST"},
},
+ {
+ "/view/{key}",
+ pageHandler,
+ []string{"GET"},
+ },
+ {
+ "/view/{key}/md",
+ pageMDHandler(
+ pageHandler),
+ []string{"GET"},
+ },
+ {
+ "/{section}/{title}",
+ pageHandler,
+ []string{"GET"},
+ },
+ {
+ "/{section}/{title}/md",
+ pageMDHandler(
+ pageHandler),
+ []string{"GET"},
+ },
+ {
+ "/{section}/{title}/share",
+ pageShareHandler,
+ []string{"GET"},
+ },
+ {
+ "/{section}/{title}/edit",
+ authHandler(
+ pageEditHandler),
+ []string{"GET", "POST"},
+ },
+ {
+ "/{section}/{title}/del",
+ authHandler(
+ pageDelHandler),
+ []string{"GET", "POST"},
+ },
}
diff --git a/pkg/server/server.go b/pkg/server/server.go
index 74f1450..ecc23d7 100644
--- a/pkg/server/server.go
+++ b/pkg/server/server.go
@@ -1,6 +1,7 @@
package server
import (
+ "bytes"
"context"
"github.com/gorilla/mux"
"html/template"
@@ -9,6 +10,7 @@ import (
"time"
"git.giftfish.de/ston1th/gowiki/pkg/db"
+ "git.giftfish.de/ston1th/gowiki/pkg/log"
"git.giftfish.de/ston1th/jwt"
)
@@ -17,9 +19,10 @@ const (
)
type HTTPServer struct {
- Version string
- listener net.Listener
- srv *http.Server
+ Version string
+ indexPath string
+ listener net.Listener
+ srv *http.Server
DB *db.DB
JWT *jwt.JWT
@@ -28,14 +31,11 @@ type HTTPServer struct {
res map[string][]byte
}
-func NewHTTPServer(l net.Listener, versin string, secCookie bool) (srv *HTTPServer) {
+func NewHTTPServer(l net.Listener, version, indexPath string, secCookie bool) (srv *HTTPServer) {
srv = &HTTPServer{
- Version: version,
- SecCookie: secCookie,
- listener: l,
- JWT: jwt.New(time.Hour*12, nil, nil),
+ Version: version,
+ listener: l,
}
- srv.cookieStore()
srv.loadTemplates()
srv.srv = &http.Server{
Handler: srv.buildRoutes(),
@@ -44,11 +44,13 @@ func NewHTTPServer(l net.Listener, versin string, secCookie bool) (srv *HTTPServ
}
func (s *HTTPServer) Start() (err error) {
- s.DB, err = db.New()
+ //TODO make secret configurable
+ buf := bytes.NewBufferString("be688838ca8686e5c90689bf2ab585cef1137c999b48c70b92f67a5c34dc15697b5d11c982ed6d71be1e1e7f7b4e0733884aa97c3f7a339a8ed03577cf74be09")
+ s.JWT, err = jwt.New(jwt.DefaultExpiry, jwt.NewMemBlacklist(), buf)
if err != nil {
return
}
- s.Index, err = NewIndex(blevePath)
+ s.DB, err = db.New(s.indexPath)
if err != nil {
return
}
@@ -59,8 +61,8 @@ func (s *HTTPServer) Start() (err error) {
}
func (s *HTTPServer) Stop() error {
- s.BS.Close()
- s.Index.Close()
+ s.DB.Close()
+ s.JWT.Stop()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
return s.srv.Shutdown(ctx)
diff --git a/pkg/server/templates.go b/pkg/server/templates.go
index 9e8e4eb..60bac8b 100644
--- a/pkg/server/templates.go
+++ b/pkg/server/templates.go
@@ -1,12 +1,13 @@
-// Copyright (C) 2017 Marius Schellenberger
+// Copyright (C) 2018 Marius Schellenberger
-// This file is auto-generated by build/templates.sh
+// This file is auto-generated by templates.sh
// using the contents of the templates directory
package server
import (
"errors"
+ "git.giftfish.de/ston1th/gowiki/pkg/log"
"html/template"
)
@@ -21,7 +22,7 @@ const (
@@ -118,16 +119,13 @@ const (
Index
- All Articles
+ All Pages
{{if .Login}}
- New Article
+ New Page
{{end}}
-
- Snippets
-