blasphem/pkg/auth/provider.go
2022-10-25 00:18:25 -04:00

96 lines
2 KiB
Go

package auth
import (
"encoding/base64"
"golang.org/x/crypto/bcrypt"
"dynatron.me/x/blasphem/pkg/storage"
)
const (
HAProviderKey = "auth_provider.homeassistant"
)
type User struct {
Password string `json:"password"`
Username string `json:"username"`
}
type HomeAssistantProvider struct {
AuthProviderBase `json:"-"`
Users []User `json:"users"`
}
func NewHAProvider(s storage.Store) (*HomeAssistantProvider, error) {
hap := &HomeAssistantProvider{
AuthProviderBase: AuthProviderBase{
Name: "Home Assistant Local",
Type: HomeAssistant,
},
}
err := s.Get(HAProviderKey, hap)
if err != nil {
return hap, err
}
return hap, nil
}
func (hap *HomeAssistantProvider) hashPass(p string) ([]byte, error) {
return bcrypt.GenerateFromPassword([]byte(p), bcrypt.DefaultCost)
}
func (hap *HomeAssistantProvider) ValidateCreds(rm map[string]interface{}) bool {
usernameE, hasU := rm["username"]
passwordE, hasP := rm["password"]
username, unStr := usernameE.(string)
password, paStr := passwordE.(string)
if !hasU || !hasP || !unStr || !paStr || username == "" || password == "" {
return false
}
var found *User
const dummyHash = "$2b$12$CiuFGszHx9eNHxPuQcwBWez4CwDTOcLTX5CbOpV6gef2nYuXkY7BO"
for _, v := range hap.Users { // iterate all to thwart timing attacks
if v.Username == username {
found = &v
}
}
if found == nil { // one more compare to thwart timing attacks
bcrypt.CompareHashAndPassword([]byte("foo"), []byte(dummyHash))
return false
}
var hash []byte
hash, err := base64.StdEncoding.DecodeString(found.Password)
if err != nil {
// XXX: probably log this
return false
}
err = bcrypt.CompareHashAndPassword(hash, []byte(password))
if err == nil {
return true
}
return false
}
func (hap *HomeAssistantProvider) FlowSchema() []FlowSchemaItem {
return []FlowSchemaItem{
{
Type: "string",
Name: "username",
Required: true,
},
{
Type: "string",
Name: "password",
Required: true,
},
}
}