# HG changeset patch # User Sascha L. Teichmann # Date 1533476129 -7200 # Node ID 33b59c848771d6e282a19baba765f2ff0754da13 # Parent dabe189369adc9ce247a65e479d2b7068aae2bf5 Factored out some miscellaneous code into own package. diff -r dabe189369ad -r 33b59c848771 auth/connection.go --- 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 diff -r dabe189369ad -r 33b59c848771 auth/encode.go --- 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)) - } -} diff -r dabe189369ad -r 33b59c848771 auth/session.go --- 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) { diff -r dabe189369ad -r 33b59c848771 controllers/pwreset.go --- 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} diff -r dabe189369ad -r 33b59c848771 misc/encode.go --- /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)) + } +} diff -r dabe189369ad -r 33b59c848771 misc/mail.go --- /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) +} diff -r dabe189369ad -r 33b59c848771 misc/random.go --- /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) +}