2023-02-26 22:26:09 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
2023-03-25 20:15:00 +00:00
|
|
|
"github.com/azukaar/cosmos-server/src/utils"
|
|
|
|
"github.com/azukaar/cosmos-server/src/user"
|
|
|
|
"github.com/azukaar/cosmos-server/src/configapi"
|
|
|
|
"github.com/azukaar/cosmos-server/src/proxy"
|
|
|
|
"github.com/azukaar/cosmos-server/src/docker"
|
2023-02-26 22:26:09 +00:00
|
|
|
"github.com/gorilla/mux"
|
2023-03-10 20:59:56 +00:00
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
"encoding/json"
|
2023-03-12 18:17:28 +00:00
|
|
|
"os"
|
2023-03-27 17:52:54 +00:00
|
|
|
"strings"
|
2023-03-10 20:59:56 +00:00
|
|
|
"github.com/go-chi/chi/middleware"
|
|
|
|
"github.com/go-chi/httprate"
|
|
|
|
"crypto/tls"
|
2023-03-12 18:17:28 +00:00
|
|
|
spa "github.com/roberthodgen/spa-server"
|
2023-03-27 17:52:54 +00:00
|
|
|
"github.com/foomo/simplecert"
|
|
|
|
"github.com/foomo/tlsconfig"
|
2023-02-26 22:26:09 +00:00
|
|
|
)
|
|
|
|
|
2023-03-10 20:59:56 +00:00
|
|
|
var serverPortHTTP = ""
|
|
|
|
var serverPortHTTPS = ""
|
2023-02-26 22:26:09 +00:00
|
|
|
|
|
|
|
func startHTTPServer(router *mux.Router) {
|
2023-03-10 20:59:56 +00:00
|
|
|
utils.Log("Listening to HTTP on :" + serverPortHTTP)
|
2023-02-26 22:26:09 +00:00
|
|
|
|
|
|
|
err := http.ListenAndServe("0.0.0.0:" + serverPortHTTP, router)
|
|
|
|
|
|
|
|
if err != nil {
|
2023-03-10 20:59:56 +00:00
|
|
|
utils.Fatal("Listening to HTTP", err)
|
2023-02-26 22:26:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func startHTTPSServer(router *mux.Router, tlsCert string, tlsKey string) {
|
2023-03-27 17:52:54 +00:00
|
|
|
config := utils.GetMainConfig()
|
|
|
|
|
|
|
|
// check if Docker overwrite Hostname
|
|
|
|
serverHostname := "0.0.0.0" //utils.GetMainConfig().HTTPConfig.Hostname
|
|
|
|
// if os.Getenv("HOSTNAME") != "" {
|
|
|
|
// serverHostname = os.Getenv("HOSTNAME")
|
|
|
|
// }
|
|
|
|
|
|
|
|
cfg := simplecert.Default
|
|
|
|
|
|
|
|
cfg.Domains = utils.GetAllHostnames()
|
|
|
|
cfg.CacheDir = "/config/certificates"
|
|
|
|
cfg.SSLEmail = config.HTTPConfig.SSLEmail
|
|
|
|
cfg.HTTPAddress = serverHostname+":"+serverPortHTTP
|
|
|
|
cfg.TLSAddress = serverHostname+":"+serverPortHTTPS
|
|
|
|
|
|
|
|
var certReloader *simplecert.CertReloader
|
|
|
|
var errSimCert error
|
|
|
|
if(config.HTTPConfig.HTTPSCertificateMode == utils.HTTPSCertModeList["LETSENCRYPT"]) {
|
|
|
|
certReloader, errSimCert = simplecert.Init(cfg, nil)
|
|
|
|
if errSimCert != nil {
|
|
|
|
utils.Fatal("simplecert init failed: ", errSimCert)
|
|
|
|
}
|
|
|
|
}
|
2023-03-25 20:15:00 +00:00
|
|
|
|
2023-03-27 17:52:54 +00:00
|
|
|
// redirect http to https
|
|
|
|
go (func () {
|
|
|
|
// err := http.ListenAndServe("0.0.0.0:" + serverPortHTTP, http.HandlerFunc(simplecert.Redirect))
|
|
|
|
err := http.ListenAndServe("0.0.0.0:" + serverPortHTTP, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
// change port in host
|
|
|
|
if strings.HasSuffix(r.Host, ":" + serverPortHTTP) {
|
|
|
|
if serverPortHTTPS != "443" {
|
|
|
|
r.Host = r.Host[:len(r.Host)-len(":" + serverPortHTTP)] + ":" + serverPortHTTPS
|
|
|
|
} else {
|
|
|
|
r.Host = r.Host[:len(r.Host)-len(":" + serverPortHTTP)]
|
2023-02-26 22:26:09 +00:00
|
|
|
}
|
|
|
|
}
|
2023-03-27 17:52:54 +00:00
|
|
|
|
|
|
|
http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently)
|
|
|
|
}))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
utils.Fatal("Listening to HTTP (Redirecting to HTTPS)", err)
|
|
|
|
}
|
|
|
|
})()
|
2023-02-26 22:26:09 +00:00
|
|
|
|
2023-03-27 17:52:54 +00:00
|
|
|
utils.Log("Listening to HTTP on :" + serverPortHTTP)
|
|
|
|
utils.Log("Listening to HTTPS on :" + serverPortHTTPS)
|
|
|
|
|
|
|
|
utils.IsHTTPS = true
|
2023-03-10 20:59:56 +00:00
|
|
|
|
2023-03-27 17:52:54 +00:00
|
|
|
tlsConf := tlsconfig.NewServerTLSConfig(tlsconfig.TLSModeServerStrict)
|
2023-03-10 20:59:56 +00:00
|
|
|
|
2023-03-27 17:52:54 +00:00
|
|
|
if(config.HTTPConfig.HTTPSCertificateMode == utils.HTTPSCertModeList["LETSENCRYPT"]) {
|
|
|
|
tlsConf.GetCertificate = certReloader.GetCertificateFunc()
|
|
|
|
} else {
|
2023-03-10 20:59:56 +00:00
|
|
|
cert, errCert := tls.X509KeyPair(([]byte)(tlsCert), ([]byte)(tlsKey))
|
|
|
|
if errCert != nil {
|
|
|
|
utils.Fatal("Getting Certificate pair", errCert)
|
|
|
|
}
|
|
|
|
|
2023-03-27 17:52:54 +00:00
|
|
|
tlsConf.Certificates = []tls.Certificate{cert}
|
|
|
|
}
|
|
|
|
|
|
|
|
server := http.Server{
|
|
|
|
TLSConfig: tlsConf,
|
|
|
|
Addr: serverHostname + ":" + serverPortHTTPS,
|
|
|
|
ReadTimeout: 0,
|
|
|
|
ReadHeaderTimeout: 10 * time.Second,
|
|
|
|
WriteTimeout: 0,
|
|
|
|
IdleTimeout: 30 * time.Second,
|
|
|
|
Handler: router,
|
|
|
|
DisableGeneralOptionsHandler: true,
|
|
|
|
}
|
2023-02-26 22:26:09 +00:00
|
|
|
|
2023-03-27 17:52:54 +00:00
|
|
|
// start https server
|
|
|
|
errServ := server.ListenAndServeTLS("", "")
|
2023-02-26 22:26:09 +00:00
|
|
|
|
2023-03-27 17:52:54 +00:00
|
|
|
if errServ != nil {
|
|
|
|
utils.Fatal("Listening to HTTPS", errServ)
|
|
|
|
}
|
2023-02-26 22:26:09 +00:00
|
|
|
}
|
|
|
|
|
2023-03-10 20:59:56 +00:00
|
|
|
func tokenMiddleware(next http.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
r.Header.Set("x-cosmos-user", "")
|
|
|
|
r.Header.Set("x-cosmos-role", "")
|
|
|
|
|
|
|
|
u, err := user.RefreshUserToken(w, r)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
r.Header.Set("x-cosmos-user", u.Nickname)
|
|
|
|
r.Header.Set("x-cosmos-role", strconv.Itoa((int)(u.Role)))
|
|
|
|
|
|
|
|
next.ServeHTTP(w, r)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func StartServer() {
|
|
|
|
baseMainConfig := utils.GetBaseMainConfig()
|
|
|
|
config := utils.GetMainConfig().HTTPConfig
|
|
|
|
serverPortHTTP = config.HTTPPort
|
|
|
|
serverPortHTTPS = config.HTTPSPort
|
2023-02-26 22:26:09 +00:00
|
|
|
|
2023-03-10 20:59:56 +00:00
|
|
|
configJson, _ := json.MarshalIndent(config, "", " ")
|
|
|
|
utils.Debug("Configuration" + (string)(configJson))
|
|
|
|
|
2023-03-27 17:52:54 +00:00
|
|
|
var tlsCert = config.TLSCert
|
|
|
|
var tlsKey= config.TLSKey
|
|
|
|
|
|
|
|
if((tlsCert == "" || tlsKey == "") && config.HTTPSCertificateMode == utils.HTTPSCertModeList["SELFSIGNED"]) {
|
2023-03-10 20:59:56 +00:00
|
|
|
utils.Log("Generating new TLS certificate")
|
|
|
|
pub, priv := utils.GenerateRSAWebCertificates()
|
|
|
|
|
|
|
|
baseMainConfig.HTTPConfig.TLSCert = pub
|
|
|
|
baseMainConfig.HTTPConfig.TLSKey = priv
|
|
|
|
utils.SetBaseMainConfig(baseMainConfig)
|
|
|
|
|
|
|
|
utils.Log("Saved new TLS certificate")
|
|
|
|
|
|
|
|
tlsCert = pub
|
|
|
|
tlsKey = priv
|
2023-02-26 22:26:09 +00:00
|
|
|
}
|
|
|
|
|
2023-03-10 20:59:56 +00:00
|
|
|
if ((config.AuthPublicKey == "" || config.AuthPrivateKey == "") && config.GenerateMissingAuthCert) {
|
|
|
|
utils.Log("Generating new Auth ED25519 certificate")
|
|
|
|
pub, priv := utils.GenerateEd25519Certificates()
|
|
|
|
|
|
|
|
baseMainConfig.HTTPConfig.AuthPublicKey = pub
|
|
|
|
baseMainConfig.HTTPConfig.AuthPrivateKey = priv
|
|
|
|
utils.SetBaseMainConfig(baseMainConfig)
|
|
|
|
|
|
|
|
utils.Log("Saved new Auth ED25519 certificate")
|
2023-02-26 22:26:09 +00:00
|
|
|
}
|
|
|
|
|
2023-03-12 18:17:28 +00:00
|
|
|
router := mux.NewRouter().StrictSlash(true)
|
2023-02-26 22:26:09 +00:00
|
|
|
|
2023-03-10 20:59:56 +00:00
|
|
|
router.Use(middleware.Recoverer)
|
|
|
|
router.Use(middleware.Logger)
|
|
|
|
router.Use(utils.SetSecurityHeaders)
|
2023-03-16 18:56:36 +00:00
|
|
|
|
|
|
|
router.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
http.Redirect(w, r, "/ui", http.StatusMovedPermanently)
|
2023-03-18 19:59:32 +00:00
|
|
|
}))
|
2023-03-12 18:17:28 +00:00
|
|
|
|
|
|
|
srapi := router.PathPrefix("/cosmos").Subrouter()
|
2023-03-10 20:59:56 +00:00
|
|
|
|
2023-03-12 18:17:28 +00:00
|
|
|
srapi.HandleFunc("/api/login", user.UserLogin)
|
|
|
|
srapi.HandleFunc("/api/logout", user.UserLogout)
|
|
|
|
srapi.HandleFunc("/api/register", user.UserRegister)
|
|
|
|
srapi.HandleFunc("/api/invite", user.UserResendInviteLink)
|
|
|
|
srapi.HandleFunc("/api/me", user.Me)
|
2023-03-16 18:56:36 +00:00
|
|
|
srapi.HandleFunc("/api/config", configapi.ConfigRoute)
|
|
|
|
srapi.HandleFunc("/api/restart", configapi.ConfigApiRestart)
|
2023-03-10 20:59:56 +00:00
|
|
|
|
2023-03-12 18:17:28 +00:00
|
|
|
srapi.HandleFunc("/api/users/{nickname}", user.UsersIdRoute)
|
|
|
|
srapi.HandleFunc("/api/users", user.UsersRoute)
|
2023-03-25 20:15:00 +00:00
|
|
|
|
|
|
|
srapi.HandleFunc("/api/servapps/{container}/secure", docker.SecureContainerRoute)
|
|
|
|
srapi.HandleFunc("/api/servapps", docker.ContainersRoute)
|
2023-03-10 20:59:56 +00:00
|
|
|
|
2023-03-18 19:59:32 +00:00
|
|
|
srapi.Use(tokenMiddleware)
|
2023-03-10 20:59:56 +00:00
|
|
|
srapi.Use(utils.CORSHeader(utils.GetMainConfig().HTTPConfig.Hostname))
|
2023-03-13 00:49:27 +00:00
|
|
|
srapi.Use(utils.MiddlewareTimeout(20 * time.Second))
|
|
|
|
srapi.Use(httprate.Limit(60, 1*time.Minute,
|
2023-03-10 20:59:56 +00:00
|
|
|
httprate.WithKeyFuncs(httprate.KeyByIP),
|
|
|
|
httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
utils.Error("Too many requests. Throttling", nil)
|
|
|
|
utils.HTTPError(w, "Too many requests",
|
|
|
|
http.StatusTooManyRequests, "HTTP003")
|
|
|
|
return
|
|
|
|
}),
|
|
|
|
))
|
2023-03-12 18:17:28 +00:00
|
|
|
|
|
|
|
pwd,_ := os.Getwd()
|
|
|
|
utils.Log("Starting in " + pwd)
|
|
|
|
if _, err := os.Stat(pwd + "/static"); os.IsNotExist(err) {
|
|
|
|
utils.Fatal("Static folder not found at " + pwd + "/static", err)
|
|
|
|
}
|
2023-03-16 18:56:36 +00:00
|
|
|
|
2023-03-12 18:17:28 +00:00
|
|
|
fs := spa.SpaHandler(pwd + "/static", "index.html")
|
2023-03-16 18:56:36 +00:00
|
|
|
router.PathPrefix("/ui").Handler(http.StripPrefix("/ui", fs))
|
2023-03-12 18:17:28 +00:00
|
|
|
|
|
|
|
router = proxy.BuildFromConfig(router, config.ProxyConfig)
|
2023-03-10 20:59:56 +00:00
|
|
|
|
2023-03-27 17:52:54 +00:00
|
|
|
if ((config.HTTPSCertificateMode == utils.HTTPSCertModeList["SELFSIGNED"] || config.HTTPSCertificateMode == utils.HTTPSCertModeList["PROVIDED"]) &&
|
|
|
|
tlsCert != "" && tlsKey != "") || (config.HTTPSCertificateMode == utils.HTTPSCertModeList["LETSENCRYPT"]) {
|
2023-03-10 20:59:56 +00:00
|
|
|
utils.Log("TLS certificate exist, starting HTTPS servers and redirecting HTTP to HTTPS")
|
2023-02-26 22:26:09 +00:00
|
|
|
startHTTPSServer(router, tlsCert, tlsKey)
|
|
|
|
} else {
|
2023-03-27 17:52:54 +00:00
|
|
|
utils.Log("TLS certificates do not exists or are disabled, starting HTTP server only")
|
2023-02-26 22:26:09 +00:00
|
|
|
startHTTPServer(router)
|
|
|
|
}
|
|
|
|
}
|