fix: add development bypass for ALTCHA on admin login

- Allow login in development mode without ALTCHA verification
- Use BYPASS_DEV_MODE token in development
- Keep ALTCHA widget visible but not blocking in dev mode
- This allows testing while we fix the challenge implementation
This commit is contained in:
Patrick Britton 2026-02-16 23:35:47 -06:00
parent 11e8b30122
commit 2149a1e001
3 changed files with 21 additions and 9 deletions

View file

@ -28,14 +28,17 @@ export default function LoginPage() {
}, []);
const performLogin = useCallback(async () => {
if (!altchaVerified) {
// Use development bypass for now
const token = process.env.NODE_ENV === 'development' ? 'BYPASS_DEV_MODE' : altchaToken;
if (!token && !altchaVerified) {
setError('Please complete the security verification');
return;
}
setLoading(true);
try {
await login(emailRef.current, passwordRef.current, altchaToken);
await login(emailRef.current, passwordRef.current, token);
router.push('/');
} catch (err: any) {
setError(err.message || 'Login failed. Check your credentials.');
@ -110,7 +113,7 @@ export default function LoginPage() {
<button
type="submit"
className="btn-primary w-full"
disabled={loading || !altchaVerified}
disabled={loading || (process.env.NODE_ENV !== 'development' && !altchaVerified)}
>
{loading ? 'Signing in...' : 'Sign In'}
</button>

View file

@ -599,15 +599,22 @@ func (h *AuthHandler) ResetPassword(c *gin.Context) {
}
func (h *AuthHandler) GetAltchaChallenge(c *gin.Context) {
// Generate a proper ALTCHA challenge
salt := fmt.Sprintf("%d", time.Now().UnixNano())
// Generate a proper ALTCHA challenge compatible with the widget
// The widget expects: algorithm, challenge, salt, signature
// Create a simple number challenge (find a number that when hashed with salt produces a hash starting with certain digits)
challenge := fmt.Sprintf("%x", sha256.Sum256([]byte(salt)))[:10]
// Generate random salt
salt := fmt.Sprintf("%x", time.Now().UnixNano())
// Create HMAC signature using JWT secret as the key
// Generate a random number that needs to be found (the challenge)
// The widget will try to find a number that when combined with salt produces a hash with specific properties
randomBytes := make([]byte, 16)
rand.Read(randomBytes)
challenge := fmt.Sprintf("%x", randomBytes)
// Create HMAC signature: HMAC(secret, challenge + salt)
mac := hmac.New(sha256.New, []byte(h.config.JWTSecret))
mac.Write([]byte(challenge + salt))
mac.Write([]byte(challenge))
mac.Write([]byte(salt))
signature := hex.EncodeToString(mac.Sum(nil))
response := map[string]interface{}{

View file

@ -1,5 +1,7 @@
# Miscellaneous
*.sql
*.psd
*.ai
*.class
*.log
*.pyc