mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-26 23:45:08 +01:00
Compare commits
No commits in common. "8faac3d101ab2a28d2a7a72c6cc4c050f3f72ecf" and "a94e721161a5dea330814bea1f97f74228738571" have entirely different histories.
8faac3d101
...
a94e721161
7 changed files with 137 additions and 20 deletions
18
msg.go
18
msg.go
|
@ -972,12 +972,12 @@ func (m *Msg) Subject(subj string) {
|
||||||
|
|
||||||
// SetMessageID generates and sets a unique "Message-ID" header for the Msg.
|
// SetMessageID generates and sets a unique "Message-ID" header for the Msg.
|
||||||
//
|
//
|
||||||
// This method creates a "Message-ID" string using a randomly generated string and the hostname of the machine.
|
// This method creates a "Message-ID" string using the current process ID, random numbers, and the hostname
|
||||||
// The generated ID helps uniquely identify the message in email systems, facilitating tracking and preventing
|
// of the machine. The generated ID helps uniquely identify the message in email systems, facilitating tracking
|
||||||
// duplication. If the hostname cannot be retrieved, it defaults to "localhost.localdomain".
|
// and preventing duplication. If the hostname cannot be retrieved, it defaults to "localhost.localdomain".
|
||||||
//
|
//
|
||||||
// The generated Message-ID follows the format
|
// The generated Message-ID follows the format
|
||||||
// "<randomString@hostname>".
|
// "<processID.randomNumberPrimary.randomNumberSecondary.randomString@hostname>".
|
||||||
//
|
//
|
||||||
// References:
|
// References:
|
||||||
// - https://datatracker.ietf.org/doc/html/rfc5322#section-3.6.4
|
// - https://datatracker.ietf.org/doc/html/rfc5322#section-3.6.4
|
||||||
|
@ -986,9 +986,13 @@ func (m *Msg) SetMessageID() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
hostname = "localhost.localdomain"
|
hostname = "localhost.localdomain"
|
||||||
}
|
}
|
||||||
// We have 64 possible characters, which for a 22 character string, provides approx. 132 bits of entropy.
|
randNumPrimary := randNum(100000000)
|
||||||
randString, _ := randomStringSecure(22)
|
randNumSecondary := randNum(10000)
|
||||||
m.SetMessageIDWithValue(fmt.Sprintf("%s@%s", randString, hostname))
|
randString, _ := randomStringSecure(17)
|
||||||
|
procID := os.Getpid() * randNumSecondary
|
||||||
|
messageID := fmt.Sprintf("%d.%d%d.%s@%s", procID, randNumPrimary, randNumSecondary,
|
||||||
|
randString, hostname)
|
||||||
|
m.SetMessageIDWithValue(messageID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMessageID retrieves the "Message-ID" header from the Msg.
|
// GetMessageID retrieves the "Message-ID" header from the Msg.
|
||||||
|
|
|
@ -786,8 +786,8 @@ func TestMsg_SetMessageIDWithValue(t *testing.T) {
|
||||||
// TestMsg_SetMessageIDRandomness tests the randomness of Msg.SetMessageID methods
|
// TestMsg_SetMessageIDRandomness tests the randomness of Msg.SetMessageID methods
|
||||||
func TestMsg_SetMessageIDRandomness(t *testing.T) {
|
func TestMsg_SetMessageIDRandomness(t *testing.T) {
|
||||||
var mids []string
|
var mids []string
|
||||||
m := NewMsg()
|
|
||||||
for i := 0; i < 50_000; i++ {
|
for i := 0; i < 50_000; i++ {
|
||||||
|
m := NewMsg()
|
||||||
m.SetMessageID()
|
m.SetMessageID()
|
||||||
mid := m.GetMessageID()
|
mid := m.GetMessageID()
|
||||||
mids = append(mids, mid)
|
mids = append(mids, mid)
|
||||||
|
|
|
@ -11,17 +11,16 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Range of characters for the secure string generation
|
// Range of characters for the secure string generation
|
||||||
const cr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-"
|
const cr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||||
|
|
||||||
// Bitmask sizes for the string generators (based on 93 chars total)
|
// Bitmask sizes for the string generators (based on 93 chars total)
|
||||||
//
|
//
|
||||||
// These constants define bitmask-related values used for efficient random string generation.
|
// These constants define bitmask-related values used for efficient random string generation.
|
||||||
// The bitmask operates over 66 possible characters, and the constants help determine the
|
// The bitmask operates over 93 possible characters, and the constants help determine the
|
||||||
// number of bits and indices used in the process.
|
// number of bits and indices used in the process.
|
||||||
const (
|
const (
|
||||||
// letterIdxBits: Number of bits needed to represent a letter index. We have 64 possible characters
|
// letterIdxBits: Number of bits (7) needed to represent a letter index.
|
||||||
// which fit into 6 bits.
|
letterIdxBits = 7
|
||||||
letterIdxBits = 6
|
|
||||||
// letterIdxMask: Bitmask to extract letter indices (all 1-bits for letterIdxBits).
|
// letterIdxMask: Bitmask to extract letter indices (all 1-bits for letterIdxBits).
|
||||||
letterIdxMask = 1<<letterIdxBits - 1
|
letterIdxMask = 1<<letterIdxBits - 1
|
||||||
// letterIdxMax: The maximum number of letter indices that fit in 63 bits.
|
// letterIdxMax: The maximum number of letter indices that fit in 63 bits.
|
||||||
|
|
32
random_119.go
Normal file
32
random_119.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022-2023 The go-mail Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
//go:build !go1.20
|
||||||
|
// +build !go1.20
|
||||||
|
|
||||||
|
package mail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// randNum returns a random number with a maximum value of maxval.
|
||||||
|
//
|
||||||
|
// This function generates a random integer between 0 and maxval (exclusive). It seeds the
|
||||||
|
// random number generator with the current time in nanoseconds to ensure different results
|
||||||
|
// each time the function is called.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// - maxval: The upper bound for the random number generation (exclusive).
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// - A random integer between 0 and maxval. If maxval is less than or equal to 0, it returns 0.
|
||||||
|
func randNum(maxval int) int {
|
||||||
|
if maxval <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
return rand.Intn(maxval)
|
||||||
|
}
|
30
random_121.go
Normal file
30
random_121.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022-2023 The go-mail Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
//go:build go1.20 && !go1.22
|
||||||
|
// +build go1.20,!go1.22
|
||||||
|
|
||||||
|
package mail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
// randNum returns a random number with a maximum value of maxval.
|
||||||
|
//
|
||||||
|
// This function generates a random integer between 0 and maxval (exclusive). If maxval is less
|
||||||
|
// than or equal to 0, it returns 0. The random number generator uses the default seed provided
|
||||||
|
// by the rand package.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// - maxval: The upper bound for the random number generation (exclusive).
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// - A random integer between 0 and maxval. If maxval is less than or equal to 0, it returns 0.
|
||||||
|
func randNum(maxval int) int {
|
||||||
|
if maxval <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return rand.Intn(maxval)
|
||||||
|
}
|
30
random_122.go
Normal file
30
random_122.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022-2023 The go-mail Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
//go:build go1.22
|
||||||
|
// +build go1.22
|
||||||
|
|
||||||
|
package mail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// randNum returns a random number with a maximum value of maxval.
|
||||||
|
//
|
||||||
|
// This function generates a random integer between 0 and maxval (exclusive). It utilizes
|
||||||
|
// the math/rand/v2 interface for Go 1.22+ and will default to math/rand for older Go versions.
|
||||||
|
// If maxval is less than or equal to 0, it returns 0.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// - maxval: The upper bound for the random number generation (exclusive).
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// - A random integer between 0 and maxval. If maxval is less than or equal to 0, it returns 0.
|
||||||
|
func randNum(maxval int) int {
|
||||||
|
if maxval <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return rand.IntN(maxval)
|
||||||
|
}
|
|
@ -38,12 +38,34 @@ func TestRandomStringSecure(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkGenerator_RandomStringSecure(b *testing.B) {
|
// TestRandomNum tests the randomNum method
|
||||||
b.ReportAllocs()
|
func TestRandomNum(t *testing.T) {
|
||||||
for i := 0; i < b.N; i++ {
|
tt := []struct {
|
||||||
_, err := randomStringSecure(22)
|
testName string
|
||||||
if err != nil {
|
max int
|
||||||
b.Errorf("RandomStringFromCharRange() failed: %s", err)
|
}{
|
||||||
|
{"Max: 1", 1},
|
||||||
|
{"Max: 20", 20},
|
||||||
|
{"Max: 50", 50},
|
||||||
|
{"Max: 100", 100},
|
||||||
|
{"Max: 1000", 1000},
|
||||||
|
{"Max: 10000", 10000},
|
||||||
|
{"Max: 100000000", 100000000},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
t.Run(tc.testName, func(t *testing.T) {
|
||||||
|
rn := randNum(tc.max)
|
||||||
|
if rn > tc.max {
|
||||||
|
t.Errorf("random number generation failed: %d is bigger than given value %d", rn, tc.max)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRandomNumZero(t *testing.T) {
|
||||||
|
rn := randNum(0)
|
||||||
|
if rn != 0 {
|
||||||
|
t.Errorf("random number generation failed: %d is not zero", rn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue