diff --git a/.gitignore b/.gitignore index a238cbe..8e78068 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ .idea assets-src/node_modules assets/js/app.js -assets/css/plugin-MultiplLocalAuth.css +assets/css/plugin-MultipleLocalAuth.css mix-manifest.json node_modules/ diff --git a/GovBr/GovBrStrategy.php b/GovBr/GovBrStrategy.php index 65d80d3..6de4d37 100644 --- a/GovBr/GovBrStrategy.php +++ b/GovBr/GovBrStrategy.php @@ -27,6 +27,7 @@ class GovBrStrategy extends OpauthStrategy public function request() { $_SESSION['govbr-state'] = md5($this->strategy['state_salt'].time()); + $_SESSION['last_auth_provider'] = get_class($this); $url = $this->strategy['auth_endpoint']; $params = array( @@ -127,6 +128,24 @@ public function oauth2callback() } } + /** + * Logout + * @return void + */ + public static function logout() + { + $app = \MapasCulturais\App::i(); + $config = $app->config['auth.config']['strategies']['govbr']; + + if (empty($config['client_id']) || empty($config['url_logout'])) { + return; + } + + $logoutUrl = $config['url_logout'] . '?client_id=' . urlencode($config['client_id']); + + $app->redirect($logoutUrl, 302, false); + } + /** * @param string $id_token * @return array Parsed JSON results diff --git a/Plugin.php b/Plugin.php index 9ad2020..233e9cb 100644 --- a/Plugin.php +++ b/Plugin.php @@ -20,7 +20,7 @@ public function _init() { // Load JS & CSS $app->hook('GET(<>.<<*>>):before', function() use ($app) { - $app->view->enqueueStyle('app-v2', 'multipleLocal-v2', 'css/plugin-MultiplLocalAuth.css'); + $app->view->enqueueStyle('app-v2', 'multipleLocal-v2', 'css/plugin-MultipleLocalAuth.css'); }); $app->hook('GET(auth.<>)', function() use($app) { @@ -34,6 +34,11 @@ public function _init() { $this->part('password/change-password'); }); + $app->hook('template(panel.<>.user-mail):begin ', function() use ($app) { + /** @var \MapasCulturais\Theme $this */ + $this->part('email/resent-email-validation'); + }); + $app->hook('entity(User).permissionsList,doctrine.emum(permission_action).values', function (&$permissions) { $permissions[] = 'changePassword'; }); @@ -50,6 +55,7 @@ public function _init() { } public function register() { + $this->registerUserMetadata(Provider::$preventOverhead, ['label' => i::__('Evitar tarefas que geram sobrecarga de processamento')]); $this->registerUserMetadata(Provider::$passMetaName, ['label' => i::__('Senha')]); $this->registerUserMetadata(Provider::$recoverTokenMetadata, ['label' => i::__('Token para recuperação de senha')]); $this->registerUserMetadata(Provider::$recoverTokenTimeMetadata, ['label' => i::__('Timestamp do token para recuperação de senha')]); diff --git a/Provider.php b/Provider.php index e668e95..b3ea64d 100644 --- a/Provider.php +++ b/Provider.php @@ -22,6 +22,8 @@ class Provider extends \MapasCulturais\AuthProvider { public static $recoverTokenMetadata = 'recover_token'; public static $recoverTokenTimeMetadata = 'recover_token_time'; + + public static $preventOverhead = 'preventOverhead'; public static $accountIsActiveMetadata = 'accountIsActive'; public static $tokenVerifyAccountMetadata = 'tokenVerifyAccount'; @@ -34,6 +36,7 @@ function __construct ($config) { $config += [ 'salt' => env('AUTH_SALT', null), + 'wizard' => env('AUTH_WIZARD_ENABLED', false), 'timeout' => env('AUTH_TIMEOUT', '24 hours'), 'loginOnRegister' => env('AUTH_LOGIN_ON_REGISTER', false), @@ -94,7 +97,7 @@ function __construct ($config) { 'app_secret' => env('AUTH_TWITTER_APP_SECRET', null), ], 'govbr' => [ - 'visible' => env('AUTH_GOV_BR_ID', false), + 'visible' => env('AUTH_GOV_BR_VISIBLE', false), 'response_type' => env('AUTH_GOV_BR_RESPONSE_TYPE', 'code'), 'client_id' => env('AUTH_GOV_BR_CLIENT_ID', null), 'client_secret' => env('AUTH_GOV_BR_SECRET', null), @@ -110,10 +113,19 @@ function __construct ($config) { 'state_salt' => env('AUTH_GOV_BR_STATE_SALT', null), 'applySealId' => env('AUTH_GOV_BR_APPLY_SEAL_ID', null), 'menssagem_authenticated' => env('AUTH_GOV_BR_MENSSAGEM_AUTHENTICATED','Usuário já se autenticou pelo GovBr'), - 'dic_agent_fields_update' => env('AUTH_GOV_BR_DICT_AGENT_FIELDS_UPDATE','[]') + 'dic_agent_fields_update' => json_decode(env('AUTH_GOV_BR_DICT_AGENT_FIELDS_UPDATE', '{}'), true), + 'post_logout_redirect_uri' => env('post_logout_redirect_uri', null), + 'url_logout' => env('url_logout', 'https://sso.staging.acesso.gov.br/logout'), ] ] ]; + + /** + * Esse método carrega as configurações do tema, pois como o plugin é carregado antes do tema, + * as configurações do tema não são carregadas. + */ + $this->preLoadThemeConfig($config); + parent::__construct($config); } @@ -134,6 +146,7 @@ protected function usingSocialLogin() { protected function _init() { $app = App::i(); + $provider = $this; $config = $this->_config; $app->hook('GET(auth.passwordvalidationinfos)', function () use($config){ @@ -259,8 +272,10 @@ protected function _init() { } // add actions to auth controller - $app->hook('GET(auth.index)', function () use($config){ - $this->render('multiple-local', [ 'config' => $config ]); + $app->hook('GET(auth.index)', function () use($config, $provider){ + $hasLocalAuth = $provider->hasLocalAuth(); + + $this->render('multiple-local', [ 'config' => $config, 'hasLocalAuth' => $hasLocalAuth ?? false ]); }); $app->hook('GET(auth.register)', function () use($config){ @@ -279,6 +294,12 @@ protected function _init() { $app->hook("<>(auth.<<{$providers}>>)", function () use($opauth, $config){ $opauth->run(); }); + + $app->hook('auth.logout:after', function () use($app, $config){ + if(isset($_SESSION['last_auth_provider']) && method_exists($_SESSION['last_auth_provider'], 'logout')) { + ($_SESSION['last_auth_provider'])::logout(); + } + }); } $app->hook('GET(auth.response)', function () use($app){ @@ -337,6 +358,9 @@ protected function _init() { $login = $app->auth->doLogin(); if ($login['success']) { + // Chamando Hook do Mapa, responsável por registrar o último login + App::i()->applyHook('auth.successful'); + $this->json([ 'error' => false, 'redirectTo' => $app->auth->getRedirectPath() @@ -346,6 +370,21 @@ protected function _init() { } }); + $app->hook('POST(auth.verify)', function () use ($app) { + /** + * @var \MapasCulturais\Controller $this + */ + + $verify = $app->auth->doVerify(); + if ($verify['success']) { + $this->json([ + 'result' => $verify['result'] + ]); + } else { + $this->errorJson($verify['errors'], 200); + } + }); + $app->hook('POST(auth.recover)', function () use($app){ /** * @var \MapasCulturais\Controller $this @@ -374,6 +413,28 @@ protected function _init() { } }); + $app->hook('POST(auth.resend-email-validation)', function () use($app){ + /** + * @var \MapasCulturais\Controller $this + */ + $userId = $app->request->post('userId'); + $user = $app->repo("User")->find($userId); + + // If the user already has a token, use it, otherwise generate a new one + $token = $user->{self::$tokenVerifyAccountMetadata} ?? $app->auth->generateToken(); + + $user->setMetadata(self::$tokenVerifyAccountMetadata, $token); + $user->save(true); + + // Send email validation + $sendEmailValidation = $app->auth->sendEmailValidation($user, $token); + if ($sendEmailValidation['success']) { + $this->json(['error' => false]); + } else { + $this->errorJson($sendEmailValidation['errors'], 200); + } + }); + $app->hook('POST(auth.changepassword)', function () use($app){ /** * @var \MapasCulturais\Controller $this @@ -441,43 +502,6 @@ function json($data, $status = 200) { $app->halt($status, json_encode($data)); } - - function verificarToken($token, $claveSecreta) - { - $url = "https://www.google.com/recaptcha/api/siteverify"; - $datos = [ - "secret" => $claveSecreta, - "response" => $token, - ]; - $opciones = array( - "http" => array( - "header" => "Content-type: application/x-www-form-urlencoded\r\n", - "method" => "POST", - "content" => http_build_query($datos), # Agregar el contenido definido antes - ), - ); - $contexto = stream_context_create($opciones); - $resultado = file_get_contents($url, false, $contexto); - if ($resultado === false) { - return false; - } - $resultado = json_decode($resultado); - $pruebaPasada = $resultado->success; - return $pruebaPasada; - } - - function verifyRecaptcha2() { - $config = $this->_config; - - if (!$config['google-recaptcha-sitekey']) return true; - if (empty($_POST["g-recaptcha-response"])) return false; - - $token = $_POST["g-recaptcha-response"]; - $verified = $this->verificarToken($token, $config["google-recaptcha-secret"]); - - return $verified ? true : false; - } - function verifyPassowrds($pass, $verify) { $config = $this->_config; $passwordLength = $config['minimumPasswordLength']; @@ -538,7 +562,7 @@ function validateRegisterFields() { ]; // validate captcha - if (!$this->verifyRecaptcha2()) { + if ((!isset($_POST["g-recaptcha-response"]) || empty($_POST["g-recaptcha-response"])) || !$app->verifyCaptcha($_POST['g-recaptcha-response'])) { array_push($errors['captcha'], i::__('Captcha incorreto, tente novamente!', 'multipleLocal')); return [ 'success' => false, @@ -690,7 +714,8 @@ function dorecover() { ]; } } - + + function recover() { $app = App::i(); $config = $app->_config; @@ -703,8 +728,8 @@ function recover() { 'email' => [], 'sendEmail' => [] ]; - - if (!$this->verifyRecaptcha2()) { + + if ((!isset($_POST["g-recaptcha-response"]) || empty($_POST["g-recaptcha-response"])) || !$app->verifyCaptcha($_POST['g-recaptcha-response'])) { array_push($errors['captcha'], i::__('Captcha incorreto, tente novamente!', 'multipleLocal')); return [ 'success' => false, @@ -902,6 +927,7 @@ function renderForm($theme) { 'feedback_msg' => $app->auth->feedback_msg, 'triedEmail' => $app->auth->triedEmail, 'triedName' => $app->auth->triedName, + 'hasLocalAuth' => $this->hasLocalAuth(), ]); } @@ -993,7 +1019,24 @@ function doLogin() { 'confirmEmail' => [] ]; - if (!$this->verifyRecaptcha2()) { + if (!$this->hasLocalAuth()) { + return; + } + + // Verifica se o login por email/senha está habilitado + if (!$this->hasLocalAuth()) { + return [ + 'success' => false, + 'errors' => [ + 'login' => [i::__( + 'Login por email e senha não está disponível. Por favor, use o login pelo Gov.br.', + 'multipleLocal' + )] + ] + ]; + } + // Se não recebemos o token, não há motivo para avançar para a verificação + if ((!isset($_POST["g-recaptcha-response"]) || empty($_POST["g-recaptcha-response"])) || !$app->verifyCaptcha($_POST['g-recaptcha-response'])) { array_push($errors['captcha'], i::__('Captcha incorreto, tente novamente!', 'multipleLocal')); return [ 'success' => false, @@ -1106,23 +1149,183 @@ function doLogin() { $meta = self::$passMetaName; $savedPass = $user->getMetadata($meta); - - if (password_verify($pass, $savedPass)) { - $this->middlewareLoginAttempts(true); - $this->authenticateUser($userToLogin); - } else { - $this->middlewareLoginAttempts(); - array_push($errors['login'], i::__('Usuário ou senha inválidos.', 'multipleLocal')); - $hasErrors = true; + + if (!$hasErrors) { + if (password_verify($pass, $savedPass)) { + $this->middlewareLoginAttempts(true); + $this->authenticateUser($userToLogin); + } else { + $this->middlewareLoginAttempts(); + array_push($errors['login'], i::__('Usuário ou senha inválidos.', 'multipleLocal')); + $hasErrors = true; + } } - } + } return [ 'success' => !$hasErrors, 'errors' => $errors ];; } + + function doVerify() + { + + $app = App::i(); + $config = $this->_config; + $hasErrors = false; + $user = false; + + $errors = [ + 'captcha' => [], + 'login' => [], + 'confirmEmail' => [] + ]; + + $email = filter_var($app->request->post('email'), FILTER_SANITIZE_EMAIL); + $emailToCheck = $email; + + if ($this->validateCPF($email) && $config['enableLoginByCPF']) { + // LOGIN COM CPF + $metadataFieldCpf = $this->getMetadataFieldCpfFromConfig(); + $cpf = $email; + $cpf = preg_replace("/(\d{3}).?(\d{3}).?(\d{3})-?(\d{2})/", "$1.$2.$3-$4", $cpf); + $cpf2 = preg_replace( '/[^0-9]/is', '', $cpf ); + $foundAgent = $app->repo("AgentMeta")->findBy(['key' => $metadataFieldCpf, 'value' => [$cpf,$cpf2]]); + if(!$foundAgent) { + return [ + 'success' => true, + 'result' => 0 + ]; + } + + //cria um array com os agentes que estão com status == 1, pois o usuario pode ter, por exemplo, 3 agentes, mas 2 estão com status == 0 + $activeAgents = []; + $active_agent_users = []; + if(count($foundAgent) > 1){ + foreach ($foundAgent as $agentMeta) { + if($agentMeta->owner->status === 1) { + $activeAgents[] = $agentMeta; + if (!in_array($agentMeta->owner->user->id, $active_agent_users)) { + $active_agent_users[] = $agentMeta->owner->user->id; + } + } + } + + //aqui foi feito um "jogo de atribuição" de variaveis para que o restando do fluxo do codigo continue funcionando normalmente + $foundAgent = $activeAgents; + } + + if(count($active_agent_users) > 1) { + array_push($errors['login'], i::__('Você possui 2 ou mais agente com o mesmo CPF! Por favor entre em contato com o suporte.', 'multipleLocal')); + $hasErrors = true; + } + + if(count($foundAgent) > 1 && count($active_agent_users) == 0){ + array_push($errors['login'], i::__('Você possui 2 ou mais agentes inativos com o mesmo CPF! Por favor entre em contato com o suporte.', 'multipleLocal')); + $hasErrors = true; + } + + $user = $app->repo("User")->findOneBy(array('id' => $foundAgent[0]->owner->user->id)); + if($user->profile->id != $foundAgent[0]->owner->id) { + array_push($errors['login'], i::__('CPF ou senha incorreta. Utilize o CPF do seu agente principal.', 'multipleLocal')); + $hasErrors = true; + } + } else { + // LOGIN COM EMAIL + $query = new \MapasCulturais\ApiQuery ('MapasCulturais\Entities\User', ['@select' => 'id', 'email' => 'ILIKE(' . $emailToCheck . ')']); + if($user = $query->findOne()){ + unset($user['@entityType']); + array_filter($user); + $user = $app->repo("User")->findOneBy($user); + } else { + return [ + 'success' => true, + 'result' => 0 + ]; // usuário não encontrado / criar conta + } + } + + // SELECT count(*) FROM user_meta um WHERE key = 'localAuthenticationPassword' AND um.object_id = :usr_id; + $query = new \MapasCulturais\ApiQuery(\MapasCulturais\Entities\UserMeta::class, ['@select' => 'count(*)', 'key' => "EQ(localAuthenticationPassword)", 'owner'=>"EQ({$user->id})"]); + $password_reset = $query->findOne(); + if ($password_reset === null) { + return [ + 'success' => true, + 'errors' => $errors, + 'result' => 1 + ]; // troca de senha necessária + } else { + return [ + 'success' => true, + 'errors' => $errors, + 'result' => 2 + ]; // nenhuma troca de senha necessária + } + } + + function sendEmailValidation(Entities\User $user, string $token) + { + $app = App::i(); + + //ATENÇÃO !! Se for necessario "padronizar" os emails com header/footers, é necessario adapatar o 'mustache', e criar uma mini estrutura de pasta de emails em 'MultipleLocalAuth\views' + $mustache = new \Mustache_Engine(); + $site_name = $app->siteName; + $baseUrl = $app->getBaseUrl(); + $template_name = 'email-to-validate-account.html'; + + $app->applyHookBoundTo($this, 'auth.sendEmailValidation', [&$template_name]); + + $template = $app->view->resolveFilename('views/auth', $template_name); + + $content = $mustache->render( + file_get_contents( + $template + ), array( + "siteName" => $site_name, + "user" => $user->profile->name, + "urlToValidateAccount" => $baseUrl.'auth/confirma-email?token='.$token, + "baseUrl" => $baseUrl, + "urlSupportChat" => $this->_config['urlSupportChat'], + "urlSupportEmail" => $this->_config['urlSupportEmail'], + "urlSupportSite" => $this->_config['urlSupportSite'], + "textSupportSite" => $this->_config['textSupportSite'], + "urlImageToUseInEmails" => $this->getImageImageURl(), + ) + ); + + try { + $app->createAndSendMailMessage([ + 'from' => $app->config['mailer.from'], + 'to' => $user->email, + 'subject' => "Bem-vindo ao ".$site_name, + 'body' => $content + ]); + + return [ + 'success' => true + ]; + } catch (\Throwable $th) { + return [ + 'success' => false, + 'error' => $th->getMessage() + ]; + } + } + + /** + * Generate a token for the user + * @return string + */ + function generateToken() { + $source = rand(3333, 8888); + $cut = rand(10, 30); + $string = $this->hashPassword($source); + $token = substr($string, $cut, 20); + return $token; + } + function doRegister() { $app = App::i(); $config = $app->_config; @@ -1136,10 +1339,7 @@ function doRegister() { $cpf = str_replace(".","",$cpf); // remove "." // generate the token hash - $source = rand(3333, 8888); - $cut = rand(10, 30); - $string = $this->hashPassword($source); - $token = substr($string, $cut, 20); + $token = $this->generateToken(); // Oauth pattern $response = [ @@ -1164,36 +1364,9 @@ function doRegister() { $user = $this->_createUser($response); $app->applyHookBoundTo($this, 'auth.createUser:after', [$user, $response]); - $baseUrl = $app->getBaseUrl(); - //ATENÇÃO !! Se for necessario "padronizar" os emails com header/footers, é necessario adapatar o 'mustache', e criar uma mini estrutura de pasta de emails em 'MultipleLocalAuth\views' - $mustache = new \Mustache_Engine(); - $site_name = $app->siteName; - $content = $mustache->render( - file_get_contents( - __DIR__. - DIRECTORY_SEPARATOR.'views'. - DIRECTORY_SEPARATOR.'auth'. - DIRECTORY_SEPARATOR.'email-to-validate-account.html' - ), array( - "siteName" => $site_name, - "user" => $user->profile->name, - "urlToValidateAccount" => $baseUrl.'auth/confirma-email?token='.$token, - "baseUrl" => $baseUrl, - "urlSupportChat" => $this->_config['urlSupportChat'], - "urlSupportEmail" => $this->_config['urlSupportEmail'], - "urlSupportSite" => $this->_config['urlSupportSite'], - "textSupportSite" => $this->_config['textSupportSite'], - "urlImageToUseInEmails" => $this->getImageImageURl(), - ) - ); - - $app->createAndSendMailMessage([ - 'from' => $app->config['mailer.from'], - 'to' => $user->email, - 'subject' => "Bem-vindo ao ".$site_name, - 'body' => $content - ]); + // Envia o email de validação de conta + $this->sendEmailValidation($user, $token); $app->disableAccessControl(); $user->{self::$passMetaName} = $app->auth->hashPassword($pass); @@ -1213,11 +1386,7 @@ function doRegister() { 'success' => true, 'authenticated' => $authenticated, 'redirectTo' => $authenticated ? $this->getRedirectPath() : '', - 'emailSent' => ( - isset($config['auth.config']) && - isset($config['auth.config']['userMustConfirmEmailToUseTheSystem']) && - $config['auth.config']['userMustConfirmEmailToUseTheSystem'] - ) ? true : false + 'emailSent' => isset($this->_config['userMustConfirmEmailToUseTheSystem']) && $this->_config['userMustConfirmEmailToUseTheSystem'] == true ]; } else { @@ -1551,4 +1720,92 @@ function getUserFromDB($email) { } return $user; } + + /** + * Verifica se o login por email/senha está habilitado para o tema atual + * + * @return bool true se habilitado, false caso contrário + */ + public function hasLocalAuth(): bool { + $app = \MapasCulturais\App::i(); + + if (env('AUTH_LOCAL_ENABLED', true) === false) { + return false; + } + + // Se o tema for PNAB, desabilita o login local por padrão. + // Permite override via AUTH_LOCAL_PNAB_ENABLED se setado explicitamente como true. + if ($app->view instanceof \Pnab\Theme) { + return filter_var(env('AUTH_LOCAL_PNAB_ENABLED', false), FILTER_VALIDATE_BOOLEAN); + } + + // DEBUG SUPREMO + if (isset($_GET['debug_env'])) { + echo "

DEBUG ENTRY POINT

"; + $conf = $app->config['plugins']['MultipleLocalAuth'] ?? 'NULL'; + echo "Config Raw:
" . var_export($conf, true) . "

"; + $enabled = $conf['enabled'] ?? 'NOT_SET'; + echo "Enabled Type: " . gettype($enabled) . "
"; + if (is_callable($enabled)) echo "Enabled is CALLABLE
"; + else echo "Enabled value: " . var_export($enabled, true) . "
"; + + die(); + } + + // Obtém a configuração do plugin + $plugin_config = $app->config['plugins']['MultipleLocalAuth'] ?? null; + + // Se não houver configuração ou 'enabled' não for uma função, retorna true (padrão) + if (!$plugin_config || !isset($plugin_config['enabled'])) { + return true; + } + + // Se 'enabled' for uma função (closure), executa e retorna o resultado + if (is_callable($plugin_config['enabled'])) { + + return (bool) $plugin_config['enabled'](); + } + + // Se 'enabled' for um valor booleano direto, retorna ele + return (bool) $plugin_config['enabled']; + } + /** + * Carrega e mescla as configurações do tema com as configurações do plugin + * + * @param array &$config Array de configurações que será modificado + * @return void + */ + protected function preLoadThemeConfig(array &$config) { + $app = App::i(); + + // Se não houver subsite, não faz nada + if (!$app->subsite) { + return; + } + + // Se a URL for diferente de $app->subsite->url, parar, pois não é o subsite atual + $domain = $_SERVER['HTTP_HOST'] ?? ''; + if ($domain !== $app->subsite->url) { + return; + } + + $theme_path = THEMES_PATH . $app->subsite->namespace . '/'; + + // Carrega conf-base.php se existir + if (file_exists($theme_path . 'conf-base.php')) { + $theme_config = require $theme_path . 'conf-base.php'; + if (isset($theme_config['auth.config'])) { + $config = array_replace_recursive($config, $theme_config['auth.config']); + } + } + + // Carrega config.php se existir + if (file_exists($theme_path . 'config.php')) { + $theme_config = require $theme_path . 'config.php'; + if (isset($theme_config['auth.config'])) { + $config = array_replace_recursive($config, $theme_config['auth.config']); + } + } + } + } diff --git a/assets-src/sass/1-settings/_s-globals.scss b/assets-src/sass/1-settings/_s-globals.scss old mode 100755 new mode 100644 diff --git a/assets-src/sass/1-settings/_s-typography.scss b/assets-src/sass/1-settings/_s-typography.scss old mode 100755 new mode 100644 diff --git a/assets-src/sass/1-settings/_s-variables.scss b/assets-src/sass/1-settings/_s-variables.scss old mode 100755 new mode 100644 diff --git a/assets-src/sass/2-atoms/_a-mixins.scss b/assets-src/sass/2-atoms/_a-mixins.scss old mode 100755 new mode 100644 diff --git a/assets-src/sass/2-atoms/_a-spacing.scss b/assets-src/sass/2-atoms/_a-spacing.scss old mode 100755 new mode 100644 diff --git a/assets-src/sass/2-atoms/_a-typography.scss b/assets-src/sass/2-atoms/_a-typography.scss old mode 100755 new mode 100644 diff --git a/assets-src/sass/4-components/_c-create-account.scss b/assets-src/sass/4-components/_c-create-account.scss index e4765b6..ad6c741 100644 --- a/assets-src/sass/4-components/_c-create-account.scss +++ b/assets-src/sass/4-components/_c-create-account.scss @@ -310,4 +310,41 @@ } } } +} + +.custom-count { + background-color: var(--mc-gray-300); // cor padrão para todos + border-radius: 50%; + color: white; + display: flex; + height: 2rem; + outline: 2px solid var(--mc-white); + transition: all 300ms linear; + width: 2rem; + z-index: 1; + justify-content: center; + align-items: center; +} + +.step.active .custom-count { + background-color: var(--mc-primary-500); + border-color: var(--mc-primary-500); +} + +.stepper .step:before { + top: 15px !important; +} + +.stepper .step.passedby:before { + background: var(--mc-primary-500); +} + +.stepper .step.active:before { + background: var(--mc-primary-500); +} + +.stepper .step.passedby:before, +.stepper .step.passedby .custom-count { + background-color: var(--mc-primary-500); + border-color: var(--mc-primary-500); } \ No newline at end of file diff --git a/assets-src/sass/4-components/_c-resent-email-validation.scss b/assets-src/sass/4-components/_c-resent-email-validation.scss new file mode 100644 index 0000000..df823b9 --- /dev/null +++ b/assets-src/sass/4-components/_c-resent-email-validation.scss @@ -0,0 +1,40 @@ +.resent-email-validation { + float: right; + margin-top: 2px; + margin-left: 16px; + + > div:not(.resent-email-validation__confirmed) { + color: inherit; + font-family: var(--mc-font-body); + word-break: break-word; + white-space: normal; + } + + .resent-email-validation__label { + display: flex; + align-items: center; + gap: 8px; + + cursor: pointer; + } + + &__confirmed { + color: var(--mc-primary-500); + } + + &__sent { + color: var(--mc-warning-500); + } +} + +@media (max-width: 500px) { + .resent-email-validation { + display: none; + } +} + +@media (max-width: 1024px) { + .resent-email-validation { + max-width: 150px; + } +} \ No newline at end of file diff --git a/assets-src/sass/plugin-MultiplLocalAuth.scss b/assets-src/sass/plugin-MultipleLocalAuth.scss old mode 100755 new mode 100644 similarity index 90% rename from assets-src/sass/plugin-MultiplLocalAuth.scss rename to assets-src/sass/plugin-MultipleLocalAuth.scss index cfa0541..4806ac6 --- a/assets-src/sass/plugin-MultiplLocalAuth.scss +++ b/assets-src/sass/plugin-MultipleLocalAuth.scss @@ -17,6 +17,7 @@ @import '4-components/c-change-password'; @import '4-components/c-create-account'; @import '4-components/c-login'; +@import '4-components/c-resent-email-validation'; /* ----- 5: AREAS ------- */ diff --git a/components/create-account/script.js b/components/create-account/script.js index bc83102..46a7b39 100644 --- a/components/create-account/script.js +++ b/components/create-account/script.js @@ -31,6 +31,7 @@ app.component('create-account', { recaptchaResponse: '', created: false, emailSent: false, + error: false } }, @@ -260,13 +261,9 @@ app.component('create-account', { }, throwErrors(errors) { + this.error = true; const messages = useMessages(); - if (this.recaptchaResponse !== '') { - grecaptcha.reset(); - this.expiredCaptcha(); - } - for (let key in errors) { if (errors[key] instanceof Array) { for (let val of errors[key]) { diff --git a/components/create-account/template.php b/components/create-account/template.php index a776a64..48e4757 100644 --- a/components/create-account/template.php +++ b/components/create-account/template.php @@ -14,21 +14,22 @@ mc-icon mc-stepper password-strongness + mc-captcha '); ?>