From 7d0b4d685d75086e62004d258f116f8f9b61e35b Mon Sep 17 00:00:00 2001 From: Kleissner Date: Tue, 16 Nov 2021 22:39:07 +0100 Subject: [PATCH] Update core. Support API key. Close #6 --- API.go | 29 +++++++++++++++++++---------- Main.go | 14 ++++++++------ README.md | 13 +++++++++---- go.mod | 3 ++- go.sum | 4 ++-- 5 files changed, 40 insertions(+), 23 deletions(-) diff --git a/API.go b/API.go index 24c74fa..916d08a 100644 --- a/API.go +++ b/API.go @@ -18,20 +18,21 @@ import ( "github.com/PeernetOfficial/core" "github.com/PeernetOfficial/core/webapi" + "github.com/google/uuid" "github.com/gorilla/websocket" ) // startAPI starts the API if enabled via command line parameter or if the settings are set in the config file. // Using the command line option always ignores any API settings from the config (including timeout settings). func startAPI() { - if apiListen := parseCmdParamWebapi(); len(apiListen) > 0 { + if apiListen, apiKey := parseCmdParamWebapi(); len(apiListen) > 0 { // API listen parameter via command line argument. // Note that read and write timeouts are set to 0 which means they are not used. SSL is not enabled. - webapi.Start(apiListen, false, "", "", 0, 0) + webapi.Start(apiListen, false, "", "", 0, 0, apiKey) } else if len(config.APIListen) != 0 { // API settings via config file. - webapi.Start(config.APIListen, config.APIUseSSL, config.APICertificateFile, config.APICertificateKey, parseDuration(config.APITimeoutRead), parseDuration(config.APITimeoutWrite)) + webapi.Start(config.APIListen, config.APIUseSSL, config.APICertificateFile, config.APICertificateKey, parseDuration(config.APITimeoutRead), parseDuration(config.APITimeoutWrite), config.APIKey) } else { return } @@ -40,17 +41,25 @@ func startAPI() { webapi.Router.HandleFunc("/shutdown", apiShutdown).Methods("GET") } -// parseCmdParamWebapi parses a "-webapi=" command line parameter -func parseCmdParamWebapi() (apiListen []string) { - var param string - flag.StringVar(¶m, "webapi", "", "Specify the list of IP:Ports for the webapi to listen. Example: -webapi=127.0.0.1:1234") +// parseCmdParamWebapi parses the "-webapi=" and "-apikey" command line parameters. The API key is optional (for now) and set to 00000000-0000-0000-0000-000000000000 if none is provided. +func parseCmdParamWebapi() (apiListen []string, apiKey uuid.UUID) { + var paramWebapi, paramWebKeyA string + flag.StringVar(¶mWebapi, "webapi", "", "Specify the list of IP:Ports for the webapi to listen. Example: -webapi=127.0.0.1:1234") + flag.StringVar(¶mWebKeyA, "apikey", "", "Specify the API key to use. Must be a UUID.") flag.Parse() - if len(param) == 0 { - return nil + if len(paramWebapi) == 0 { + return nil, apiKey } - return strings.Split(param, ",") + if len(paramWebKeyA) != 0 { + var err error + if apiKey, err = uuid.Parse(paramWebKeyA); err != nil { + os.Exit(core.ExitParamApiKeyInvalid) + } + } + + return strings.Split(paramWebapi, ","), apiKey } // parseDuration is the same as time.ParseDuration without returning an error. Valid units are ms, s, m, h. For example "10s". diff --git a/Main.go b/Main.go index db99d14..bb30526 100644 --- a/Main.go +++ b/Main.go @@ -11,6 +11,7 @@ import ( "os" "github.com/PeernetOfficial/core" + "github.com/google/uuid" ) const configFile = "Config.yaml" @@ -21,12 +22,13 @@ var config struct { ErrorOutput int `yaml:"ErrorOutput"` // 0 = Log file (default), 1 = Command line, 2 = Log file + command line, 3 = None // API settings - APIListen []string `yaml:"APIListen"` // WebListen is in format IP:Port and declares where the web-interface should listen on. IP can also be ommitted to listen on any. - APIUseSSL bool `yaml:"APIUseSSL"` // Enables SSL. - APICertificateFile string `yaml:"APICertificateFile"` // This is the certificate received from the CA. This can also include the intermediate certificate from the CA. - APICertificateKey string `yaml:"APICertificateKey"` // This is the private key. - APITimeoutRead string `yaml:"APITimeoutRead"` // The maximum duration for reading the entire request, including the body. - APITimeoutWrite string `yaml:"APITimeoutWrite"` // The maximum duration before timing out writes of the response. This includes processing time and is therefore the max time any HTTP function may take. + APIListen []string `yaml:"APIListen"` // WebListen is in format IP:Port and declares where the web-interface should listen on. IP can also be ommitted to listen on any. + APIUseSSL bool `yaml:"APIUseSSL"` // Enables SSL. + APICertificateFile string `yaml:"APICertificateFile"` // This is the certificate received from the CA. This can also include the intermediate certificate from the CA. + APICertificateKey string `yaml:"APICertificateKey"` // This is the private key. + APITimeoutRead string `yaml:"APITimeoutRead"` // The maximum duration for reading the entire request, including the body. + APITimeoutWrite string `yaml:"APITimeoutWrite"` // The maximum duration before timing out writes of the response. This includes processing time and is therefore the max time any HTTP function may take. + APIKey uuid.UUID `yaml:"APIKey"` // API key. Empty UUID 00000000-0000-0000-0000-000000000000 = not used. } func init() { diff --git a/README.md b/README.md index 2044396..1edd0bd 100644 --- a/README.md +++ b/README.md @@ -52,18 +52,20 @@ The web API described in the [core library](https://github.com/PeernetOfficial/c As described in the linked specification, do not expose this API on the internet or local network, it allows sensitive operations such as deleting the private key and access to local files. It shall only be used by local clients on the same machine. Set the listen parameter only to a loopback IP address such as `::1`. +API key authentication enforces the `x-api-key` header in each API request. + ### Option 1: Command Line Parameter -Specify the `webapi` parameter with an IP:Port to listen: +Specify the `webapi` parameter with an IP:Port to listen and a random API key (UUID) in `apikey`: ``` -Cmd -webapi=[::1]:1234 +Cmd -webapi=[::1]:1234 -apikey=a30c01eb-856c-4b79-bdde-3c56a248f71b ``` Multiple addresses can be specified by separating them with a comma: ``` -Cmd -webapi=127.0.0.1:1337,[::1]:1234 +Cmd -webapi=127.0.0.1:1337,[::1]:1234 -apikey=a30c01eb-856c-4b79-bdde-3c56a248f71b ``` Note that the command line parameter does not support the SSL and timeout settings. The API settings in the config file are ignored in case the command line parameter is specified. @@ -72,8 +74,11 @@ Note that the command line parameter does not support the SSL and timeout settin In the `Config.yaml` specify the below line. The `APIListen` is a list of IP:Port pairs. IPv4 and IPv6 are supported. The SSL and timeout settings are optional. If the timeouts are not specified, they are not used. Valid units for the timeout settings are ms, s, m, h. +API key authentication can be disabled by specifying a null UUID (= `00000000-0000-0000-0000-000000000000`) in the config which may be useful for development purposes, but should never be disabled in production. + ```yaml -APIListen: ["127.0.0.1:112","[::1]:112"] +APIListen: ["127.0.0.1:112","[::1]:112"] +APIKey: "a30c01eb-856c-4b79-bdde-3c56a248f71b" # optional enable SSL APIUseSSL: true diff --git a/go.mod b/go.mod index ea5082c..8009265 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/PeernetOfficial/Cmd go 1.16 require ( - github.com/PeernetOfficial/core v0.0.0-20211115020024-d06c2e0b1a65 + github.com/PeernetOfficial/core v0.0.0-20211116210418-83e6e5fb62f3 + github.com/google/uuid v1.3.0 github.com/gorilla/websocket v1.4.3-0.20210424162022-e8629af678b7 ) diff --git a/go.sum b/go.sum index a136447..d3e712c 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/PeernetOfficial/core v0.0.0-20211115020024-d06c2e0b1a65 h1:WD3/HFSv4+z/hxD5fAXrShgwbtcC8tigre3tQN9Ck8c= -github.com/PeernetOfficial/core v0.0.0-20211115020024-d06c2e0b1a65/go.mod h1:0D/jIDYdV0WXg5WACS+fR5keafLhYB89WUs6ZEE8t4Y= +github.com/PeernetOfficial/core v0.0.0-20211116210418-83e6e5fb62f3 h1:IzkdQYr/GNE4ejWs/oDYWT8VEjkXNAtB4TpQ+w5+Iy8= +github.com/PeernetOfficial/core v0.0.0-20211116210418-83e6e5fb62f3/go.mod h1:0D/jIDYdV0WXg5WACS+fR5keafLhYB89WUs6ZEE8t4Y= github.com/akrylysov/pogreb v0.10.1 h1:FqlR8VR7uCbJdfUob916tPM+idpKgeESDXOA1K0DK4w= github.com/akrylysov/pogreb v0.10.1/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=