1616/** File-backed account registry with salted SHA-256 token hashes. */
1717public final class AccountStore {
1818 private static final String HASH_ALGORITHM = "SHA-256" ;
19+ private static final int MIN_USER_NAME_LENGTH = 3 ;
20+ private static final int MAX_USER_NAME_LENGTH = 64 ;
21+ private static final String USER_NAME_PATTERN = "[\\ p{L}\\ p{N}_-]+" ;
1922
2023 private final Map <String , AccountRecord > accounts ;
2124 private final boolean enabled ;
@@ -39,7 +42,9 @@ public static AccountStore load(Path accountFile) throws IOException {
3942 continue ;
4043 }
4144 AccountRecord account = parseLine (line , lineNumber );
42- loadedAccounts .put (account .userName (), account );
45+ if (loadedAccounts .putIfAbsent (account .userName (), account ) != null ) {
46+ throw new IllegalArgumentException ("Duplicate account user name on line " + lineNumber );
47+ }
4348 }
4449 return new AccountStore (loadedAccounts , true );
4550 }
@@ -78,6 +83,13 @@ public int size() {
7883 return accounts .size ();
7984 }
8085
86+ public static boolean isValidUserName (String userName ) {
87+ return userName != null
88+ && userName .length () >= MIN_USER_NAME_LENGTH
89+ && userName .length () <= MAX_USER_NAME_LENGTH
90+ && userName .matches (USER_NAME_PATTERN );
91+ }
92+
8193 private static AccountRecord parseLine (String line , int lineNumber ) {
8294 String [] columns = line .split ("," , -1 );
8395 if (columns .length != 4 ) {
@@ -87,7 +99,7 @@ private static AccountRecord parseLine(String line, int lineNumber) {
8799 UserRole role = parseRole (columns [1 ].trim (), lineNumber );
88100 String salt = columns [2 ].trim ();
89101 String tokenHash = columns [3 ].trim ().toLowerCase (Locale .ROOT );
90- if (userName . isBlank ( ) || salt .isBlank () || tokenHash .isBlank ()) {
102+ if (! isValidUserName ( userName ) || salt .isBlank () || tokenHash .isBlank ()) {
91103 throw new IllegalArgumentException ("Invalid account file line " + lineNumber );
92104 }
93105 return new AccountRecord (userName , role , salt , tokenHash );
0 commit comments