diff --git a/FAQ.md b/FAQ.md index 73ec365..f1b3ccb 100644 --- a/FAQ.md +++ b/FAQ.md @@ -20,7 +20,10 @@ Yes, MediaWEB only allows read access of media files whithin your media folder. * Access non-media files within your media folder * Access any file outside of your media folder -If you protect your content using a username and password (enable in mediaweb.conf) you should enable TLS/HTTPS (separate server as proxy is currently needed), otherwise it would be possible to sniff the network for your username and password. +If you protect your content using a username and password (enable in mediaweb.conf) you should enable TLS/HTTPS, +otherwise it would be possible to sniff the network for your username and password. + +See [README](README.md) for how to enable authentication and TLS/HTTPS. ## How do I view my media? diff --git a/README.md b/README.md index d8f8ffe..e1b29fe 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,9 @@ Interface suited for mobile devices * Thumbnail support for images and videos, primary by reading of EXIF thumbnail if it exist, otherwise thumbnails will be created and stored in a thumbnail cache. Video thumbnails requires [ffmpeg](https://www.ffmpeg.org/) to be installed * Automatic rotation JPEG images when needed (based on EXIF information) * Generate thumbnails on the fly, on start-up and/or when new files are added to the media directory -* **NEW!** Automatically resize images to reduce network bandwidth and get a smoother navigation at client +* Automatically resize images to reduce network bandwidth and get a smoother navigation at client * Optional authentication with username and password +* **NEW!** Support for both HTTP and encryption using HTTPS (TLS) ## Download and install Linux @@ -250,10 +251,27 @@ out with the *cachepath* has enough disk space. Also, if you have many images and are running on an SBC it might take very, very long time the first time the images are resized. Count with several days. +### Enable encryption with TLS (HTTPS) and password protection -## Future improvements +By default MediaWEB will use the standard open HTTP protocol without +any authentication. If you decide to add authentication you should +always enable encryption using TLS (HTTPS). If you don't do this +it would be possible to sniff the network and get your user name +and password. -* Add support for TLS/SSL + username = myusername + password = mypassword + tlscertfile = public.crt + tlskeyfile = private.key + +OpenSSL can be used to generate the public and private key: + + openssl genrsa -out private.key 2048 + openssl req -new -x509 -sha256 -key private.key -out public.crt -days 3650 + +The above key is self signed, which basically means that your browser +won't trust it by default, but you can always ignore the warnings +in your browser. The link will still be secure. ## Author and license diff --git a/configs/example.crt b/configs/example.crt new file mode 100644 index 0000000..38674ae --- /dev/null +++ b/configs/example.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDYDCCAkigAwIBAgIJANn5CV2NXnnlMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAlNFMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMjAwNjA3MTgzNDI3WhcNMzAwNjA1MTgzNDI3WjBF +MQswCQYDVQQGEwJTRTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAxE1tZNyhjLUBH19LcALeYUpi3WVLVAvXh/ohXftVvJIpKgbM2l6xeAFD ++N5dR+N3qcgUm4cQZ2jJPx9vpAeIQZT6siH2ySaMUp7UQE8Kt9t6GH5x6mC7nShG ++clLE3AKJaG5TyyNccHIX9dAt3wlYWho8L76kXFOn2+v2hBKUy7Vyhn27hJlDBOY +iCWj5WkrcF/6mEmKUtxY1NTe+BpkCNddMVtXsFH5GC6XV/4x83KhnJak7IRPGn1e +ueiu3KbCafwJXHbgZWBIkfVmdnDUGYQvyeKrAiLkAqvNrV3zl8FRrW+k8LBHVbEa +zyDfHW3VxG+6IGLX+S9Q+l4vgeZGxwIDAQABo1MwUTAdBgNVHQ4EFgQUsBZUbZN+ +3Bx+XylnZw7bT8f3ruIwHwYDVR0jBBgwFoAUsBZUbZN+3Bx+XylnZw7bT8f3ruIw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAbZx9ns6EFEnv5cXL +K1fj6WG0Oq9w5MFWElaNOTtNcTop1lFuat2fl2TWgsR/FK9u/13IZWqRGTmE97AZ +WGyk9sRl6kF0ilApeiofTzJmDQ00VH06h6ouZgvd41TkVeLrC3WRVynizGIiGmXD +G2pvVocLfS9wRCRabvvkHQbJxrOAW8OEqvb9Xy4YVTS7NnkvW6ZUarSfrNsJBf5w +HO6OI8+py+a41sH8wugg31L8cDvo3uCoPSPocjU7kJtmNaWjSDkT1cXWWm5P4zKG +qMprN/4CvZBkJukrd77h7Aj7szuJdoDwMqi48BARtfnkGDMf1CbraN2KdFcwpg1d +hJCgtA== +-----END CERTIFICATE----- diff --git a/configs/example.key b/configs/example.key new file mode 100644 index 0000000..bdf3560 --- /dev/null +++ b/configs/example.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAxE1tZNyhjLUBH19LcALeYUpi3WVLVAvXh/ohXftVvJIpKgbM +2l6xeAFD+N5dR+N3qcgUm4cQZ2jJPx9vpAeIQZT6siH2ySaMUp7UQE8Kt9t6GH5x +6mC7nShG+clLE3AKJaG5TyyNccHIX9dAt3wlYWho8L76kXFOn2+v2hBKUy7Vyhn2 +7hJlDBOYiCWj5WkrcF/6mEmKUtxY1NTe+BpkCNddMVtXsFH5GC6XV/4x83KhnJak +7IRPGn1eueiu3KbCafwJXHbgZWBIkfVmdnDUGYQvyeKrAiLkAqvNrV3zl8FRrW+k +8LBHVbEazyDfHW3VxG+6IGLX+S9Q+l4vgeZGxwIDAQABAoIBAFkF6Bt6t0TRfV3V +4Kc+lc03Z9iRrHTEHg2LkQBHEB3BhyuJA/PwR7ltkX7WkSUd8lGr7DSQLw9GhSW8 +Quv3goKDZqHMJ1gXxEFfyFAVyH2S6i8bgNvS3KKr9mwnLoX1JJTmX9yZDthNEmrs +emv7wBQJvrWXVpkI8qf5hZ12D87ivjpZPiTgET9l9Iz8tGaT+0DU5gMx7V9XuVxB +5vGGZOl/AROVhste1ZRCY84r4+A9xksKjPPwjTTE+2KJWDpOmIgZsjipXQ2dRMbQ +hUHVMt8DozLa28RlKUDmMQ/raeXZrmsyswMRziM1NgWxrRfXLWAWPbXmMvpPDp/k +MCze3ukCgYEA4eFjx1N6RRyZ3hM5dT7k6LJ+qqCMhndrsJjSLw9uWXkNaEfi6NOG +Q/xj/aQIAy0mqKEFJ6ku0StBNvcFY9mcwq9GJ2OUIR/yPHM0e6Bl+zbt9V+MlB2c +8w4AwwJZEdFU6HyzMrkGUUQInZqaPjDLFBHoLqTMuEgao2Ip0YUGAnsCgYEA3npe +lUI38i9670ZbK/GCtABdruMTQaxrIUDdwEDlhglIO75shHUPBZvkBtbJ1OsHCN4R +kjlSH3E8aZJ08sL3GAWX//p0+t4m59S8WgG3mdMEmVTLKG1tAiOXHn7GvwSBEEiT +vLv5/KQTMvDg6GuJBI+sl86wjQa9udxLn3MNUSUCgYAXOgj7jx7simNcDZgD8WKy +duBFhVrN3OvK7fv28NxFAQia54FytYWB6isSAtL8GKF4B46zJFd3FL6Q+1eni9Ht +xv4swLWTrmhHRQVpjPXPnjdb2uZmuKDR8Wespcoo5eCYQ3Jdzd7Tbm6AXkxsBrJr +Lug0G6gdbvSmRkrMi6QxjwKBgDubf7Hv7vtle0OWjyDj8Uf2/SK5VlR3NLDRJ1i2 +Soix/fd72qlWj7LKBLtMWwFAAz99+Ck8UGN6PFxw0AKm9/sorIP5/9OjJ7tfhSN8 +aEu/fPD0BgaL4vP6wyd5ghh1xXquZ17e4mitMTOp1CiRf0GImQ6HY0g1sSmV+3D6 +K2w9AoGAeIhCMXA8+k7fB/89keUNxODlAY+edk8H/IW0pnX0ljXdOt+XguImcFxE +V3/PM6FtHNFV0TWM3YSl3Ot6iPuM2+IF1gNVuxDvgGzhoiCQOivpL9UB+PwweoOq +gPIzosENPxsC2oeaMwJkPXTD2VUX/wJl6j+dNIETWfrlJjqPDIU= +-----END RSA PRIVATE KEY----- diff --git a/configs/mediaweb.conf b/configs/mediaweb.conf index 3a266aa..e44d1e1 100644 --- a/configs/mediaweb.conf +++ b/configs/mediaweb.conf @@ -6,6 +6,11 @@ # This parameter is MANDATORY port = 9834 +# Network inteface to listen to. +# If parameter is not set, the server will listen to +# all interfaces. +#ip = 127.0.0.1 + # Media path, i.e. where is your media located # This parameter is MANADTORY # @@ -18,9 +23,11 @@ mediapath = pictures # temp folder + mediaweb. Cache path is where # thumbnails and preview images are stored. # +# Is not allowed to be the same as mediapath. +# # For example: -# mediapath = /home/fobar/cache/mediaweb -# mediapath = c:\users\fobar\cache\mediaweb +# cachepath = /home/fobar/cache/mediaweb +# cachepath = c:\users\fobar\cache\mediaweb #cachepath = tmpcache # Thumb cache is by default on. Uncomment below to @@ -87,3 +94,14 @@ mediapath = pictures #username = myusername #password = mypassword +# User name and password for authentication. Leave commented +# for no authentication +#username = myusername +#password = mypassword + +# TLS (HTTPS) certification file and key file. Leave commented +# for no encryption (HTTP). If both parameters are set TlS +# will be enabled. +#tlscertfile = public.crt +#tlskeyfile = private.key + diff --git a/main_common.go b/main_common.go index 95e9026..b349798 100644 --- a/main_common.go +++ b/main_common.go @@ -20,6 +20,7 @@ func mainCommon() *WebAPI { s.enableThumbCache, s.genThumbsOnStartup, s.genThumbsOnAdd, s.autoRotate, s.enablePreview, s.previewMaxSide, s.genPreviewOnStartup, s.genPreviewOnAdd) - webAPI := CreateWebAPI(s.port, "templates", media, box, s.userName, s.password) + webAPI := CreateWebAPI(s.port, s.ip, "templates", media, box, + s.userName, s.password, s.tlsCertFile, s.tlsKeyFile) return webAPI } diff --git a/mediaweb.conf b/mediaweb.conf index 4307817..ed9e1e3 100644 --- a/mediaweb.conf +++ b/mediaweb.conf @@ -6,6 +6,11 @@ # This parameter is MANDATORY port = 9834 +# Network inteface to listen to. +# If parameter is not set, the server will listen to +# all interfaces. +#ip = 127.0.0.1 + # Media path, i.e. where is your media located # This parameter is MANADTORY # @@ -18,9 +23,11 @@ mediapath = testmedia # temp folder + mediaweb. Cache path is where # thumbnails and preview images are stored. # +# Is not allowed to be the same as mediapath. +# # For example: -# mediapath = /home/fobar/cache/mediaweb -# mediapath = c:\users\fobar\cache\mediaweb +# cachepath = /home/fobar/cache/mediaweb +# cachepath = c:\users\fobar\cache\mediaweb cachepath = tmpcache # Thumb cache is by default on. Uncomment below to @@ -86,3 +93,9 @@ cachepath = tmpcache #username = myusername #password = mypassword +# TLS (HTTPS) certification file and key file. Leave commented +# for no encryption (HTTP). If both parameters are set TlS +# will be enabled. +#tlscertfile = public.crt +#tlskeyfile = private.key + diff --git a/scripts/windows_installer.nsi b/scripts/windows_installer.nsi index c7c7ab4..5496e9b 100644 --- a/scripts/windows_installer.nsi +++ b/scripts/windows_installer.nsi @@ -175,6 +175,11 @@ Section "${APPLICATION_NAME}" SectionMain FileWrite $4 "# This parameter is MANDATORY$\r$\n" FileWrite $4 "port = 9834$\r$\n" FileWrite $4 "$\r$\n" + FileWrite $4 "# Network inteface to listen to.$\r$\n" + FileWrite $4 "# If parameter is not set, the server will listen to$\r$\n" + FileWrite $4 "# all interfaces.$\r$\n" + FileWrite $4 "#ip = 127.0.0.1$\r$\n" + FileWrite $4 "$\r$\n" FileWrite $4 "# Media path, i.e. where is your media located$\r$\n" FileWrite $4 "# This parameter is MANADTORY$\r$\n" FileWrite $4 "mediapath = $0$\r$\n" @@ -182,6 +187,9 @@ Section "${APPLICATION_NAME}" SectionMain FileWrite $4 "# Cache path is by default your operating systems$\r$\n" FileWrite $4 "# temp folder + mediaweb. Cache path is where$\r$\n" FileWrite $4 "# thumbnails and preview images are stored.$\r$\n" + FileWrite $4 "#$\r$\n" + FileWrite $4 "# Is not allowed to be the same as mediapath.$\r$\n" + FileWrite $4 "#$\r$\n" FileWrite $4 "#cachepath =$\r$\n" FileWrite $4 "$\r$\n" FileWrite $4 "# Thumbnail cache is on by default$\r$\n" @@ -242,6 +250,13 @@ Section "${APPLICATION_NAME}" SectionMain FileWrite $4 "# for no authentication$\r$\n" FileWrite $4 "#username = myusername$\r$\n" FileWrite $4 "#password = mypassword$\r$\n" + FileWrite $4 "$\r$\n" + FileWrite $4 "# TLS (HTTPS) certification file and key file. Leave commented\r$\n" + FileWrite $4 "# for no encryption (HTTP). If both parameters are set TlS\r$\n" + FileWrite $4 "# will be enabled.\r$\n" + FileWrite $4 "#tlscertfile = public.crt\r$\n" + FileWrite $4 "#tlskeyfile = private.key\r$\n" + FileWrite $4 "$\r$\n" FileClose $4 diff --git a/settings.go b/settings.go index f1680c4..3cf83a2 100644 --- a/settings.go +++ b/settings.go @@ -11,6 +11,7 @@ import ( type settings struct { port int // Network port + ip string // Network IP ("" means any) mediaPath string // Top level path for media files cachePath string // Top level path for cache (thumbs and preview) enableThumbCache bool // Generate thumbnails @@ -25,6 +26,8 @@ type settings struct { logFile string // Log file ("" means stderr) userName string // User name ("" means no authentication) password string // Password + tlsCertFile string // TLS certification file + tlsKeyFile string // TLS key file } // defaultConfPath holds configuration file paths in priority order @@ -69,6 +72,11 @@ func loadSettings(fileName string) settings { } result.port = port + // Load IP (OPTIONAL) + // Default: "" + ip := config.GetString("ip", "") + result.ip = ip + // Load mediaPath (MANDATORY) if !config.HasKey("mediapath") { llog.Panic("Mandatory property 'mediapath' is not defined in %s", fileName) @@ -93,6 +101,11 @@ func loadSettings(fileName string) settings { } } + // Check that mediapath and cachepath are not the same + if pathEquals(result.mediaPath, result.cachePath) { + llog.Panic("cachepath and mediapath have the same value '%s'", result.mediaPath) + } + // Load enableThumbCache (OPTIONAL) // Default: true enableThumbCache, err := config.GetBool("enablethumbcache", true) @@ -177,6 +190,16 @@ func loadSettings(fileName string) settings { password := config.GetString("password", "") result.password = password + // Load tlsCertFile (OPTIONAL) + // Default: "" + tlsCertFile := config.GetString("tlscertfile", "") + result.tlsCertFile = tlsCertFile + + // Load tlsKeyFile (OPTIONAL) + // Default: "" + tlsKeyFile := config.GetString("tlskeyfile", "") + result.tlsKeyFile = tlsKeyFile + return result } @@ -202,3 +225,11 @@ func toLogLvl(level string) llog.Level { return logLevel } + +func pathEquals(path1, path2 string) bool { + diffPath, err := filepath.Rel(path1, path2) + if err == nil && (diffPath == "" || diffPath == ".") { + return true + } + return false +} diff --git a/settings_test.go b/settings_test.go index 8637b6b..989dd2d 100644 --- a/settings_test.go +++ b/settings_test.go @@ -35,6 +35,9 @@ mediapath = Y:\pictures` assertEqualsStr(t, "logFile", "", s.logFile) assertEqualsStr(t, "userName", "", s.userName) assertEqualsStr(t, "password", "", s.password) + assertEqualsStr(t, "ip", "", s.ip) + assertEqualsStr(t, "tlsCertFile", "", s.tlsCertFile) + assertEqualsStr(t, "tlsKeyFile", "", s.tlsKeyFile) } @@ -42,6 +45,7 @@ func TestSettings(t *testing.T) { contents := ` port = 80 +ip = 192.168.1.2 mediapath = /media/usb/pictures cachepath = /tmp/thumb enablethumbcache = off @@ -56,6 +60,8 @@ loglevel = debug logfile = /tmp/log/mediaweb.log username = an_email@password.com password = A!#_q7*+ +tlscertfile = /file/my_cert_file.crt +tlskeyfile = /file/my_cert_file.key ` fullPath := createConfigFile(t, "TestSettings.conf", contents) s := loadSettings(fullPath) @@ -78,6 +84,9 @@ password = A!#_q7*+ assertEqualsStr(t, "logFile", "/tmp/log/mediaweb.log", s.logFile) assertEqualsStr(t, "userName", "an_email@password.com", s.userName) assertEqualsStr(t, "password", "A!#_q7*+", s.password) + assertEqualsStr(t, "ip", "192.168.1.2", s.ip) + assertEqualsStr(t, "tlsCertFile", "/file/my_cert_file.crt", s.tlsCertFile) + assertEqualsStr(t, "tlsKeyFile", "/file/my_cert_file.key", s.tlsKeyFile) } @@ -235,3 +244,27 @@ func TestFindConfFileMissing(t *testing.T) { findConfFile() // Shall panic t.Fatalf("Should have paniced here") } + + +func TestPathEquals(t *testing.T) { + assertTrue(t, "", pathEquals("adir", "adir")) + assertTrue(t, "", pathEquals("adir/anotherdir", "adir/anotherdir")) + assertTrue(t, "", pathEquals("adir/anotherdir", "adir/anotherdir/third/..")) + + assertFalse(t, "", pathEquals("adir", "bdir")) + assertFalse(t, "", pathEquals("sameroot/leaf1", "sameroot/leaf2")) + assertFalse(t, "", pathEquals("root1/leaf1", "root2/leaf1")) + assertFalse(t, "", pathEquals("/unix/u", "C:\\windows\\w")) +} + +func TestSettingsSameMediaAndCachePath(t *testing.T) { + contents := + ` +port = 80 +mediapath = Y:\pictures +cachepath = Y:\pictures` + fullPath := createConfigFile(t, "TestSettingsSameMediaAndCachePath.conf", contents) + defer expectPanic(t) + loadSettings(fullPath) + t.Fatal("Panic expected") +} diff --git a/webapi.go b/webapi.go index e9159cf..a4b9f03 100644 --- a/webapi.go +++ b/webapi.go @@ -21,11 +21,14 @@ type WebAPI struct { box *rice.Box userName string // User name ("" means no authentication) password string // Password + tlsCertFile string // TLS certification file ("" means no TLS) + tlsKeyFile string // TLS key file ("" means no TLS) } // CreateWebAPI creates a new Web API instance -func CreateWebAPI(port int, templatePath string, media *Media, box *rice.Box, userName, password string) *WebAPI { - portStr := fmt.Sprintf(":%d", port) +func CreateWebAPI(port int, ip, templatePath string, media *Media, box *rice.Box, userName, password, + tlsCertFile, tlsKeyFile string) *WebAPI { + portStr := fmt.Sprintf("%s:%d", ip, port) server := &http.Server{Addr: portStr} webAPI := &WebAPI{ server: server, @@ -33,7 +36,9 @@ func CreateWebAPI(port int, templatePath string, media *Media, box *rice.Box, us media: media, box: box, userName: userName, - password: password} + password: password, + tlsCertFile: tlsCertFile, + tlsKeyFile: tlsKeyFile} http.Handle("/", webAPI) return webAPI } @@ -45,9 +50,17 @@ func (wa *WebAPI) Start() chan bool { go func() { llog.Info("Starting Web API on port %s\n", wa.server.Addr) - if err := wa.server.ListenAndServe(); err != nil { - // cannot panic, because this probably is an intentional close - llog.Info("WebAPI: ListenAndServe() shutdown reason: %s", err) + if wa.tlsCertFile != "" && wa.tlsKeyFile != "" { + llog.Info("Using TLS (HTTPS)") + if err := wa.server.ListenAndServeTLS(wa.tlsCertFile, wa.tlsKeyFile); err != nil { + // cannot panic, because this probably is an intentional close + llog.Info("WebAPI: ListenAndServeTLS() shutdown reason: %s", err) + } + } else { + if err := wa.server.ListenAndServe(); err != nil { + // cannot panic, because this probably is an intentional close + llog.Info("WebAPI: ListenAndServeTLS() shutdown reason: %s", err) + } } // TODO fix this wa.media.stopWatcher() // Stop the folder watcher (if it is running) done <- true // Signal that http server has stopped diff --git a/webapi_test.go b/webapi_test.go index b7aafce..b68d007 100644 --- a/webapi_test.go +++ b/webapi_test.go @@ -10,11 +10,13 @@ import ( "strings" "testing" "time" + "crypto/tls" rice "github.com/GeertJohan/go.rice" ) var baseURL = "http://localhost:9834" +var baseHttpsURL = "https://localhost:9835" func respToString(response io.ReadCloser) string { defer response.Close() @@ -107,7 +109,7 @@ func waitserver(t *testing.T) { // shutdown shuts down server and clears the serveMux func shutdown(t *testing.T) { - // No answer expecetd on POST shutdown (short timeout) + // No answer expected on POST shutdown (short timeout) client := http.Client{Timeout: 1 * time.Second} client.Post(fmt.Sprintf("%s/shutdown", baseURL), "", nil) @@ -222,7 +224,7 @@ func TestGetThumbnail(t *testing.T) { func TestGetThumbnailNoCache(t *testing.T) { box := rice.MustFindBox("templates") media := createMedia(box, "testmedia", "", false, false, false, true, false, 0, false, false) - webAPI := CreateWebAPI(9834, "templates", media, box, "", "") + webAPI := CreateWebAPI(9834, "", "templates", media, box, "", "", "", "") webAPI.Start() waitserver(t) defer shutdown(t) @@ -254,7 +256,7 @@ func TestGetThumbnailNoCache(t *testing.T) { func TestGetPreview(t *testing.T) { box := rice.MustFindBox("templates") media := createMedia(box, "testmedia", "tmpcache/TestGetPreview", true, false, false, true, true, 1280, false, false) - webAPI := CreateWebAPI(9834, "templates", media, box, "", "") + webAPI := CreateWebAPI(9834, "", "templates", media, box, "", "", "", "") webAPI.Start() waitserver(t) defer shutdown(t) @@ -281,7 +283,7 @@ func TestInvalidPath(t *testing.T) { func TestAuthentication(t *testing.T) { box := rice.MustFindBox("templates") media := createMedia(box, "testmedia", "", true, false, false, true, false, 0, false, false) - webAPI := CreateWebAPI(9834, "templates", media, box, "myuser", "mypass") + webAPI := CreateWebAPI(9834, "", "templates", media, box, "myuser", "mypass", "", "") webAPI.Start() waitserver(t) defer shutdown(t) @@ -314,7 +316,7 @@ func TestAuthentication(t *testing.T) { func TestIsPreCacheInProgress(t *testing.T) { box := rice.MustFindBox("templates") media := createMedia(box, "testmedia", "", false, false, false, true, false, 0, false, false) - webAPI := CreateWebAPI(9834, "templates", media, box, "", "") + webAPI := CreateWebAPI(9834, "", "templates", media, box, "", "", "", "") webAPI.Start() waitserver(t) defer shutdown(t) @@ -328,3 +330,45 @@ func TestIsPreCacheInProgress(t *testing.T) { assertTrue(t, "", isPreCacheInProgress) } + +func TestTLS(t *testing.T) { + box := rice.MustFindBox("templates") + media := createMedia(box, "testmedia", "tmpcache/TestTLS", true, false, false, true, true, 1280, false, false) + webAPI := CreateWebAPI(9835, "", "templates", media, box, "", "", + "configs/example.crt", "configs/example.key") + webAPI.Start() + + // Create the client + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + httpsClient := &http.Client{Transport: tr, Timeout: 100 * time.Millisecond} + + // Wait until server goes up + maxTries := 50 + i := 0 + for i = 0; i < maxTries; i++ { + _, err := httpsClient.Get(baseHttpsURL) + if err == nil { + // Up and running :-) + break + } + } + assertTrue(t, "Server never started using TLS", i < maxTries) + + // Access the main page + resp, err := httpsClient.Get(baseHttpsURL) + assertExpectNoErr(t, "Unable to connect over TLS", err) + defer resp.Body.Close() + assertEqualsInt(t, "", int(http.StatusOK), int(resp.StatusCode)) + assertEqualsStr(t, "", "text/html", resp.Header.Get("content-type")) + + // Shutdown the server + // No answer expected on POST shutdown (short timeout) + httpsClient = &http.Client{Timeout: 1 * time.Second, Transport: tr} + httpsClient.Post(fmt.Sprintf("%s/shutdown", baseHttpsURL), "", nil) + + // Reset the serveMux + http.DefaultServeMux = new(http.ServeMux) + +}