-
Notifications
You must be signed in to change notification settings - Fork 0
passkeys #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
passkeys #32
Changes from all commits
4ac9f2c
04f2db5
8c92a87
0c1c4fd
84db270
e255368
7934cb7
66796aa
2b8e4e7
398c264
162ead7
abb84f1
5a723c3
86758f5
5380291
6dcd489
88e701a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -15,7 +15,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||
| import backendlab.team4you.user.UserEntity; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import backendlab.team4you.user.UserService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.security.core.userdetails.UsernameNotFoundException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.security.core.userdetails.User; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.security.config.annotation.web.configurers.WebAuthnConfigurer; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class SecurityConfig { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -25,23 +25,20 @@ SecurityFilterChain securityFilterChain(HttpSecurity http, | |||||||||||||||||||||||||||||||||||||||||||||||||||
| CustomAuthenticationSuccessHandler successHandler) throws Exception { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| return http | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .csrf(csrf -> csrf.disable()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .csrf(csrf -> csrf.ignoringRequestMatchers("/webauthn/**", "/api/files/**")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .authorizeHttpRequests( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| authorizeHttp -> authorizeHttp | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Public endpoints | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/css/**", "/js/**", "/images/**").permitAll() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers( "/","/login", "/login/webauthn", "/signup", "/error").permitAll() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/webauthn/authenticate/**").permitAll() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/api/files/**").permitAll() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/api/files/**", "/webauthn/authenticate/**").permitAll() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // .requestMatchers("/profile", "/logout").authenticated() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/webauthn-check").authenticated() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/webauthn/**").hasAnyRole("USER", "ADMIN") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/admin/**").hasRole("ADMIN") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/dashboard", "/profile/**").hasAnyRole("USER", "ADMIN") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/add-passkey").hasAnyRole("USER", "ADMIN") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/webauthn/register/**").hasAnyRole("USER", "ADMIN") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/home", "/profile/**").hasRole("USER") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requestMatchers("/add-passkey", "/webauthn/register/**").hasAnyRole("USER", "ADMIN") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
33
to
+41
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check controller mappings vs. security matchers for the /login/webauthn paths
rg -nP --type=java -C2 '"/login/webauthn/?"'
rg -nP --type=java -C2 '"/webauthn/login'Repository: ithsjava25/project-backend-team4you Length of output: 2502 🏁 Script executed: #!/bin/bash
# 1. Check for /home endpoint mappings
echo "=== Searching for /home endpoint mapping ==="
rg -nP --type=java '"/home' src/
# 2. Check for /webauthn/login endpoint (not the matcher, but actual endpoints)
echo "=== Searching for /webauthn/login endpoint ==="
rg -nP --type=java '@GetMapping|@PostMapping|@RequestMapping' src/ | grep -i webauthn
# 3. Check CustomAuthenticationSuccessHandler to see admin routing
echo "=== Examining CustomAuthenticationSuccessHandler ==="
rg -nP --type=java -A 10 'isAdmin|ADMIN' src/main/java/backendlab/team4you/config/CustomAuthenticationSuccessHandler.javaRepository: ithsjava25/project-backend-team4you Length of output: 1091 🏁 Script executed: #!/bin/bash
# Search for WebAuthn configuration
echo "=== Searching for WebAuthn configuration ==="
fd -t f '\.java$' src/ | xargs grep -l -i 'webauthn' | head -20
echo "=== Check what WebAuthn library is being used ==="
grep -i webauthn pom.xml build.gradle 2>/dev/null || echo "Checking for pom.xml/build.gradle..."
# Search for WebAuthn endpoints more broadly
echo "=== All webauthn-related endpoint mappings ==="
rg -nP --type=java '@(Get|Post|Put|Delete)Mapping.*webauthn' -i
# Check for WebAuthnConfigurer or similar Spring Security WebAuthn configuration
echo "=== WebAuthnConfigurer or security configuration for webauthn ==="
rg -nP --type=java 'WebAuthConfigurer|webauthnConfigurer|/webauthn' src/main/java/backendlab/team4you/config/Repository: ithsjava25/project-backend-team4you Length of output: 2360 🏁 Script executed: #!/bin/bash
# Read the full SecurityConfig.java file
echo "=== Full SecurityConfig.java ==="
cat -n src/main/java/backendlab/team4you/config/SecurityConfig.javaRepository: ithsjava25/project-backend-team4you Length of output: 4893 Path matcher inconsistencies worth tightening. A few issues in the authorize chain:
📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| .anyRequest().authenticated() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -52,8 +49,10 @@ SecurityFilterChain securityFilterChain(HttpSecurity http, | |||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .formLogin(form -> form | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .loginPage("/login") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .successHandler(successHandler)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| .loginProcessingUrl("/login") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .successHandler(successHandler) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .permitAll() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .logout(logout -> logout.logoutSuccessUrl("/").permitAll()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -79,7 +78,7 @@ public UserDetailsService userDetailsService(UserService userService){ | |||||||||||||||||||||||||||||||||||||||||||||||||||
| return User.builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .username(user.getName()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .password(user.getPasswordHash()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .roles(user.getRole()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .authorities(user.getRole()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .accountLocked(false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
78
to
83
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Inspect the role enum and any string concatenation around roles in the codebase.
rg -nP --type=java -C2 '\bUserRole\.'
rg -nP --type=java -C2 '"ROLE_'
ast-grep --pattern 'enum UserRole { $$$ }'Repository: ithsjava25/project-backend-team4you Length of output: 2540 🏁 Script executed: # Find and inspect the UserRole enum definition
fd -t f UserRole.javaRepository: ithsjava25/project-backend-team4you Length of output: 131 🏁 Script executed: # Read the UserEntity.getRole() method to see its return type
rg -n "getRole" src/main/java/backendlab/team4you/user/UserEntity.java -A 3Repository: ithsjava25/project-backend-team4you Length of output: 159 🏁 Script executed: # Search for the UserRole enum definition with ast-grep and also cat the file if found
find . -name "UserRole.java" -type fRepository: ithsjava25/project-backend-team4you Length of output: 133 🏁 Script executed: # Read the full UserRole enum definition
cat -n src/main/java/backendlab/team4you/user/UserRole.javaRepository: ithsjava25/project-backend-team4you Length of output: 227 Fix double-prefix bug in SignupController authentication setup. The concern is partially addressed: However, verification reveals a critical bug in "ROLE_" + userEntity.getRole() // produces "ROLE_ROLE_USER" or "ROLE_ROLE_ADMIN"This must be corrected to just 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -89,4 +88,4 @@ public UserDetailsService userDetailsService(UserService userService){ | |||||||||||||||||||||||||||||||||||||||||||||||||||
| public BCryptPasswordEncoder passwordEncoder() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new BCryptPasswordEncoder(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package backendlab.team4you.controller; | ||
|
|
||
| import backendlab.team4you.user.UserService; | ||
| import org.springframework.stereotype.Controller; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
|
|
||
| @Controller | ||
| public class DashboardController { | ||
|
|
||
| private final UserService userService; | ||
|
|
||
| public DashboardController(UserService userService){ | ||
| this.userService = userService; | ||
| } | ||
|
|
||
| @GetMapping("/dashboard") | ||
| public String dashboard(){ | ||
| return "dashboard"; | ||
| } | ||
|
|
||
| @GetMapping("/dashboard/home") | ||
| public String dashboardHome() { | ||
| return "dashboard :: content"; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,8 +3,6 @@ | |
| import backendlab.team4you.user.UserEntity; | ||
| import backendlab.team4you.user.UserService; | ||
|
|
||
| import backendlab.team4you.user.UserRepository; | ||
|
|
||
| import jakarta.servlet.http.HttpServletRequest; | ||
| import jakarta.servlet.http.HttpServletResponse; | ||
| import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
|
|
@@ -36,13 +34,9 @@ public SignupController(PublicKeyCredentialUserEntityRepository users, | |
| this.userService = userService; | ||
| } | ||
|
|
||
| @GetMapping("/webauthn-check") | ||
| public String showWebAuthnCheck(){ | ||
| return "webauthn-check"; | ||
| } | ||
| @GetMapping("/dashboard") | ||
| public String dashboard() { | ||
| return "dashboard"; | ||
| @GetMapping("/login/webauthn") | ||
| public String webauthnCheck() { | ||
| return "check"; | ||
|
Comment on lines
+37
to
+39
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Description: Verify dashboard links still have controller mappings.
echo "Controller mappings for /dashboard:"
rg -n -C3 '@(GetMapping|PostMapping|RequestMapping)\s*\([^)]*["'\'']/dashboard\b' src/main/java
echo
echo "Template/static references to /dashboard:"
rg -n -C2 '(/dashboard\b|@\{/dashboard\})' src/main/resourcesRepository: ithsjava25/project-backend-team4you Length of output: 1215 🏁 Script executed: #!/bin/bash
# Search for any dashboard-related mappings that might exist
echo "Searching for all `@GetMapping/`@PostMapping/@RequestMapping containing 'dashboard':"
rg -i 'dashboard' src/main/java --type java -B2 -A2
echo
echo "Searching for any /dashboard* patterns in Java files:"
rg '"/dashboard' src/main/java --type javaRepository: ithsjava25/project-backend-team4you Length of output: 216 Add a The Either restore the 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| @GetMapping("/signup") | ||
|
|
@@ -64,7 +58,7 @@ public void signup(@RequestBody SignupRequest req, HttpServletRequest request, H | |
| ); | ||
|
|
||
| Authentication auth = new UsernamePasswordAuthenticationToken( | ||
| userEntity.getName(), null, List.of(new SimpleGrantedAuthority("ROLE_" + userEntity.getRole()))); | ||
| userEntity.getName(), null, List.of(new SimpleGrantedAuthority(userEntity.getRole()))); | ||
|
|
||
| SecurityContext context = SecurityContextHolder.createEmptyContext(); | ||
| context.setAuthentication(auth); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ | |
|
|
||
| public enum UserRole { | ||
|
|
||
| USER, | ||
| ADMIN, | ||
| ROLE_USER, | ||
| ROLE_ADMIN, | ||
|
Comment on lines
+5
to
+6
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Description: Verify how UserRole is persisted and whether a Flyway migration updates old role values.
# Expectation:
# - If UserRole is persisted as a string, SQL migrations should update USER -> ROLE_USER and ADMIN -> ROLE_ADMIN.
# - Spring Security should use hasAuthority("ROLE_ADMIN") or hasRole("ADMIN"), not hasRole("ROLE_ADMIN").
echo "UserRole usages and persistence annotations:"
rg -n -C4 --type=java '\bUserRole\b|@Enumerated|EnumType\.STRING|hasRole\s*\(|hasAuthority\s*\(|authorities\s*\('
echo
echo "SQL migrations touching role values:"
fd -e sql -x sh -c 'echo "--- $1"; rg -n -C3 "USER|ADMIN|ROLE_USER|ROLE_ADMIN|role" "$1"' sh {}Repository: ithsjava25/project-backend-team4you Length of output: 6685 Add a migration to backfill existing role values before deployment. The Add a Flyway migration to update existing role values before this change is deployed: Required migrationUPDATE user_entities SET role = 'ROLE_USER' WHERE role = 'USER';
UPDATE user_entities SET role = 'ROLE_ADMIN' WHERE role = 'ADMIN';🤖 Prompt for AI Agents |
||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| /* | ||
| * Copyright 2004-present the original author or authors. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * https://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| "use strict"; | ||
|
|
||
| const holder = { | ||
| controller: new AbortController(), | ||
| }; | ||
|
|
||
| /** | ||
| * Returns a new AbortSignal to be used in the options for the registration and authentication ceremonies. | ||
| * Aborts the existing AbortController if it exists, cancelling any existing ceremony. | ||
| * | ||
| * The authentication ceremony, when triggered with conditional mediation, shows a non-modal | ||
| * interaction. If the user does not interact with the non-modal dialog, the existing ceremony MUST | ||
| * be cancelled before initiating a new one, hence the need for a singleton AbortController. | ||
| * | ||
| * @returns {AbortSignal} a new, non-aborted AbortSignal | ||
| */ | ||
| function newSignal() { | ||
| if (!!holder.controller) { | ||
| holder.controller.abort("Initiating new WebAuthN ceremony, cancelling current ceremony"); | ||
| } | ||
| holder.controller = new AbortController(); | ||
| return holder.controller.signal; | ||
| } | ||
|
|
||
| export default { | ||
| newSignal, | ||
| }; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,33 @@ | ||||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||||
| * Copyright 2004-present the original author or authors. | ||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||||||||||||||||||||||||
| * you may not use this file except in compliance with the License. | ||||||||||||||||||||||||||||
| * You may obtain a copy of the License at | ||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||
| * https://www.apache.org/licenses/LICENSE-2.0 | ||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||
| * Unless required by applicable law or agreed to in writing, software | ||||||||||||||||||||||||||||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||||||||||||||||||||||||||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||||||||||||||||||||||||
| * See the License for the specific language governing permissions and | ||||||||||||||||||||||||||||
| * limitations under the License. | ||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| "use strict"; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| export default { | ||||||||||||||||||||||||||||
| encode: function (buffer) { | ||||||||||||||||||||||||||||
| const base64 = window.btoa(String.fromCharCode(...new Uint8Array(buffer))); | ||||||||||||||||||||||||||||
| return base64.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_"); | ||||||||||||||||||||||||||||
|
Comment on lines
+20
to
+22
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: git ls-files | grep -i base64Repository: ithsjava25/project-backend-team4you Length of output: 120 🏁 Script executed: find . -name "base64url.js" -o -name "*base64*"Repository: ithsjava25/project-backend-team4you Length of output: 122 🏁 Script executed: cat -n src/main/resources/static/js/base64url.jsRepository: ithsjava25/project-backend-team4you Length of output: 1513 🌐 Web query:
💡 Result: There is no specified maximum number of arguments for String.fromCharCode in the ECMAScript standard or official documentation like MDN. The method accepts a variable number of numeric arguments (num1, ..., numN), each representing a UTF-16 code unit between 0 and 65535. Citations:
🌐 Web query:
💡 Result: There is no defined maximum size in the WebAuthn specification for attestation credential data. The WebAuthn Level 3 specification (as of 2026) does not specify a maximum size for the attestationObject, which contains the authenticatorData (including attestedCredentialData with credentialPublicKey) and attStmt. The credential ID within attestedCredentialData is limited to at most 1023 bytes. The credentialPublicKey is a variable-length COSE_Key whose length must be parsed from CBOR, with no explicit maximum. CTAP specifications require authenticators to support messages of at least 1024 bytes by default (via maxMsgSize), but responses like authenticatorMakeCredential can be larger depending on transport (e.g., up to ~7600 bytes for USB HID). A recent proposal suggests non-normative guidance of attestationObject <= 8 KB, but this is not official. In practice, sizes are typically a few hundred to a few thousand bytes, limited by transport and authenticator capabilities. Citations:
🌐 Web query:
💡 Result: JavaScript engines impose practical limits on the maximum number of arguments that can be passed to String.fromCharCode, particularly when using spread syntax (...) or Function.prototype.apply. These limits arise from implementation constraints like stack size, FixedArray capacity in V8, and resource allocation policies, not from the ECMAScript specification, which allows arbitrary-length argument lists. For V8 (Chrome, Node.js): - Spread syntax or apply typically fails around 125,000-130,000 arguments with "RangeError: too many function arguments" or "Maximum call stack size exceeded". - Tied to FixedArray::kMaxLength, approximately 64MB or 128MB worth of elements (around 8-16 million in some configs, but practical stack limits reduce it to ~125k). - Older tests showed ~65k-131k depending on version and call method. For SpiderMonkey (Firefox): - Higher tolerance, up to ~500,000 arguments via apply in older tests (Firefox 30/106). - May throw stack overflow for very large lists but generally handles more than V8. Workarounds for large inputs (e.g., Uint8Array to string): - Chunk the array and concatenate results: process in batches of ~65k or less. - Use TextDecoder: new TextDecoder.decode(uint8Array) - efficient, no argument limit issues. - Avoid spread/apply for large arrays; loop or reduce instead. No official documentation specifies exact current (2026) limits as they are internal and version-dependent. Test in target environment or use chunking/TextDecoder for safety. MDN notes no validity checks on inputs but omits argument count limits. Citations:
🌐 Web query:
💡 Result: The RangeError "too many arguments" with String.fromCharCode occurs when passing too many arguments to the function, typically via the spread operator (...) on large arrays (e.g., Uint8Array from file buffers > ~500KB) or Function.prototype.apply with large arrays. JavaScript engines impose implementation-specific limits on the number of arguments a function call can accept, often around 65K-500K depending on the browser and stack state (e.g., Chrome ~65K literal, higher with apply; Firefox ~65K literal, 500K apply). The ECMAScript spec does not define a hard limit, but practical constraints exist due to stack size and memory. This error is common when converting binary data (ArrayBuffer, Uint8Array) to strings for base64 encoding, like btoa(String.fromCharCode(...new Uint8Array(buffer))), which fails for files larger than a few hundred KB. To fix, process the array in smaller chunks to stay under the argument limit: function uint8ArrayToStringChunked(uint8Array, chunkSize = 32768) { let result = ''; for (let i = 0; i < uint8Array.length; i += chunkSize) { const chunk = uint8Array.subarray(i, i + chunkSize); result += String.fromCharCode.apply(null, chunk); } return result; } // Usage for base64: function bufferToBase64(buffer) { return btoa(uint8ArrayToStringChunked(new Uint8Array(buffer))); } Using subarray and apply(null, chunk) is efficient and avoids quadratic string concatenation. Chunk sizes like 32K-65K work across browsers; test for your environment. Alternatives include TextEncoder/Decoder for UTF-8 (if data is text) or modern TypedArray methods, but for latin1/binary-to-string, this is standard. MDN docs confirm String.fromCharCode accepts a variable number of UTF-16 code units (0-65535) with no explicit limit mentioned. Citations:
Use chunking to avoid potential argument limit issues with spread operator. While Proposed fix encode: function (buffer) {
- const base64 = window.btoa(String.fromCharCode(...new Uint8Array(buffer)));
+ const bytes = new Uint8Array(buffer);
+ let binary = "";
+ const chunkSize = 0x8000;
+ for (let i = 0; i < bytes.length; i += chunkSize) {
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
+ }
+ const base64 = window.btoa(binary);
return base64.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
},📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| decode: function (base64url) { | ||||||||||||||||||||||||||||
| const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/"); | ||||||||||||||||||||||||||||
| const binStr = window.atob(base64); | ||||||||||||||||||||||||||||
| const bin = new Uint8Array(binStr.length); | ||||||||||||||||||||||||||||
| for (let i = 0; i < binStr.length; i++) { | ||||||||||||||||||||||||||||
| bin[i] = binStr.charCodeAt(i); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| return bin.buffer; | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: ithsjava25/project-backend-team4you
Length of output: 9666
🏁 Script executed:
cat -n src/main/java/backendlab/team4you/Team4youApplication.java | head -60Repository: ithsjava25/project-backend-team4you
Length of output: 2069
Seed each dev account idempotently rather than gating both on repository count.
With
repository.count() == 0, developers with an existing database will never receive the new admin account after pulling this PR. Check for each account by username usingrepository.findByName()instead, so each account is created independently if missing.🤖 Prompt for AI Agents