initial commit
This commit is contained in:
commit
18995db757
871 changed files with 492725 additions and 0 deletions
36
pkg/db/blacklist.go
Normal file
36
pkg/db/blacklist.go
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package db
|
||||
|
||||
import "git.giftfish.de/ston1th/jwt/v3"
|
||||
|
||||
const blacklistPrefix = "blacklist/"
|
||||
|
||||
func (db *DB) Add(sig string, exp int64) error {
|
||||
return db.store.Set(blacklistPrefix+sig, exp)
|
||||
}
|
||||
|
||||
func (db *DB) Remove(sig string) error {
|
||||
return db.store.Delete(blacklistPrefix + sig)
|
||||
}
|
||||
|
||||
func (db *DB) Check(sig string) (ok bool) {
|
||||
if db.store.Get(blacklistPrefix+sig, nil) == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *DB) Map() (list jwt.BlacklistMap, err error) {
|
||||
list = make(jwt.BlacklistMap)
|
||||
err = db.store.ForEach(func(k string, v []byte) error {
|
||||
if trim, ok := hasTrimPrefix(k, blacklistPrefix); ok {
|
||||
var exp int64
|
||||
err := db.store.Unmarshal(v, &exp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
list[trim] = exp
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
63
pkg/db/db.go
Normal file
63
pkg/db/db.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (C) 2019 Marius Schellenberger
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"git.giftfish.de/ston1th/docstore/pkg/core"
|
||||
"git.giftfish.de/ston1th/docstore/pkg/index"
|
||||
"git.giftfish.de/ston1th/docstore/pkg/store"
|
||||
"git.giftfish.de/ston1th/godrop/v2"
|
||||
"io"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
storeFile = "store.db"
|
||||
bcryptCost = 13
|
||||
)
|
||||
|
||||
const blevePath = "bleve"
|
||||
|
||||
type DB struct {
|
||||
store store.Store
|
||||
Index *index.Index
|
||||
}
|
||||
|
||||
func New(cfg core.Config) (db *DB, err error) {
|
||||
db = new(DB)
|
||||
dbFile := filepath.Join(cfg.DataDir, storeFile)
|
||||
err = godrop.Unveil(dbFile, "rwc")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
db.store, err = store.NewBoltStore(dbFile, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
db.Index, err = index.NewIndex(filepath.Join(cfg.DataDir, blevePath))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = db.UnlockUser()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = db.RunMigrations()
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) Dump(w io.Writer) error {
|
||||
return db.store.Dump(w)
|
||||
}
|
||||
|
||||
func (db *DB) Restore(r io.Reader) error {
|
||||
return db.store.Restore(r)
|
||||
}
|
||||
|
||||
func (db *DB) Close() (err error) {
|
||||
err = db.store.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return db.Index.Close()
|
||||
}
|
||||
24
pkg/db/helper.go
Normal file
24
pkg/db/helper.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (C) 2019 Marius Schellenberger
|
||||
|
||||
package db
|
||||
|
||||
import "crypto/sha256"
|
||||
|
||||
// Parts taken from strings.TrimPrefix
|
||||
func hasTrimPrefix(s, prefix string) (string, bool) {
|
||||
if len(s) >= len(prefix) && s[0:len(prefix)] == prefix {
|
||||
return s[len(prefix):], true
|
||||
}
|
||||
return s, false
|
||||
}
|
||||
|
||||
func validatePassword(pw string) (b []byte) {
|
||||
b = []byte(pw)
|
||||
if len(pw) <= 56 {
|
||||
return
|
||||
}
|
||||
hash := sha256.New()
|
||||
hash.Write(b)
|
||||
b = hash.Sum(nil)
|
||||
return
|
||||
}
|
||||
48
pkg/db/migration.go
Normal file
48
pkg/db/migration.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"git.giftfish.de/ston1th/docstore/pkg/log"
|
||||
"git.giftfish.de/ston1th/docstore/pkg/store"
|
||||
)
|
||||
|
||||
const (
|
||||
versionKey = "version/version"
|
||||
currentVersion = 1
|
||||
)
|
||||
|
||||
type migrator func(*DB) (int, error)
|
||||
|
||||
var migrators = []migrator{
|
||||
func(db *DB) (int, error) {
|
||||
return 0, nil
|
||||
},
|
||||
}
|
||||
|
||||
func (db *DB) RunMigrations() (err error) {
|
||||
var version int
|
||||
err = db.store.Get(versionKey, &version)
|
||||
if err == store.ErrKeyNotFound {
|
||||
err = db.store.Set(versionKey, currentVersion)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = db.store.Get(versionKey, &version)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Printf("db: database version %d", version)
|
||||
for version < currentVersion {
|
||||
v := version + 1
|
||||
log.Printf("db: running migration %d", v)
|
||||
version, err = migrators[v](db)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = db.store.Set(versionKey, version)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
169
pkg/db/user.go
Normal file
169
pkg/db/user.go
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
// Copyright (C) 2019 Marius Schellenberger
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.giftfish.de/ston1th/docstore/pkg/core"
|
||||
"git.giftfish.de/ston1th/docstore/pkg/otp"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
userPrefix = "user/"
|
||||
userKey = "user"
|
||||
)
|
||||
|
||||
var (
|
||||
errWrongLogin = errors.New("db: wrong login")
|
||||
errLocked = errors.New("db: user locked")
|
||||
errUserExists = errors.New("db: user already exist")
|
||||
|
||||
userRe = regexp.MustCompile("[^a-zA-Z0-9]+")
|
||||
)
|
||||
|
||||
func (db *DB) UserExists() (b bool) {
|
||||
db.store.ForEach(func(k string, _ []byte) error {
|
||||
if strings.HasPrefix(k, userPrefix) {
|
||||
b = true
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) GetUserWithoutPassword() (u core.User, err error) {
|
||||
u, err = db.GetUser()
|
||||
u.Password = ""
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) GetUserSecret() (secret string, err error) {
|
||||
var user core.User
|
||||
user, err = db.GetUser()
|
||||
secret = user.Secret
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) GetUser() (u core.User, err error) {
|
||||
err = db.store.Get(userPrefix+userKey, &u)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) CreateUser(username, password string) error {
|
||||
username = userRe.ReplaceAllString(username, "")
|
||||
if db.UserExists() {
|
||||
return errUserExists
|
||||
}
|
||||
hash, err := bcrypt.GenerateFromPassword(validatePassword(password), bcryptCost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.store.Set(userPrefix+userKey, &core.User{
|
||||
Username: username,
|
||||
Password: string(hash),
|
||||
})
|
||||
}
|
||||
|
||||
func (db *DB) Login(username, password string) (u core.User, err error) {
|
||||
u, err = db.GetUser()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if u.Username != username {
|
||||
err = errWrongLogin
|
||||
return
|
||||
}
|
||||
if u.Locked == 3 {
|
||||
err = errLocked
|
||||
return
|
||||
}
|
||||
if err = bcrypt.CompareHashAndPassword([]byte(u.Password), validatePassword(password)); err != nil {
|
||||
u.Locked++
|
||||
err = db.store.Set(userPrefix+username, u)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = errWrongLogin
|
||||
return
|
||||
}
|
||||
if u.Locked > 0 {
|
||||
u.Locked = 0
|
||||
err = db.store.Set(userPrefix+userKey, u)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) Totp(pin string) (u core.User, err error) {
|
||||
u, err = db.GetUser()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if u.Locked == 3 {
|
||||
err = errLocked
|
||||
return
|
||||
}
|
||||
if !otp.Validate(pin, u.Secret) {
|
||||
u.Locked++
|
||||
err = db.store.Set(userPrefix+userKey, u)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = errors.New("db: wrong pin")
|
||||
return
|
||||
}
|
||||
if u.Locked > 0 {
|
||||
u.Locked = 0
|
||||
err = db.store.Set(userPrefix+userKey, u)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) UnlockUser() (err error) {
|
||||
var u core.User
|
||||
u, err = db.GetUser()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if u.Locked > 0 {
|
||||
u.Locked = 0
|
||||
err = db.store.Set(userPrefix+userKey, u)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) UpdateUserSecret(secret string) error {
|
||||
u, err := db.GetUser()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.Secret = secret
|
||||
return db.store.Set(userPrefix+userKey, u)
|
||||
}
|
||||
|
||||
func (db *DB) UpdateUserPassword(password string) error {
|
||||
if password == "" {
|
||||
return errors.New("empty password")
|
||||
}
|
||||
u, err := db.GetUser()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash, err := bcrypt.GenerateFromPassword(validatePassword(password), bcryptCost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.Password = string(hash)
|
||||
return db.store.Set(userPrefix+userKey, u)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue