2 Commits
5571401103
...
aa65b64867
Author | SHA1 | Message | Date |
---|---|---|---|
Christopher Ramey | aa65b64867 |
added client calls for running servers
|
3 years ago |
Christopher Ramey | 86f304e1b8 |
segregated api machinery
|
3 years ago |
5 changed files with 163 additions and 76 deletions
-
80api/command.go
-
44client/client.go
-
29main.go
-
72server/apicommand.go
-
14server/http.go
@ -0,0 +1,80 @@ |
|||
package api |
|||
|
|||
import ( |
|||
"crypto/hmac" |
|||
"crypto/sha256" |
|||
"encoding/json" |
|||
"fmt" |
|||
"time" |
|||
) |
|||
|
|||
type Command struct { |
|||
Expires time.Time `json:"exp"` |
|||
Command string `json:"cmd"` |
|||
Scheme string `json:"sch"` |
|||
Signature []byte `json:"sig,omitempty"` |
|||
} |
|||
|
|||
func NewCommand(cm string) *Command { |
|||
return &Command{ |
|||
Expires: time.Now().Add(time.Second * 5), |
|||
Command: cm, |
|||
Scheme: "hmac-sha256", |
|||
} |
|||
} |
|||
|
|||
func ParseCommand(jsn []byte) (*Command, error) { |
|||
cmd := &Command{} |
|||
err := json.Unmarshal(jsn, cmd) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
return cmd, nil |
|||
} |
|||
|
|||
func (c *Command) JSON() ([]byte, error) { |
|||
return json.Marshal(c) |
|||
} |
|||
|
|||
func (c *Command) Sign(key []byte) error { |
|||
switch c.Scheme { |
|||
case "hmac-sha256": |
|||
j, err := c.JSON() |
|||
if err != nil { |
|||
return fmt.Errorf("json encoding error") |
|||
} |
|||
|
|||
mac := hmac.New(sha256.New, key) |
|||
mac.Write(j) |
|||
c.Signature = mac.Sum(nil) |
|||
|
|||
case "": |
|||
return fmt.Errorf("scheme may not be empty") |
|||
|
|||
default: |
|||
return fmt.Errorf("unsupported scheme: %s", c.Scheme) |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
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 |
|||
} |
|||
|
|||
if !hmac.Equal(cpy.Signature, c.Signature) { |
|||
return fmt.Errorf("invalid signature") |
|||
} |
|||
|
|||
if time.Now().After(c.Expires) { |
|||
return fmt.Errorf("command expired") |
|||
} |
|||
|
|||
return nil |
|||
} |
@ -0,0 +1,44 @@ |
|||
package client |
|||
|
|||
import ( |
|||
"git.binarythought.com/cdramey/alrm/api" |
|||
"git.binarythought.com/cdramey/alrm/config" |
|||
"net/http" |
|||
"net/url" |
|||
) |
|||
|
|||
func Shutdown(cfg *config.Config) error { |
|||
return doCommand(cfg, "shutdown") |
|||
} |
|||
|
|||
func Restart(cfg *config.Config) error { |
|||
return doCommand(cfg, "restart") |
|||
} |
|||
|
|||
func doCommand(cfg *config.Config, cm string) error { |
|||
aurl, err := url.Parse("http://" + cfg.Listen + "/api") |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
cmd := api.NewCommand(cm) |
|||
err = cmd.Sign(cfg.APIKey) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
cjson, err := cmd.JSON() |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
params := url.Values{} |
|||
params.Add("cmd", string(cjson)) |
|||
|
|||
resp, err := http.PostForm(aurl.String(), params) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
defer resp.Body.Close() |
|||
|
|||
return nil |
|||
} |
@ -1,72 +0,0 @@ |
|||
package server |
|||
|
|||
import ( |
|||
"crypto/hmac" |
|||
"crypto/sha256" |
|||
"encoding/json" |
|||
"fmt" |
|||
"time" |
|||
) |
|||
|
|||
type APICommand struct { |
|||
Expires time.Time `json:"exp"` |
|||
Command string `json:"cmd"` |
|||
Scheme string `json:"sch"` |
|||
Signature []byte `json:"sig,omitempty"` |
|||
} |
|||
|
|||
func ParseAPICommand(jsn []byte) (*APICommand, error) { |
|||
api := &APICommand{} |
|||
err := json.Unmarshal(jsn, api) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
return api, nil |
|||
} |
|||
|
|||
func (ac *APICommand) JSON() ([]byte, error) { |
|||
return json.Marshal(ac) |
|||
} |
|||
|
|||
func (ac *APICommand) Sign(key []byte) error { |
|||
switch ac.Scheme { |
|||
case "hmac-sha256": |
|||
j, err := ac.JSON() |
|||
if err != nil { |
|||
return fmt.Errorf("json encoding error") |
|||
} |
|||
|
|||
mac := hmac.New(sha256.New, key) |
|||
mac.Write(j) |
|||
ac.Signature = mac.Sum(nil) |
|||
|
|||
case "": |
|||
return fmt.Errorf("scheme may not be empty") |
|||
|
|||
default: |
|||
return fmt.Errorf("unsupported scheme: %s", ac.Scheme) |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (ac *APICommand) Validate(key []byte) error { |
|||
cpy := &APICommand{ |
|||
Expires: ac.Expires, |
|||
Command: ac.Command, |
|||
Scheme: ac.Scheme, |
|||
} |
|||
err := cpy.Sign(key) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
if !hmac.Equal(cpy.Signature, ac.Signature) { |
|||
return fmt.Errorf("invalid signature") |
|||
} |
|||
|
|||
if time.Now().After(ac.Expires) { |
|||
return fmt.Errorf("command expired") |
|||
} |
|||
|
|||
return nil |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue