diff --git a/README.md b/README.md index 6dd94a07a..90aac2596 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,8 @@ $ yopass-server -h --redis string Redis URL (default "redis://localhost:6379/0") --tls-cert string path to TLS certificate --tls-key string path to TLS key + --cors-allow-origin Access-Control-Allow-Origin CORS setting (default *) + ``` Encrypted secrets can be stored either in Memcached or Redis by changing the `--database` flag. diff --git a/cmd/yopass-server/main.go b/cmd/yopass-server/main.go index 31a7ff3e9..4abf68dda 100644 --- a/cmd/yopass-server/main.go +++ b/cmd/yopass-server/main.go @@ -37,6 +37,7 @@ func init() { pflag.String("tls-cert", "", "path to TLS certificate") pflag.String("tls-key", "", "path to TLS key") pflag.Bool("force-onetime-secrets", false, "reject non onetime secrets from being created") + pflag.String("cors-allow-origin", "*", "Access-Control-Allow-Origin") pflag.CommandLine.AddGoFlag(&flag.Flag{Name: "log-level", Usage: "Log level", Value: &logLevel}) viper.AutomaticEnv() diff --git a/pkg/server/server.go b/pkg/server/server.go index 874c837dd..adf5d0176 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -2,6 +2,7 @@ package server import ( "encoding/json" + "github.com/spf13/viper" "net/http" "strconv" "strings" @@ -41,7 +42,7 @@ func New(db Database, maxLength int, r *prometheus.Registry, forceOneTimeSecrets // createSecret creates secret func (y *Server) createSecret(w http.ResponseWriter, request *http.Request) { - w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Origin", viper.GetString("cors-allow-origin")) decoder := json.NewDecoder(request.Body) var s yopass.Secret @@ -95,7 +96,7 @@ func (y *Server) createSecret(w http.ResponseWriter, request *http.Request) { // getSecret from database func (y *Server) getSecret(w http.ResponseWriter, request *http.Request) { - w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Origin", viper.GetString("cors-allow-origin")) w.Header().Set("Cache-Control", "private, no-cache") secretKey := mux.Vars(request)["key"] @@ -120,7 +121,7 @@ func (y *Server) getSecret(w http.ResponseWriter, request *http.Request) { // deleteSecret from database func (y *Server) deleteSecret(w http.ResponseWriter, request *http.Request) { - w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Origin", viper.GetString("cors-allow-origin")) deleted, err := y.db.Delete(mux.Vars(request)["key"]) if err != nil { @@ -138,21 +139,29 @@ func (y *Server) deleteSecret(w http.ResponseWriter, request *http.Request) { // optionsSecret handle the Options http method by returning the correct CORS headers func (y *Server) optionsSecret(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Origin", viper.GetString("cors-allow-origin")) w.Header().Set("Access-Control-Allow-Methods", strings.Join([]string{http.MethodGet, http.MethodDelete, http.MethodOptions}, ",")) } +// optionsSecret handle the Options http method by returning the correct CORS headers +func (y *Server) optionsCreateSecret(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", viper.GetString("cors-allow-origin")) + w.Header().Set("Access-Control-Allow-Methods", strings.Join([]string{http.MethodPost}, ",")) +} + // HTTPHandler containing all routes func (y *Server) HTTPHandler() http.Handler { mx := mux.NewRouter() mx.Use(newMetricsMiddleware(y.registry)) mx.HandleFunc("/secret", y.createSecret).Methods(http.MethodPost) + mx.HandleFunc("/secret", y.optionsCreateSecret).Methods(http.MethodOptions) mx.HandleFunc("/secret/"+keyParameter, y.getSecret).Methods(http.MethodGet) mx.HandleFunc("/secret/"+keyParameter, y.deleteSecret).Methods(http.MethodDelete) mx.HandleFunc("/secret/"+keyParameter, y.optionsSecret).Methods(http.MethodOptions) mx.HandleFunc("/file", y.createSecret).Methods(http.MethodPost) + mx.HandleFunc("/file", y.optionsCreateSecret).Methods(http.MethodOptions) mx.HandleFunc("/file/"+keyParameter, y.getSecret).Methods(http.MethodGet) mx.HandleFunc("/file/"+keyParameter, y.deleteSecret).Methods(http.MethodDelete) mx.HandleFunc("/file/"+keyParameter, y.optionsSecret).Methods(http.MethodOptions) diff --git a/website/src/utils/utils.tsx b/website/src/utils/utils.tsx index 151417127..7502a1157 100644 --- a/website/src/utils/utils.tsx +++ b/website/src/utils/utils.tsx @@ -50,6 +50,9 @@ const post = async (url: string, body: any): Promise => { const request = await fetch(url, { body: JSON.stringify(body), method: 'POST', + headers: { + ContentType: 'application/json', + }, }); return { data: await request.json(), status: request.status }; };