diff --git a/utils/utils.go b/utils/utils.go index 8fe8471a..9c5fa58f 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -40,6 +40,21 @@ var ( // We do NOT want to support formats like SVG since they can be used for javascript injection // If we get pushback on only supporting png, we can support jpg, jpeg, gif, etc. later ImageExtensions = []string{".png"} + + // Regular expression to ethereum address + ethAddrPattern = regexp.MustCompile("^0x[0-9a-fA-F]{40}$") + + // Regular expression to validate text + textPattern = regexp.MustCompile(TextRegex) + + // Regular expression to validate URLs + rawGitHubUrlPattern = regexp.MustCompile(`^https?://raw\.githubusercontent\.com/.*$`) + + // Regular expression to validate URLs + twitterUrlPattern = regexp.MustCompile(`^(?:https?://)?(?:www\.)?(?:twitter\.com/\w+|x\.com/\w+)(?:/?|$)`) + + // Regular expression to validate URLs + urlPattern = regexp.MustCompile(`^(https?)://[^\s/$.?#].[^\s]*$`) ) func ReadFile(path string) ([]byte, error) { @@ -100,8 +115,7 @@ func RoundUpDivideBig(a, b *big.Int) *big.Int { } func IsValidEthereumAddress(address string) bool { - re := regexp.MustCompile("^0x[0-9a-fA-F]{40}$") - return re.MatchString(address) + return ethAddrPattern.MatchString(address) } func ReadPublicURL(url string) ([]byte, error) { @@ -150,11 +164,8 @@ func CheckIfValidTwitterURL(twitterURL string) error { return err } - // Regular expression to validate URLs - urlPattern := regexp.MustCompile(`^(?:https?://)?(?:www\.)?(?:twitter\.com/\w+|x\.com/\w+)(?:/?|$)`) - // Check if the URL matches the regular expression - if !urlPattern.MatchString(twitterURL) { + if !twitterUrlPattern.MatchString(twitterURL) { return ErrInvalidTwitterUrlRegex } @@ -194,9 +205,6 @@ func CheckIfUrlIsValid(rawUrl string) error { return err } - // Regular expression to validate URLs - urlPattern := regexp.MustCompile(`^(https?)://[^\s/$.?#].[^\s]*$`) - // Check if the URL matches the regular expression if !urlPattern.MatchString(rawUrl) { return ErrInvalidUrl @@ -246,9 +254,6 @@ func ValidateText(text string) error { return ErrTextTooLong(TextCharsLimit) } - // Regular expression to validate text - textPattern := regexp.MustCompile(TextRegex) - // Check if the URL matches the regular expression if !textPattern.MatchString(text) { return ErrInvalidText @@ -264,9 +269,6 @@ func ValidateRawGithubUrl(url string) error { return err } - // Regular expression to validate URLs - rawGitHubUrlPattern := regexp.MustCompile(`^https?://raw\.githubusercontent\.com/.*$`) - // Check if the URL matches the regular expression if !rawGitHubUrlPattern.MatchString(url) { return ErrInvalidGithubRawUrl diff --git a/utils/utils_test.go b/utils/utils_test.go index 8905f23e..0f7e4885 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -1,36 +1,149 @@ package utils import ( + "strings" "testing" "github.com/stretchr/testify/assert" ) -func TestValidateRawGithubUrl(t *testing.T) { +func TestIsValidEthereumAddress(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + address string + expected bool + }{ + { + name: "valid address", + address: "0x1234567890abcdef1234567890abcdef12345678", + expected: true, + }, + { + name: "uppercase", + address: "0x1234567890ABCDEF1234567890ABCDEF12345678", + expected: true, + }, + { + name: "too short", + address: "0x1234567890abcdef1234567890abcdef123456", + expected: false, + }, + { + name: "missing 0x prefix", + address: "001234567890abcdef1234567890abcdef12345678", + expected: false, + }, + { + name: "non-hex characters", + address: "0x1234567890abcdef1234567890abcdef123ÅÅÅÅÅ", + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := IsValidEthereumAddress(tt.address) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestCheckIfValidTwitterURL(t *testing.T) { + t.Parallel() + tests := []struct { name string - url string + twitterURL string expectedErr error }{ { - name: "valid raw github url", - url: "https://raw.githubusercontent.com/Layr-Labs/eigensdk-go/main/README.md", + name: "valid Twitter URL", + twitterURL: "https://twitter.com/user", + expectedErr: nil, }, { - name: "invalid raw github url", - url: "https://facebook.com", - expectedErr: ErrInvalidGithubRawUrl, + name: "valid X URL", + twitterURL: "https://x.com/user", + expectedErr: nil, + }, + { + name: "invalid non-Twitter URL", + twitterURL: "https://example.com/user", + expectedErr: ErrInvalidTwitterUrlRegex, + }, + { + name: "empty URL", + twitterURL: "", + expectedErr: ErrEmptyUrl, + }, + { + name: "URL pointing to localhost", + twitterURL: "http://localhost", + expectedErr: ErrUrlPointingToLocalServer, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := ValidateRawGithubUrl(tt.url) + err := CheckIfValidTwitterURL(tt.twitterURL) + assert.Equal(t, tt.expectedErr, err) + }) + } +} + +func TestCheckIfUrlIsValid(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + rawUrl string + expectedErr error + }{ + { + name: "valid http URL", + rawUrl: "http://example.com", + expectedErr: nil, + }, + { + name: "valid https URL", + rawUrl: "https://example.com", + expectedErr: nil, + }, + { + name: "empty URL", + rawUrl: "", + expectedErr: ErrEmptyUrl, + }, + { + name: "localhost", + rawUrl: "http://localhost", + expectedErr: ErrUrlPointingToLocalServer, + }, + { + name: "too long", + rawUrl: "http://example.com/" + string(make([]byte, 1025)), + expectedErr: ErrInvalidUrlLength, + }, + { + name: "invalid basic URL format", + rawUrl: "invalid-url", + expectedErr: ErrInvalidUrl, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := CheckIfUrlIsValid(tt.rawUrl) assert.Equal(t, tt.expectedErr, err) }) } } func TestReadPublicURL(t *testing.T) { + t.Parallel() + tests := []struct { name string url string @@ -55,3 +168,138 @@ func TestReadPublicURL(t *testing.T) { }) } } + +func TestValidateText(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + text string + expectedErr error + }{ + { + name: "valid text", + text: "Hello, World!", + expectedErr: nil, + }, + { + name: "empty text", + text: "", + expectedErr: ErrEmptyText, + }, + { + name: "text too long", + text: strings.Repeat("a", TextCharsLimit+1), + expectedErr: ErrTextTooLong(TextCharsLimit), + }, + { + name: "text not too long", + text: strings.Repeat("a", TextCharsLimit-1), + expectedErr: nil, + }, + { + name: "invalid text with special characters", + text: "Invalid chars: @#$%^", + expectedErr: ErrInvalidText, + }, + { + name: "valid text with allowed special characters", + text: "Valid chars: -_(),.!?", + expectedErr: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := ValidateText(tt.text) + assert.Equal(t, tt.expectedErr, err) + }) + } +} + +func TestValidateRawGithubUrl(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + url string + expectedErr error + }{ + { + name: "valid raw github url", + url: "https://raw.githubusercontent.com/Layr-Labs/eigensdk-go/main/README.md", + }, + { + name: "localhost", + url: "localhost", + expectedErr: ErrUrlPointingToLocalServer, + }, + { + name: "invalid raw github url", + url: "https://facebook.com", + expectedErr: ErrInvalidGithubRawUrl, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := ValidateRawGithubUrl(tt.url) + assert.Equal(t, tt.expectedErr, err) + }) + } +} + +func TestAdd0x(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + address string + expected string + }{ + { + name: "address with 0x prefix", + address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + expected: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + }, + { + name: "address without 0x prefix", + address: "d8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + expected: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := Add0x(tt.address) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestTrim0x(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + address string + expected string + }{ + { + name: "address with 0x prefix", + address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + expected: "d8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + }, + { + name: "address without 0x prefix", + address: "d8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + expected: "d8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := Trim0x(tt.address) + assert.Equal(t, tt.expected, result) + }) + } +}