mirror of
https://github.com/halverneus/static-file-server.git
synced 2024-11-24 09:05:30 +00:00
Added ability to set minimum TLS version. Updated compiler version. Minor code clean-up. Added funding info.
This commit is contained in:
parent
7d738d7188
commit
ea0bcf28bb
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
github: halverneus
|
@ -1,9 +1,9 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
## GO BUILDER
|
## GO BUILDER
|
||||||
################################################################################
|
################################################################################
|
||||||
FROM golang:1.16.5 as builder
|
FROM golang:1.17.2 as builder
|
||||||
|
|
||||||
ENV VERSION 1.8.4
|
ENV VERSION 1.8.5
|
||||||
ENV BUILD_DIR /build
|
ENV BUILD_DIR /build
|
||||||
|
|
||||||
RUN mkdir -p ${BUILD_DIR}
|
RUN mkdir -p ${BUILD_DIR}
|
||||||
@ -36,5 +36,5 @@ LABEL life.apets.vendor="Halverneus" \
|
|||||||
life.apets.url="https://github.com/halverneus/static-file-server" \
|
life.apets.url="https://github.com/halverneus/static-file-server" \
|
||||||
life.apets.name="Static File Server" \
|
life.apets.name="Static File Server" \
|
||||||
life.apets.description="A tiny static file server" \
|
life.apets.description="A tiny static file server" \
|
||||||
life.apets.version="v1.8.4" \
|
life.apets.version="v1.8.5" \
|
||||||
life.apets.schema-version="1.0"
|
life.apets.schema-version="1.0"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
FROM golang:1.16.5 as builder
|
FROM golang:1.17.2 as builder
|
||||||
|
|
||||||
ENV VERSION 1.8.4
|
ENV VERSION 1.8.5
|
||||||
ENV BUILD_DIR /build
|
ENV BUILD_DIR /build
|
||||||
|
|
||||||
RUN mkdir -p ${BUILD_DIR}
|
RUN mkdir -p ${BUILD_DIR}
|
||||||
@ -21,5 +21,5 @@ LABEL life.apets.vendor="Halverneus" \
|
|||||||
life.apets.url="https://github.com/halverneus/static-file-server" \
|
life.apets.url="https://github.com/halverneus/static-file-server" \
|
||||||
life.apets.name="Static File Server" \
|
life.apets.name="Static File Server" \
|
||||||
life.apets.description="A tiny static file server" \
|
life.apets.description="A tiny static file server" \
|
||||||
life.apets.version="v1.8.4" \
|
life.apets.version="v1.8.5" \
|
||||||
life.apets.schema-version="1.0"
|
life.apets.schema-version="1.0"
|
||||||
|
14
README.md
14
README.md
@ -1,5 +1,12 @@
|
|||||||
# static-file-server
|
# static-file-server
|
||||||
|
|
||||||
|
<a href="https://github.com/sponsors/halverneus" style="background-color:#fff;color:#000;padding:3px 12px;font-size:12px;border-color:#000;border:1px solid;border-radius:6px;box-sizing:border-box;line-height:20px;display:inline-block;">
|
||||||
|
<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" style="vertical-align: middle; margin-right:4px;color:#f00;">
|
||||||
|
<path fill-rule="evenodd" style="color:#f00;fill: currentColor;" d="M4.25 2.5c-1.336 0-2.75 1.164-2.75 3 0 2.15 1.58 4.144 3.365 5.682A20.565 20.565 0 008 13.393a20.561 20.561 0 003.135-2.211C12.92 9.644 14.5 7.65 14.5 5.5c0-1.836-1.414-3-2.75-3-1.373 0-2.609.986-3.029 2.456a.75.75 0 01-1.442 0C6.859 3.486 5.623 2.5 4.25 2.5zM8 14.25l-.345.666-.002-.001-.006-.003-.018-.01a7.643 7.643 0 01-.31-.17 22.075 22.075 0 01-3.434-2.414C2.045 10.731 0 8.35 0 5.5 0 2.836 2.086 1 4.25 1 5.797 1 7.153 1.802 8 3.02 8.847 1.802 10.203 1 11.75 1 13.914 1 16 2.836 16 5.5c0 2.85-2.045 5.231-3.885 6.818a22.08 22.08 0 01-3.744 2.584l-.018.01-.006.003h-.002L8 14.25zm0 0l.345.666a.752.752 0 01-.69 0L8 14.25z"></path>
|
||||||
|
</svg>
|
||||||
|
<span style="color:#000">Buy me a Smoothie</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
Tiny, simple static file server using environment variables for configuration.
|
Tiny, simple static file server using environment variables for configuration.
|
||||||
@ -47,6 +54,12 @@ URL_PREFIX=
|
|||||||
TLS_CERT=
|
TLS_CERT=
|
||||||
TLS_KEY=
|
TLS_KEY=
|
||||||
|
|
||||||
|
# If TLS certificates are set then the minimum TLS version may also be set. If
|
||||||
|
# the value isn't set then the default minimum TLS version is 1.0. Allowed
|
||||||
|
# values include "TLS10", "TLS11", "TLS12" and "TLS13" for TLS1.0, TLS1.1,
|
||||||
|
# TLS1.2 and TLS1.3, respectively. The value is not case-sensitive.
|
||||||
|
TLS_MIN_VERS=
|
||||||
|
|
||||||
# List of accepted HTTP referrers. Return 403 if HTTP header `Referer` does not
|
# List of accepted HTTP referrers. Return 403 if HTTP header `Referer` does not
|
||||||
# match prefixes provided in the list.
|
# match prefixes provided in the list.
|
||||||
# Examples:
|
# Examples:
|
||||||
@ -73,6 +86,7 @@ referrers: []
|
|||||||
show-listing: true
|
show-listing: true
|
||||||
tls-cert: ""
|
tls-cert: ""
|
||||||
tls-key: ""
|
tls-key: ""
|
||||||
|
tls-min-vers: ""
|
||||||
url-prefix: ""
|
url-prefix: ""
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -75,6 +75,10 @@ ENVIRONMENT VARIABLES
|
|||||||
Path to the TLS key file to serve files using HTTPS. If supplied then
|
Path to the TLS key file to serve files using HTTPS. If supplied then
|
||||||
TLS_CERT must also be supplied. If not supplied, contents will be served
|
TLS_CERT must also be supplied. If not supplied, contents will be served
|
||||||
via HTTPS
|
via HTTPS
|
||||||
|
TLS_MIN_VERS
|
||||||
|
The minimum TLS version to use. If not supplied, defaults to TLS1.0.
|
||||||
|
Acceptable values are 'TLS10', 'TLS11', 'TLS12' and 'TLS13' for TLS1.0,
|
||||||
|
TLS1.1, TLS1.2 and TLS1.3, respectively. Values are not case-sensitive.
|
||||||
URL_PREFIX
|
URL_PREFIX
|
||||||
The prefix to use in the URL path. If supplied, then the prefix must
|
The prefix to use in the URL path. If supplied, then the prefix must
|
||||||
start with a forward-slash and NOT end with a forward-slash. If not
|
start with a forward-slash and NOT end with a forward-slash. If not
|
||||||
@ -98,6 +102,7 @@ CONFIGURATION FILE
|
|||||||
show-listing: true
|
show-listing: true
|
||||||
tls-cert: ""
|
tls-cert: ""
|
||||||
tls-key: ""
|
tls-key: ""
|
||||||
|
tls-min-vers: ""
|
||||||
url-prefix: ""
|
url-prefix: ""
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -150,6 +155,7 @@ USAGE
|
|||||||
export PORT=443
|
export PORT=443
|
||||||
export TLS_CERT=/etc/server/my.machine.crt
|
export TLS_CERT=/etc/server/my.machine.crt
|
||||||
export TLS_KEY=/etc/server/my.machine.key
|
export TLS_KEY=/etc/server/my.machine.key
|
||||||
|
export TLS_MIN_VERS=TLS12
|
||||||
static-file-server
|
static-file-server
|
||||||
Retrieve with: wget https://my.machine/my.file
|
Retrieve with: wget https://my.machine/my.file
|
||||||
|
|
||||||
|
@ -76,6 +76,7 @@ func listenerSelector() (listener handle.ListenerFunc) {
|
|||||||
// Serve files over HTTP or HTTPS based on paths to TLS files being
|
// Serve files over HTTP or HTTPS based on paths to TLS files being
|
||||||
// provided.
|
// provided.
|
||||||
if 0 < len(config.Get.TLSCert) {
|
if 0 < len(config.Get.TLSCert) {
|
||||||
|
handle.SetMinimumTLSVersion(config.Get.TLSMinVers)
|
||||||
listener = handle.TLSListening(
|
listener = handle.TLSListening(
|
||||||
config.Get.TLSCert,
|
config.Get.TLSCert,
|
||||||
config.Get.TLSKey,
|
config.Get.TLSKey,
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
@ -14,16 +16,18 @@ import (
|
|||||||
var (
|
var (
|
||||||
// Get the desired configuration value.
|
// Get the desired configuration value.
|
||||||
Get struct {
|
Get struct {
|
||||||
Cors bool `yaml:"cors"`
|
Cors bool `yaml:"cors"`
|
||||||
Debug bool `yaml:"debug"`
|
Debug bool `yaml:"debug"`
|
||||||
Folder string `yaml:"folder"`
|
Folder string `yaml:"folder"`
|
||||||
Host string `yaml:"host"`
|
Host string `yaml:"host"`
|
||||||
Port uint16 `yaml:"port"`
|
Port uint16 `yaml:"port"`
|
||||||
ShowListing bool `yaml:"show-listing"`
|
ShowListing bool `yaml:"show-listing"`
|
||||||
TLSCert string `yaml:"tls-cert"`
|
TLSCert string `yaml:"tls-cert"`
|
||||||
TLSKey string `yaml:"tls-key"`
|
TLSKey string `yaml:"tls-key"`
|
||||||
URLPrefix string `yaml:"url-prefix"`
|
TLSMinVers uint16 `yaml:"-"`
|
||||||
Referrers []string `yaml:"referrers"`
|
TLSMinVersStr string `yaml:"tls-min-vers"`
|
||||||
|
URLPrefix string `yaml:"url-prefix"`
|
||||||
|
Referrers []string `yaml:"referrers"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,6 +41,7 @@ const (
|
|||||||
showListingKey = "SHOW_LISTING"
|
showListingKey = "SHOW_LISTING"
|
||||||
tlsCertKey = "TLS_CERT"
|
tlsCertKey = "TLS_CERT"
|
||||||
tlsKeyKey = "TLS_KEY"
|
tlsKeyKey = "TLS_KEY"
|
||||||
|
tlsMinVersKey = "TLS_MIN_VERS"
|
||||||
urlPrefixKey = "URL_PREFIX"
|
urlPrefixKey = "URL_PREFIX"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,6 +54,7 @@ var (
|
|||||||
defaultShowListing = true
|
defaultShowListing = true
|
||||||
defaultTLSCert = ""
|
defaultTLSCert = ""
|
||||||
defaultTLSKey = ""
|
defaultTLSKey = ""
|
||||||
|
defaultTLSMinVers = ""
|
||||||
defaultURLPrefix = ""
|
defaultURLPrefix = ""
|
||||||
defaultCors = false
|
defaultCors = false
|
||||||
)
|
)
|
||||||
@ -67,6 +73,7 @@ func setDefaults() {
|
|||||||
Get.ShowListing = defaultShowListing
|
Get.ShowListing = defaultShowListing
|
||||||
Get.TLSCert = defaultTLSCert
|
Get.TLSCert = defaultTLSCert
|
||||||
Get.TLSKey = defaultTLSKey
|
Get.TLSKey = defaultTLSKey
|
||||||
|
Get.TLSMinVersStr = defaultTLSMinVers
|
||||||
Get.URLPrefix = defaultURLPrefix
|
Get.URLPrefix = defaultURLPrefix
|
||||||
Get.Cors = defaultCors
|
Get.Cors = defaultCors
|
||||||
}
|
}
|
||||||
@ -74,7 +81,7 @@ func setDefaults() {
|
|||||||
// Load the configuration file.
|
// Load the configuration file.
|
||||||
func Load(filename string) (err error) {
|
func Load(filename string) (err error) {
|
||||||
// If no filename provided, assign envvars.
|
// If no filename provided, assign envvars.
|
||||||
if "" == filename {
|
if filename == "" {
|
||||||
overrideWithEnvVars()
|
overrideWithEnvVars()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -116,6 +123,7 @@ func overrideWithEnvVars() {
|
|||||||
Get.ShowListing = envAsBool(showListingKey, Get.ShowListing)
|
Get.ShowListing = envAsBool(showListingKey, Get.ShowListing)
|
||||||
Get.TLSCert = envAsStr(tlsCertKey, Get.TLSCert)
|
Get.TLSCert = envAsStr(tlsCertKey, Get.TLSCert)
|
||||||
Get.TLSKey = envAsStr(tlsKeyKey, Get.TLSKey)
|
Get.TLSKey = envAsStr(tlsKeyKey, Get.TLSKey)
|
||||||
|
Get.TLSMinVersStr = envAsStr(tlsMinVersKey, Get.TLSMinVersStr)
|
||||||
Get.URLPrefix = envAsStr(urlPrefixKey, Get.URLPrefix)
|
Get.URLPrefix = envAsStr(urlPrefixKey, Get.URLPrefix)
|
||||||
Get.Referrers = envAsStrSlice(referrersKey, Get.Referrers)
|
Get.Referrers = envAsStrSlice(referrersKey, Get.Referrers)
|
||||||
}
|
}
|
||||||
@ -123,8 +131,9 @@ func overrideWithEnvVars() {
|
|||||||
// validate the configuration.
|
// validate the configuration.
|
||||||
func validate() error {
|
func validate() error {
|
||||||
// If HTTPS is to be used, verify both TLS_* environment variables are set.
|
// If HTTPS is to be used, verify both TLS_* environment variables are set.
|
||||||
|
useTLS := false
|
||||||
if 0 < len(Get.TLSCert) || 0 < len(Get.TLSKey) {
|
if 0 < len(Get.TLSCert) || 0 < len(Get.TLSKey) {
|
||||||
if 0 == len(Get.TLSCert) || 0 == len(Get.TLSKey) {
|
if len(Get.TLSCert) == 0 || len(Get.TLSKey) == 0 {
|
||||||
msg := "if value for either 'TLS_CERT' or 'TLS_KEY' is set then " +
|
msg := "if value for either 'TLS_CERT' or 'TLS_KEY' is set then " +
|
||||||
"then value for the other must also be set (values are " +
|
"then value for the other must also be set (values are " +
|
||||||
"currently '%s' and '%s', respectively)"
|
"currently '%s' and '%s', respectively)"
|
||||||
@ -132,11 +141,30 @@ func validate() error {
|
|||||||
}
|
}
|
||||||
if _, err := os.Stat(Get.TLSCert); nil != err {
|
if _, err := os.Stat(Get.TLSCert); nil != err {
|
||||||
msg := "value of TLS_CERT is set with filename '%s' that returns %v"
|
msg := "value of TLS_CERT is set with filename '%s' that returns %v"
|
||||||
return fmt.Errorf(msg, err)
|
return fmt.Errorf(msg, Get.TLSCert, err)
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(Get.TLSKey); nil != err {
|
if _, err := os.Stat(Get.TLSKey); nil != err {
|
||||||
msg := "value of TLS_KEY is set with filename '%s' that returns %v"
|
msg := "value of TLS_KEY is set with filename '%s' that returns %v"
|
||||||
return fmt.Errorf(msg, err)
|
return fmt.Errorf(msg, Get.TLSKey, err)
|
||||||
|
}
|
||||||
|
useTLS = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify TLS_MIN_VERS is only (optionally) set if TLS is to be used.
|
||||||
|
Get.TLSMinVers = tls.VersionTLS10
|
||||||
|
if useTLS {
|
||||||
|
if 0 < len(Get.TLSMinVersStr) {
|
||||||
|
var err error
|
||||||
|
if Get.TLSMinVers, err = tlsMinVersAsUint16(
|
||||||
|
Get.TLSMinVersStr,
|
||||||
|
); nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if 0 < len(Get.TLSMinVersStr) {
|
||||||
|
msg := "value for 'TLS_MIN_VERS' is set but 'TLS_CERT' and 'TLS_KEY' are not"
|
||||||
|
return errors.New(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +182,7 @@ func validate() error {
|
|||||||
|
|
||||||
// envAsStr returns the value of the environment variable as a string if set.
|
// envAsStr returns the value of the environment variable as a string if set.
|
||||||
func envAsStr(key, fallback string) string {
|
func envAsStr(key, fallback string) string {
|
||||||
if value := os.Getenv(key); "" != value {
|
if value := os.Getenv(key); value != "" {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
return fallback
|
return fallback
|
||||||
@ -163,7 +191,7 @@ func envAsStr(key, fallback string) string {
|
|||||||
// envAsStrSlice returns the value of the environment variable as a slice of
|
// envAsStrSlice returns the value of the environment variable as a slice of
|
||||||
// strings if set.
|
// strings if set.
|
||||||
func envAsStrSlice(key string, fallback []string) []string {
|
func envAsStrSlice(key string, fallback []string) []string {
|
||||||
if value := os.Getenv(key); "" != value {
|
if value := os.Getenv(key); value != "" {
|
||||||
return strings.Split(value, ",")
|
return strings.Split(value, ",")
|
||||||
}
|
}
|
||||||
return fallback
|
return fallback
|
||||||
@ -174,7 +202,7 @@ func envAsUint16(key string, fallback uint16) uint16 {
|
|||||||
// Retrieve the string value of the environment variable. If not set,
|
// Retrieve the string value of the environment variable. If not set,
|
||||||
// fallback is used.
|
// fallback is used.
|
||||||
valueStr := os.Getenv(key)
|
valueStr := os.Getenv(key)
|
||||||
if "" == valueStr {
|
if valueStr == "" {
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +226,7 @@ func envAsBool(key string, fallback bool) bool {
|
|||||||
// Retrieve the string value of the environment variable. If not set,
|
// Retrieve the string value of the environment variable. If not set,
|
||||||
// fallback is used.
|
// fallback is used.
|
||||||
valueStr := os.Getenv(key)
|
valueStr := os.Getenv(key)
|
||||||
if "" == valueStr {
|
if valueStr == "" {
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,8 +253,26 @@ func strAsBool(value string) (result bool, err error) {
|
|||||||
result = true
|
result = true
|
||||||
default:
|
default:
|
||||||
result = false
|
result = false
|
||||||
msg := "Unknown conversion from string to bool for value '%s'"
|
msg := "unknown conversion from string to bool for value '%s'"
|
||||||
err = fmt.Errorf(msg, value)
|
err = fmt.Errorf(msg, value)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tlsMinVersAsUint16 converts the intent of the passed value into an
|
||||||
|
// enumeration for the crypto/tls package.
|
||||||
|
func tlsMinVersAsUint16(value string) (result uint16, err error) {
|
||||||
|
switch strings.ToLower(value) {
|
||||||
|
case "tls10":
|
||||||
|
result = tls.VersionTLS10
|
||||||
|
case "tls11":
|
||||||
|
result = tls.VersionTLS11
|
||||||
|
case "tls12":
|
||||||
|
result = tls.VersionTLS12
|
||||||
|
case "tls13":
|
||||||
|
result = tls.VersionTLS13
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("unknown value for TLS_MIN_VERS: %s", value)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -160,27 +161,33 @@ func TestValidate(t *testing.T) {
|
|||||||
cert string
|
cert string
|
||||||
key string
|
key string
|
||||||
prefix string
|
prefix string
|
||||||
|
minTLS string
|
||||||
isError bool
|
isError bool
|
||||||
}{
|
}{
|
||||||
{"Valid paths w/prefix", validPath, validPath, prefix, false},
|
{"Valid paths w/prefix", validPath, validPath, prefix, "", false},
|
||||||
{"Valid paths wo/prefix", validPath, validPath, empty, false},
|
{"Valid paths wo/prefix", validPath, validPath, empty, "", false},
|
||||||
{"Empty paths w/prefix", empty, empty, prefix, false},
|
{"Empty paths w/prefix", empty, empty, prefix, "", false},
|
||||||
{"Empty paths wo/prefix", empty, empty, empty, false},
|
{"Empty paths wo/prefix", empty, empty, empty, "", false},
|
||||||
{"Mixed paths w/prefix", empty, validPath, prefix, true},
|
{"Mixed paths w/prefix", empty, validPath, prefix, "", true},
|
||||||
{"Alt mixed paths w/prefix", validPath, empty, prefix, true},
|
{"Alt mixed paths w/prefix", validPath, empty, prefix, "", true},
|
||||||
{"Mixed paths wo/prefix", empty, validPath, empty, true},
|
{"Mixed paths wo/prefix", empty, validPath, empty, "", true},
|
||||||
{"Alt mixed paths wo/prefix", validPath, empty, empty, true},
|
{"Alt mixed paths wo/prefix", validPath, empty, empty, "", true},
|
||||||
{"Invalid cert w/prefix", invalidPath, validPath, prefix, true},
|
{"Invalid cert w/prefix", invalidPath, validPath, prefix, "", true},
|
||||||
{"Invalid key w/prefix", validPath, invalidPath, prefix, true},
|
{"Invalid key w/prefix", validPath, invalidPath, prefix, "", true},
|
||||||
{"Invalid cert & key w/prefix", invalidPath, invalidPath, prefix, true},
|
{"Invalid cert & key w/prefix", invalidPath, invalidPath, prefix, "", true},
|
||||||
{"Prefix missing leading /", empty, empty, "my/prefix", true},
|
{"Prefix missing leading /", empty, empty, "my/prefix", "", true},
|
||||||
{"Prefix with trailing /", empty, empty, "/my/prefix/", true},
|
{"Prefix with trailing /", empty, empty, "/my/prefix/", "", true},
|
||||||
|
{"Valid paths w/min ok TLS", validPath, validPath, prefix, "tls11", false},
|
||||||
|
{"Valid paths w/min bad TLS", validPath, validPath, prefix, "bad", true},
|
||||||
|
{"Empty paths w/min ok TLS", empty, empty, prefix, "tls11", true},
|
||||||
|
{"Empty paths w/min bad TLS", empty, empty, prefix, "bad", true},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
Get.TLSCert = tc.cert
|
Get.TLSCert = tc.cert
|
||||||
Get.TLSKey = tc.key
|
Get.TLSKey = tc.key
|
||||||
|
Get.TLSMinVersStr = tc.minTLS
|
||||||
Get.URLPrefix = tc.prefix
|
Get.URLPrefix = tc.prefix
|
||||||
err := validate()
|
err := validate()
|
||||||
hasError := nil != err
|
hasError := nil != err
|
||||||
@ -461,3 +468,42 @@ func TestStrAsBool(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTlsMinVersAsUint16(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
result uint16
|
||||||
|
isError bool
|
||||||
|
}{
|
||||||
|
{"Empty value", "", 0, true},
|
||||||
|
{"Valid TLS1.0", "TLS10", tls.VersionTLS10, false},
|
||||||
|
{"Valid TLS1.1", "tls11", tls.VersionTLS11, false},
|
||||||
|
{"Valid TLS1.2", "tls12", tls.VersionTLS12, false},
|
||||||
|
{"Valid TLS1.3", "tLS13", tls.VersionTLS13, false},
|
||||||
|
{"Invalid TLS1.4", "tls14", 0, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result, err := tlsMinVersAsUint16(tc.value)
|
||||||
|
if result != tc.result {
|
||||||
|
t.Errorf(
|
||||||
|
"Expected %d for %s but got %d",
|
||||||
|
tc.result, tc.value, result,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if tc.isError && nil == err {
|
||||||
|
t.Errorf(
|
||||||
|
"Expected error for %s but got no error",
|
||||||
|
tc.value,
|
||||||
|
)
|
||||||
|
} else if !tc.isError && nil != err {
|
||||||
|
t.Errorf(
|
||||||
|
"Expected no error for %s but got %v",
|
||||||
|
tc.value, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package handle
|
package handle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -10,14 +11,46 @@ import (
|
|||||||
var (
|
var (
|
||||||
// These assignments are for unit testing.
|
// These assignments are for unit testing.
|
||||||
listenAndServe = http.ListenAndServe
|
listenAndServe = http.ListenAndServe
|
||||||
listenAndServeTLS = http.ListenAndServeTLS
|
listenAndServeTLS = defaultListenAndServeTLS
|
||||||
setHandler = http.HandleFunc
|
setHandler = http.HandleFunc
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
server http.Server
|
// Server options to be set prior to calling the listening function.
|
||||||
|
// minTLSVersion is the minimum allowed TLS version to be used by the
|
||||||
|
// server.
|
||||||
|
minTLSVersion uint16 = tls.VersionTLS10
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// defaultListenAndServeTLS is the default implementation of the listening
|
||||||
|
// function for serving with TLS enabled. This is, effectively, a copy from
|
||||||
|
// the standard library but with the ability to set the minimum TLS version.
|
||||||
|
func defaultListenAndServeTLS(
|
||||||
|
binding, certFile, keyFile string, handler http.Handler,
|
||||||
|
) error {
|
||||||
|
if handler == nil {
|
||||||
|
handler = http.DefaultServeMux
|
||||||
|
}
|
||||||
|
server := &http.Server{
|
||||||
|
Addr: binding,
|
||||||
|
Handler: handler,
|
||||||
|
TLSConfig: &tls.Config{
|
||||||
|
MinVersion: minTLSVersion,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return server.ListenAndServeTLS(certFile, keyFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMinimumTLSVersion to be used by the server.
|
||||||
|
func SetMinimumTLSVersion(version uint16) {
|
||||||
|
if version < tls.VersionTLS10 {
|
||||||
|
version = tls.VersionTLS10
|
||||||
|
} else if version > tls.VersionTLS13 {
|
||||||
|
version = tls.VersionTLS13
|
||||||
|
}
|
||||||
|
minTLSVersion = version
|
||||||
|
}
|
||||||
|
|
||||||
// ListenerFunc accepts the {hostname:port} binding string required by HTTP
|
// ListenerFunc accepts the {hostname:port} binding string required by HTTP
|
||||||
// listeners and the handler (router) function and returns any errors that
|
// listeners and the handler (router) function and returns any errors that
|
||||||
// occur.
|
// occur.
|
||||||
@ -50,7 +83,7 @@ func WithReferrers(serveFile FileServerFunc, referrers []string) FileServerFunc
|
|||||||
func WithLogging(serveFile FileServerFunc) FileServerFunc {
|
func WithLogging(serveFile FileServerFunc) FileServerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request, name string) {
|
return func(w http.ResponseWriter, r *http.Request, name string) {
|
||||||
referer := r.Referer()
|
referer := r.Referer()
|
||||||
if 0 == len(referer) {
|
if len(referer) == 0 {
|
||||||
log.Printf(
|
log.Printf(
|
||||||
"REQ from '%s': %s %s %s%s -> %s\n",
|
"REQ from '%s': %s %s %s%s -> %s\n",
|
||||||
r.RemoteAddr,
|
r.RemoteAddr,
|
||||||
@ -139,7 +172,7 @@ func TLSListening(tlsCert, tlsKey string) ListenerFunc {
|
|||||||
// passed list of referrers.
|
// passed list of referrers.
|
||||||
func validReferrer(s []string, e string) bool {
|
func validReferrer(s []string, e string) bool {
|
||||||
// Whitelisted referer list is empty. All requests are allowed.
|
// Whitelisted referer list is empty. All requests are allowed.
|
||||||
if 0 == len(s) {
|
if len(s) == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package handle
|
package handle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
@ -84,6 +85,28 @@ func teardown() (err error) {
|
|||||||
return os.RemoveAll("tmp")
|
return os.RemoveAll("tmp")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetMinimumTLSVersion(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
value uint16
|
||||||
|
expected uint16
|
||||||
|
}{
|
||||||
|
{"Too low", tls.VersionTLS10 - 1, tls.VersionTLS10},
|
||||||
|
{"Lower bounds", tls.VersionTLS10, tls.VersionTLS10},
|
||||||
|
{"Upper bounds", tls.VersionTLS13, tls.VersionTLS13},
|
||||||
|
{"Too high", tls.VersionTLS13 + 1, tls.VersionTLS13},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
SetMinimumTLSVersion(tc.value)
|
||||||
|
if tc.expected != minTLSVersion {
|
||||||
|
t.Errorf("Expected %d but got %d", tc.expected, minTLSVersion)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestWithReferrers(t *testing.T) {
|
func TestWithReferrers(t *testing.T) {
|
||||||
forbidden := http.StatusForbidden
|
forbidden := http.StatusForbidden
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user