diff --git a/msg.go b/msg.go index 0e1aca3..762dbd2 100644 --- a/msg.go +++ b/msg.go @@ -12,7 +12,6 @@ import ( "fmt" ht "html/template" "io" - "math/rand" "mime" "net/mail" "os" @@ -357,12 +356,11 @@ func (m *Msg) SetMessageID() { if err != nil { hn = "localhost.localdomain" } - ct := time.Now().UnixNano() - r := rand.New(rand.NewSource(ct)) - rn := r.Int63() - pid := os.Getpid() * (r.Intn(10000) + 1) - cts := fmt.Sprintf("%d", ct) - mid := fmt.Sprintf("%d.%d.%s@%s", pid, rn, cts[:16], hn) + rn, _ := randNum(100000000) + rm, _ := randNum(10000) + rs, _ := randomStringSecure(25) + pid := os.Getpid() * rm + mid := fmt.Sprintf("%d.%d%d.%s@%s", pid, rn, rm, rs, hn) m.SetMessageIDWithValue(mid) } diff --git a/random.go b/random.go new file mode 100644 index 0000000..5c23972 --- /dev/null +++ b/random.go @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: 2022 Winni Neessen +// +// SPDX-License-Identifier: MIT + +package mail + +import ( + "crypto/rand" + "encoding/binary" + "fmt" + "math/big" + "strings" +) + +// Range of characters for the secure string generation +const cr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" + +// Bitmask sizes for the string generators (based on 93 chars total) +const ( + letterIdxBits = 7 // 7 bits to represent a letter index + letterIdxMask = 1<= 0; { + if r == 0 { + _, err := rand.Read(rp) + if err != nil { + return rs.String(), err + } + c, r = binary.BigEndian.Uint64(rp), letterIdxMax + } + if idx := int(c & letterIdxMask); idx < crl { + rs.WriteByte(cr[idx]) + i-- + } + c >>= letterIdxBits + r-- + } + + return rs.String(), nil +} + +// randNum returns a random number with a maximum value of n +func randNum(n int) (int, error) { + if n <= 0 { + return 0, fmt.Errorf("provided number is <= 0: %d", n) + } + mbi := big.NewInt(int64(n)) + if !mbi.IsUint64() { + return 0, fmt.Errorf("big.NewInt() generation returned negative value: %d", mbi) + } + rn64, err := rand.Int(rand.Reader, mbi) + if err != nil { + return 0, err + } + rn := int(rn64.Int64()) + if rn < 0 { + return 0, fmt.Errorf("generated random number does not fit as int64: %d", rn64) + } + return rn, nil +}