segregated api machinery

This commit is contained in:
Christopher Ramey 2021-03-07 16:43:51 -09:00
parent 5571401103
commit 86f304e1b8
2 changed files with 22 additions and 21 deletions

View File

@ -1,4 +1,4 @@
package server package api
import ( import (
"crypto/hmac" "crypto/hmac"
@ -8,63 +8,63 @@ import (
"time" "time"
) )
type APICommand struct { type Command struct {
Expires time.Time `json:"exp"` Expires time.Time `json:"exp"`
Command string `json:"cmd"` Command string `json:"cmd"`
Scheme string `json:"sch"` Scheme string `json:"sch"`
Signature []byte `json:"sig,omitempty"` Signature []byte `json:"sig,omitempty"`
} }
func ParseAPICommand(jsn []byte) (*APICommand, error) { func ParseCommand(jsn []byte) (*Command, error) {
api := &APICommand{} cmd := &Command{}
err := json.Unmarshal(jsn, api) err := json.Unmarshal(jsn, cmd)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return api, nil return cmd, nil
} }
func (ac *APICommand) JSON() ([]byte, error) { func (c *Command) JSON() ([]byte, error) {
return json.Marshal(ac) return json.Marshal(c)
} }
func (ac *APICommand) Sign(key []byte) error { func (c *Command) Sign(key []byte) error {
switch ac.Scheme { switch c.Scheme {
case "hmac-sha256": case "hmac-sha256":
j, err := ac.JSON() j, err := c.JSON()
if err != nil { if err != nil {
return fmt.Errorf("json encoding error") return fmt.Errorf("json encoding error")
} }
mac := hmac.New(sha256.New, key) mac := hmac.New(sha256.New, key)
mac.Write(j) mac.Write(j)
ac.Signature = mac.Sum(nil) c.Signature = mac.Sum(nil)
case "": case "":
return fmt.Errorf("scheme may not be empty") return fmt.Errorf("scheme may not be empty")
default: default:
return fmt.Errorf("unsupported scheme: %s", ac.Scheme) return fmt.Errorf("unsupported scheme: %s", c.Scheme)
} }
return nil return nil
} }
func (ac *APICommand) Validate(key []byte) error { func (c *Command) Validate(key []byte) error {
cpy := &APICommand{ cpy := &Command{
Expires: ac.Expires, Expires: c.Expires,
Command: ac.Command, Command: c.Command,
Scheme: ac.Scheme, Scheme: c.Scheme,
} }
err := cpy.Sign(key) err := cpy.Sign(key)
if err != nil { if err != nil {
return err return err
} }
if !hmac.Equal(cpy.Signature, ac.Signature) { if !hmac.Equal(cpy.Signature, c.Signature) {
return fmt.Errorf("invalid signature") return fmt.Errorf("invalid signature")
} }
if time.Now().After(ac.Expires) { if time.Now().After(c.Expires) {
return fmt.Errorf("command expired") return fmt.Errorf("command expired")
} }

View File

@ -3,6 +3,7 @@ package server
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"git.binarythought.com/cdramey/alrm/api"
) )
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@ -14,7 +15,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Error(w, "no command given", http.StatusBadRequest) http.Error(w, "no command given", http.StatusBadRequest)
return return
} }
cmd, err := ParseAPICommand([]byte(c)) cmd, err := api.ParseCommand([]byte(c))
if err != nil { if err != nil {
http.Error(w, fmt.Sprintf("error parsing command: %s", err.Error()), http.Error(w, fmt.Sprintf("error parsing command: %s", err.Error()),
http.StatusBadRequest) http.StatusBadRequest)