config+lnd+rpcserver: add CORS origin config for REST

This commit is contained in:
Anthony Ronning 2020-04-06 15:16:02 +02:00 committed by Oliver Gugger
parent 6250ed1cf1
commit a76e752f3b
No known key found for this signature in database
GPG Key ID: 8E4256593F177720
2 changed files with 55 additions and 1 deletions

@ -159,6 +159,7 @@ type Config struct {
RawExternalIPs []string `long:"externalip" description:"Add an ip:port to the list of local addresses we claim to listen on to peers. If a port is not specified, the default (9735) will be used regardless of other parameters"` RawExternalIPs []string `long:"externalip" description:"Add an ip:port to the list of local addresses we claim to listen on to peers. If a port is not specified, the default (9735) will be used regardless of other parameters"`
RPCListeners []net.Addr RPCListeners []net.Addr
RESTListeners []net.Addr RESTListeners []net.Addr
RestCORS []string `long:"restcors" description:"Add an ip:port/hostname to allow cross origin access from. To allow all origins, set as \"*\"."`
Listeners []net.Addr Listeners []net.Addr
ExternalIPs []net.Addr ExternalIPs []net.Addr
DisableListen bool `long:"nolisten" description:"Disable listening for incoming peer connections"` DisableListen bool `long:"nolisten" description:"Disable listening for incoming peer connections"`

@ -802,6 +802,12 @@ func (r *rpcServer) Start() error {
// Wrap the default grpc-gateway handler with the WebSocket handler. // Wrap the default grpc-gateway handler with the WebSocket handler.
restHandler := lnrpc.NewWebSocketProxy(restMux, rpcsLog) restHandler := lnrpc.NewWebSocketProxy(restMux, rpcsLog)
// Set the CORS headers if configured. This wraps the HTTP handler with
// another handler.
if len(r.cfg.RestCORS) > 0 {
restHandler = allowCORS(restHandler, r.cfg.RestCORS)
}
// With our custom REST proxy mux created, register our main RPC and // With our custom REST proxy mux created, register our main RPC and
// give all subservers a chance to register as well. // give all subservers a chance to register as well.
err := lnrpc.RegisterLightningHandlerFromEndpoint( err := lnrpc.RegisterLightningHandlerFromEndpoint(
@ -855,7 +861,8 @@ func (r *rpcServer) Start() error {
// Create our proxy chain now. A request will pass // Create our proxy chain now. A request will pass
// through the following chain: // through the following chain:
// req ---> WS proxy ---> REST proxy --> gRPC endpoint // req ---> CORS handler --> WS proxy --->
// REST proxy --> gRPC endpoint
err := http.Serve(lis, restHandler) err := http.Serve(lis, restHandler)
if err != nil && !lnrpc.IsClosedConnError(err) { if err != nil && !lnrpc.IsClosedConnError(err) {
rpcsLog.Error(err) rpcsLog.Error(err)
@ -922,6 +929,52 @@ func addrPairsToOutputs(addrPairs map[string]int64) ([]*wire.TxOut, error) {
return outputs, nil return outputs, nil
} }
// allowCORS wraps the given http.Handler with a function that adds the
// Access-Control-Allow-Origin header to the response.
func allowCORS(handler http.Handler, origins []string) http.Handler {
allowHeaders := "Access-Control-Allow-Headers"
allowMethods := "Access-Control-Allow-Methods"
allowOrigin := "Access-Control-Allow-Origin"
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get("Origin")
// Skip everything if the browser doesn't send the Origin field.
if origin == "" {
handler.ServeHTTP(w, r)
return
}
// Set the static header fields first.
w.Header().Set(
allowHeaders,
"Content-Type, Accept, Grpc-Metadata-Macaroon",
)
w.Header().Set(allowMethods, "GET, POST, DELETE")
// Either we allow all origins or the incoming request matches
// a specific origin in our list of allowed origins.
for _, allowedOrigin := range origins {
if allowedOrigin == "*" || origin == allowedOrigin {
// Only set allowed origin to requested origin.
w.Header().Set(allowOrigin, origin)
break
}
}
// For a pre-flight request we only need to send the headers
// back. No need to call the rest of the chain.
if r.Method == "OPTIONS" {
return
}
// Everything's prepared now, we can pass the request along the
// chain of handlers.
handler.ServeHTTP(w, r)
})
}
// sendCoinsOnChain makes an on-chain transaction in or to send coins to one or // sendCoinsOnChain makes an on-chain transaction in or to send coins to one or
// more addresses specified in the passed payment map. The payment map maps an // more addresses specified in the passed payment map. The payment map maps an
// address to a specified output value to be sent to that address. // address to a specified output value to be sent to that address.