package main import ( "fmt" "os" "net/http" "syscall" "os/signal" "time" "context" //"encoding/json" "strings" "github.com/ProtonMail/go-crypto/openpgp" //"github.com/ProtonMail/go-crypto/openpgp/packet" ) type Server struct { PublicKeys openpgp.EntityList PrivateKeys openpgp.EntityList //PubkeyGroups []*openpgp.Entity } func NewServer(publicKeys, privateKeys []string) (*Server, error) { pub, err := loadKeysFromFiles(publicKeys) if err != nil { return nil, err } priv, err := loadKeysFromFiles(privateKeys) if err != nil { return nil, err } return &Server{PublicKeys: pub, PrivateKeys: priv}, nil } func loadKeysFromFiles(filenames []string) (openpgp.EntityList, error) { var keyring openpgp.EntityList for _, f := range filenames { file, err := os.Open(f) if err != nil { return nil, err } keys, err := openpgp.ReadArmoredKeyRing(file) if err != nil { file.Close() return nil, err } file.Close() keyring = append(keyring, keys...) } return keyring, nil } func (s *Server) handler_publickey(w http.ResponseWriter, r *http.Request) { path := strings.Split(strings.Trim(r.URL.Path, "/"), "/") if len(path) < 2 { fmt.Fprintln(w, "missing path stuff") return } fmt.Println(r.URL.Path) search := strings.ToLower(path[1]) fmt.Println("searching for", search) key := s.findPubKey(search) if key == nil { http.Error(w, "Key not found", 500) return } err := key.Serialize(w) if err != nil { fmt.Printf("Serialization error: %s\n", err) } } func (s *Server) findPubKey(search string) *openpgp.Entity { for _, k := range s.PublicKeys { for _, id := range k.Identities { if strings.ToLower(id.UserId.Name) == search { return k } if strings.ToLower(id.UserId.Email) == search { return k } } } return nil } func (s *Server) handler_privatekey(w http.ResponseWriter, r *http.Request) { path := strings.Split(strings.Trim(r.URL.Path, "/"), "/") if len(path) < 2 { fmt.Fprintln(w, "missing path stuff") return } fmt.Println(r.URL.Path) search := strings.ToLower(path[1]) fmt.Println("searching for", search) key := s.findPrivKey(search) if key == nil { http.Error(w, "Key not found", 500) return } err := key.SerializePrivate(w, nil) if err != nil { fmt.Printf("Serialization error: %s\n", err) } } func (s *Server) findPrivKey(search string) *openpgp.Entity { for _, k := range s.PrivateKeys { fmt.Printf("%X\n", k.PrimaryKey.KeyId) for _, id := range k.Identities { if strings.ToLower(id.UserId.Name) == search { return k } if strings.ToLower(id.UserId.Email) == search { return k } } for _, sub := range k.Subkeys { fmt.Printf("%#v\n", sub) if sub.PrivateKey == nil { continue } if fmt.Sprintf("%x", sub.PrivateKey.KeyId) == search { return k } } } return nil } func (s *Server) handler_debug(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Public Keys:") for _, key := range s.PublicKeys { //fmt.Fprintf(w, "%#v\n", key.PrimaryIdentity()) fmt.Fprintf(w,"%s\n\t%X\n\t%X\n", key.PrimaryIdentity().Name, key.PrimaryKey.Fingerprint, key.PrimaryKey.KeyId, ) //j, err := json.Marshal(key) //if err != nil { // fmt.Fprintf(w, "ERROR: %s", err) // return //} //fmt.Fprintf(w,"\t\t%s\n", j) } fmt.Fprintln(w, "\nPrivate Keys:") for _, key := range s.PrivateKeys { //fmt.Fprintf(w, "%#v\n", key.PrimaryIdentity()) fmt.Fprintf(w,"%s\n\t%X\n\t%X\n", key.PrimaryIdentity().Name, key.PrimaryKey.Fingerprint, key.PrivateKey.KeyId, ) for _, sub := range key.Subkeys { fmt.Fprintf(w, "\t>%X\n\t>%X\n", sub.PublicKey.KeyId, sub.PrivateKey.KeyId, ) } } } func handler_default(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "henlo") } func run() error { sv, err := NewServer( []string{ //"keys/gpg-generated/cust-a.pub", //"keys/gpg-generated/cust-b.pub", //"keys/gpg-generated/internal-public.asc", "keys/public/Customer.asc", "keys/public/Company.asc", }, []string{ //"keys/gpg-generated/internal-private.asc", "keys/private/Company.asc", }, ) if err != nil { return err } mux := http.NewServeMux() mux.HandleFunc("/pubkey/", sv.handler_publickey) mux.HandleFunc("/privkey/", sv.handler_privatekey) mux.HandleFunc("/debug/", sv.handler_debug) mux.HandleFunc("/", handler_default) server := &http.Server{ Addr: ":8080", Handler: mux, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } done := make(chan os.Signal, 1) signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) go func() { fmt.Println("listening on", server.Addr) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { fmt.Println("Listen: ", err) } }() <-done fmt.Println("stopping") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := server.Shutdown(ctx); err != nil { fmt.Println("Clean shutdown failed: ", err) } fmt.Println("goodbye") return nil } func main() { err := run() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }