From 09b07992d4316899ee6878585622c0762588a82a Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Mon, 12 Aug 2019 16:14:57 +0800 Subject: Add username validator. --- Timeline/Services/UserService.cs | 73 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) (limited to 'Timeline/Services/UserService.cs') diff --git a/Timeline/Services/UserService.cs b/Timeline/Services/UserService.cs index 28218612..50aa4187 100644 --- a/Timeline/Services/UserService.cs +++ b/Timeline/Services/UserService.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using System; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Timeline.Entities; using Timeline.Models; @@ -102,6 +103,74 @@ namespace Timeline.Services public long RequiredVersion { get; private set; } } + /// + /// Thrown when username is of bad format. + /// + [Serializable] + public class UsernameBadFormatException : Exception + { + public UsernameBadFormatException(string username, string message) : base(message) { Username = username; } + public UsernameBadFormatException(string username, string message, Exception inner) : base(message, inner) { Username = username; } + protected UsernameBadFormatException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + + /// + /// Username of bad format. + /// + public string Username { get; private set; } + } + + public class UsernameValidator + { + public const int MaxLength = 26; + public const string RegexPattern = @"^[a-zA-Z0-9_][a-zA-Z0-9-_]*$"; + + private readonly Regex _regex = new Regex(RegexPattern); + + /// + /// Validate a username. + /// + /// The username. Can't be null. + /// Set as error message if there is error. Or null if no error. + /// True if validation passed. Otherwise false. + /// Thrown when is null. + public bool Validate(string username, out string message) + { + if (username == null) + throw new ArgumentNullException(nameof(username)); + + if (username.Length == 0) + { + message = "An empty string is not permitted."; + return false; + } + + if (username.Length > 26) + { + message = $"Too long, more than 26 characters is not premitted, found {username.Length}."; + return false; + } + + foreach ((char c, int i) in username.Select((c, i) => (c, i))) + if (char.IsWhiteSpace(c)) + { + message = $"A whitespace is found at {i} . Whitespace is not permited."; + return false; + } + + var match = _regex.Match(username); + if (!match.Success) + { + message = "Regex match failed."; + return false; + } + + message = null; + return true; + } + } + public interface IUserService { /// @@ -144,14 +213,14 @@ namespace Timeline.Services /// /// Create or modify a user with given username. - /// Return if a new user is created. - /// Return if a existing user is modified. + /// Username must be match with [a-zA-z0-9-_]. /// /// Username of user. /// Password of user. /// Whether the user is administrator. /// Return if a new user is created. /// Return if a existing user is modified. + /// Thrown when is of bad format. /// Thrown when or is null. Task PutUser(string username, string password, bool administrator); -- cgit v1.2.3