changeset 339:33b59c848771

Factored out some miscellaneous code into own package.
author Sascha L. Teichmann <teichmann@intevation.de>
date Sun, 05 Aug 2018 15:35:29 +0200
parents dabe189369ad
children 4c211ad5349e
files auth/connection.go auth/encode.go auth/session.go controllers/pwreset.go misc/encode.go misc/mail.go misc/random.go
diffstat 7 files changed, 163 insertions(+), 145 deletions(-) [+]
line wrap: on
line diff
--- a/auth/connection.go	Fri Aug 03 22:20:06 2018 +0200
+++ b/auth/connection.go	Sun Aug 05 15:35:29 2018 +0200
@@ -7,6 +7,8 @@
 	"log"
 	"sync"
 	"time"
+
+	"gemma.intevation.de/gemma/misc"
 )
 
 var ErrNoSuchToken = errors.New("No such token")
@@ -34,10 +36,10 @@
 	if err != nil {
 		return err
 	}
-	wr := binWriter{w: w}
-	wr.write(uint32(len(access)))
-	wr.write(access)
-	return wr.err
+	wr := misc.BinWriter{W: w}
+	wr.Write(uint32(len(access)))
+	wr.Write(access)
+	return wr.Err
 }
 
 func (c *Connection) deserialize(r io.Reader) error {
@@ -46,14 +48,14 @@
 		return err
 	}
 
-	rd := binReader{r: r}
+	rd := misc.BinReader{R: r}
 	var l uint32
-	rd.read(&l)
+	rd.Read(&l)
 	access := make([]byte, l)
-	rd.read(access)
+	rd.Read(access)
 
-	if rd.err != nil {
-		return rd.err
+	if rd.Err != nil {
+		return rd.Err
 	}
 
 	var t time.Time
--- a/auth/encode.go	Fri Aug 03 22:20:06 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-package auth
-
-import (
-	"encoding/binary"
-	"io"
-)
-
-type binReader struct {
-	r   io.Reader
-	err error
-}
-
-func (r *binReader) read(x interface{}) {
-	if r.err == nil {
-		r.err = binary.Read(r.r, binary.BigEndian, x)
-	}
-}
-
-func (r *binReader) readString(s *string) {
-	if r.err != nil {
-		return
-	}
-	var l uint32
-	if r.err = binary.Read(r.r, binary.BigEndian, &l); r.err != nil {
-		return
-	}
-	b := make([]byte, l)
-	if r.err = binary.Read(r.r, binary.BigEndian, b); r.err != nil {
-		return
-	}
-	*s = string(b)
-}
-
-type binWriter struct {
-	w   io.Writer
-	err error
-}
-
-func (w *binWriter) write(x interface{}) {
-	if w.err == nil {
-		w.err = binary.Write(w.w, binary.BigEndian, x)
-	}
-}
-
-func (w *binWriter) writeString(s string) {
-	if w.err == nil {
-		w.err = binary.Write(w.w, binary.BigEndian, uint32(len(s)))
-	}
-	if w.err == nil {
-		w.err = binary.Write(w.w, binary.BigEndian, []byte(s))
-	}
-}
--- a/auth/session.go	Fri Aug 03 22:20:06 2018 +0200
+++ b/auth/session.go	Sun Aug 05 15:35:29 2018 +0200
@@ -1,10 +1,11 @@
 package auth
 
 import (
-	"crypto/rand"
 	"encoding/base64"
 	"io"
 	"time"
+
+	"gemma.intevation.de/gemma/misc"
 )
 
 type Roles []string
@@ -42,45 +43,38 @@
 }
 
 func (s *Session) serialize(w io.Writer) error {
-	wr := binWriter{w: w}
-	wr.write(s.ExpiresAt)
-	wr.writeString(s.User)
-	wr.writeString(s.Password)
-	wr.write(uint32(len(s.Roles)))
+	wr := misc.BinWriter{W: w}
+	wr.Write(s.ExpiresAt)
+	wr.WriteString(s.User)
+	wr.WriteString(s.Password)
+	wr.Write(uint32(len(s.Roles)))
 	for _, role := range s.Roles {
-		wr.writeString(role)
+		wr.WriteString(role)
 	}
-	return wr.err
+	return wr.Err
 }
 
 func (s *Session) deserialize(r io.Reader) error {
 	var x Session
 	var n uint32
-	rd := binReader{r: r}
-	rd.read(&x.ExpiresAt)
-	rd.readString(&x.User)
-	rd.readString(&x.Password)
-	rd.read(&n)
+	rd := misc.BinReader{R: r}
+	rd.Read(&x.ExpiresAt)
+	rd.ReadString(&x.User)
+	rd.ReadString(&x.Password)
+	rd.Read(&n)
 	x.Roles = make(Roles, n)
 	for i := uint32(0); n > 0 && i < n; i++ {
-		rd.readString(&x.Roles[i])
+		rd.ReadString(&x.Roles[i])
 	}
-	if rd.err == nil {
+	if rd.Err == nil {
 		*s = x
 	}
-	return rd.err
+	return rd.Err
 }
 
 func GenerateSessionKey() string {
-	return base64.URLEncoding.EncodeToString(GenerateRandomKey(sessionKeyLength))
-}
-
-func GenerateRandomKey(length int) []byte {
-	k := make([]byte, length)
-	if _, err := io.ReadFull(rand.Reader, k); err != nil {
-		return nil
-	}
-	return k
+	return base64.URLEncoding.EncodeToString(
+		misc.GenerateRandomKey(sessionKeyLength))
 }
 
 func GenerateSession(user, password string) (string, *Session, error) {
--- a/controllers/pwreset.go	Fri Aug 03 22:20:06 2018 +0200
+++ b/controllers/pwreset.go	Sun Aug 05 15:35:29 2018 +0200
@@ -2,22 +2,20 @@
 
 import (
 	"bytes"
-	"crypto/rand"
 	"database/sql"
 	"encoding/hex"
 	"log"
-	"math/big"
 	"net/http"
 	"os/exec"
 	"strings"
 	"text/template"
 	"time"
 
+	"github.com/gorilla/mux"
+
 	"gemma.intevation.de/gemma/auth"
 	"gemma.intevation.de/gemma/config"
-	"github.com/gorilla/mux"
-
-	gomail "gopkg.in/gomail.v2"
+	"gemma.intevation.de/gemma/misc"
 )
 
 const (
@@ -157,38 +155,7 @@
 }
 
 func generateHash() string {
-	return hex.EncodeToString(auth.GenerateRandomKey(hashLength))
-}
-
-func randomString(n int) string {
-
-	const (
-		special  = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
-		alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
-			"abcdefghijklmnopqrstuvwxyz" +
-			"0123456789" +
-			special
-	)
-
-	max := big.NewInt(int64(len(alphabet)))
-	out := make([]byte, n)
-
-	for i := 0; i < 1000; i++ {
-		for i := range out {
-			v, err := rand.Int(rand.Reader, max)
-			if err != nil {
-				log.Panicf("error: %v\n", err)
-			}
-			out[i] = alphabet[v.Int64()]
-		}
-		// Ensure at least one special char.
-		if bytes.IndexAny(out, special) >= 0 {
-			return string(out)
-		}
-	}
-	log.Println("warn: Your random generator may be broken.")
-	out[0] = special[0]
-	return string(out)
+	return hex.EncodeToString(misc.GenerateRandomKey(hashLength))
 }
 
 func generateNewPassword() string {
@@ -198,26 +165,7 @@
 		return strings.TrimSpace(string(out))
 	}
 	// Use internal generator.
-	return randomString(20)
-}
-
-func sendMail(email, subject, body string) error {
-	m := gomail.NewMessage()
-	m.SetHeader("From", config.MailFrom())
-	m.SetHeader("To", email)
-	m.SetHeader("Subject", subject)
-	m.SetBody("text/plain", body)
-
-	d := gomail.Dialer{
-		Host:      config.MailHost(),
-		Port:      int(config.MailPort()),
-		Username:  config.MailUser(),
-		Password:  config.MailPassword(),
-		LocalName: config.MailHelo(),
-		SSL:       config.MailPort() == 465,
-	}
-
-	return d.DialAndSend(m)
+	return misc.RandomString(20)
 }
 
 func passwordResetRequest(
@@ -277,7 +225,7 @@
 	}); err == nil {
 		body := requestMessageBody(useHTTPS(req), user.User, hash, req.Host)
 
-		if err = sendMail(email, "Password Reset Link", body); err == nil {
+		if err = misc.SendMail(email, "Password Reset Link", body); err == nil {
 			jr.Result = &struct {
 				SendTo string `json:"send-to"`
 			}{email}
@@ -320,7 +268,7 @@
 		return err
 	}); err == nil {
 		body := changedMessageBody(useHTTPS(req), user, password, req.Host)
-		if err = sendMail(email, "Password Reset Done", body); err == nil {
+		if err = misc.SendMail(email, "Password Reset Done", body); err == nil {
 			jr.Result = &struct {
 				SendTo string `json:"send-to"`
 			}{email}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/encode.go	Sun Aug 05 15:35:29 2018 +0200
@@ -0,0 +1,52 @@
+package misc
+
+import (
+	"encoding/binary"
+	"io"
+)
+
+type BinReader struct {
+	R   io.Reader
+	Err error
+}
+
+func (r *BinReader) Read(x interface{}) {
+	if r.Err == nil {
+		r.Err = binary.Read(r.R, binary.BigEndian, x)
+	}
+}
+
+func (r *BinReader) ReadString(s *string) {
+	if r.Err != nil {
+		return
+	}
+	var l uint32
+	if r.Err = binary.Read(r.R, binary.BigEndian, &l); r.Err != nil {
+		return
+	}
+	b := make([]byte, l)
+	if r.Err = binary.Read(r.R, binary.BigEndian, b); r.Err != nil {
+		return
+	}
+	*s = string(b)
+}
+
+type BinWriter struct {
+	W   io.Writer
+	Err error
+}
+
+func (w *BinWriter) Write(x interface{}) {
+	if w.Err == nil {
+		w.Err = binary.Write(w.W, binary.BigEndian, x)
+	}
+}
+
+func (w *BinWriter) WriteString(s string) {
+	if w.Err == nil {
+		w.Err = binary.Write(w.W, binary.BigEndian, uint32(len(s)))
+	}
+	if w.Err == nil {
+		w.Err = binary.Write(w.W, binary.BigEndian, []byte(s))
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/mail.go	Sun Aug 05 15:35:29 2018 +0200
@@ -0,0 +1,26 @@
+package misc
+
+import (
+	gomail "gopkg.in/gomail.v2"
+
+	"gemma.intevation.de/gemma/config"
+)
+
+func SendMail(email, subject, body string) error {
+	m := gomail.NewMessage()
+	m.SetHeader("From", config.MailFrom())
+	m.SetHeader("To", email)
+	m.SetHeader("Subject", subject)
+	m.SetBody("text/plain", body)
+
+	d := gomail.Dialer{
+		Host:      config.MailHost(),
+		Port:      int(config.MailPort()),
+		Username:  config.MailUser(),
+		Password:  config.MailPassword(),
+		LocalName: config.MailHelo(),
+		SSL:       config.MailPort() == 465,
+	}
+
+	return d.DialAndSend(m)
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/random.go	Sun Aug 05 15:35:29 2018 +0200
@@ -0,0 +1,48 @@
+package misc
+
+import (
+	"bytes"
+	"crypto/rand"
+	"io"
+	"log"
+	"math/big"
+)
+
+func GenerateRandomKey(length int) []byte {
+	k := make([]byte, length)
+	if _, err := io.ReadFull(rand.Reader, k); err != nil {
+		return nil
+	}
+	return k
+}
+
+func RandomString(n int) string {
+
+	const (
+		special  = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
+		alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
+			"abcdefghijklmnopqrstuvwxyz" +
+			"0123456789" +
+			special
+	)
+
+	max := big.NewInt(int64(len(alphabet)))
+	out := make([]byte, n)
+
+	for i := 0; i < 1000; i++ {
+		for i := range out {
+			v, err := rand.Int(rand.Reader, max)
+			if err != nil {
+				log.Panicf("error: %v\n", err)
+			}
+			out[i] = alphabet[v.Int64()]
+		}
+		// Ensure at least one special char.
+		if bytes.IndexAny(out, special) >= 0 {
+			return string(out)
+		}
+	}
+	log.Println("warn: Your random generator may be broken.")
+	out[0] = special[0]
+	return string(out)
+}