Skip to content

Commit d591d5a

Browse files
committed
config+terminal: enable CORS and WebSocket support for REST
We want to give the REST proxy the same functionality as the lnd built in REST proxy has and therefore enable CORS and WebSocket support on it as well.
1 parent 0159e0a commit d591d5a

File tree

2 files changed

+66
-7
lines changed

2 files changed

+66
-7
lines changed

config.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,13 @@ var (
118118
// all config items of its enveloping subservers, each prefixed with their
119119
// daemon's short name.
120120
type Config struct {
121-
HTTPSListen string `long:"httpslisten" description:"The host:port to listen for incoming HTTP/2 connections on for the web UI only."`
122-
HTTPListen string `long:"insecure-httplisten" description:"The host:port to listen on with TLS disabled. This is dangerous to enable as credentials will be submitted without encryption. Should only be used in combination with Tor hidden services or other external encryption."`
123-
EnableREST bool `long:"enablerest" description:"Also allow REST requests to be made to the main HTTP(s) port(s) configured above."`
124-
UIPassword string `long:"uipassword" description:"The password that must be entered when using the loop UI. use a strong password to protect your node from unauthorized access through the web UI."`
125-
UIPasswordFile string `long:"uipassword_file" description:"Same as uipassword but instead of passing in the value directly, read the password from the specified file."`
126-
UIPasswordEnv string `long:"uipassword_env" description:"Same as uipassword but instead of passing in the value directly, read the password from the specified environment variable."`
121+
HTTPSListen string `long:"httpslisten" description:"The host:port to listen for incoming HTTP/2 connections on for the web UI only."`
122+
HTTPListen string `long:"insecure-httplisten" description:"The host:port to listen on with TLS disabled. This is dangerous to enable as credentials will be submitted without encryption. Should only be used in combination with Tor hidden services or other external encryption."`
123+
EnableREST bool `long:"enablerest" description:"Also allow REST requests to be made to the main HTTP(s) port(s) configured above."`
124+
RestCORS []string `long:"restcors" description:"Add an ip:port/hostname to allow cross origin access from. To allow all origins, set as \"*\"."`
125+
UIPassword string `long:"uipassword" description:"The password that must be entered when using the loop UI. use a strong password to protect your node from unauthorized access through the web UI."`
126+
UIPasswordFile string `long:"uipassword_file" description:"Same as uipassword but instead of passing in the value directly, read the password from the specified file."`
127+
UIPasswordEnv string `long:"uipassword_env" description:"Same as uipassword but instead of passing in the value directly, read the password from the specified environment variable."`
127128

128129
LetsEncrypt bool `long:"letsencrypt" description:"Use Let's Encrypt to create a TLS certificate for the UI instead of using lnd's TLS certificate. Port 80 must be free to listen on and must be reachable from the internet for this to work."`
129130
LetsEncryptHost string `long:"letsencrypthost" description:"The host name to create a Let's Encrypt certificate for."`

terminal.go

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,13 @@ func (g *LightningTerminal) createRESTProxy() error {
794794
restMux := restProxy.NewServeMux(customMarshalerOption)
795795
ctx, cancel := context.WithCancel(context.Background())
796796
g.restCancel = cancel
797-
g.restHandler = restMux
797+
798+
// Enable WebSocket and CORS support as well. A request will pass
799+
// through the following chain:
800+
// req ---> CORS handler --> WS proxy ---> REST proxy --> gRPC endpoint
801+
// where gRPC endpoint is our main HTTP(S) listener again.
802+
restHandler := lnrpc.NewWebSocketProxy(restMux, log)
803+
g.restHandler = allowCORS(restHandler, g.cfg.RestCORS)
798804

799805
// First register all lnd handlers. This will make it possible to speak
800806
// REST over the main RPC listener port in both remote and integrated
@@ -821,6 +827,58 @@ func (g *LightningTerminal) createRESTProxy() error {
821827
return nil
822828
}
823829

830+
// allowCORS wraps the given http.Handler with a function that adds the
831+
// Access-Control-Allow-Origin header to the response.
832+
func allowCORS(handler http.Handler, origins []string) http.Handler {
833+
allowHeaders := "Access-Control-Allow-Headers"
834+
allowMethods := "Access-Control-Allow-Methods"
835+
allowOrigin := "Access-Control-Allow-Origin"
836+
837+
// If the user didn't supply any origins that means CORS is disabled
838+
// and we should return the original handler.
839+
if len(origins) == 0 {
840+
return handler
841+
}
842+
843+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
844+
origin := r.Header.Get("Origin")
845+
846+
// Skip everything if the browser doesn't send the Origin field.
847+
if origin == "" {
848+
handler.ServeHTTP(w, r)
849+
return
850+
}
851+
852+
// Set the static header fields first.
853+
w.Header().Set(
854+
allowHeaders,
855+
"Content-Type, Accept, Grpc-Metadata-Macaroon",
856+
)
857+
w.Header().Set(allowMethods, "GET, POST, DELETE")
858+
859+
// Either we allow all origins or the incoming request matches
860+
// a specific origin in our list of allowed origins.
861+
for _, allowedOrigin := range origins {
862+
if allowedOrigin == "*" || origin == allowedOrigin {
863+
// Only set allowed origin to requested origin.
864+
w.Header().Set(allowOrigin, origin)
865+
866+
break
867+
}
868+
}
869+
870+
// For a pre-flight request we only need to send the headers
871+
// back. No need to call the rest of the chain.
872+
if r.Method == "OPTIONS" {
873+
return
874+
}
875+
876+
// Everything's prepared now, we can pass the request along the
877+
// chain of handlers.
878+
handler.ServeHTTP(w, r)
879+
})
880+
}
881+
824882
// showStartupInfo shows useful information to the user to easily access the
825883
// web UI that was just started.
826884
func (g *LightningTerminal) showStartupInfo() error {

0 commit comments

Comments
 (0)