Rename group package and defaults to halls
This commit is contained in:
+150
@@ -0,0 +1,150 @@
|
||||
package hall
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"hash"
|
||||
"net"
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
|
||||
"git.stormux.org/storm/skald/conn"
|
||||
)
|
||||
|
||||
type RawPassword struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Hash string `json:"hash,omitempty"`
|
||||
Key *string `json:"key,omitempty"`
|
||||
Salt string `json:"salt,omitempty"`
|
||||
Iterations int `json:"iterations,omitempty"`
|
||||
}
|
||||
|
||||
type Password RawPassword
|
||||
|
||||
// limit the number of concurrent hashing operations. This avoids running
|
||||
// out of memory when doing too many BCrypt hashes at the same time.
|
||||
var hashSemaphore = make(chan struct{}, runtime.GOMAXPROCS(-1))
|
||||
|
||||
// ConstantTimeCompare compares a and b in time proportional to the length of a.
|
||||
func ConstantTimeCompare(a, b string) bool {
|
||||
as := []byte(a)
|
||||
bs := make([]byte, len(as))
|
||||
copy(bs, b)
|
||||
equal := subtle.ConstantTimeCompare(as, bs) == 1
|
||||
return len(a) == len(b) && equal
|
||||
}
|
||||
|
||||
func (p Password) Match(pw string) (bool, error) {
|
||||
switch p.Type {
|
||||
case "":
|
||||
return false, nil
|
||||
case "plain":
|
||||
if p.Key == nil {
|
||||
return false, errors.New("missing key")
|
||||
}
|
||||
return ConstantTimeCompare(pw, *p.Key), nil
|
||||
case "wildcard":
|
||||
return true, nil
|
||||
case "pbkdf2":
|
||||
if p.Key == nil {
|
||||
return false, errors.New("missing key")
|
||||
}
|
||||
key, err := hex.DecodeString(*p.Key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
salt, err := hex.DecodeString(p.Salt)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
var h func() hash.Hash
|
||||
switch p.Hash {
|
||||
case "sha-256":
|
||||
h = sha256.New
|
||||
default:
|
||||
return false, errors.New("unknown hash type")
|
||||
}
|
||||
hashSemaphore <- struct{}{}
|
||||
defer func() {
|
||||
<-hashSemaphore
|
||||
}()
|
||||
theirKey := pbkdf2.Key(
|
||||
[]byte(pw), salt, p.Iterations, len(key), h,
|
||||
)
|
||||
return bytes.Equal(key, theirKey), nil
|
||||
case "bcrypt":
|
||||
if p.Key == nil {
|
||||
return false, errors.New("missing key")
|
||||
}
|
||||
hashSemaphore <- struct{}{}
|
||||
defer func() {
|
||||
<-hashSemaphore
|
||||
}()
|
||||
err := bcrypt.CompareHashAndPassword([]byte(*p.Key), []byte(pw))
|
||||
if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
|
||||
return false, nil
|
||||
}
|
||||
return err == nil, err
|
||||
default:
|
||||
return false, errors.New("unknown password type")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Password) UnmarshalJSON(b []byte) error {
|
||||
var k string
|
||||
err := json.Unmarshal(b, &k)
|
||||
if err == nil {
|
||||
*p = Password{
|
||||
Type: "plain",
|
||||
Key: &k,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var r RawPassword
|
||||
err = json.Unmarshal(b, &r)
|
||||
if err == nil {
|
||||
*p = Password(r)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p Password) MarshalJSON() ([]byte, error) {
|
||||
if p.Type == "plain" && p.Hash == "" && p.Salt == "" && p.Iterations == 0 {
|
||||
return json.Marshal(p.Key)
|
||||
}
|
||||
return json.Marshal(RawPassword(p))
|
||||
}
|
||||
|
||||
type ClientPattern struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Password *Password `json:"password,omitempty"`
|
||||
}
|
||||
|
||||
type ClientCredentials struct {
|
||||
System bool
|
||||
Username *string
|
||||
Password string
|
||||
Token string
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
Hall() *Hall
|
||||
Addr() net.Addr
|
||||
Id() string
|
||||
Username() string
|
||||
SetUsername(string)
|
||||
Permissions() []string
|
||||
SetPermissions([]string)
|
||||
Data() map[string]interface{}
|
||||
PushConn(g *Hall, id string, conn conn.Up, tracks []conn.UpTrack, replace string) error
|
||||
RequestConns(target Client, g *Hall, id string) error
|
||||
Joined(hall, kind string) error
|
||||
PushClient(hall, kind, id, username string, perms []string, data map[string]interface{}) error
|
||||
Kick(id string, user *string, message string) error
|
||||
}
|
||||
Reference in New Issue
Block a user