Feature: Password Security Bar - #199
Conversation
📝 WalkthroughWalkthroughAdded shared password-strength calculation and a visual strength indicator. Signup and password-reset forms now require a strong password before submission. ChangesPassword strength validation
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant PasswordForm
participant calculatePasswordStrength
participant PasswordStrengthBar
participant SubmitButton
PasswordForm->>calculatePasswordStrength: calculate current password score
calculatePasswordStrength-->>PasswordForm: return score and label
PasswordForm->>PasswordStrengthBar: display score and guidance
PasswordForm->>SubmitButton: disable when score is below 3
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
components/passwordStrengthBar.tsxESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox. pages/forgot-password.tsxESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox. pages/login.tsxESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pages/login.tsx (1)
800-846: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winEnforce the password policy in all three API handlers.
/api/auth/signup/finish,/api/setupworkspace, and/api/auth/reset/finishdo not enforcecalculatePasswordStrength(password).score >= 3before hashing the password.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pages/login.tsx` around lines 800 - 846, Enforce calculatePasswordStrength(password).score >= 3 in all three server-side API handlers before hashing: /api/auth/signup/finish (pages/login.tsx, lines 800-846), /api/setupworkspace (pages/welcome.tsx, lines 383-445), and /api/auth/reset/finish (pages/forgot-password.tsx, lines 292-332). Reject passwords below the threshold using the handlers’ existing validation/error response pattern; the client-side checks in the signup and reset flows require no direct change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@utils/passwordStrength.ts`:
- Line 18: Update the password scoring call around zxcvbn to pass only
password.slice(0, 100). Apply the same 100-character bound consistently wherever
password inputs are processed and password-writing APIs accept or persist
passwords.
---
Outside diff comments:
In `@pages/login.tsx`:
- Around line 800-846: Enforce calculatePasswordStrength(password).score >= 3 in
all three server-side API handlers before hashing: /api/auth/signup/finish
(pages/login.tsx, lines 800-846), /api/setupworkspace (pages/welcome.tsx, lines
383-445), and /api/auth/reset/finish (pages/forgot-password.tsx, lines 292-332).
Reject passwords below the threshold using the handlers’ existing
validation/error response pattern; the client-side checks in the signup and
reset flows require no direct change.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: d2624137-4eee-435f-869c-b5931c9be7c9
📒 Files selected for processing (5)
components/passwordStrengthBar.tsxpages/forgot-password.tsxpages/login.tsxpages/welcome.tsxutils/passwordStrength.ts
| }; | ||
| } | ||
|
|
||
| const result = zxcvbn(password); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- candidate files ---'
git ls-files | grep -E '(^|/)(passwordStrength\.ts|package\.json|tsconfig[^/]*\.json|.*lock.*)$' || true
printf '%s\n' '--- passwordStrength.ts ---'
file=$(git ls-files | grep -E '(^|/)utils/passwordStrength\.ts$' | head -n 1)
if [ -n "${file:-}" ]; then
cat -n "$file"
printf '%s\n' '--- references ---'
rg -n -C 3 'passwordStrength|zxcvbn|password' --glob '!**/node_modules/**' --glob '!**/dist/**' .
fi
printf '%s\n' '--- package/config declarations ---'
for f in $(git ls-files | grep -E '(^|/)(package\.json|tsconfig[^/]*\.json|.*lock.*)$' || true); do
printf '\n### %s\n' "$f"
case "$f" in
*.json) sed -n '1,240p' "$f" ;;
*) rg -n -C 2 'zxcvbn|password|maximum|maxLength|100' "$f" || true ;;
esac
doneRepository: PlanetaryOrbit/orbit
Length of output: 50376
🌐 Web query:
zxcvbn GitHub Dropbox maximum password length first 100 characters scoring latency recommendation
💡 Result:
Zxcvbn, originally developed by Dropbox, is a password strength estimator that uses pattern matching and conservative estimation [1][2]. Because its internal pattern-matching algorithms can exhibit super-quadratic runtime for certain adversarial inputs, the library includes mechanisms to manage performance and mitigate potential denial-of-service (DoS) risks [1][3]. Performance and Latency Under typical conditions, zxcvbn operates well below the threshold of human-perceived latency [1][4]. For standard inputs, scoring takes approximately 5–20ms for passwords around 25 characters and grows to about 100ms for passwords around 100 characters [1][2][4]. However, performance can degrade significantly with long or complex, adversarial inputs (e.g., repeated patterns or complex character combinations), sometimes leading to multi-second delays [3][5][6]. Recommendations for Password Length To maintain consistent performance and protect against DoS attacks, it is strongly recommended to bound the input size passed to the library [1][7]. The official Dropbox implementation documentation suggests that for very long passwords, you should consider passing only the first 100 characters of the user input to the scoring function [1][2][8]. Many implementations of the library enforce a maximum length limit to prevent resource exhaustion. For example, some ports (such as the Python implementation) default to a 72-character limit and advise against increasing it [7][9][10]. Other implementations (such as the Ruby port) may set a default limit of 256 characters [3]. Developers are advised to apply a length check before calling the library and to be cautious if overriding these default maximums, as doing so can re-expose the application to runtime risks [3][7][9].
Citations:
- 1: https://github.com/dropbox/zxcvbn
- 2: https://github.com/dropbox/zxcvbn/blob/master/README.md
- 3: https://github.com/envato/zxcvbn-ruby
- 4: https://zxcvbn-ts.github.io/zxcvbn/guide/
- 5: Very slow for certain inputs dropbox/zxcvbn#316
- 6: Performance issues zxcvbn-ts/zxcvbn#31
- 7: https://github.com/dwolfhub/zxcvbn-python/blob/d32d30be/README.rst
- 8: https://github.com/dropbox/zxcvbn/tree/63bd219723de9052b5db1b1b288ab7c7ca573df9
- 9: https://github.com/dwolfhub/zxcvbn-python
- 10: https://pypi.org/project/zxcvbn/
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- relevant password inputs and API handlers ---'
for f in pages/login.tsx pages/welcome.tsx pages/forgot-password.tsx pages/api/auth/signup/finish.ts pages/api/auth/reset/finish.ts pages/api/setupworkspace.ts; do
if git ls-files --error-unmatch "$f" >/dev/null 2>&1; then
printf '\n### %s\n' "$f"
rg -n -C 8 'register\(.*password|type="password"|password\.length|req\.body\.password|const \{[^}]*password|bcryptjs\.hash' "$f" || true
fi
done
printf '%s\n' '--- Input component ---'
input_file=$(git ls-files | grep -E '(^|/)components/.*/?input\.tsx$|(^|/)components/input\.tsx$' | head -n 1 || true)
if [ -n "${input_file:-}" ]; then
cat -n "$input_file"
else
rg -l 'function Input|const Input|export default.*Input' components pages | head -n 10 | while read -r f; do
printf '\n### %s\n' "$f"
rg -n -C 12 'function Input|const Input|export default.*Input' "$f"
done
fi
printf '%s\n' '--- upstream README and implementation references ---'
curl -L --fail --silent --show-error https://raw.githubusercontent.com/dropbox/zxcvbn/master/README.md |
rg -n -C 4 '100|long password|maximum|performance|latency' || true
curl -L --fail --silent --show-error https://raw.githubusercontent.com/dropbox/zxcvbn/master/src/main.coffee |
rg -n -C 4 'length|password' | head -n 120 || trueRepository: PlanetaryOrbit/orbit
Length of output: 16958
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
strength = Path("utils/passwordStrength.ts").read_text()
print("strength_call:", re.findall(r"zxcvbn\(([^)]*)\)", strength))
targets = [
"pages/login.tsx",
"pages/welcome.tsx",
"pages/forgot-password.tsx",
"pages/api/auth/signup/finish.ts",
"pages/api/auth/reset/finish.ts",
"pages/api/setupworkspace.ts",
]
for name in targets:
text = Path(name).read_text()
if name.startswith("pages/api/"):
password_checks = re.findall(
r"(?i).{0,80}(?:password\.length|maxLength|password.{0,20}100|100.{0,20}password).{0,120}",
text,
)
print(f"{name}: password_length_checks={password_checks}")
else:
usages = []
for match in re.finditer(r"<Input\b[\s\S]*?/>", text):
element = match.group(0)
if re.search(r'type="password"', element):
usages.append("maxLength" in element)
print(f"{name}: password_input_maxLength_flags={usages}")
PYRepository: PlanetaryOrbit/orbit
Length of output: 589
Bound password input before scoring.
zxcvbn recommends scoring only the first 100 characters for very long inputs. Pass password.slice(0, 100) to zxcvbn. Apply the same 100-character limit to password inputs and password-writing APIs.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@utils/passwordStrength.ts` at line 18, Update the password scoring call
around zxcvbn to pass only password.slice(0, 100). Apply the same 100-character
bound consistently wherever password inputs are processed and password-writing
APIs accept or persist passwords.
Pull Request
Thank you for contributing to Orbit! 🐈
Before submitting, please make sure you have read the Contributing Guide.
Description
Related Issues
Type of Change
Testing
Describe how you tested your changes.
Screenshots / Videos
Checklist
Additional Notes
Added 1 package. Made all components require a password score of 3+ to accept the password.
Summary by CodeRabbit