major changes

This commit is contained in:
ston1th 2018-02-07 21:41:54 +01:00
commit 2b56832843
83 changed files with 7760 additions and 1244 deletions

View file

@ -3,63 +3,16 @@
package main
import (
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"errors"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
"html/template"
"io"
"net/http"
"time"
)
const (
keyLen = 32
authLen = keyLen * 2
cookieName = "gosession"
)
var store *sessions.CookieStore
func cookieStore() {
options := &sessions.Options{
Path: "/",
MaxAge: 3600 * 12,
Secure: secureCookie,
HttpOnly: true,
}
authKey := genKey(authLen)
encKey := genKey(keyLen)
store = sessions.NewCookieStore(authKey, encKey)
store.Options = options
go func() {
for {
time.Sleep(time.Hour * 12)
newAuthKey := genKey(authLen)
newEncKey := genKey(keyLen)
newStore := sessions.NewCookieStore(newAuthKey, newEncKey, authKey, encKey)
newStore.Options = options
store = newStore
authKey = newAuthKey
encKey = newEncKey
}
}()
}
func genKey(length int) (bytes []byte) {
bytes = make([]byte, length)
if _, err := io.ReadFull(rand.Reader, bytes); err != nil {
log.Println("genKey:", err)
}
return
}
func newContext(w http.ResponseWriter, r *http.Request) *Context {
log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL.Path)
func newContext(w http.ResponseWriter, r *http.Request, s *HTTPServer) *Context {
h := w.Header()
h.Set("X-Frame-Options", "DENY")
h.Set("X-Content-Type-Options", "nosniff")
@ -68,18 +21,27 @@ func newContext(w http.ResponseWriter, r *http.Request) *Context {
return &Context{
Request: r,
Response: w,
Srv: s,
Time: time.Now(),
}
}
type Context struct {
Request *http.Request
Response http.ResponseWriter
Srv *HTTPServer
T *template.Template
Status int
Err error
Time time.Time
Data webData
}
type webData struct {
Version string
Time int64
Title string
BodyTitle string
@ -91,25 +53,53 @@ type webData struct {
Msg string
Search string
Editor *Editor
Data interface{}
}
func (c *Context) Exec() {
defer c.log()
if c.T == nil {
log.Println("Exec:", errors.New("template is nil"))
c.Status = http.StatusInternalServerError
c.Err = errors.New("template is nil")
return
}
c.newToken()
c.Data.Version = c.Srv.Version
if c.Data.BodyTitle == "" {
c.Data.BodyTitle = c.Data.Title
}
c.Data.Admin = c.GetAdmin()
c.Data.User = c.GetUser()
c.Data.Login = c.LoggedOn()
err := c.T.Execute(c.Response, c.Data)
if err != nil {
log.Println("Exec:", err)
c.Data.Time = time.Since(c.Time).Nanoseconds() / 1e6
c.Err = c.T.Execute(c.Response, c.Data)
if c.Err != nil {
c.Status = http.StatusInternalServerError
}
if c.Status == 0 {
c.Status = http.StatusOK
}
}
func (c *Context) log() {
if c.Err != nil {
log.Printf("%s %s %s %d error: %s\n", c.Request.RemoteAddr, c.Request.Method, c.Request.URL, c.Status, c.Err)
return
}
log.Printf("%s %s %s %d\n", c.Request.RemoteAddr, c.Request.Method, c.Request.URL, c.Status)
}
func (c *Context) NotFound() {
c.Template("notFoundHandler")
c.Data = webData{Title: "404"}
c.Status = http.StatusNotFound
c.Response.WriteHeader(http.StatusNotFound)
c.Exec()
}
func (c *Context) Template(name string) {
c.T = templ[name]
c.T = c.Srv.templ[name]
}
func (c *Context) Write(buf []byte) (err error) {
@ -122,6 +112,7 @@ func (c *Context) SetHeader(name, value string) {
}
func (c *Context) Redirect(uri string, code int) {
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)
}
@ -149,12 +140,12 @@ func (c *Context) Var(name string) (ret string) {
return
}
func (c *Context) InitToken() {
func (c *Context) initToken() {
token := c.getToken()
if token == nil || len(token) != keyLen {
s, _ := store.Get(c.Request, cookieName)
s, _ := c.Srv.Store.Get(c.Request, cookieName)
s.Values["token"] = genKey(keyLen)
s.Options = store.Options
s.Options = c.Srv.Store.Options
err := s.Save(c.Request, c.Response)
if err != nil {
log.Println("InitToken: ", err)
@ -162,14 +153,14 @@ func (c *Context) InitToken() {
}
}
// NewToken sets and returns the xsrf token
func (c *Context) NewToken() {
func (c *Context) newToken() {
c.initToken()
rnd := genKey(keyLen)
c.Data.Token = base64.StdEncoding.EncodeToString(append(rnd, xor(rnd, c.getToken())...))
}
// CheckToken validates the xsrf token
func (c *Context) CheckToken() bool {
func (c *Context) CheckToken(f func()) bool {
token, err := base64.StdEncoding.DecodeString(c.Form("token"))
if err != nil {
log.Println("CheckToken: ", err)
@ -178,36 +169,45 @@ func (c *Context) CheckToken() bool {
if len(token) != authLen {
return false
}
return subtle.ConstantTimeCompare(c.getToken(), xor(token[keyLen:], token[:keyLen])) == 1
ok := subtle.ConstantTimeCompare(c.getToken(), xor(token[keyLen:], token[:keyLen])) == 1
if !ok {
if f != nil {
f()
return ok
}
c.Data.Msg = "wrong csrf token"
c.Exec()
}
return ok
}
func (c *Context) LoggedOn() (ok bool) {
s, _ := store.Get(c.Request, cookieName)
s, _ := c.Srv.Store.Get(c.Request, cookieName)
_, ok = s.Values["user"]
return
}
func (c *Context) SetUdata(user string, admin bool) {
s, _ := store.Get(c.Request, cookieName)
s, _ := c.Srv.Store.Get(c.Request, cookieName)
s.Values["user"] = user
s.Values["admin"] = admin
s.Options = store.Options
s.Options = c.Srv.Store.Options
if err := s.Save(c.Request, c.Response); err != nil {
log.Println(err)
}
}
func (c *Context) UnsetUdata() {
s, _ := store.Get(c.Request, cookieName)
s, _ := c.Srv.Store.Get(c.Request, cookieName)
s.Values = make(map[interface{}]interface{})
s.Options = store.Options
s.Options = c.Srv.Store.Options
if err := s.Save(c.Request, c.Response); err != nil {
log.Println(err)
}
}
func (c *Context) GetUser() string {
s, _ := store.Get(c.Request, cookieName)
s, _ := c.Srv.Store.Get(c.Request, cookieName)
if ret, ok := s.Values["user"].(string); ok {
return ret
}
@ -215,7 +215,7 @@ func (c *Context) GetUser() string {
}
func (c *Context) GetAdmin() bool {
s, _ := store.Get(c.Request, cookieName)
s, _ := c.Srv.Store.Get(c.Request, cookieName)
if ret, ok := s.Values["admin"].(bool); ok {
return ret
}
@ -223,7 +223,7 @@ func (c *Context) GetAdmin() bool {
}
func (c *Context) getToken() []byte {
s, _ := store.Get(c.Request, cookieName)
s, _ := c.Srv.Store.Get(c.Request, cookieName)
t, ok := s.Values["token"]
if !ok {
return nil