Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package galene for openSUSE:Factory checked in at 2021-03-02 12:32:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/galene (Old) and /work/SRC/openSUSE:Factory/.galene.new.2378 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "galene" Tue Mar 2 12:32:05 2021 rev:4 rq:875522 version:0.3.1 Changes: -------- --- /work/SRC/openSUSE:Factory/galene/galene.changes 2021-02-25 18:27:21.494177397 +0100 +++ /work/SRC/openSUSE:Factory/.galene.new.2378/galene.changes 2021-03-02 12:44:36.212311266 +0100 @@ -1,0 +2,8 @@ +Fri Feb 26 20:06:42 UTC 2021 - mich...@stroeder.com + +- Update to version 0.3.1: + * We now notice when the TLS certificate has changed on disk; which can + therefore be rotated without a restart. + * We now generate a self-signed certificate if none is found on disk. + +------------------------------------------------------------------- Old: ---- galene-0.3.tar.gz New: ---- galene-0.3.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ galene.spec ++++++ --- /var/tmp/diff_new_pack.rTCVSy/_old 2021-03-02 12:44:36.996311944 +0100 +++ /var/tmp/diff_new_pack.rTCVSy/_new 2021-03-02 12:44:37.000311947 +0100 @@ -25,7 +25,7 @@ %bcond_without apparmor Name: galene -Version: 0.3 +Version: 0.3.1 Release: 0 Summary: Gal??ne videoconferencing server License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.rTCVSy/_old 2021-03-02 12:44:37.024311968 +0100 +++ /var/tmp/diff_new_pack.rTCVSy/_new 2021-03-02 12:44:37.024311968 +0100 @@ -3,8 +3,8 @@ <param name="url">git://github.com/jech/galene.git</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">galene-0.3</param> - <param name="version">0.3</param> + <param name="revision">galene-0.3.1</param> + <param name="version">0.3.1</param> <param name="changesgenerate">enable</param> <!--param name="versionrewrite-pattern">galene-(\d+)</param> <param name="versionrewrite-replacement">\1</param--> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.rTCVSy/_old 2021-03-02 12:44:37.036311978 +0100 +++ /var/tmp/diff_new_pack.rTCVSy/_new 2021-03-02 12:44:37.040311982 +0100 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">git://github.com/jech/galene.git</param> - <param name="changesrevision">6cf82f6e0c5da736aea9dd1139a8639fe5d30291</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">b7db959bfb7b021521c15c3550d7a31ed0228b79</param></service></servicedata> \ No newline at end of file ++++++ galene-0.3.tar.gz -> galene-0.3.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/CHANGES new/galene-0.3.1/CHANGES --- old/galene-0.3/CHANGES 2021-02-18 22:53:05.000000000 +0100 +++ new/galene-0.3.1/CHANGES 2021-02-26 19:13:15.000000000 +0100 @@ -1,3 +1,9 @@ +26 February 2021: Gal??ne 0.3.1 + + * We now notice when the TLS certificate has changed on disk; which can + therefore be rotated without a restart. + * We now generate a self-signed certificate if none is found on disk. + 18 February 2021: Gal??ne 0.3 * Implemented the command /muteall. This allows muting all users except diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/README new/galene-0.3.1/README --- old/galene-0.3/README 2021-02-18 22:53:05.000000000 +0100 +++ new/galene-0.3.1/README 2021-02-26 19:13:15.000000000 +0100 @@ -4,15 +4,11 @@ CGO_ENABLED=0 go build -ldflags='-s -w' -## Create a server certificate - - mkdir data - openssl req -newkey rsa:2048 -nodes -keyout data/key.pem -x509 -days 365 -out data/cert.pem - ## Set the server administrator credentials This step is optional. + mkdir data echo 'god:topsecret' > data/passwd ## Set up a group @@ -110,6 +106,16 @@ Set up a user *galene* on your server, then do: rsync -a galene static data groups gal...@server.example.org: + +If you don't have a TLS certificate, Gal??ne will generate a self-signed +certificate automatically (and print a warning to the logs). If you have +a certificate, install it in the files `data/cert.pem` and `data/key.pem`: + + ssh gal...@server.example.org + sudo cp /etc/letsencrypt/live/server.example.org/fullchain.pem data/cert.pem + sudo cp /etc/letsencrypt/live/server.example.org/key.pem data/key.pem + sudo chown galene:galene data/*.pem + sudo chmod go-rw data/key.pem Now run the binary on the server: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/galene.go new/galene-0.3.1/galene.go --- old/galene-0.3/galene.go 2021-02-18 22:53:05.000000000 +0100 +++ new/galene-0.3.1/galene.go 2021-02-26 19:13:15.000000000 +0100 @@ -130,7 +130,7 @@ func relayTest() { now := time.Now() - d, err := ice.RelayTest() + d, err := ice.RelayTest(20 * time.Second) if err != nil { log.Printf("Relay test failed: %v", err) log.Printf("Perhaps you didn't configure a TURN server?") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/group/client.go new/galene-0.3.1/group/client.go --- old/galene-0.3/group/client.go 2021-02-18 22:53:05.000000000 +0100 +++ new/galene-0.3.1/group/client.go 2021-02-26 19:13:15.000000000 +0100 @@ -101,8 +101,5 @@ OverridePermissions(*Group) bool PushConn(g *Group, id string, conn conn.Up, tracks []conn.UpTrack, replace string) error PushClient(id, username string, add bool) error -} - -type Kickable interface { Kick(id, user, message string) error } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/group/group.go new/galene-0.3.1/group/group.go --- old/galene-0.3/group/group.go 2021-02-18 22:53:05.000000000 +0100 +++ new/galene-0.3.1/group/group.go 2021-02-26 19:13:15.000000000 +0100 @@ -586,10 +586,7 @@ func kickall(g *Group, message string) { g.Range(func(c Client) bool { - cc, ok := c.(Kickable) - if ok { - cc.Kick("", "", message) - } + c.Kick("", "", message) return true }) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/ice/ice.go new/galene-0.3.1/ice/ice.go --- old/galene-0.3/ice/ice.go 2021-02-18 22:53:05.000000000 +0100 +++ new/galene-0.3.1/ice/ice.go 2021-02-26 19:13:15.000000000 +0100 @@ -137,7 +137,7 @@ return &conf.conf } -func RelayTest() (time.Duration, error) { +func RelayTest(timeout time.Duration) (time.Duration, error) { conf := ICEConfiguration() conf2 := *conf @@ -223,7 +223,7 @@ }) }) - timer := time.NewTimer(20 * time.Second) + timer := time.NewTimer(timeout) defer timer.Stop() select { case err := <-ch1: @@ -235,6 +235,6 @@ } return time.Now().Sub(tm), nil case <-timer.C: - return 0, errors.New("timeout") + return 0, os.ErrDeadlineExceeded } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/ice/ice_test.go new/galene-0.3.1/ice/ice_test.go --- old/galene-0.3/ice/ice_test.go 2021-02-18 22:53:05.000000000 +0100 +++ new/galene-0.3.1/ice/ice_test.go 2021-02-26 19:13:15.000000000 +0100 @@ -5,11 +5,15 @@ "crypto/hmac" "crypto/sha1" "encoding/base64" + "os" "reflect" "strings" "testing" + "time" "github.com/pion/webrtc/v3" + + "github.com/jech/galene/turnserver" ) func TestPassword(t *testing.T) { @@ -63,3 +67,31 @@ t.Errorf("Got %v, expected %v", sss, ss) } } + +func TestICEConfiguration(t *testing.T) { + ICEFilename = "/tmp/no/such/file" + turnserver.Address = "" + + conf := ICEConfiguration() + if conf == nil { + t.Errorf("conf is nil") + } + conf2 := ICEConfiguration() + if conf2 != conf { + t.Errorf("conf2 != conf") + } + + if len(conf.ICEServers) != 0 { + t.Errorf("len(ICEServers) = %v", len(conf.ICEServers)) + } +} + +func TestRelayTest(t *testing.T) { + ICEFilename = "/tmp/no/such/file" + turnserver.Address = "" + + _, err := RelayTest(200 * time.Millisecond) + if err == nil || !os.IsTimeout(err) { + t.Errorf("Relay test returned %v", err) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/rtpconn/webclient.go new/galene-0.3.1/rtpconn/webclient.go --- old/galene-0.3/rtpconn/webclient.go 2021-02-18 22:53:05.000000000 +0100 +++ new/galene-0.3.1/rtpconn/webclient.go 2021-02-26 19:13:15.000000000 +0100 @@ -1099,12 +1099,7 @@ return group.UserError("no such user") } - c, ok := client.(group.Kickable) - if !ok { - return group.UserError("this client is not kickable") - } - - return c.Kick(id, user, message) + return client.Kick(id, user, message) } func handleClientMessage(c *webClient, m clientMessage) error { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/static/protocol.js new/galene-0.3.1/static/protocol.js --- old/galene-0.3/static/protocol.js 2021-02-18 22:53:05.000000000 +0100 +++ new/galene-0.3.1/static/protocol.js 2021-02-26 19:13:15.000000000 +0100 @@ -523,7 +523,7 @@ * * @param {string} kind - The kind of application-specific message. * @param {string} dest - The id to send the message to, empty for broadcast. - * @param {string} [value] - An optional parameter. + * @param {unknown} [value] - An optional parameter. * @param {boolean} [noecho] - If set, don't echo back the message to the sender. */ ServerConnection.prototype.userMessage = function(kind, dest, value, noecho) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/webserver/certificate.go new/galene-0.3.1/webserver/certificate.go --- old/galene-0.3/webserver/certificate.go 1970-01-01 01:00:00.000000000 +0100 +++ new/galene-0.3.1/webserver/certificate.go 2021-02-26 19:13:15.000000000 +0100 @@ -0,0 +1,145 @@ +package webserver + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "errors" + "log" + "math/big" + "os" + "path/filepath" + "sync" + "sync/atomic" + "time" +) + +type certInfo struct { + certificate *tls.Certificate + keyTime time.Time + certTime time.Time +} + +// certMu protects writing to certificate +var certMu sync.Mutex + +// certificate holds our current certificate, of type certInfo +var certificate atomic.Value + +// generateCertificate generates a self-signed certficate +func generateCertificate() (tls.Certificate, error) { + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return tls.Certificate{}, err + } + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + now := time.Now() + + template := x509.Certificate{ + SerialNumber: serialNumber, + NotBefore: now, + NotAfter: now.Add(365 * 24 * time.Hour), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + bytes, err := x509.CreateCertificate( + rand.Reader, &template, &template, &priv.PublicKey, priv, + ) + if err != nil { + return tls.Certificate{}, err + } + + return tls.Certificate{ + Certificate: [][]byte{bytes}, + PrivateKey: priv, + }, nil +} + +func modTime(filename string) time.Time { + fi, err := os.Stat(filename) + if err != nil { + if !os.IsNotExist(err) { + log.Printf("%v: %v", filename, err) + } + return time.Time{} + } + return fi.ModTime() +} + +// loadCertificate returns the current certificate if it is still valid. +func loadCertificate(certFile string, certTime time.Time, keyFile string, keyTime time.Time) *certInfo { + info, ok := certificate.Load().(*certInfo) + if !ok { + return nil + } + + if !info.certTime.Equal(certTime) || !info.keyTime.Equal(keyTime) { + return nil + } + + return info +} + +// storeCertificate returns the current certificate if it is still valid, +// and either reads or generates a new one otherwise. +func storeCertificate(certFile string, certTime time.Time, keyFile string, keyTime time.Time) (info *certInfo, err error) { + certMu.Lock() + defer certMu.Unlock() + + // the certificate may have been updated since we checked + info = loadCertificate(certFile, certTime, keyFile, keyTime) + if info != nil { + return + } + + var cert tls.Certificate + nocert := certTime.Equal(time.Time{}) + nokey := keyTime.Equal(time.Time{}) + + if nocert != nokey { + err = errors.New("only one of cert.pem and key.pem exists") + return + } else if nokey { + log.Printf("Generating self-signed certificate") + cert, err = generateCertificate() + if err != nil { + return + } + } else { + cert, err = tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return + } + } + info = &certInfo{ + certificate: &cert, + certTime: certTime, + keyTime: keyTime, + } + certificate.Store(info) + return +} + +func getCertificate(dataDir string) (*tls.Certificate, error) { + certFile := filepath.Join(dataDir, "cert.pem") + keyFile := filepath.Join(dataDir, "key.pem") + certTime := modTime(certFile) + keyTime := modTime(keyFile) + + info := loadCertificate(certFile, certTime, keyFile, keyTime) + + if info == nil { + var err error + info, err = storeCertificate( + certFile, certTime, keyFile, keyTime, + ) + if info == nil || err != nil { + return nil, err + } + } + return info.certificate, nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/webserver/certificate_test.go new/galene-0.3.1/webserver/certificate_test.go --- old/galene-0.3/webserver/certificate_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/galene-0.3.1/webserver/certificate_test.go 2021-02-26 19:13:15.000000000 +0100 @@ -0,0 +1,51 @@ +package webserver + +import ( + "testing" +) + +func TestGenerateCertificate(t *testing.T) { + _, err := generateCertificate() + if err != nil { + t.Errorf("generateCertificate: %v", err) + } +} + +func BenchmarkGenerateCertificate(b *testing.B) { + for i := 0; i < b.N; i++ { + _, err := generateCertificate() + if err != nil { + b.Errorf("generateCertificate: %v", err) + } + } +} + +func TestGetCertificate(t *testing.T) { + cert1, err := getCertificate("/tmp/no/such/file") + if err != nil { + t.Errorf("getCertificate: %v", err) + } + + cert2, err := getCertificate("/tmp/no/such/file") + if err != nil { + t.Errorf("getCertificate: %v", err) + } + + if cert1 != cert2 { + t.Errorf("cert1 != cert2") + } +} + +func BenchmarkGetCertificate(b *testing.B) { + _, err := getCertificate("/tmp/no/such/file") + if err != nil { + b.Errorf("getCertificate: %v", err) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + _, err := getCertificate("/tmp/no/such/file") + if err != nil { + b.Errorf("getCertificate: %v", err) + } + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/galene-0.3/webserver/webserver.go new/galene-0.3.1/webserver/webserver.go --- old/galene-0.3/webserver/webserver.go 2021-02-18 22:53:05.000000000 +0100 +++ new/galene-0.3.1/webserver/webserver.go 2021-02-26 19:13:15.000000000 +0100 @@ -3,6 +3,7 @@ import ( "bufio" "context" + "crypto/tls" "encoding/json" "errors" "fmt" @@ -55,6 +56,13 @@ ReadHeaderTimeout: 60 * time.Second, IdleTimeout: 120 * time.Second, } + if !Insecure { + s.TLSConfig = &tls.Config{ + GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { + return getCertificate(dataDir) + }, + } + } s.RegisterOnShutdown(func() { group.Range(func(g *group.Group) bool { go g.Shutdown("server is shutting down") @@ -67,10 +75,7 @@ var err error if !Insecure { - err = s.ListenAndServeTLS( - filepath.Join(dataDir, "cert.pem"), - filepath.Join(dataDir, "key.pem"), - ) + err = s.ListenAndServeTLS("", "") } else { err = s.ListenAndServe() } @@ -273,8 +278,8 @@ return } - if r.URL.Path != "/group/" + name { - http.Redirect(w, r, "/group/" + name, + if r.URL.Path != "/group/"+name { + http.Redirect(w, r, "/group/"+name, http.StatusPermanentRedirect) return } @@ -433,7 +438,7 @@ fmt.Fprintf(w, "</body></html>\n") } -var wsUpgrader = websocket.Upgrader { +var wsUpgrader = websocket.Upgrader{ HandshakeTimeout: 30 * time.Second, } ++++++ vendor.tar.gz ++++++