diff --git a/pkgs/shared/common/src/Helpers/ValidationUtils.cs b/pkgs/shared/common/src/Helpers/ValidationUtils.cs index 7a11780d..b66b84cb 100644 --- a/pkgs/shared/common/src/Helpers/ValidationUtils.cs +++ b/pkgs/shared/common/src/Helpers/ValidationUtils.cs @@ -9,9 +9,36 @@ namespace LaunchDarkly.Sdk.Helpers public static class ValidationUtils { private static readonly Regex ValidCharsRegex = new Regex("^[-a-zA-Z0-9._]+\\z"); + private const int MaxSdkKeyLength = 8192; /// - /// Validates that a string is non-empty, not too longer for our systems, and only contains + /// Validates that a string does not contain invalid characters and is not too long for our systems. + /// + /// the SDK key to validate. + /// True if the SDK key format is valid, otherwise false. + public static bool IsValidSdkKeyFormat(string sdkKey) + { + // For offline mode, we allow a null or empty SDK key and it is not invalid. + if (string.IsNullOrEmpty(sdkKey)) + { + return true; + } + + if (sdkKey.Length > MaxSdkKeyLength) + { + return false; + } + + if (!ValidCharsRegex.IsMatch(sdkKey)) + { + return false; + } + + return true; + } + + /// + /// Validates that a string is non-empty, not too long for our systems, and only contains /// alphanumeric characters, hyphens, periods, and underscores. /// /// the string to validate. diff --git a/pkgs/shared/common/test/Helpers/ValidationUtilsTest.cs b/pkgs/shared/common/test/Helpers/ValidationUtilsTest.cs index 26f9c342..12d56aa9 100644 --- a/pkgs/shared/common/test/Helpers/ValidationUtilsTest.cs +++ b/pkgs/shared/common/test/Helpers/ValidationUtilsTest.cs @@ -4,18 +4,60 @@ namespace LaunchDarkly.Sdk.Helpers { public class ValidationUtilsTest { + [Theory] + [InlineData(null)] + [InlineData("")] + public void IsValidSdkKeyFormat_EmptyOrNullKey_ReturnsTrue(string key) + { + Assert.True(ValidationUtils.IsValidSdkKeyFormat(key)); + } + + [Theory] + [InlineData("sdk-key-123")] + [InlineData("sdk.key.123")] + [InlineData("sdk_key_123")] + [InlineData("SDKKEY123")] + public void IsValidSdkKeyFormat_ValidKey_ReturnsTrue(string key) + { + Assert.True(ValidationUtils.IsValidSdkKeyFormat(key)); + } + [Fact] - public void ValidateStringValue() + public void IsValidSdkKeyFormat_TooLongKey_ReturnsFalseWithError() + { + var longKey = new string('a', 8193); // Creates a string longer than MaxSdkKeyLength (8192) + Assert.False(ValidationUtils.IsValidSdkKeyFormat(longKey)); + } + + [Theory] + [InlineData("sdk key")] // Contains space + [InlineData("sdk#key")] // Contains special character + [InlineData("sdk/key")] // Contains slash + [InlineData("sdk\nkey")] // Contains newline + public void IsValidSdkKeyFormat_InvalidCharacters_ReturnsFalseWithError(string key) + { + Assert.False(ValidationUtils.IsValidSdkKeyFormat(key)); + } + + [Theory] + [InlineData("bad-\n")] // Contains newline + [InlineData("bad-\t")] // Contains tab + [InlineData("###invalid")] // Contains special characters + [InlineData("")] // Empty string + [InlineData("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEFwhoops")] // Too long + [InlineData("#@$%^&")] // Invalid characters + public void ValidateStringValue_Invalid_ReturnsErrorMessage(string input) + { + Assert.NotNull(ValidationUtils.ValidateStringValue(input)); + } + + [Theory] + [InlineData("a-Az-Z0-9._-")] + [InlineData("valid-string-123")] + [InlineData("VALIDSTRING")] + public void ValidateStringValue_Valid_ReturnsNull(string input) { - Assert.NotNull(ValidationUtils.ValidateStringValue("bad-\n")); - Assert.NotNull(ValidationUtils.ValidateStringValue("bad-\t")); - Assert.NotNull(ValidationUtils.ValidateStringValue("###invalid")); - Assert.NotNull(ValidationUtils.ValidateStringValue("")); - Assert.NotNull( - ValidationUtils.ValidateStringValue( - "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEFwhoops")); - Assert.NotNull(ValidationUtils.ValidateStringValue("#@$%^&")); - Assert.Null(ValidationUtils.ValidateStringValue("a-Az-Z0-9._-")); + Assert.Null(ValidationUtils.ValidateStringValue(input)); } [Fact]