protected override bool TryValidateKeyIdInternal(string keyId, out ValidationStatus status, out string?message) { //B2 master keys are 12. Application keys are 25 if (keyId.Length != 12 && keyId.Length != 25) { status = ValidationStatus.WrongLength; message = "12 / 25"; return(false); } foreach (char c in keyId) { if (CharHelper.InRange(c, 'a', 'f') || CharHelper.InRange(c, '0', '9')) { continue; } status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } status = ValidationStatus.Ok; message = null; return(true); }
protected override bool TryValidateKeyIdInternal(string keyId, out ValidationStatus status, out string?message) { if (keyId.Length != 20) { status = ValidationStatus.WrongLength; message = null; return(false); } foreach (char c in keyId) { if (CharHelper.InRange(c, 'A', 'Z') || CharHelper.InRange(c, '0', '9')) { continue; } status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } status = ValidationStatus.Ok; message = null; return(true); }
protected override bool TryValidateKeyIdInternal(string keyId, out ValidationStatus status, out string?message) { //https://cloud.google.com/storage/docs/authentication/hmackeys //Google service keys are 61. User keys are 24 if (keyId.Length != 61 && keyId.Length != 24) { status = ValidationStatus.WrongLength; message = "24 / 61"; return(false); } foreach (char c in keyId) { if (CharHelper.InRange(c, 'a', 'z') || CharHelper.InRange(c, 'A', 'Z') || CharHelper.InRange(c, '0', '9')) { continue; } status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } status = ValidationStatus.Ok; message = null; return(true); }
protected override bool TryValidateObjectKeyInternal(string objectKey, ObjectKeyValidationMode mode, out ValidationStatus status, out string?message) { //https://www.backblaze.com/b2/docs/files.html //Spec: Names can be pretty much any UTF-8 string up to 1024 bytes long if (objectKey.Length < 1 || Encoding.UTF8.GetByteCount(objectKey) > 1024) { status = ValidationStatus.WrongLength; message = "1-1024"; return(false); } foreach (char c in objectKey) { //Spec: No character codes below 32 are allowed. DEL characters (127) are not allowed if (CharHelper.InRange(c, (char)0, (char)31) || c == (char)127) { status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } } status = ValidationStatus.Ok; message = null; return(true); }
protected override bool TryValidateAccessKeyInternal(byte[] accessKey, out ValidationStatus status, out string?message) { //https://cloud.google.com/storage/docs/authentication/hmackeys //Spec: A 40-character Base-64 encoded string that is linked to a specific access ID. if (accessKey.Length != 40) { status = ValidationStatus.WrongLength; message = "40"; return(false); } //Check that it is actually base64 foreach (byte b in accessKey) { char c = (char)b; if (CharHelper.InRange(c, 'a', 'z') || CharHelper.InRange(c, 'A', 'Z') || CharHelper.InRange(c, '0', '9') || CharHelper.OneOf(c, '/', '+', '=')) { continue; } status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } status = ValidationStatus.Ok; message = null; return(true); }
protected bool TryValidateBucketDns(string input, out ValidationStatus status, out string?message) { int curPos = 0; int end = input.Length; do { //find the dot or hit the end int newPos = curPos; while (newPos < end) { if (input[newPos] == '.') { break; } ++newPos; } if (curPos == newPos || newPos - curPos > 63) { message = "1-63"; status = ValidationStatus.WrongLength; return(false); } char start = input[curPos]; if (!CharHelper.InRange(start, 'a', 'z') && !CharHelper.InRange(start, '0', '9')) { message = start.ToString(); status = ValidationStatus.WrongFormat; return(false); } curPos++; //check the label content while (curPos < newPos) { char c = input[curPos++]; if (CharHelper.InRange(c, 'a', 'z') || CharHelper.InRange(c, '0', '9') || c == '-') { continue; } message = c.ToString(); status = ValidationStatus.WrongFormat; return(false); } ++curPos; } while (curPos < end); message = null; status = ValidationStatus.Ok; return(true); }
protected override bool TryValidateBucketNameInternal(string bucketName, BucketNameValidationMode mode, out ValidationStatus status, out string?message) { //Source: https://wasabi.com/wp-content/themes/wasabi/docs/User_Guide/topics/Creating_a_Bucket.htm //Spec: A bucket name can consist of 3 to 63 characters if (bucketName.Length < 3 || bucketName.Length > 63) { status = ValidationStatus.WrongLength; message = "3-63"; return(false); } //Spec: lowercase letters, numbers, periods, and dashes. foreach (char c in bucketName) { if (CharHelper.InRange(c, 'a', 'z') || CharHelper.InRange(c, '0', '9') || CharHelper.OneOf(c, '.', '-')) { continue; } status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } //Spec: The name must begin with a lowercase letter or number. char start = bucketName[0]; if (!CharHelper.InRange(start, 'a', 'z') && !CharHelper.InRange(start, '0', '9')) { status = ValidationStatus.WrongFormat; message = start.ToString(); return(false); } //Spec: The name must begin with a lowercase letter or number. char end = bucketName[bucketName.Length - 1]; if (!CharHelper.InRange(end, 'a', 'z') && !CharHelper.InRange(end, '0', '9')) { status = ValidationStatus.WrongFormat; message = end.ToString(); return(false); } //Spec: name cannot be formatted as an IP address (123.45.678.90) if (_ipRegex.IsMatch(bucketName)) { status = ValidationStatus.WrongFormat; message = bucketName; return(false); } status = ValidationStatus.Ok; message = null; return(true); }
protected override bool TryValidateBucketNameInternal(string bucketName, BucketNameValidationMode mode, out ValidationStatus status, out string?message) { //https://cloud.google.com/storage/docs/naming-buckets //Spec: Bucket names must contain 3-63 characters. Names containing dots can contain up to 222 characters, but each dot-separated component can be no longer than 63 characters. if (bucketName.Length < 3 || bucketName.Length > 63) { status = ValidationStatus.WrongLength; message = "3-63"; return(false); } //Spec: Bucket names must start and end with a number or letter. char start = bucketName[0]; char end = bucketName[bucketName.Length - 1]; if (!CharHelper.InRange(start, 'a', 'z') && !CharHelper.InRange(start, '0', '9')) { status = ValidationStatus.WrongFormat; message = start.ToString(); return(false); } if (!CharHelper.InRange(end, 'a', 'z') && !CharHelper.InRange(end, '0', '9')) { status = ValidationStatus.WrongFormat; message = end.ToString(); return(false); } //Spec: Bucket names must contain only lowercase letters, numbers, dashes (-), underscores (_), and dots (.). Spaces are not allowed. Names containing dots require verification. foreach (char c in bucketName) { if (CharHelper.InRange(c, 'a', 'z') || CharHelper.InRange(c, '0', '9') || CharHelper.OneOf(c, '-', '_', '.')) { continue; } status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } //Spec: Bucket names cannot begin with the "goog" prefix. //Spec: Bucket names cannot contain "google" or close misspellings, such as "g00gle". if (bucketName.StartsWith("goog", StringComparison.Ordinal) || bucketName.Contains("google") || bucketName.Contains("g00gle")) { status = ValidationStatus.ReservedName; message = bucketName; return(false); } status = ValidationStatus.Ok; message = null; return(true); }
protected override bool TryValidateObjectKeyInternal(string objectKey, ObjectKeyValidationMode mode, out ValidationStatus status, out string?message) { //Source: https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html //Spec: The name for a key is a sequence of Unicode characters whose UTF-8 encoding is at most 1,024 bytes long. if (objectKey.Length < 1 || Constants.Utf8NoBom.GetByteCount(objectKey) > 1024) { status = ValidationStatus.WrongLength; message = "1-1024"; return(false); } //Spec: You can use any UTF-8 character in an object key name. However, using certain characters in key names can cause problems with some applications and protocols. foreach (char c in objectKey) { //Spec: Safe characters if (CharHelper.InRange(c, 'a', 'z') || CharHelper.InRange(c, 'A', 'Z') || CharHelper.InRange(c, '0', '9')) { continue; } //Spec: Safe characters if (CharHelper.OneOf(c, '/', '!', '-', '_', '.', '*', '\'', '(', ')')) { continue; } if (mode == ObjectKeyValidationMode.DefaultStrict) { //Spec: Characters that might require special handling if (CharHelper.OneOf(c, '&', '$', '@', '=', ';', ':', '+', ' ', ',', '?') || CharHelper.InRange(c, (char)0, (char)31) || c == (char)127) { status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } //Spec: Characters to avoid if (CharHelper.OneOf(c, '\\', '{', '}', '^', '%', '`', '[', ']', '"', '<', '>', '~', '#', '|')) { status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } } } status = ValidationStatus.Ok; message = null; return(true); }
protected bool TryValidateBlacklisted(string input, out ValidationStatus status, out string?message) { foreach (char c in input) { //0xD800 to 0xDFFF are reserved code points in UTF-16. Since they will always be URL encoded to %EF%BF%BD (the � char) in UTF-8 if (CharHelper.InRange(c, '\uD800', '\uDFFF')) { status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } } message = null; status = ValidationStatus.Ok; return(true); }
protected bool TryValidateObjectSafeOnly(string input, out ValidationStatus status, out string?message) { foreach (char c in input) { if (CharHelper.InRange(c, 'a', 'z') || CharHelper.InRange(c, 'A', 'Z') || CharHelper.InRange(c, '0', '9')) { continue; } message = c.ToString(); status = ValidationStatus.WrongFormat; return(false); } message = null; status = ValidationStatus.Ok; return(true); }
protected bool TryValidateObjectExtAsciiOnly(string input, out ValidationStatus status, out string?message) { foreach (char c in input) { if (CharHelper.InRange(c, (char)0, (char)255)) { continue; } message = c.ToString(); status = ValidationStatus.WrongFormat; return(false); } message = null; status = ValidationStatus.Ok; return(true); }
private bool IsValidChar(char c) { // According to https://www.w3.org/TR/xml/#charsets #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] are valid if (_xmlStandard == XmlStandard.Xml10) { return(c == '\u0009' || c == '\u000A' || c == '\u000D' || CharHelper.InRange(c, '\u0020', '\uD7FF') || CharHelper.InRange(c, '\uE000', '\uFFFD')); } // According to https://www.w3.org/TR/xml11/#charsets [#x1-#xD7FF] | [#xE000-#xFFFD] are valid characters if (_xmlStandard == XmlStandard.Xml11) { return(CharHelper.InRange(c, '\u0001', '\uD7FF') || CharHelper.InRange(c, '\uE000', '\uFFFD')); } throw new S3Exception("Invalid XML standard"); }
private bool IsDiscouraged(char c) { // According to https://www.w3.org/TR/xml/#charsets [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDEF] are discouraged if (_xmlStandard == XmlStandard.Xml10) { return(CharHelper.InRange(c, '\u007F', '\u0084') || CharHelper.InRange(c, '\u0086', '\u009F') || CharHelper.InRange(c, '\uFDD0', '\uFDEF')); //Unicode non-characters } // According to https://www.w3.org/TR/xml11/#charsets [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F] are discouraged if (_xmlStandard == XmlStandard.Xml11) { return(CharHelper.InRange(c, '\u0001', '\u0008') || CharHelper.InRange(c, '\u000B', '\u000C') || CharHelper.InRange(c, '\u000E', '\u001F') || CharHelper.InRange(c, '\u007F', '\u0084') || CharHelper.InRange(c, '\u0086', '\u009F') || CharHelper.InRange(c, '\uFDD0', '\uFDEF')); //Unicode non-characters } throw new S3Exception("Invalid XML standard"); }
public static bool ContainsInvalidXml(string xml) { if (string.IsNullOrEmpty(xml)) { return(false); } foreach (char c in xml) { //Invalid if (c == '\"' || c == '\'' || c == '<' || c == '>' || c == '&' || c == '\uFFFE' || c == '\uFFFF') { return(true); } //See https://www.w3.org/TR/unicode-xml/#Noncharacters if (CharHelper.InRange(c, '\uFDD0', '\uFDEF')) { return(true); } } return(false); }
protected override bool TryValidateBucketNameInternal(string bucketName, BucketNameValidationMode mode, out ValidationStatus status, out string?message) { //https://www.backblaze.com/b2/docs/buckets.html //Spec: A bucket name must be at least 6 characters long, and can be at most 50 characters if (bucketName.Length < 6 || bucketName.Length > 50) { status = ValidationStatus.WrongLength; message = "6-50"; return(false); } //Spec: Bucket names that start with "b2-" are reserved for BackBlaze use. if (bucketName.StartsWith("b2-", StringComparison.OrdinalIgnoreCase)) { status = ValidationStatus.ReservedName; message = bucketName; return(false); } //Spec: Bucket names can consist of upper-case letters, lower-case letters, numbers, and "-". No other characters are allowed. foreach (char c in bucketName) { if (CharHelper.InRange(c, 'a', 'z') || CharHelper.InRange(c, 'A', 'Z') || CharHelper.InRange(c, '0', '9') || c == '-') { continue; } status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } status = ValidationStatus.Ok; message = null; return(true); }
/// <summary> /// Validates a bucket name according to standard DNS rules. See /// https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html#bucketnamingrules for more details. /// </summary> /// <param name="bucketName">The bucket name</param> /// <param name="status">Contains the error if validation failed</param> /// <returns>True if validation succeeded, false otherwise</returns> public static bool TryValidateBucketName(string bucketName, out ValidationStatus status) { if (bucketName == null) { status = ValidationStatus.NullInput; return(false); } if (bucketName.Length < 3 || bucketName.Length > 63) { status = ValidationStatus.WrongLength; return(false); } int curPos = 0; int end = bucketName.Length; do { //find the dot or hit the end int newPos = curPos; while (newPos < end) { if (bucketName[newPos] == '.') { break; } ++newPos; } if (curPos == newPos || newPos - curPos > 63) { status = ValidationStatus.WrongLength; return(false); } char start = bucketName[curPos]; if (!CharHelper.InRange(start, 'a', 'z') && !CharHelper.InRange(start, '0', '9')) { status = ValidationStatus.WrongFormat; return(false); } curPos++; //check the label content while (curPos < newPos) { char c = bucketName[curPos++]; if (CharHelper.InRange(c, 'a', 'z') || CharHelper.InRange(c, '0', '9') || c == '-') { continue; } status = ValidationStatus.WrongFormat; return(false); } ++curPos; } while (curPos < end); status = ValidationStatus.Ok; return(true); }
public static bool TryValidateObjectKey(string objectKey, KeyValidationMode mode, out ValidationStatus status) { if (string.IsNullOrEmpty(objectKey)) { status = ValidationStatus.NullInput; return(false); } if (objectKey.Length > 1024) { status = ValidationStatus.WrongLength; return(false); } if (mode == KeyValidationMode.Unrestricted) { status = ValidationStatus.Ok; return(true); } foreach (char c in objectKey) { if (CharHelper.InRange(c, 'a', 'z')) { continue; } if (CharHelper.InRange(c, 'A', 'Z')) { continue; } if (CharHelper.InRange(c, '0', '9')) { continue; } //See https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html if (CharHelper.OneOf(c, '/', '!', '-', '_', '.', '*', '\'', '(', ')')) { continue; } //0xD800 to 0xDFFF are reserved code points in UTF-16. Since they will always be URL encoded to %EF%BF%BD (the � char) in UTF-8 if (CharHelper.InRange(c, '\uD800', '\uDFFF')) { status = ValidationStatus.WrongFormat; return(false); } if (mode == KeyValidationMode.SafeMode) { status = ValidationStatus.WrongFormat; return(false); } if (CharHelper.OneOf(c, '&', '$', '@', '=', ';', ':', '+', ' ', ',', '?')) { continue; } if (CharHelper.InRange(c, (char)0, (char)31) || c == (char)127) { continue; } if (mode == KeyValidationMode.AsciiMode) { status = ValidationStatus.WrongFormat; return(false); } if (CharHelper.OneOf(c, '\\', '{', '}', '^', '%', '`', '[', ']', '"', '<', '>', '~', '#', '|')) { continue; } if (CharHelper.InRange(c, (char)128, (char)255)) { continue; } if (mode == KeyValidationMode.ExtendedAsciiMode) { status = ValidationStatus.WrongFormat; return(false); } } status = ValidationStatus.Ok; return(true); }
public bool CharRangeWithHelper() { char c = 'f'; return(CharHelper.InRange(c, 'a', 'z')); }
protected override bool TryValidateBucketNameInternal(string bucketName, BucketNameValidationMode mode, out ValidationStatus status, out string?message) { //Source: https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html //Spec: Bucket names must be between 3 and 63 characters long. if (bucketName.Length < 3 || bucketName.Length > 63) { status = ValidationStatus.WrongLength; message = "3-63"; return(false); } //Spec: Bucket names can consist only of lowercase letters, numbers, dots (.), and hyphens (-). foreach (char c in bucketName) { if (CharHelper.InRange(c, 'a', 'z') || CharHelper.InRange(c, '0', '9') || CharHelper.OneOf(c, '.', '-')) { continue; } status = ValidationStatus.WrongFormat; message = c.ToString(); return(false); } //Spec: Bucket names must begin and end with a letter or number. char start = bucketName[0]; if (!CharHelper.InRange(start, 'a', 'z') && !CharHelper.InRange(start, '0', '9')) { status = ValidationStatus.WrongFormat; message = start.ToString(); return(false); } //Spec: Bucket names must begin and end with a letter or number. char end = bucketName[bucketName.Length - 1]; if (!CharHelper.InRange(end, 'a', 'z') && !CharHelper.InRange(end, '0', '9')) { status = ValidationStatus.WrongFormat; message = end.ToString(); return(false); } //Spec: Bucket names must not be formatted as an IP address (for example, 192.168.5.4). if (_ipRegex.IsMatch(bucketName)) { status = ValidationStatus.WrongFormat; message = bucketName; return(false); } //Spec: Bucket names must not start with the prefix xn--. if (bucketName.StartsWith("xn--", StringComparison.Ordinal)) { status = ValidationStatus.WrongFormat; message = "xn--"; return(false); } //Spec: Bucket names must not end with the suffix -s3alias. This suffix is reserved for access point alias names. For more information, see Using a bucket-style alias for your access point. if (bucketName.EndsWith("-s3alias", StringComparison.Ordinal)) { status = ValidationStatus.WrongFormat; message = "-s3alias"; return(false); } status = ValidationStatus.Ok; message = null; return(true); }