Files
DdnsClient/database.go
2021-07-21 15:38:38 +02:00

159 lines
3.0 KiB
Go

package main
import (
"crypto/sha256"
"errors"
"github.com/miekg/dns"
"github.com/patrickmn/go-cache"
password "github.com/sethvargo/go-password/password"
log "github.com/sirupsen/logrus"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util"
bcrypt "golang.org/x/crypto/bcrypt"
"os"
"path"
"strings"
"time"
)
type Database struct {
_db *leveldb.DB
_cache *cache.Cache
_zone string
}
func (d *Database) ExistHost(host string) bool {
ret, err := d._db.Has([]byte("hosts/" + host), nil)
if err != nil {
log.Fatal(err)
}
return ret
}
func (d *Database) DeleteHost(host string) bool {
err := d._db.Delete([]byte("hosts/" + host), nil)
return err == nil
}
func (d *Database) GetExistingHosts(match string) map[string]string {
iter := d._db.NewIterator(util.BytesPrefix([]byte("hosts/" + match)), nil)
ret := make(map[string]string)
for iter.Next() {
hostname := strings.TrimPrefix(string(iter.Key()), "hosts/")
ret[hostname] = string(iter.Value())
}
return ret
}
func (d *Database) Authorize(host string, token_user string) bool {
token, err := d._db.Get([]byte("hosts/" + host), nil)
if err != nil {
return false
}
if len(token) < sha256.Size {
return false
}
if len(token_user) < sha256.Size {
return false
}
if string(token) == token_user {
return true
}
log.Error(string(token), "!=", token_user)
return false
}
func generateToken() (string, []byte, error) {
pw, err := password.Generate(64, 10, 10, false, false)
if err != nil {
return "", nil, err
}
hash, errHash := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost)
if errHash != nil {
return "", nil , errHash
}
return pw, hash, nil
}
func (d *Database) IsBannedHost(host string) bool {
val, ok := d._cache.Get(host)
var counter int
if ok {
counter = val.(int)
if counter > 3 {
return true
} else {
return false
}
} else {
return false
}
}
func (d *Database) IncrementBanHost(host string) {
_, ok := d._cache.Get(host)
if ok {
d._cache.IncrementInt(host,1)
} else {
d._cache.Add(host, 1, cache.DefaultExpiration)
}
}
func (d *Database) CreateHost(host string) (string, []byte, error) {
if d.ExistHost(host) {
return "", nil, errors.New("host already existent")
}
if host == "" {
return "", nil, errors.New("given hostname is empty")
}
if _, ok := dns.IsDomainName(host + "." + d._zone); !ok {
return "", nil, errors.New("given hostname is invalid")
}
pw, hash, errToken := generateToken()
if errToken != nil {
return "", nil, errToken
}
d._db.Put([]byte("hosts/" + host), hash, nil)
return pw, hash, nil
}
func CreateDatabase(config *Config) (*Database, error){
_, err := os.Stat(config.DataDir)
if err != nil {
if os.IsNotExist(err) {
os.MkdirAll(config.DataDir, os.ModeDir)
}
}
file := path.Join(config.DataDir, "ddnsService.db")
store, err := leveldb.OpenFile(file, nil)
db := cache.New(5*time.Minute, 10*time.Minute)
if err != nil {
return nil, err
}
return &Database{_db: store, _cache: db}, nil
}