mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-12-12 05:20:26 +00:00
Save active sessions between launches
This commit is contained in:
parent
f4ba0f5498
commit
4686b79226
5
go.mod
5
go.mod
@ -2,4 +2,7 @@ module github.com/bouncepaw/mycorrhiza
|
|||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require github.com/valyala/quicktemplate v1.6.3
|
require (
|
||||||
|
github.com/adrg/xdg v0.2.2
|
||||||
|
github.com/valyala/quicktemplate v1.6.3
|
||||||
|
)
|
||||||
|
8
go.sum
8
go.sum
@ -1,6 +1,12 @@
|
|||||||
|
github.com/adrg/xdg v0.2.2 h1:A7ZHKRz5KGOLJX/bg7IPzStryhvCzAE1wX+KWawPiAo=
|
||||||
|
github.com/adrg/xdg v0.2.2/go.mod h1:7I2hH/IT30IsupOpKZ5ue7/qNi3CoKzD6tL3HwpaRMQ=
|
||||||
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
|
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
|
||||||
@ -13,3 +19,5 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
69
user/fs.go
Normal file
69
user/fs.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg"
|
||||||
|
"github.com/bouncepaw/mycorrhiza/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PopulateFixedUserStorage() {
|
||||||
|
contents, err := ioutil.ReadFile(util.FixedCredentialsPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(contents, &UserStorage.Users)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, user := range UserStorage.Users {
|
||||||
|
user.Group = groupFromString(user.GroupString)
|
||||||
|
}
|
||||||
|
log.Println("Found", len(UserStorage.Users), "fixed users")
|
||||||
|
|
||||||
|
contents, err = ioutil.ReadFile(tokenStoragePath())
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
var tmp map[string]string
|
||||||
|
err = json.Unmarshal(contents, &tmp)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
for token, username := range tmp {
|
||||||
|
user := UserStorage.userByName(username)
|
||||||
|
UserStorage.Tokens[token] = user
|
||||||
|
}
|
||||||
|
log.Println("Found", len(tmp), "active sessions")
|
||||||
|
}
|
||||||
|
|
||||||
|
func dumpTokens() {
|
||||||
|
tmp := make(map[string]string)
|
||||||
|
for token, user := range UserStorage.Tokens {
|
||||||
|
tmp[token] = user.Name
|
||||||
|
}
|
||||||
|
blob, err := json.Marshal(tmp)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
} else {
|
||||||
|
ioutil.WriteFile(tokenStoragePath(), blob, 0644)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return path to tokens.json.
|
||||||
|
func tokenStoragePath() string {
|
||||||
|
dir, err := xdg.DataFile("mycorrhiza/tokens.json")
|
||||||
|
if err != nil {
|
||||||
|
// Yes, it is unix-only, but function above rarely fails, so this block is probably never reached.
|
||||||
|
path := "/home/" + os.Getenv("HOME") + "/.local/share/mycorrhiza/tokens.json"
|
||||||
|
os.MkdirAll(path, 0777)
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
return dir
|
||||||
|
}
|
61
user/group.go
Normal file
61
user/group.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func groupFromString(s string) UserGroup {
|
||||||
|
switch s {
|
||||||
|
case "admin":
|
||||||
|
return UserAdmin
|
||||||
|
case "moderator":
|
||||||
|
return UserModerator
|
||||||
|
case "trusted":
|
||||||
|
return UserTrusted
|
||||||
|
case "editor":
|
||||||
|
return UserEditor
|
||||||
|
default:
|
||||||
|
log.Fatal("Unknown user group", s)
|
||||||
|
return UserAnon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserGroup represents a group that a user is part of.
|
||||||
|
type UserGroup int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UserAnon is the default user group which all unauthorized visitors have.
|
||||||
|
UserAnon UserGroup = iota
|
||||||
|
// UserEditor is a user who can edit and upload stuff.
|
||||||
|
UserEditor
|
||||||
|
// UserTrusted is a trusted editor who can also rename stuff.
|
||||||
|
UserTrusted
|
||||||
|
// UserModerator is a moderator who can also delete stuff.
|
||||||
|
UserModerator
|
||||||
|
// UserAdmin can do everything.
|
||||||
|
UserAdmin
|
||||||
|
)
|
||||||
|
|
||||||
|
var minimalRights = map[string]UserGroup{
|
||||||
|
"edit": UserEditor,
|
||||||
|
"upload-binary": UserEditor,
|
||||||
|
"upload-text": UserEditor,
|
||||||
|
"rename-ask": UserTrusted,
|
||||||
|
"rename-confirm": UserTrusted,
|
||||||
|
"delete-ask": UserModerator,
|
||||||
|
"delete-confirm": UserModerator,
|
||||||
|
"reindex": UserAdmin,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ug UserGroup) CanAccessRoute(route string) bool {
|
||||||
|
if !AuthUsed {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if minimalRight, ok := minimalRights[route]; ok {
|
||||||
|
if ug >= minimalRight {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
84
user/user.go
84
user/user.go
@ -1,8 +1,6 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
@ -25,6 +23,15 @@ func (us *FixedUserStorage) userByToken(token string) *User {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (us *FixedUserStorage) userByName(username string) *User {
|
||||||
|
for _, user := range us.Users {
|
||||||
|
if user.Name == username {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func FromRequest(rq *http.Request) *User {
|
func FromRequest(rq *http.Request) *User {
|
||||||
cookie, err := rq.Cookie("mycorrhiza_token")
|
cookie, err := rq.Cookie("mycorrhiza_token")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -62,6 +69,7 @@ func AddSession(username string) (string, error) {
|
|||||||
for _, user := range UserStorage.Users {
|
for _, user := range UserStorage.Users {
|
||||||
if user.Name == username {
|
if user.Name == username {
|
||||||
UserStorage.Tokens[token] = user
|
UserStorage.Tokens[token] = user
|
||||||
|
go dumpTokens()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Println("New token for", username, "is", token)
|
log.Println("New token for", username, "is", token)
|
||||||
@ -71,6 +79,7 @@ func AddSession(username string) (string, error) {
|
|||||||
|
|
||||||
func terminateSession(token string) {
|
func terminateSession(token string) {
|
||||||
delete(UserStorage.Tokens, token)
|
delete(UserStorage.Tokens, token)
|
||||||
|
go dumpTokens()
|
||||||
}
|
}
|
||||||
|
|
||||||
func HasUsername(username string) bool {
|
func HasUsername(username string) bool {
|
||||||
@ -98,21 +107,6 @@ type FixedUserStorage struct {
|
|||||||
|
|
||||||
var UserStorage = FixedUserStorage{Tokens: make(map[string]*User)}
|
var UserStorage = FixedUserStorage{Tokens: make(map[string]*User)}
|
||||||
|
|
||||||
func PopulateFixedUserStorage() {
|
|
||||||
contents, err := ioutil.ReadFile(util.FixedCredentialsPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(contents, &UserStorage.Users)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
for _, user := range UserStorage.Users {
|
|
||||||
user.Group = groupFromString(user.GroupString)
|
|
||||||
}
|
|
||||||
log.Println("Found", len(UserStorage.Users), "fixed users")
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthUsed shows if a method of authentication is used. You should set it by yourself.
|
// AuthUsed shows if a method of authentication is used. You should set it by yourself.
|
||||||
var AuthUsed bool
|
var AuthUsed bool
|
||||||
|
|
||||||
@ -126,62 +120,6 @@ type User struct {
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func groupFromString(s string) UserGroup {
|
|
||||||
switch s {
|
|
||||||
case "admin":
|
|
||||||
return UserAdmin
|
|
||||||
case "moderator":
|
|
||||||
return UserModerator
|
|
||||||
case "trusted":
|
|
||||||
return UserTrusted
|
|
||||||
case "editor":
|
|
||||||
return UserEditor
|
|
||||||
default:
|
|
||||||
log.Fatal("Unknown user group", s)
|
|
||||||
return UserAnon
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserGroup represents a group that a user is part of.
|
|
||||||
type UserGroup int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// UserAnon is the default user group which all unauthorized visitors have.
|
|
||||||
UserAnon UserGroup = iota
|
|
||||||
// UserEditor is a user who can edit and upload stuff.
|
|
||||||
UserEditor
|
|
||||||
// UserTrusted is a trusted editor who can also rename stuff.
|
|
||||||
UserTrusted
|
|
||||||
// UserModerator is a moderator who can also delete stuff.
|
|
||||||
UserModerator
|
|
||||||
// UserAdmin can do everything.
|
|
||||||
UserAdmin
|
|
||||||
)
|
|
||||||
|
|
||||||
var minimalRights = map[string]UserGroup{
|
|
||||||
"edit": UserEditor,
|
|
||||||
"upload-binary": UserEditor,
|
|
||||||
"upload-text": UserEditor,
|
|
||||||
"rename-ask": UserTrusted,
|
|
||||||
"rename-confirm": UserTrusted,
|
|
||||||
"delete-ask": UserModerator,
|
|
||||||
"delete-confirm": UserModerator,
|
|
||||||
"reindex": UserAdmin,
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ug UserGroup) CanAccessRoute(route string) bool {
|
|
||||||
if !AuthUsed {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if minimalRight, ok := minimalRights[route]; ok {
|
|
||||||
if ug >= minimalRight {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// A handy cookie constructor
|
// A handy cookie constructor
|
||||||
func cookie(name_suffix, val string, t time.Time) *http.Cookie {
|
func cookie(name_suffix, val string, t time.Time) *http.Cookie {
|
||||||
return &http.Cookie{
|
return &http.Cookie{
|
||||||
|
Loading…
Reference in New Issue
Block a user