Skip to content

Commit 05bdde0

Browse files
authored
Split dockerui.go in separate files in api/ (#231)
Split dockerui.go in separate files in api/
1 parent e73f2c8 commit 05bdde0

File tree

8 files changed

+247
-193
lines changed

8 files changed

+247
-193
lines changed

api/api.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package main // import "github.com/kevana/ui-for-docker"
2+
3+
import (
4+
"flag"
5+
"log"
6+
"net/http"
7+
)
8+
9+
func main() {
10+
var (
11+
endpoint = flag.String("H", "unix:///var/run/docker.sock", "Dockerd endpoint")
12+
addr = flag.String("p", ":9000", "Address and port to serve UI For Docker")
13+
assets = flag.String("a", ".", "Path to the assets")
14+
data = flag.String("d", ".", "Path to the data")
15+
tlsverify = flag.Bool("tlsverify", false, "TLS support")
16+
tlscacert = flag.String("tlscacert", "/certs/ca.pem", "Path to the CA")
17+
tlscert = flag.String("tlscert", "/certs/cert.pem", "Path to the TLS certificate file")
18+
tlskey = flag.String("tlskey", "/certs/key.pem", "Path to the TLS key")
19+
)
20+
flag.Parse()
21+
22+
tlsFlags := newTLSFlags(*tlsverify, *tlscacert, *tlscert, *tlskey)
23+
24+
handler := newHandler(*assets, *data, *endpoint, tlsFlags)
25+
if err := http.ListenAndServe(*addr, handler); err != nil {
26+
log.Fatal(err)
27+
}
28+
}

api/csrf.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package main
2+
3+
import (
4+
"github.com/gorilla/csrf"
5+
"github.com/gorilla/securecookie"
6+
"io/ioutil"
7+
"log"
8+
"net/http"
9+
)
10+
11+
const keyFile = "authKey.dat"
12+
13+
// newAuthKey reuses an existing CSRF authkey if present or generates a new one
14+
func newAuthKey(path string) []byte {
15+
var authKey []byte
16+
authKeyPath := path + "/" + keyFile
17+
data, err := ioutil.ReadFile(authKeyPath)
18+
if err != nil {
19+
log.Print("Unable to find an existing CSRF auth key. Generating a new key.")
20+
authKey = securecookie.GenerateRandomKey(32)
21+
err := ioutil.WriteFile(authKeyPath, authKey, 0644)
22+
if err != nil {
23+
log.Fatal("Unable to persist CSRF auth key.")
24+
log.Fatal(err)
25+
}
26+
} else {
27+
authKey = data
28+
}
29+
return authKey
30+
}
31+
32+
// newCSRF initializes a new CSRF handler
33+
func newCSRFHandler(keyPath string) func(h http.Handler) http.Handler {
34+
authKey := newAuthKey(keyPath)
35+
return csrf.Protect(
36+
authKey,
37+
csrf.HttpOnly(false),
38+
csrf.Secure(false),
39+
)
40+
}
41+
42+
// newCSRFWrapper wraps a http.Handler to add the CSRF token
43+
func newCSRFWrapper(h http.Handler) http.Handler {
44+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45+
w.Header().Set("X-CSRF-Token", csrf.Token(r))
46+
h.ServeHTTP(w, r)
47+
})
48+
}

api/flags.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package main
2+
3+
// TLSFlags defines all the flags associated to the SSL configuration
4+
type TLSFlags struct {
5+
tls bool
6+
caPath string
7+
certPath string
8+
keyPath string
9+
}
10+
11+
// newTLSFlags creates a new TLSFlags from command flags
12+
func newTLSFlags(tls bool, cacert string, cert string, key string) TLSFlags {
13+
return TLSFlags{
14+
tls: tls,
15+
caPath: cacert,
16+
certPath: cert,
17+
keyPath: key,
18+
}
19+
}

api/handler.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"net/http"
6+
"net/http/httputil"
7+
"net/url"
8+
"os"
9+
)
10+
11+
// newHandler creates a new http.Handler with CSRF protection
12+
func newHandler(dir string, d string, e string, tlsFlags TLSFlags) http.Handler {
13+
var (
14+
mux = http.NewServeMux()
15+
fileHandler = http.FileServer(http.Dir(dir))
16+
)
17+
18+
u, perr := url.Parse(e)
19+
if perr != nil {
20+
log.Fatal(perr)
21+
}
22+
23+
handler := newAPIHandler(u, tlsFlags)
24+
CSRFHandler := newCSRFHandler(d)
25+
26+
mux.Handle("/dockerapi/", http.StripPrefix("/dockerapi", handler))
27+
mux.Handle("/", fileHandler)
28+
return CSRFHandler(newCSRFWrapper(mux))
29+
}
30+
31+
// newAPIHandler initializes a new http.Handler based on the URL scheme
32+
func newAPIHandler(u *url.URL, tlsFlags TLSFlags) http.Handler {
33+
var handler http.Handler
34+
if u.Scheme == "tcp" {
35+
if tlsFlags.tls {
36+
handler = newTCPHandlerWithTLS(u, tlsFlags)
37+
} else {
38+
handler = newTCPHandler(u)
39+
}
40+
} else if u.Scheme == "unix" {
41+
socketPath := u.Path
42+
if _, err := os.Stat(socketPath); err != nil {
43+
if os.IsNotExist(err) {
44+
log.Fatalf("Unix socket %s does not exist", socketPath)
45+
}
46+
log.Fatal(err)
47+
}
48+
handler = newUnixHandler(socketPath)
49+
} else {
50+
log.Fatalf("Bad Docker enpoint: %s. Only unix:// and tcp:// are supported.", u)
51+
}
52+
return handler
53+
}
54+
55+
// newUnixHandler initializes a new UnixHandler
56+
func newUnixHandler(e string) http.Handler {
57+
return &unixHandler{e}
58+
}
59+
60+
// newTCPHandler initializes a HTTP reverse proxy
61+
func newTCPHandler(u *url.URL) http.Handler {
62+
u.Scheme = "http"
63+
return httputil.NewSingleHostReverseProxy(u)
64+
}
65+
66+
// newTCPHandlerWithL initializes a HTTPS reverse proxy with a TLS configuration
67+
func newTCPHandlerWithTLS(u *url.URL, tlsFlags TLSFlags) http.Handler {
68+
u.Scheme = "https"
69+
var tlsConfig = newTLSConfig(tlsFlags)
70+
proxy := httputil.NewSingleHostReverseProxy(u)
71+
proxy.Transport = &http.Transport{
72+
TLSClientConfig: tlsConfig,
73+
}
74+
return proxy
75+
}

api/ssl.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package main
2+
3+
import (
4+
"crypto/tls"
5+
"crypto/x509"
6+
"io/ioutil"
7+
"log"
8+
)
9+
10+
// newTLSConfig initializes a tls.Config from the TLS flags
11+
func newTLSConfig(tlsFlags TLSFlags) *tls.Config {
12+
cert, err := tls.LoadX509KeyPair(tlsFlags.certPath, tlsFlags.keyPath)
13+
if err != nil {
14+
log.Fatal(err)
15+
}
16+
caCert, err := ioutil.ReadFile(tlsFlags.caPath)
17+
if err != nil {
18+
log.Fatal(err)
19+
}
20+
caCertPool := x509.NewCertPool()
21+
caCertPool.AppendCertsFromPEM(caCert)
22+
tlsConfig := &tls.Config{
23+
Certificates: []tls.Certificate{cert},
24+
RootCAs: caCertPool,
25+
}
26+
return tlsConfig
27+
}

api/unix_handler.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package main
2+
3+
import (
4+
"io"
5+
"log"
6+
"net"
7+
"net/http"
8+
"net/http/httputil"
9+
)
10+
11+
// unixHandler defines a handler holding the path to a socket under UNIX
12+
type unixHandler struct {
13+
path string
14+
}
15+
16+
// ServeHTTP implementation for unixHandler
17+
func (h *unixHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
18+
conn, err := net.Dial("unix", h.path)
19+
if err != nil {
20+
w.WriteHeader(http.StatusInternalServerError)
21+
log.Println(err)
22+
return
23+
}
24+
c := httputil.NewClientConn(conn, nil)
25+
defer c.Close()
26+
27+
res, err := c.Do(r)
28+
if err != nil {
29+
w.WriteHeader(http.StatusInternalServerError)
30+
log.Println(err)
31+
return
32+
}
33+
defer res.Body.Close()
34+
35+
copyHeader(w.Header(), res.Header)
36+
if _, err := io.Copy(w, res.Body); err != nil {
37+
log.Println(err)
38+
}
39+
}
40+
41+
func copyHeader(dst, src http.Header) {
42+
for k, vv := range src {
43+
for _, v := range vv {
44+
dst.Add(k, v)
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)