1
0
mirror of https://github.com/docker/docs.git synced 2026-11-05 00:14:17 +03:00
Files
docs/signer/api/api.go
HuKeping 74d4af37a3 Stop injecting to the helper function
GetCryptoService is a helper function and we have injected a specific
http.ResponseWriter object for it to write back error message. Meanwhile
the caller for that function checks whether the cryptoService is nil
or not and return immediately if it is nil.

I think it's not a good idea to write back HTTP response in the helper function,
it's the caller's work and thus there is no need to inject the specific
ResponseWriter object into it.

Signed-off-by: Hu Keping <hukeping@huawei.com>
2015-12-30 09:42:51 +08:00

206 lines
6.1 KiB
Go

package api
import (
"crypto/rand"
"encoding/json"
"fmt"
"net/http"
"github.com/docker/notary/signer"
"github.com/docker/notary/signer/keys"
"github.com/docker/notary/tuf/signed"
"github.com/gorilla/mux"
pb "github.com/docker/notary/proto"
)
// Handlers sets up all the handers for the routes, injecting a specific CryptoService object for them to use
func Handlers(cryptoServices signer.CryptoServiceIndex) *mux.Router {
r := mux.NewRouter()
r.Methods("GET").Path("/{ID}").Handler(KeyInfo(cryptoServices))
r.Methods("POST").Path("/new/{Algorithm}").Handler(CreateKey(cryptoServices))
r.Methods("POST").Path("/delete").Handler(DeleteKey(cryptoServices))
r.Methods("POST").Path("/sign").Handler(Sign(cryptoServices))
return r
}
// getCryptoService handles looking up the correct signing service, given the
// algorithm specified in the HTTP request. If the algorithm isn't specified
// or isn't supported, an error is returned to the client and this function
// returns a nil CryptoService
func getCryptoService(algorithm string, cryptoServices signer.CryptoServiceIndex) (signed.CryptoService, error) {
if algorithm == "" {
return nil, fmt.Errorf("algorithm not specified")
}
if service, ok := cryptoServices[algorithm]; ok {
return service, nil
}
return nil, fmt.Errorf("algorithm " + algorithm + " not supported")
}
// KeyInfo returns a Handler that given a specific Key ID param, returns the public key bits of that key
func KeyInfo(cryptoServices signer.CryptoServiceIndex) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
tufKey, _, err := FindKeyByID(cryptoServices, &pb.KeyID{ID: vars["ID"]})
if err != nil {
switch err {
// If we received an ErrInvalidKeyID, the key doesn't exist, return 404
case keys.ErrInvalidKeyID:
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(err.Error()))
return
// If we received anything else, it is unexpected, and we return a 500
default:
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
}
key := &pb.PublicKey{
KeyInfo: &pb.KeyInfo{
KeyID: &pb.KeyID{ID: tufKey.ID()},
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm()},
},
PublicKey: tufKey.Public(),
}
json.NewEncoder(w).Encode(key)
return
})
}
// CreateKey returns a handler that generates a new key using the provided
// algorithm. Only the public component of the key is returned.
func CreateKey(cryptoServices signer.CryptoServiceIndex) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
cryptoService, err := getCryptoService(vars["Algorithm"], cryptoServices)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
tufKey, err := cryptoService.Create("", vars["Algorithm"])
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
key := &pb.PublicKey{
KeyInfo: &pb.KeyInfo{
KeyID: &pb.KeyID{ID: tufKey.ID()},
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm()},
},
PublicKey: tufKey.Public(),
}
json.NewEncoder(w).Encode(key)
return
})
}
// DeleteKey returns a handler that delete a specific KeyID
func DeleteKey(cryptoServices signer.CryptoServiceIndex) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var keyID *pb.KeyID
err := json.NewDecoder(r.Body).Decode(&keyID)
defer r.Body.Close()
if err != nil || keyID.ID == "" {
w.WriteHeader(http.StatusBadRequest)
jsonErr, _ := json.Marshal("Malformed request")
w.Write([]byte(jsonErr))
return
}
_, cryptoService, err := FindKeyByID(cryptoServices, keyID)
if err != nil {
switch err {
// If we received an ErrInvalidKeyID, the key doesn't exist, return 404
case keys.ErrInvalidKeyID:
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(err.Error()))
return
// If we received anything else, it is unexpected, and we return a 500
default:
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
}
if err = cryptoService.RemoveKey(keyID.ID); err != nil {
switch err {
// If we received an ErrInvalidKeyID, the key doesn't exist, return 404
case keys.ErrInvalidKeyID:
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(err.Error()))
return
// If we received anything else, it is unexpected, and we return a 500
default:
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
}
// In case we successfully delete this key, return 200
return
})
}
// Sign returns a handler that is able to perform signatures on a given blob
func Sign(cryptoServices signer.CryptoServiceIndex) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var sigRequest *pb.SignatureRequest
err := json.NewDecoder(r.Body).Decode(&sigRequest)
defer r.Body.Close()
if err != nil || sigRequest.Content == nil ||
sigRequest.KeyID == nil {
w.WriteHeader(http.StatusBadRequest)
jsonErr, _ := json.Marshal("Malformed request")
w.Write([]byte(jsonErr))
return
}
tufKey, cryptoService, err := FindKeyByID(cryptoServices, sigRequest.KeyID)
if err == keys.ErrInvalidKeyID {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(err.Error()))
return
} else if err != nil {
// We got an unexpected error
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
privKey, _, err := cryptoService.GetPrivateKey(tufKey.ID())
if err != nil {
// We got an unexpected error
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
sig, err := privKey.Sign(rand.Reader, sigRequest.Content, nil)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
signature := &pb.Signature{
KeyInfo: &pb.KeyInfo{
KeyID: &pb.KeyID{ID: tufKey.ID()},
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm()},
},
Algorithm: &pb.Algorithm{Algorithm: privKey.SignatureAlgorithm().String()},
Content: sig,
}
json.NewEncoder(w).Encode(signature)
return
})
}