updated jwt and added share token invalidation

This commit is contained in:
ston1th 2018-12-28 19:14:21 +01:00
commit c28249e1ce
11 changed files with 48 additions and 34 deletions

2
go.mod
View file

@ -2,7 +2,7 @@ module git.giftfish.de/ston1th/gowiki
require ( require (
git.giftfish.de/ston1th/godrop/v2 v2.1.0 git.giftfish.de/ston1th/godrop/v2 v2.1.0
git.giftfish.de/ston1th/jwt/v3 v3.1.0 git.giftfish.de/ston1th/jwt/v3 v3.2.0
github.com/RoaringBitmap/roaring v0.4.16 // indirect github.com/RoaringBitmap/roaring v0.4.16 // indirect
github.com/Smerity/govarint v0.0.0-20150407073650-7265e41f48f1 // indirect github.com/Smerity/govarint v0.0.0-20150407073650-7265e41f48f1 // indirect
github.com/blevesearch/bleve v0.7.0 github.com/blevesearch/bleve v0.7.0

4
go.sum
View file

@ -1,7 +1,7 @@
git.giftfish.de/ston1th/godrop/v2 v2.1.0 h1:vR4aWVeMGJ+tHQH0p44esZrSl5dYJzuCmZqhKWP/vwI= git.giftfish.de/ston1th/godrop/v2 v2.1.0 h1:vR4aWVeMGJ+tHQH0p44esZrSl5dYJzuCmZqhKWP/vwI=
git.giftfish.de/ston1th/godrop/v2 v2.1.0/go.mod h1:z8KA3HP/vB04wddLXZfYVKURYDxBGau9hlHtV61x9mM= git.giftfish.de/ston1th/godrop/v2 v2.1.0/go.mod h1:z8KA3HP/vB04wddLXZfYVKURYDxBGau9hlHtV61x9mM=
git.giftfish.de/ston1th/jwt/v3 v3.1.0 h1:SaSpVyl98iqnsRIh9tA8/XJpU6nCYIGa4L85rLvQWC0= git.giftfish.de/ston1th/jwt/v3 v3.2.0 h1:V6Lh7OjXn4D3HPd/LoDf7w5N7cyiSXEPAQCIfSVZ05c=
git.giftfish.de/ston1th/jwt/v3 v3.1.0/go.mod h1:jDALrW7OKeIaqYuMxs3GWyPRnQZmk/R+Lu9p/Em3Ziw= git.giftfish.de/ston1th/jwt/v3 v3.2.0/go.mod h1:jDALrW7OKeIaqYuMxs3GWyPRnQZmk/R+Lu9p/Em3Ziw=
github.com/RoaringBitmap/roaring v0.4.16 h1:NholfewybRLOwACgfqfzn/N5xa6keKNs4fP00t0cwLo= github.com/RoaringBitmap/roaring v0.4.16 h1:NholfewybRLOwACgfqfzn/N5xa6keKNs4fP00t0cwLo=
github.com/RoaringBitmap/roaring v0.4.16/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= github.com/RoaringBitmap/roaring v0.4.16/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
github.com/Smerity/govarint v0.0.0-20150407073650-7265e41f48f1 h1:G/NOANWMQev0CftoyxQwtRakdyNNNMB3qxkt/tj1HGs= github.com/Smerity/govarint v0.0.0-20150407073650-7265e41f48f1 h1:G/NOANWMQev0CftoyxQwtRakdyNNNMB3qxkt/tj1HGs=

View file

@ -16,7 +16,8 @@ import (
const ( const (
userClaim = "user" userClaim = "user"
adminClaim = "admin" adminClaim = "admin"
createdClaim = "created" userCreatedClaim = "user_created"
pageCreatedClaim = "page_created"
sharedClaim = "shared" sharedClaim = "shared"
sectionClaim = "section" sectionClaim = "section"
titleClaim = "title" titleClaim = "title"
@ -60,7 +61,7 @@ func newContext(w http.ResponseWriter, r *http.Request, s *HTTPServer) (ctx *Con
return nil return nil
} }
if !s.DB.LockedOut(t.Claims.GetString(userClaim), t.Claims.GetString(createdClaim)) { if !s.DB.LockedOut(t.Claims.GetString(userClaim), t.Claims.GetString(userCreatedClaim)) {
ctx.Token = *t ctx.Token = *t
return return
} }
@ -239,7 +240,7 @@ func (c *Context) Login(u core.User, remember string) {
if remember != "" { if remember != "" {
d = day * 7 d = day * 7
} }
c.SetCookie(jwt.Claims{userClaim: u.Username, createdClaim: u.Created, adminClaim: u.Admin}, d) c.SetCookie(jwt.Claims{userClaim: u.Username, userCreatedClaim: u.Created, adminClaim: u.Admin}, d)
} }
func (c *Context) SetCookie(claims jwt.Claims, d time.Duration) { func (c *Context) SetCookie(claims jwt.Claims, d time.Duration) {

View file

@ -251,13 +251,15 @@ func pageNewHandler(ctx *Context) {
} }
func pageHandler(ctx *Context) { func pageHandler(ctx *Context) {
var pageCreated string
ctx.Data = webData{ ctx.Data = webData{
Admin: ctx.Admin(), Admin: ctx.Admin(),
} }
section := ctx.Var("section") section := ctx.Var("section")
title := ctx.Var("title") title := ctx.Var("title")
user := ctx.User() user := ctx.User()
if key := ctx.Var("key"); key != "" { key := ctx.Var("key")
if key != "" {
t, err := jwt.DecodeToken(key) t, err := jwt.DecodeToken(key)
if err != nil { if err != nil {
log.Println("share: DecodeToken:", err) log.Println("share: DecodeToken:", err)
@ -270,7 +272,7 @@ func pageHandler(ctx *Context) {
return return
} }
user = t.Claims.GetString(sharedClaim) user = t.Claims.GetString(sharedClaim)
if ctx.Srv.DB.LockedOut(user, t.Claims.GetString(createdClaim)) { if ctx.Srv.DB.LockedOut(user, t.Claims.GetString(userCreatedClaim)) {
if err = ctx.Srv.JWT.Invalidate(t); err != nil { if err = ctx.Srv.JWT.Invalidate(t); err != nil {
log.Println("share: Invalidate:", err) log.Println("share: Invalidate:", err)
} }
@ -279,6 +281,7 @@ func pageHandler(ctx *Context) {
} }
section = t.Claims.GetString(sectionClaim) section = t.Claims.GetString(sectionClaim)
title = t.Claims.GetString(titleClaim) title = t.Claims.GetString(titleClaim)
pageCreated = t.Claims.GetString(pageCreatedClaim)
ctx.Data.Key = key ctx.Data.Key = key
if ctx.T == nil { if ctx.T == nil {
ctx.Template("pageViewHandler") ctx.Template("pageViewHandler")
@ -294,6 +297,10 @@ func pageHandler(ctx *Context) {
ctx.NotFound() ctx.NotFound()
return return
} }
if key != "" && page.Created != pageCreated {
ctx.NotFound()
return
}
ctx.Data.Data = page ctx.Data.Data = page
ctx.Data.Title = page.Title ctx.Data.Title = page.Title
ctx.Data.BodyTitle = page.Title ctx.Data.BodyTitle = page.Title
@ -340,7 +347,8 @@ func pageShareHandler(ctx *Context) {
} }
t := jwt.NewToken(map[string]interface{}{ t := jwt.NewToken(map[string]interface{}{
sharedClaim: user, sharedClaim: user,
createdClaim: ctx.Token.Claims.GetString(createdClaim), userCreatedClaim: ctx.Token.Claims.GetString(userCreatedClaim),
pageCreatedClaim: page.Created,
sectionClaim: section, sectionClaim: section,
titleClaim: title, titleClaim: title,
jwt.ExpClaim: jwt.NewExp(d), jwt.ExpClaim: jwt.NewExp(d),

View file

@ -396,7 +396,7 @@ const (
<input type="hidden" name="token" value="{{.Token}}"> <input type="hidden" name="token" value="{{.Token}}">
<div class="form-group"> <div class="form-group">
<label class="col-form-label" for="duration">Lifetime</label> <label class="col-form-label" for="duration">Lifetime</label>
<input class="form-control input-sm" type="text" id="duration" name="duration" placeholder="min: 30s max: 90d" autocomplete="off" autofocus required> <input class="form-control input-sm" type="text" id="duration" name="duration" autocomplete="off" autofocus required>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="custom-control custom-radio"> <div class="custom-control custom-radio">
@ -405,7 +405,7 @@ const (
</div> </div>
<div class="custom-control custom-radio"> <div class="custom-control custom-radio">
<input type="radio" id="mode2" name="mode" value="2" class="custom-control-input"> <input type="radio" id="mode2" name="mode" value="2" class="custom-control-input">
<label class="custom-control-label" for="mode2">Day</label> <label class="custom-control-label" for="mode2">Day(s) (Numbers only)</label>
</div> </div>
</div> </div>
<button class="btn btn-sm btn-primary" type="submit">Share</button> <button class="btn btn-sm btn-primary" type="submit">Share</button>

View file

@ -22,11 +22,11 @@ func genKey(length int) (bytes []byte) {
func newXsrf(secret []byte) string { func newXsrf(secret []byte) string {
rnd := genKey(keySize) rnd := genKey(keySize)
return base64.StdEncoding.EncodeToString(append(rnd, xor(rnd, secret)...)) return base64.RawStdEncoding.EncodeToString(append(rnd, xor(rnd, secret)...))
} }
func checkXsrf(xsrf string, secret []byte) bool { func checkXsrf(xsrf string, secret []byte) bool {
t, err := base64.StdEncoding.DecodeString(xsrf) t, err := base64.RawStdEncoding.DecodeString(xsrf)
if err != nil { if err != nil {
return false return false
} }

View file

@ -19,7 +19,7 @@
<input type="hidden" name="token" value="{{.Token}}"> <input type="hidden" name="token" value="{{.Token}}">
<div class="form-group"> <div class="form-group">
<label class="col-form-label" for="duration">Lifetime</label> <label class="col-form-label" for="duration">Lifetime</label>
<input class="form-control input-sm" type="text" id="duration" name="duration" placeholder="min: 30s max: 90d" autocomplete="off" autofocus required> <input class="form-control input-sm" type="text" id="duration" name="duration" autocomplete="off" autofocus required>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="custom-control custom-radio"> <div class="custom-control custom-radio">
@ -28,7 +28,7 @@
</div> </div>
<div class="custom-control custom-radio"> <div class="custom-control custom-radio">
<input type="radio" id="mode2" name="mode" value="2" class="custom-control-input"> <input type="radio" id="mode2" name="mode" value="2" class="custom-control-input">
<label class="custom-control-label" for="mode2">Day</label> <label class="custom-control-label" for="mode2">Day(s) (Numbers only)</label>
</div> </div>
</div> </div>
<button class="btn btn-sm btn-primary" type="submit">Share</button> <button class="btn btn-sm btn-primary" type="submit">Share</button>

View file

@ -0,0 +1,7 @@
// Copyright (C) 2018 Marius Schellenberger
package jwt
import "encoding/base64"
var enc = base64.RawURLEncoding

View file

@ -6,7 +6,6 @@ package jwt
import ( import (
"crypto/hmac" "crypto/hmac"
"crypto/rand" "crypto/rand"
"encoding/base64"
"encoding/json" "encoding/json"
"errors" "errors"
"io" "io"
@ -210,9 +209,9 @@ func (jwt *JWT) Sign(t *Token) (err error) {
if err != nil { if err != nil {
return return
} }
t.data = base64.URLEncoding.EncodeToString(head) + TokenSeparator + base64.URLEncoding.EncodeToString(claims) t.data = enc.EncodeToString(head) + TokenSeparator + enc.EncodeToString(claims)
t.rawSignature = jwt.sum(t.data, h) t.rawSignature = jwt.sum(t.data, h)
t.signature = base64.URLEncoding.EncodeToString(t.rawSignature) t.signature = enc.EncodeToString(t.rawSignature)
t.raw = t.data + TokenSeparator + t.signature t.raw = t.data + TokenSeparator + t.signature
return return
} }

View file

@ -3,7 +3,6 @@
package jwt package jwt
import ( import (
"encoding/base64"
"encoding/json" "encoding/json"
"strings" "strings"
) )
@ -75,7 +74,7 @@ func DecodeToken(token string) (t *Token, err error) {
} }
} }
t = new(Token) t = new(Token)
header, err := base64.URLEncoding.DecodeString(parts[0]) header, err := enc.DecodeString(parts[0])
if err != nil { if err != nil {
return return
} }
@ -83,7 +82,7 @@ func DecodeToken(token string) (t *Token, err error) {
if err != nil { if err != nil {
return return
} }
claims, err := base64.URLEncoding.DecodeString(parts[1]) claims, err := enc.DecodeString(parts[1])
if err != nil { if err != nil {
return return
} }
@ -91,7 +90,7 @@ func DecodeToken(token string) (t *Token, err error) {
if err != nil { if err != nil {
return return
} }
t.rawSignature, err = base64.URLEncoding.DecodeString(parts[2]) t.rawSignature, err = enc.DecodeString(parts[2])
t.signature = parts[2] t.signature = parts[2]
t.data = parts[0] + TokenSeparator + parts[1] t.data = parts[0] + TokenSeparator + parts[1]
t.raw = token t.raw = token

2
vendor/modules.txt vendored
View file

@ -1,6 +1,6 @@
# git.giftfish.de/ston1th/godrop/v2 v2.1.0 # git.giftfish.de/ston1th/godrop/v2 v2.1.0
git.giftfish.de/ston1th/godrop/v2 git.giftfish.de/ston1th/godrop/v2
# git.giftfish.de/ston1th/jwt/v3 v3.1.0 # git.giftfish.de/ston1th/jwt/v3 v3.2.0
git.giftfish.de/ston1th/jwt/v3 git.giftfish.de/ston1th/jwt/v3
# github.com/RoaringBitmap/roaring v0.4.16 # github.com/RoaringBitmap/roaring v0.4.16
github.com/RoaringBitmap/roaring github.com/RoaringBitmap/roaring