2022-09-25 22:16:21 -04:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2022-09-30 10:08:42 -04:00
|
|
|
"crypto/rand"
|
|
|
|
"encoding/hex"
|
2022-09-25 22:16:21 -04:00
|
|
|
"encoding/json"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
)
|
|
|
|
|
|
|
|
type AuthProvider interface {
|
|
|
|
ProviderName() string
|
|
|
|
ProviderID() *string
|
|
|
|
ProviderType() string
|
|
|
|
}
|
|
|
|
|
|
|
|
type AuthProviderBase struct {
|
2022-09-26 15:00:21 -04:00
|
|
|
Name string `json:"name"`
|
|
|
|
ID *string `json:"id"`
|
|
|
|
Type string `json:"type"`
|
2022-09-25 22:16:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (bp *AuthProviderBase) ProviderName() string { return bp.Name }
|
2022-09-26 15:00:21 -04:00
|
|
|
func (bp *AuthProviderBase) ProviderID() *string { return bp.ID }
|
2022-09-25 22:16:21 -04:00
|
|
|
func (bp *AuthProviderBase) ProviderType() string { return bp.Type }
|
|
|
|
|
|
|
|
type LocalProvider struct {
|
|
|
|
AuthProviderBase
|
|
|
|
}
|
|
|
|
|
2022-09-30 10:08:42 -04:00
|
|
|
var HomeAssistant = "homeassistant"
|
|
|
|
|
2022-09-25 22:16:21 -04:00
|
|
|
func hassProvider() *LocalProvider {
|
|
|
|
return &LocalProvider{
|
|
|
|
AuthProviderBase: AuthProviderBase{
|
|
|
|
Name: "Home Assistant Local",
|
2022-09-30 10:08:42 -04:00
|
|
|
Type: HomeAssistant,
|
2022-09-25 22:16:21 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: make this configurable
|
|
|
|
func (s *Server) providersHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
providers := []AuthProvider{
|
|
|
|
hassProvider(),
|
|
|
|
}
|
|
|
|
|
|
|
|
rjs, err := json.Marshal(providers)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
logRequest(http.StatusOK, r)
|
|
|
|
|
2022-09-30 10:08:42 -04:00
|
|
|
w.Header()["Content-Type"] = []string{"application/json"}
|
2022-09-25 22:16:21 -04:00
|
|
|
_, err = w.Write(rjs)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) authorizeHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
authPage, err := s.rootFS.Open("authorize.html")
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
defer authPage.Close()
|
|
|
|
|
|
|
|
logRequest(http.StatusOK, r)
|
|
|
|
|
|
|
|
_, err = io.Copy(w, authPage)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
2022-09-26 15:00:21 -04:00
|
|
|
|
|
|
|
type flowRequest struct {
|
|
|
|
ClientID string `json:"client_id"`
|
|
|
|
Handler []*string `json:"handler"`
|
|
|
|
RedirectURI string `json:"redirect_uri"`
|
|
|
|
}
|
|
|
|
|
2022-09-30 10:08:42 -04:00
|
|
|
type FlowSchemaItem struct {
|
|
|
|
Type string `json:"type"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Required bool `json:"required"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type FlowType string
|
|
|
|
|
|
|
|
const (
|
|
|
|
TypeForm FlowType = "form"
|
|
|
|
)
|
|
|
|
|
|
|
|
type FlowID string
|
|
|
|
type Step string
|
|
|
|
|
|
|
|
const (
|
|
|
|
StepInit Step = "init"
|
|
|
|
)
|
|
|
|
|
|
|
|
type flowResponse struct {
|
|
|
|
Type FlowType `json:"type"`
|
|
|
|
ID FlowID `json:"flow_id"`
|
|
|
|
Handler []*string `json:"handler"`
|
|
|
|
StepID Step `json:"step_id"`
|
|
|
|
Schema []FlowSchemaItem `json:"data_schema"`
|
|
|
|
Errors []string `json:"errors"`
|
|
|
|
DescPlace *string `json:"description_placeholders"`
|
|
|
|
LastStep *string `json:"last_step"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func GenFlowID() FlowID {
|
|
|
|
b := make([]byte, 16)
|
|
|
|
if _, err := rand.Read(b); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return FlowID(hex.EncodeToString(b))
|
|
|
|
}
|
|
|
|
|
2022-09-26 15:00:21 -04:00
|
|
|
func (s *Server) loginFlowHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
var flowReq flowRequest
|
|
|
|
err := json.NewDecoder(r.Body).Decode(&flowReq)
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-09-30 10:08:42 -04:00
|
|
|
resp := flowResponse{
|
|
|
|
Type: TypeForm,
|
|
|
|
ID: GenFlowID(),
|
|
|
|
StepID: StepInit,
|
|
|
|
Schema: []FlowSchemaItem{
|
|
|
|
{
|
|
|
|
Type: "string",
|
|
|
|
Name: "username",
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: "string",
|
|
|
|
Name: "password",
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Handler: []*string{
|
|
|
|
&HomeAssistant,
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
Errors: []string{},
|
|
|
|
}
|
|
|
|
|
|
|
|
w.Header()["Content-Type"] = []string{"application/json"}
|
|
|
|
|
|
|
|
respByte, err := json.Marshal(&resp)
|
|
|
|
_, err = w.Write(respByte)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2022-09-26 15:00:21 -04:00
|
|
|
}
|