watchman/server/api.go

140 lines
3.4 KiB
Go
Executable File

package main
import (
"encoding/json"
"local/encryptor"
"local/system/sysconf"
"local/watchman/client/watchman"
"log"
"net/http"
)
type API struct {
conf sysconf.Conf
enc encryptor.Encryptor
storage *Storage
junk map[string]string
nextJunk string
}
func newAPI(conf sysconf.Conf) (*API, error) {
store, err := newStorage()
if err != nil {
return nil, err
}
enc := encryptor.NewEncryptor("", "")
if err := store.set(keyBucket, serviceName, enc.GetPublic()); err != nil {
return nil, err
}
return &API{
storage: store,
conf: conf,
enc: enc,
junk: make(map[string]string),
nextJunk: encryptor.NewEncryptor("", "").GetPublic(),
}, nil
}
func (api *API) ServeHTTP(w http.ResponseWriter, r *http.Request) {
httpr := &HTTPRequest{w: w, r: r}
action := httpr.PathAdvance()
if action == "getpub" {
api.pubKeyGet(httpr)
return
}
if err := httpr.readBody(api.enc); err != nil {
return
}
switch action {
case "setpub":
api.pubKeySet(httpr)
case "push":
api.push(httpr)
case "pull":
api.pull(httpr)
default:
w.WriteHeader(http.StatusNotFound)
}
}
func (api *API) pubKeyGet(httpr *HTTPRequest) {
body, err := httpr.limitReader()
if err != nil {
httpr.result(http.StatusRequestEntityTooLarge, err, nil)
return
}
if len(body) == 0 {
httpr.result(http.StatusBadRequest, nil, nil)
return
}
// if asks for server pub, then return server pub
if string(body) == serviceName {
httpr.result(http.StatusOK, nil, api.enc.GetPublic())
return
}
// else if encrypted with server's pub, then return any
if decrypted := api.enc.Decrypt(string(body)); decrypted != "" {
if pub, err := api.storage.get(keyBucket, decrypted); err == nil {
httpr.result(http.StatusOK, nil, pub)
}
httpr.result(http.StatusNotFound, nil, nil)
return
}
// else return garbage
if v, ok := api.junk[string(body)]; ok {
httpr.result(secretError, nil, v)
} else {
api.junk[string(body)] = api.nextJunk
httpr.result(secretError, nil, api.junk[string(body)])
go func() {
api.nextJunk = encryptor.NewEncryptor("", "").GetPublic()
}()
}
}
func (api *API) pubKeySet(httpr *HTTPRequest) {
var setRequest struct {
Key string `json:"key"`
ID string `json:"id"`
}
if err := json.Unmarshal([]byte(httpr.body), &setRequest); err != nil {
httpr.result(http.StatusBadRequest, nil, nil)
return
}
api.storage.set(keyBucket, setRequest.ID, setRequest.Key)
}
func (api *API) push(httpr *HTTPRequest) {
var pack watchman.Package
if err := json.Unmarshal([]byte(httpr.body), &pack); err != nil {
httpr.result(http.StatusBadRequest, err, nil)
return
}
if err := api.storage.set("objects", storePath(pack), httpr.body); err != nil {
httpr.result(http.StatusInternalServerError, err, nil)
return
}
httpr.result(http.StatusOK, nil, nil)
}
func (api *API) pull(httpr *HTTPRequest) {
var pack watchman.Package
if err := json.Unmarshal([]byte(httpr.body), &pack); err != nil {
httpr.result(http.StatusBadRequest, err, nil)
return
}
b, err := api.storage.get("objects", storePath(pack))
if err != nil {
httpr.result(http.StatusNotFound, err, nil)
return
}
enc := encryptor.NewEncryptor("", "")
enc.SetSymmetric(string(pack.Packs[0]))
encrypted := enc.Encrypt(string(b))
log.Print("returning content", string(b))
httpr.result(http.StatusOK, nil, encrypted)
}
func storePath(pack watchman.Package) string {
return pack.ID + "_" + pack.Path
}