Implement HTTPS for GUI

This commit is contained in:
Jakob Borg 2014-05-21 14:04:16 +02:00
parent 30837a7d95
commit 7c8652b600
6 changed files with 43 additions and 14 deletions

File diff suppressed because one or more lines are too long

View File

@ -13,6 +13,7 @@ import (
"sync"
"time"
"crypto/tls"
"code.google.com/p/go.crypto/bcrypt"
"github.com/calmh/syncthing/config"
"github.com/calmh/syncthing/logger"
@ -42,9 +43,30 @@ func init() {
}
func startGUI(cfg config.GUIConfiguration, m *model.Model) error {
listener, err := net.Listen("tcp", cfg.Address)
if err != nil {
return err
var listener net.Listener
var err error
if cfg.UseTLS {
cert, err := loadCert(confDir, "https-")
if err != nil {
newCertificate(confDir, "https-")
cert, err = loadCert(confDir, "https-")
}
if err != nil {
return err
}
tlsCfg := &tls.Config{
Certificates: []tls.Certificate{cert},
ServerName: "syncthing",
}
listener, err = tls.Listen("tcp", cfg.Address, tlsCfg)
if err != nil {
return err
}
} else {
listener, err = net.Listen("tcp", cfg.Address)
if err != nil {
return err
}
}
router := martini.NewRouter()

View File

@ -144,10 +144,10 @@ func main() {
// Ensure that our home directory exists and that we have a certificate and key.
ensureDir(confDir, 0700)
cert, err := loadCert(confDir)
cert, err := loadCert(confDir, "")
if err != nil {
newCertificate(confDir)
cert, err = loadCert(confDir)
newCertificate(confDir, "")
cert, err = loadCert(confDir, "")
l.FatalErr(err)
}
@ -272,13 +272,18 @@ func main() {
hostShow = hostOpen
}
l.Infof("Starting web GUI on http://%s:%d/", hostShow, addr.Port)
var proto = "http"
if cfg.GUI.UseTLS {
proto = "https"
}
l.Infof("Starting web GUI on %s://%s:%d/", proto, hostShow, addr.Port)
err := startGUI(cfg.GUI, m)
if err != nil {
l.Fatalln("Cannot start GUI:", err)
}
if cfg.Options.StartBrowser && len(os.Getenv("STRESTART")) == 0 {
openURL(fmt.Sprintf("http://%s:%d", hostOpen, addr.Port))
openURL(fmt.Sprintf("%s://%s:%d", proto, hostOpen, addr.Port))
}
}
}

View File

@ -22,8 +22,8 @@ const (
tlsName = "syncthing"
)
func loadCert(dir string) (tls.Certificate, error) {
return tls.LoadX509KeyPair(filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem"))
func loadCert(dir string, prefix string) (tls.Certificate, error) {
return tls.LoadX509KeyPair(filepath.Join(dir, prefix+"cert.pem"), filepath.Join(dir, prefix+"key.pem"))
}
func certID(bs []byte) string {
@ -40,7 +40,7 @@ func certSeed(bs []byte) int64 {
return int64(binary.BigEndian.Uint64(id))
}
func newCertificate(dir string) {
func newCertificate(dir string, prefix string) {
l.Infoln("Generating RSA certificate and key...")
priv, err := rsa.GenerateKey(rand.Reader, tlsRSABits)
@ -65,13 +65,13 @@ func newCertificate(dir string) {
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
l.FatalErr(err)
certOut, err := os.Create(filepath.Join(dir, "cert.pem"))
certOut, err := os.Create(filepath.Join(dir, prefix+"cert.pem"))
l.FatalErr(err)
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
certOut.Close()
l.Okln("Created RSA certificate file")
keyOut, err := os.OpenFile(filepath.Join(dir, "key.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
keyOut, err := os.OpenFile(filepath.Join(dir, prefix+"key.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
l.FatalErr(err)
pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
keyOut.Close()

View File

@ -73,6 +73,7 @@ type GUIConfiguration struct {
Address string `xml:"address" default:"127.0.0.1:8080"`
User string `xml:"user,omitempty"`
Password string `xml:"password,omitempty"`
UseTLS bool `xml:"tls,attr"`
}
func setDefaults(data interface{}) error {

View File

@ -40,6 +40,7 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
{id: 'Address', descr: 'GUI Listen Addresses', type: 'text', restart: true},
{id: 'User', descr: 'GUI Authentication User', type: 'text', restart: true},
{id: 'Password', descr: 'GUI Authentication Password', type: 'password', restart: true},
{id: 'UseTLS', descr: 'Use HTTPS for GUI', type: 'bool', restart: true},
];
function getSucceeded() {