';
- }
- imageContainer.appendChild(imageElement);
-
- // Refresh button
- const refreshButton = document.createElement('button');
- refreshButton.classList.add('button', 'button-small');
- refreshButton.innerHTML = '⟳';
- refreshButton.setAttribute('title', i18n('refresh_captcha'));
- refreshButton.style.minWidth = '30px';
- refreshButton.style.fontSize = '30px';
- refreshButton.style.height = 'auto';
- refreshButton.style.marginBottom = '4px';
- refreshButton.setAttribute('type', 'button');
- refreshButton.addEventListener('click', (e) => {
- e.preventDefault();
- e.stopPropagation();
- refresh();
- });
- imageContainer.appendChild(refreshButton);
-
- // Input field
- const inputField = document.createElement('input');
- inputField.id = `captcha-input-${Date.now()}`;
- inputField.classList.add('captcha-input');
- inputField.type = 'text';
- inputField.placeholder = i18n('enter_captcha_text');
- inputField.setAttribute('autocomplete', 'off');
- inputField.setAttribute('spellcheck', 'false');
- inputField.setAttribute('autocorrect', 'off');
- inputField.setAttribute('autocapitalize', 'off');
- inputField.value = state.answer || '';
- inputField.addEventListener('input', (e) => {
- state.answer = e.target.value;
- });
-
- // Prevent Enter key from triggering refresh and allow it to submit the form
- inputField.addEventListener('keydown', (e) => {
- if (e.key === 'Enter') {
- // Don't prevent default here - let Enter bubble up to the form
- // Just make sure we don't refresh the captcha
- e.stopPropagation();
- }
- });
-
- captchaWrapper.appendChild(inputField);
-
- // Helper text
- const helperText = document.createElement('div');
- helperText.classList.add('captcha-helper-text');
- helperText.style.fontSize = '12px';
- helperText.style.color = '#666';
- helperText.textContent = i18n('captcha_case_sensitive');
- captchaWrapper.appendChild(helperText);
- };
-
- // Fetch a new captcha
- const refresh = async () => {
- // Skip if not required
- if (!state.required) {
- return;
- }
-
- try {
- state.loading = true;
- state.error = null;
- render();
-
- const response = await fetch(window.gui_origin + '/api/captcha/generate');
-
- if (!response.ok) {
- throw new Error(`Failed to load captcha: ${response.status}`);
- }
-
- const data = await response.json();
-
- state.token = data.token;
- state.image = data.image;
- state.loading = false;
-
- render();
-
- if (typeof options.onReady === 'function') {
- options.onReady();
- }
- } catch (error) {
- state.loading = false;
- state.error = error.message || 'Failed to load captcha';
-
- render();
-
- if (typeof options.onError === 'function') {
- options.onError(error);
- }
- }
- };
-
- // Public API
- const api = {
- /**
- * Get the current captcha token
- * @returns {string} The captcha token
- */
- getToken: () => state.token,
-
- /**
- * Get the current captcha answer
- * @returns {string} The user's answer
- */
- getAnswer: () => state.answer,
-
- /**
- * Reset the captcha - clear answer and get a new challenge
- */
- reset: () => {
- state.answer = '';
- refresh();
- },
-
- /**
- * Get the container element
- * @returns {HTMLElement} The container element
- */
- getElement: () => state.container,
-
- /**
- * Check if captcha is required
- * @returns {boolean} Whether captcha is required
- */
- isRequired: () => state.required,
-
- /**
- * Set whether captcha is required
- * @param {boolean} required - Whether captcha is required
- */
- setRequired: setRequired
- };
-
- // Set initial required state from options
- if (options.required !== undefined) {
- state.required = options.required;
- }
-
- // Initialize the component
- init();
-
- return api;
-}
-
-export default CaptchaView;
\ No newline at end of file
diff --git a/src/gui/src/UI/UIWindowLogin.js b/src/gui/src/UI/UIWindowLogin.js
index c99b64a3..65ded877 100644
--- a/src/gui/src/UI/UIWindowLogin.js
+++ b/src/gui/src/UI/UIWindowLogin.js
@@ -28,8 +28,6 @@ import JustHTML from './Components/JustHTML.js';
import StepView from './Components/StepView.js';
import Button from './Components/Button.js';
import RecoveryCodeEntryView from './Components/RecoveryCodeEntryView.js';
-import CaptchaView from './Components/CaptchaView.js'
-import { isCaptchaRequired } from '../helpers/captchaHelper.js';
async function UIWindowLogin(options){
options = options ?? {};
@@ -40,10 +38,6 @@ async function UIWindowLogin(options){
return new Promise(async (resolve) => {
const internal_id = window.uuidv4();
- // Check if captcha is required for login
- const captchaRequired = await isCaptchaRequired('login');
- console.log('Login captcha required:', captchaRequired);
-
let h = ``;
h += `
`;
// logo
@@ -77,10 +71,6 @@ async function UIWindowLogin(options){
`;
h += `
`;
- // captcha placeholder - will be replaced with actual captcha component
- h += ``;
- // captcha-specific error message
- h += ``;
// login
h += ``;
// password recovery
@@ -141,46 +131,6 @@ async function UIWindowLogin(options){
}
})
- // Initialize the captcha component with the required state
- const captchaContainer = $(el_window).find('.captcha-container')[0];
- const captcha = CaptchaView({
- container: captchaContainer,
- required: captchaRequired,
- });
-
- // Function to show captcha-specific error
- const showCaptchaError = (message) => {
- // Hide the general error message if shown
- $(el_window).find('.login-error-msg').hide();
-
- // Show captcha-specific error
- const captchaError = $(el_window).find('.captcha-error-msg');
- captchaError.html(message);
- captchaError.fadeIn();
-
- // Add visual indication of error to captcha container
- $(captchaContainer).addClass('error');
- $(captchaContainer).css('border', '1px solid #e74c3c');
- $(captchaContainer).css('border-radius', '4px');
- $(captchaContainer).css('padding', '10px');
-
- // Focus on the captcha input for better UX
- setTimeout(() => {
- const captchaInput = $(captchaContainer).find('.captcha-input');
- if (captchaInput.length) {
- captchaInput.focus();
- }
- }, 100);
- };
-
- // Function to clear captcha errors
- const clearCaptchaError = () => {
- $(el_window).find('.captcha-error-msg').hide();
- $(captchaContainer).removeClass('error');
- $(captchaContainer).css('border', '');
- $(captchaContainer).css('padding', '');
- };
-
$(el_window).find('.forgot-password-link').on('click', function(e){
UIWindowRecoverPassword({
window_options: {
@@ -197,7 +147,6 @@ async function UIWindowLogin(options){
// Clear previous error states
$(el_window).find('.login-error-msg').hide();
- clearCaptchaError();
const email_username = $(el_window).find('.email_or_username').val();
const password = $(el_window).find('.password').val();
@@ -215,61 +164,17 @@ async function UIWindowLogin(options){
return;
}
- // Get captcha token and answer if required
- let captchaToken = null;
- let captchaAnswer = null;
-
- if (captcha.isRequired()) {
- captchaToken = captcha.getToken();
- captchaAnswer = captcha.getAnswer();
-
- // Validate captcha if it's required
- if (!captcha || !captchaContainer) {
- $(el_window).find('.login-error-msg').html(i18n('captcha_system_error') || 'Verification system error. Please refresh the page.');
- $(el_window).find('.login-error-msg').fadeIn();
- return;
- }
-
- if (!captchaToken) {
- showCaptchaError(i18n('captcha_load_error') || 'Could not load verification code. Please refresh the page or try again later.');
- return;
- }
-
- if (!captchaAnswer) {
- showCaptchaError(i18n('captcha_required') || 'Please enter the verification code');
- return;
- }
-
- if (captchaAnswer.trim().length < 3) {
- showCaptchaError(i18n('captcha_too_short') || 'Verification code answer is too short.');
- return;
- }
-
- if (captchaAnswer.trim().length > 12) {
- showCaptchaError(i18n('captcha_too_long') || 'Verification code answer is too long.');
- return;
- }
- }
-
// Prepare data for the request
let data;
if(window.is_email(email_username)){
data = JSON.stringify({
email: email_username,
password: password,
- ...(captchaToken && captchaAnswer ? {
- captchaToken: captchaToken,
- captchaAnswer: captchaAnswer
- } : {})
});
} else {
data = JSON.stringify({
username: email_username,
password: password,
- ...(captchaToken && captchaAnswer ? {
- captchaToken: captchaToken,
- captchaAnswer: captchaAnswer
- } : {})
});
}
@@ -485,31 +390,11 @@ async function UIWindowLogin(options){
// Handle captcha-specific errors
const errorText = err.responseText || '';
- const errorStatus = err.status || 0;
// Try to parse error as JSON
try {
const errorJson = JSON.parse(errorText);
- // Check for specific error codes
- if (errorJson.code === 'captcha_required') {
- // If captcha is now required but wasn't before, update the component
- if (!captcha.isRequired()) {
- captcha.setRequired(true);
- showCaptchaError(i18n('captcha_now_required') || 'Verification is now required. Please complete the verification below.');
- } else {
- showCaptchaError(i18n('captcha_required') || 'Please enter the verification code');
- }
- return;
- }
-
- if (errorJson.code === 'captcha_invalid' || errorJson.code === 'captcha_error') {
- showCaptchaError(i18n('captcha_invalid') || 'Invalid verification code');
- // Refresh the captcha if it's invalid
- captcha.reset();
- return;
- }
-
// If it's a message in the JSON, use that
if (errorJson.message) {
$(el_window).find('.login-error-msg').html(errorJson.message);
@@ -520,33 +405,6 @@ async function UIWindowLogin(options){
// Not JSON, continue with text analysis
}
- // Check for specific captcha errors using more robust detection for text responses
- if (
- errorText.includes('captcha_required') ||
- errorText.includes('Captcha verification required') ||
- (errorText.includes('captcha') && errorText.includes('required'))
- ) {
- // If captcha is now required but wasn't before, update the component
- if (!captcha.isRequired()) {
- captcha.setRequired(true);
- showCaptchaError(i18n('captcha_now_required') || 'Verification is now required. Please complete the verification below.');
- } else {
- showCaptchaError(i18n('captcha_required') || 'Please enter the verification code');
- }
- return;
- }
-
- if (
- errorText.includes('captcha_invalid') ||
- errorText.includes('Invalid captcha') ||
- (errorText.includes('captcha') && (errorText.includes('invalid') || errorText.includes('incorrect')))
- ) {
- showCaptchaError(i18n('captcha_invalid') || 'Invalid verification code');
- // Refresh the captcha if it's invalid
- captcha.reset();
- return;
- }
-
// Fall back to original error handling
const $errorMessage = $(el_window).find('.login-error-msg');
if (err.status === 404) {
diff --git a/src/gui/src/UI/UIWindowSignup.js b/src/gui/src/UI/UIWindowSignup.js
index cd5c56fe..92ea375b 100644
--- a/src/gui/src/UI/UIWindowSignup.js
+++ b/src/gui/src/UI/UIWindowSignup.js
@@ -21,8 +21,6 @@ import UIWindow from './UIWindow.js'
import UIWindowLogin from './UIWindowLogin.js'
import UIWindowEmailConfirmationRequired from './UIWindowEmailConfirmationRequired.js'
import check_password_strength from '../helpers/check_password_strength.js'
-import CaptchaView from './Components/CaptchaView.js'
-import { isCaptchaRequired } from '../helpers/captchaHelper.js'
function UIWindowSignup(options){
options = options ?? {};
@@ -34,10 +32,6 @@ function UIWindowSignup(options){
return new Promise(async (resolve) => {
const internal_id = window.uuidv4();
- // Check if captcha is required for signup
- const captchaRequired = await isCaptchaRequired('signup');
- console.log('Signup captcha required:', captchaRequired);
-
let h = '';
h += `
`;
// logo
@@ -82,10 +76,6 @@ function UIWindowSignup(options){
`;
h += `
`;
- // captcha placeholder - will be replaced with actual captcha component
- h += ``;
- // captcha-specific error message
- h += ``;
// bot trap - if this value is submitted server will ignore the request
h += ``;
@@ -143,13 +133,6 @@ function UIWindowSignup(options){
}
})
- // Initialize the captcha component with the required state
- const captchaContainer = $(el_window).find('.captcha-container')[0];
- const captcha = CaptchaView({
- container: captchaContainer,
- required: captchaRequired
- });
-
$(el_window).find('.login-c2a-clickable').on('click', async function(e){
$('.login-c2a-clickable').parents('.window').close();
const login = await UIWindowLogin({
@@ -164,43 +147,9 @@ function UIWindowSignup(options){
resolve(true);
})
- // Function to show captcha-specific error
- const showCaptchaError = (message) => {
- // Hide the general error message if shown
- $(el_window).find('.signup-error-msg').hide();
-
- // Show captcha-specific error
- const captchaError = $(el_window).find('.captcha-error-msg');
- captchaError.html(message);
- captchaError.fadeIn();
-
- // Add visual indication of error to captcha container
- $(captchaContainer).addClass('error');
- $(captchaContainer).css('border', '1px solid #e74c3c');
- $(captchaContainer).css('border-radius', '4px');
- $(captchaContainer).css('padding', '10px');
-
- // Focus on the captcha input for better UX
- setTimeout(() => {
- const captchaInput = $(captchaContainer).find('.captcha-input');
- if (captchaInput.length) {
- captchaInput.focus();
- }
- }, 100);
- };
-
- // Function to clear captcha errors
- const clearCaptchaError = () => {
- $(el_window).find('.captcha-error-msg').hide();
- $(captchaContainer).removeClass('error');
- $(captchaContainer).css('border', '');
- $(captchaContainer).css('padding', '');
- };
-
$(el_window).find('.signup-btn').on('click', function(e){
// Clear previous error states
$(el_window).find('.signup-error-msg').hide();
- clearCaptchaError();
//Username
let username = $(el_window).find('.username').val();
@@ -255,46 +204,6 @@ function UIWindowSignup(options){
$(el_window).find('.signup-error-msg').html(i18n('passwords_do_not_match'));
$(el_window).find('.signup-error-msg').fadeIn();
return;
-}
-
- // Get captcha token and answer if required
- let captchaToken = null;
- let captchaAnswer = null;
-
- if (captcha.isRequired()) {
- captchaToken = captcha.getToken();
- captchaAnswer = captcha.getAnswer();
-
- // Check if the captcha component is properly loaded
- if (!captcha || !captchaContainer) {
- $(el_window).find('.signup-error-msg').html(i18n('captcha_system_error') || 'Verification system error. Please refresh the page.');
- $(el_window).find('.signup-error-msg').fadeIn();
- return;
- }
-
- // Check if captcha token exists
- if (!captchaToken) {
- showCaptchaError(i18n('captcha_load_error') || 'Could not load verification code. Please refresh the page or try again later.');
- return;
- }
-
- // Check if the answer is provided
- if (!captchaAnswer) {
- showCaptchaError(i18n('captcha_required'));
- return;
- }
-
- // Check if answer meets minimum length requirement
- if (captchaAnswer.trim().length < 3) {
- showCaptchaError(i18n('captcha_too_short') || 'Verification code answer is too short.');
- return;
- }
-
- // Check if answer meets maximum length requirement
- if (captchaAnswer.trim().length > 12) {
- showCaptchaError(i18n('captcha_too_long') || 'Verification code answer is too long.');
- return;
- }
}
//xyzname
@@ -316,10 +225,6 @@ function UIWindowSignup(options){
referrer: options.referrer ?? window.referrerStr,
send_confirmation_code: options.send_confirmation_code,
p102xyzname: p102xyzname,
- ...(captchaToken && captchaAnswer ? {
- captchaToken: captchaToken,
- captchaAnswer: captchaAnswer
- } : {})
};
$.ajax({
@@ -352,32 +257,12 @@ function UIWindowSignup(options){
// Process error response
const errorText = err.responseText || '';
- const errorStatus = err.status || 0;
// Handle JSON error response
try {
// Try to parse error as JSON
const errorJson = JSON.parse(errorText);
- // Check for specific error codes
- if (errorJson.code === 'captcha_required') {
- // If captcha is now required but wasn't before, update the component
- if (!captcha.isRequired()) {
- captcha.setRequired(true);
- showCaptchaError(i18n('captcha_now_required') || 'Verification is now required. Please complete the verification below.');
- } else {
- showCaptchaError(i18n('captcha_required') || 'Please enter the verification code');
- }
- return;
- }
-
- if (errorJson.code === 'captcha_invalid' || errorJson.code === 'captcha_error') {
- showCaptchaError(i18n('captcha_invalid') || 'Invalid verification code');
- // Refresh the captcha if it's invalid
- captcha.reset();
- return;
- }
-
// Handle timeout specifically
if (errorJson?.code === 'response_timeout' || errorText.includes('timeout')) {
$(el_window).find('.signup-error-msg').html(i18n('server_timeout') || 'The server took too long to respond. Please try again.');
@@ -394,27 +279,6 @@ function UIWindowSignup(options){
} catch (e) {
// Not JSON, continue with text analysis
}
-
- // Check for specific captcha errors using more robust detection for text responses
- if (
- errorText.includes('captcha_required') ||
- errorText.includes('Captcha verification required') ||
- (errorText.includes('captcha') && errorText.includes('required'))
- ) {
- showCaptchaError(i18n('captcha_required'));
- return;
- }
-
- if (
- errorText.includes('captcha_invalid') ||
- errorText.includes('Invalid captcha') ||
- (errorText.includes('captcha') && (errorText.includes('invalid') || errorText.includes('incorrect')))
- ) {
- showCaptchaError(i18n('captcha_invalid'));
- // Refresh the captcha if it's invalid
- captcha.reset();
- return;
- }
// Default general error handling
$(el_window).find('.signup-error-msg').html(errorText || i18n('signup_error') || 'An error occurred during signup. Please try again.');
diff --git a/src/gui/src/helpers/captchaHelper.js b/src/gui/src/helpers/captchaHelper.js
deleted file mode 100644
index 878307b5..00000000
--- a/src/gui/src/helpers/captchaHelper.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * Copyright (C) 2024-present Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-/**
- * Cache for captcha requirements to avoid repeated API calls
- */
-let captchaRequirementsCache = null;
-
-/**
- * Checks if captcha is required for a specific action
- *
- * This function first checks GUI parameters, then falls back to the /whoarewe endpoint
- *
- * @param {string} actionType - The type of action (e.g., 'login', 'signup')
- * @returns {Promise} - Whether captcha is required for this action
- */
-async function isCaptchaRequired(actionType) {
- console.log('CAPTCHA DIAGNOSTIC (Client): isCaptchaRequired called for', actionType);
-
- // Check if we have the info in GUI parameters
- if (window.gui_params?.captchaRequired?.[actionType] !== undefined) {
- console.log(`CAPTCHA DIAGNOSTIC (Client): Requirement for ${actionType} from GUI params:`, window.gui_params.captchaRequired[actionType]);
- console.log('CAPTCHA DIAGNOSTIC (Client): Full gui_params.captchaRequired =', JSON.stringify(window.gui_params.captchaRequired));
- return window.gui_params.captchaRequired[actionType];
- }
-
- // If not in GUI params, check the cache
- if (captchaRequirementsCache && captchaRequirementsCache.captchaRequired?.[actionType] !== undefined) {
- console.log(`CAPTCHA DIAGNOSTIC (Client): Requirement for ${actionType} from cache:`, captchaRequirementsCache.captchaRequired[actionType]);
- console.log('CAPTCHA DIAGNOSTIC (Client): Full cache =', JSON.stringify(captchaRequirementsCache.captchaRequired));
- return captchaRequirementsCache.captchaRequired[actionType];
- }
-
- // If not in cache, fetch from the /whoarewe endpoint
- try {
- console.log(`CAPTCHA DIAGNOSTIC (Client): Fetching from /whoarewe for ${actionType}`);
- const response = await fetch(window.api_origin + '/whoarewe');
-
- if (!response.ok) {
- console.warn(`CAPTCHA DIAGNOSTIC (Client): Failed to get requirements: ${response.status}`);
- return true; // Default to requiring captcha if we can't determine
- }
-
- const data = await response.json();
- console.log(`CAPTCHA DIAGNOSTIC (Client): /whoarewe response:`, data);
-
- // Cache the result
- captchaRequirementsCache = data;
-
- // Return the requirement or default to true if not specified
- const result = data.captchaRequired?.[actionType] ?? true;
- console.log(`CAPTCHA DIAGNOSTIC (Client): Final result for ${actionType}:`, result);
- return result;
- } catch (error) {
- console.error('CAPTCHA DIAGNOSTIC (Client): Error checking requirements:', error);
- return true; // Default to requiring captcha on error
- }
-}
-
-/**
- * Invalidates the captcha requirements cache
- * This is useful when the requirements might have changed
- */
-function invalidateCaptchaRequirementsCache() {
- captchaRequirementsCache = null;
-}
-
-export {
- isCaptchaRequired,
- invalidateCaptchaRequirementsCache
-};
\ No newline at end of file
diff --git a/src/gui/src/i18n/translations/en.js b/src/gui/src/i18n/translations/en.js
index 49fb5f0b..51ec6c0b 100644
--- a/src/gui/src/i18n/translations/en.js
+++ b/src/gui/src/i18n/translations/en.js
@@ -417,20 +417,6 @@ const en = {
'billing.expanded': 'Expanded',
'billing.accelerated': 'Accelerated',
'billing.enjoy_msg': 'Enjoy %% of Cloud Storage plus other benefits.',
-
- // Captcha related strings
- 'captcha_verification': 'Verification Code',
- 'enter_captcha_text': 'Enter the text you see above',
- 'refresh_captcha': 'Get a new code',
- 'captcha_case_sensitive': 'Please enter the characters exactly as they appear. Case sensitive.',
- 'captcha_required': 'Please complete the verification code.',
- 'captcha_now_required': 'Verification is now required. Please complete the verification below.',
- 'captcha_invalid': 'Incorrect verification code. Please try again.',
- 'captcha_expired': 'Verification code has expired. Please try a new one.',
- 'captcha_system_error': 'Verification system error. Please refresh the page.',
- 'captcha_load_error': 'Could not load verification code. Please refresh the page or try again later.',
- 'captcha_too_short': 'Verification code answer is too short.',
- 'captcha_too_long': 'Verification code answer is too long.',
'too_many_attempts': 'Too many attempts. Please try again later.',
'server_timeout': 'The server took too long to respond. Please try again.',
'signup_error': 'An error occurred during signup. Please try again.'
diff --git a/src/gui/src/index.js b/src/gui/src/index.js
index a959f4c1..c08cb4bd 100644
--- a/src/gui/src/index.js
+++ b/src/gui/src/index.js
@@ -20,8 +20,6 @@
window.puter_gui_enabled = true;
-import { isCaptchaRequired } from './helpers/captchaHelper.js';
-
/**
* Initializes and configures the GUI (Graphical User Interface) settings based on the provided options.
*
@@ -61,18 +59,6 @@ window.gui = async (options) => {
window.disable_temp_users = options.disable_temp_users ?? false;
window.co_isolation_enabled = options.co_isolation_enabled;
- // Preload captcha requirements if not already in GUI parameters
- if (!options.captchaRequired) {
- // Start loading in the background, but don't await
- // This way we don't delay the GUI initialization
- Promise.all([
- isCaptchaRequired('login'),
- isCaptchaRequired('signup')
- ]).catch(err => {
- console.warn('Failed to preload captcha requirements:', err);
- });
- }
-
// DEV: Load the initgui.js file if we are in development mode
if(!window.gui_env || window.gui_env === "dev"){
await window.loadScript('/sdk/puter.dev.js');