2015-05-01 20:59:46 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
2016-01-04 18:26:32 +00:00
|
|
|
"net"
|
2015-05-01 20:59:46 +00:00
|
|
|
"net/http"
|
2016-01-04 18:26:32 +00:00
|
|
|
"net/http/httputil"
|
|
|
|
"net/url"
|
|
|
|
"strings"
|
2015-05-01 20:59:46 +00:00
|
|
|
"sync"
|
|
|
|
|
2015-12-11 03:35:48 +00:00
|
|
|
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/gorilla/websocket"
|
2016-01-04 18:26:32 +00:00
|
|
|
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/spf13/viper"
|
2016-01-08 17:53:02 +00:00
|
|
|
"github.com/khlieng/dispatch/Godeps/_workspace/src/golang.org/x/net/http2"
|
2015-05-01 20:59:46 +00:00
|
|
|
|
2016-01-04 18:26:32 +00:00
|
|
|
"github.com/khlieng/dispatch/letsencrypt"
|
2015-12-11 03:35:48 +00:00
|
|
|
"github.com/khlieng/dispatch/storage"
|
2015-05-01 20:59:46 +00:00
|
|
|
)
|
|
|
|
|
2016-01-15 01:27:30 +00:00
|
|
|
const (
|
|
|
|
cookieName = "dispatch"
|
|
|
|
)
|
|
|
|
|
2015-05-01 20:59:46 +00:00
|
|
|
var (
|
|
|
|
channelStore *storage.ChannelStore
|
2016-01-15 01:27:30 +00:00
|
|
|
sessions map[uint64]*Session
|
2015-05-01 20:59:46 +00:00
|
|
|
sessionLock sync.Mutex
|
2015-05-15 05:32:32 +00:00
|
|
|
|
2016-01-15 01:27:30 +00:00
|
|
|
hmacKey []byte
|
|
|
|
|
2015-05-01 22:20:22 +00:00
|
|
|
upgrader = websocket.Upgrader{
|
|
|
|
ReadBufferSize: 1024,
|
|
|
|
WriteBufferSize: 1024,
|
2015-05-11 03:13:35 +00:00
|
|
|
CheckOrigin: func(r *http.Request) bool {
|
|
|
|
return true
|
|
|
|
},
|
2015-05-01 22:20:22 +00:00
|
|
|
}
|
2015-05-01 20:59:46 +00:00
|
|
|
)
|
|
|
|
|
2016-01-04 18:26:32 +00:00
|
|
|
func Run() {
|
2015-05-01 23:02:21 +00:00
|
|
|
defer storage.Close()
|
2015-05-01 20:59:46 +00:00
|
|
|
|
|
|
|
channelStore = storage.NewChannelStore()
|
2016-01-15 01:27:30 +00:00
|
|
|
sessions = make(map[uint64]*Session)
|
|
|
|
|
|
|
|
var err error
|
|
|
|
hmacKey, err = getHMACKey()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2015-05-01 20:59:46 +00:00
|
|
|
|
2016-01-04 18:26:32 +00:00
|
|
|
reconnectIRC()
|
|
|
|
startHTTP()
|
2015-05-01 20:59:46 +00:00
|
|
|
|
2016-01-04 18:26:32 +00:00
|
|
|
select {}
|
2015-06-06 23:18:26 +00:00
|
|
|
}
|
2015-05-01 20:59:46 +00:00
|
|
|
|
2016-01-04 18:26:32 +00:00
|
|
|
func startHTTP() {
|
|
|
|
port := viper.GetString("port")
|
2015-05-01 20:59:46 +00:00
|
|
|
|
2016-01-04 18:26:32 +00:00
|
|
|
if viper.GetBool("https.enabled") {
|
|
|
|
portHTTPS := viper.GetString("https.port")
|
|
|
|
redirect := viper.GetBool("https.redirect")
|
|
|
|
|
2016-01-06 21:19:06 +00:00
|
|
|
if redirect {
|
2016-01-04 18:26:32 +00:00
|
|
|
log.Println("[HTTP] Listening on port", port, "(HTTPS Redirect)")
|
|
|
|
go http.ListenAndServe(":"+port, createHTTPSRedirect(portHTTPS))
|
|
|
|
}
|
|
|
|
|
2016-01-06 21:19:06 +00:00
|
|
|
server := &http.Server{
|
|
|
|
Addr: ":" + portHTTPS,
|
|
|
|
Handler: http.HandlerFunc(serve),
|
|
|
|
}
|
|
|
|
|
2016-01-08 17:53:02 +00:00
|
|
|
http2.ConfigureServer(server, nil)
|
|
|
|
|
2016-01-04 18:26:32 +00:00
|
|
|
if certExists() {
|
2016-01-06 21:19:06 +00:00
|
|
|
log.Println("[HTTPS] Listening on port", portHTTPS)
|
|
|
|
server.ListenAndServeTLS(viper.GetString("https.cert"), viper.GetString("https.key"))
|
2016-01-04 18:26:32 +00:00
|
|
|
} else if domain := viper.GetString("letsencrypt.domain"); domain != "" {
|
|
|
|
dir := storage.Path.LetsEncrypt()
|
|
|
|
email := viper.GetString("letsencrypt.email")
|
|
|
|
lePort := viper.GetString("letsencrypt.port")
|
|
|
|
|
|
|
|
if viper.GetBool("letsencrypt.proxy") && lePort != "" && (port != "80" || !redirect) {
|
|
|
|
log.Println("[HTTP] Listening on port 80 (Let's Encrypt Proxy))")
|
|
|
|
go http.ListenAndServe(":80", http.HandlerFunc(letsEncryptProxy))
|
|
|
|
}
|
|
|
|
|
2016-01-15 18:48:03 +00:00
|
|
|
letsEncrypt, err := letsencrypt.Run(dir, domain, email, ":"+lePort)
|
2016-01-04 18:26:32 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2016-01-06 21:19:06 +00:00
|
|
|
|
2016-01-08 17:53:02 +00:00
|
|
|
server.TLSConfig.GetCertificate = letsEncrypt.GetCertificate
|
2016-01-06 21:19:06 +00:00
|
|
|
|
|
|
|
log.Println("[HTTPS] Listening on port", portHTTPS)
|
|
|
|
log.Fatal(listenAndServeTLS(server))
|
2016-01-04 18:26:32 +00:00
|
|
|
} else {
|
|
|
|
log.Fatal("Could not locate SSL certificate or private key")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Println("[HTTP] Listening on port", port)
|
|
|
|
log.Fatal(http.ListenAndServe(":"+port, http.HandlerFunc(serve)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func serve(w http.ResponseWriter, r *http.Request) {
|
2015-06-06 23:18:26 +00:00
|
|
|
if r.Method != "GET" {
|
2016-01-15 01:27:30 +00:00
|
|
|
w.WriteHeader(404)
|
2015-06-06 23:18:26 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if r.URL.Path == "/ws" {
|
2016-01-15 01:27:30 +00:00
|
|
|
session := handleAuth(w, r)
|
|
|
|
if session == nil {
|
|
|
|
log.Println("[Auth] No session")
|
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
upgradeWS(w, r, session)
|
2015-06-06 23:18:26 +00:00
|
|
|
} else {
|
|
|
|
serveFiles(w, r)
|
|
|
|
}
|
2015-05-01 20:59:46 +00:00
|
|
|
}
|
|
|
|
|
2016-01-15 01:27:30 +00:00
|
|
|
func upgradeWS(w http.ResponseWriter, r *http.Request, session *Session) {
|
|
|
|
conn, err := upgrader.Upgrade(w, r, w.Header())
|
2015-05-01 22:20:22 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-01-15 01:27:30 +00:00
|
|
|
newWSHandler(conn, session).run()
|
2015-05-01 22:20:22 +00:00
|
|
|
}
|
|
|
|
|
2016-01-04 18:26:32 +00:00
|
|
|
func createHTTPSRedirect(portHTTPS string) http.HandlerFunc {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge") {
|
|
|
|
letsEncryptProxy(w, r)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
host, _, err := net.SplitHostPort(r.Host)
|
|
|
|
if err != nil {
|
|
|
|
host = r.Host
|
2015-05-01 20:59:46 +00:00
|
|
|
}
|
2016-01-04 18:26:32 +00:00
|
|
|
|
|
|
|
u := url.URL{
|
|
|
|
Scheme: "https",
|
|
|
|
Host: net.JoinHostPort(host, portHTTPS),
|
|
|
|
Path: r.RequestURI,
|
|
|
|
}
|
|
|
|
|
|
|
|
w.Header().Set("Location", u.String())
|
|
|
|
w.WriteHeader(http.StatusMovedPermanently)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func letsEncryptProxy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
host, _, err := net.SplitHostPort(r.Host)
|
|
|
|
if err != nil {
|
|
|
|
host = r.Host
|
2015-05-01 20:59:46 +00:00
|
|
|
}
|
2016-01-04 18:26:32 +00:00
|
|
|
|
|
|
|
upstream := &url.URL{
|
|
|
|
Scheme: "http",
|
|
|
|
Host: net.JoinHostPort(host, viper.GetString("letsencrypt.port")),
|
|
|
|
}
|
|
|
|
|
|
|
|
httputil.NewSingleHostReverseProxy(upstream).ServeHTTP(w, r)
|
2015-05-01 20:59:46 +00:00
|
|
|
}
|