alrm/api/command.go

73 lines
1.2 KiB
Go
Raw Normal View History

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