-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
182 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// Package utils contains utility functions for the application | ||
package utils | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"regexp" | ||
"time" | ||
|
||
"github.com/oklog/ulid/v2" | ||
"golang.org/x/exp/rand" | ||
) | ||
|
||
// IsULID checks if the given string is a valid ULID | ||
// ULID pattern: | ||
// | ||
// 01AN4Z07BY 79KA1307SR9X4MV3 | ||
// |----------| |----------------| | ||
// Timestamp Randomness | ||
// | ||
// 10 characters 16 characters | ||
// Crockford's Base32 is used (excludes I, L, O, and U to avoid confusion and abuse) | ||
func isULID(s string) bool { | ||
ulidRegex := `^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$` | ||
matched, _ := regexp.MatchString(ulidRegex, s) | ||
return matched | ||
} | ||
|
||
func getMACAddress() ([]byte, error) { | ||
interfaces, err := net.Interfaces() | ||
if err != nil { | ||
return nil, err | ||
} | ||
for _, intf := range interfaces { | ||
if (intf.Flags&net.FlagLoopback) == 0 && intf.HardwareAddr != nil { | ||
return intf.HardwareAddr, nil | ||
} | ||
} | ||
return nil, fmt.Errorf("no non-loopback interfaces found") | ||
} | ||
|
||
// ValidID checks if the given id is valid | ||
func ValidID(id string) bool { | ||
_, err := ulid.Parse(id) | ||
|
||
return err == nil && isULID(id) | ||
} | ||
|
||
// GenerateID generates a new universal ID | ||
func GenerateID() string { | ||
// mac, _ := getMACAddress() | ||
|
||
// var seed int64 | ||
// if len(mac) >= 8 { | ||
// seed = int64(binary.BigEndian.Uint64(mac[:8])) | ||
// } else { | ||
// paddedMAC := make([]byte, 8) | ||
// copy(paddedMAC, mac) | ||
// seed = int64(binary.BigEndian.Uint64(paddedMAC)) | ||
// } | ||
|
||
// ---- | ||
// now := time.Now() | ||
// ts := ulid.Timestamp(now) | ||
// monoTonicEntropy := ulid.Monotonic(rand.New(rand.NewSource(seed)), 0) | ||
// return ulid.MustNew(ts, monoTonicEntropy).String() | ||
|
||
// ---- | ||
// rng := rand.New(rand.NewSource(time.Now().UnixNano())) | ||
// safe := &ulid.LockedMonotonicReader{MonotonicReader: ulid.Monotonic(rng, 0)} | ||
// t0 := ulid.Timestamp(time.Now()) | ||
|
||
// return ulid.MustNew(t0, safe).String() | ||
|
||
// ---- | ||
// return ulid.Make().String() | ||
|
||
// ---- | ||
|
||
// Create a source of entropy. Use time.Now().UnixNano() as the seed. | ||
// x/exp/rand uses a Seed method that accepts a uint64, so we need to convert the int64 seed. | ||
seed := uint64(time.Now().UnixNano()) | ||
source := rand.NewSource(seed) | ||
|
||
// Create a rand.Rand object using the source. | ||
rng := rand.New(source) | ||
|
||
// Generate a ULID with the current time and the new RNG source. | ||
// x/exp/rand package is directly compatible with the ULID package since it implements rand.Source. | ||
return ulid.MustNew(ulid.Timestamp(time.Now()), rng).String() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package utils | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
) | ||
|
||
// TestValidID tests the ValidID function with both valid and invalid inputs. | ||
func TestValidID(t *testing.T) { | ||
// Generate a valid ULID for testing. | ||
validULID := GenerateID() | ||
|
||
tests := []struct { | ||
id string | ||
expected bool | ||
}{ | ||
{validULID, true}, | ||
{"0", false}, | ||
{"invalidulid", false}, | ||
{"invalidulid", false}, | ||
{"01B4E6BXY0PRJ5G420D25MWQY!", false}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.id, func(t *testing.T) { | ||
if got := ValidID(tt.id); got != tt.expected { | ||
t.Errorf("ValidID(%s) = %v; want %v", tt.id, got, tt.expected) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestGenerateID(t *testing.T) { | ||
id := GenerateID() | ||
if !ValidID(id) { | ||
t.Errorf("Generated ID is not a valid ULID: %s", id) | ||
} | ||
|
||
if len(id) != 26 { | ||
t.Errorf("Generated ID does not have the correct length: got %v want %v", len(id), 26) | ||
} | ||
|
||
if strings.ContainsAny(id, "ilou") { | ||
t.Errorf("Generated ID contains invalid characters: %s", id) | ||
} | ||
} |