You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

130 lines
2.6 KiB

package main
import (
"bytes"
"crypto/ed25519"
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"net/http"
"os"
"os/user"
"path/filepath"
"time"
)
func validKey() (ed25519.PublicKey, ed25519.PrivateKey) {
pub, priv, err := ed25519.GenerateKey(nil)
if err != nil {
panic(err)
}
// TODO: generate a new key if necessary
target, err := hex.DecodeString("ed2023")
if err != nil {
panic(err)
}
for bytes.Compare(pub[29:32], target) != 0 {
pub, priv, err = ed25519.GenerateKey(nil)
if err != nil {
panic(err)
}
}
fmt.Printf("%s\n", fmt.Sprintf("%x", pub))
return pub, priv
}
func fileExists(name string) bool {
if _, err := os.Stat(name); errors.Is(err, os.ErrNotExist) {
return false
}
return true
}
func getKeys() (ed25519.PublicKey, ed25519.PrivateKey) {
user, err := user.Current()
if err != nil {
panic(err)
}
configPath := os.Getenv("XDG_CONFIG_HOME")
if configPath == "" {
configPath = filepath.Join(user.HomeDir, ".config", "spring83")
}
if err = os.MkdirAll(configPath, os.ModePerm); err != nil {
panic(err)
}
pubfile := filepath.Join(configPath, "key.pub")
privfile := filepath.Join(configPath, "key.priv")
var pubkey ed25519.PublicKey
var privkey ed25519.PrivateKey
if fileExists(pubfile) && fileExists(privfile) {
pubkey, err = ioutil.ReadFile(pubfile)
if err != nil {
panic(err)
}
privkey, err = ioutil.ReadFile(privfile)
if err != nil {
panic(err)
}
} else {
fmt.Printf("Generating key, give this a minute or two\n")
pubkey, privkey = validKey()
os.WriteFile(pubfile, pubkey, 0666)
os.WriteFile(privfile, privkey, 0600)
}
return pubkey, privkey
}
func main() {
pubkey, privkey := getKeys()
client := &http.Client{}
body, err := ioutil.ReadAll(os.Stdin)
if err != nil {
panic(err)
}
if len(body) == 0 {
panic(fmt.Errorf("input required"))
}
if len(body) > 2217 {
panic(fmt.Errorf("input body too long"))
}
// TODO: take the URL as a command line param
// set the HTTP method, url, and request body
url := fmt.Sprintf("http://localhost:8000/%x", pubkey)
fmt.Printf("URL: %s\n", url)
req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(body))
if err != nil {
panic(err)
}
sig := ed25519.Sign(privkey, body)
fmt.Printf("Spring-83 Signature=%x\n", sig)
req.Header.Set("Authorization", fmt.Sprintf("Spring-83 Signature=%x", sig))
dt := time.Now().Format(time.RFC1123)
req.Header.Set("If-Unmodified-Since", dt)
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
responseBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Printf("%s: %s\n", resp.Status, responseBody)
}