2021-03-07 16:43:51 -09:00
|
|
|
package api
|
2021-03-01 07:26:27 -09:00
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/hmac"
|
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2021-03-07 16:43:51 -09:00
|
|
|
type Command struct {
|
2021-03-01 07:26:27 -09:00
|
|
|
Expires time.Time `json:"exp"`
|
|
|
|
Command string `json:"cmd"`
|
|
|
|
Scheme string `json:"sch"`
|
|
|
|
Signature []byte `json:"sig,omitempty"`
|
|
|
|
}
|
|
|
|
|
2021-03-07 18:40:45 -09:00
|
|
|
func NewCommand(cm string) *Command {
|
|
|
|
return &Command{
|
|
|
|
Expires: time.Now().Add(time.Second * 5),
|
|
|
|
Command: cm,
|
|
|
|
Scheme: "hmac-sha256",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-07 16:43:51 -09:00
|
|
|
func ParseCommand(jsn []byte) (*Command, error) {
|
|
|
|
cmd := &Command{}
|
|
|
|
err := json.Unmarshal(jsn, cmd)
|
2021-03-01 07:26:27 -09:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-03-07 16:43:51 -09:00
|
|
|
return cmd, nil
|
2021-03-01 07:26:27 -09:00
|
|
|
}
|
|
|
|
|
2021-03-07 16:43:51 -09:00
|
|
|
func (c *Command) JSON() ([]byte, error) {
|
|
|
|
return json.Marshal(c)
|
2021-03-01 07:26:27 -09:00
|
|
|
}
|
|
|
|
|
2021-03-07 16:43:51 -09:00
|
|
|
func (c *Command) Sign(key []byte) error {
|
|
|
|
switch c.Scheme {
|
2021-03-01 07:26:27 -09:00
|
|
|
case "hmac-sha256":
|
2021-03-07 16:43:51 -09:00
|
|
|
j, err := c.JSON()
|
2021-03-01 07:26:27 -09:00
|
|
|
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)
|
2021-03-01 07:26:27 -09:00
|
|
|
|
|
|
|
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)
|
2021-03-01 07:26:27 -09:00
|
|
|
}
|
|
|
|
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,
|
2021-03-01 07:26:27 -09:00
|
|
|
}
|
|
|
|
err := cpy.Sign(key)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-03-07 16:43:51 -09:00
|
|
|
if !hmac.Equal(cpy.Signature, c.Signature) {
|
2021-03-01 07:26:27 -09:00
|
|
|
return fmt.Errorf("invalid signature")
|
|
|
|
}
|
|
|
|
|
2021-03-07 16:43:51 -09:00
|
|
|
if time.Now().After(c.Expires) {
|
2021-03-01 07:26:27 -09:00
|
|
|
return fmt.Errorf("command expired")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|