Add v17.7.1 account password security
This commit is contained in:
parent
f8bb0a78b4
commit
10d022641e
81
public/core/account-security-v1771.js
Normal file
81
public/core/account-security-v1771.js
Normal file
@ -0,0 +1,81 @@
|
||||
(()=>{
|
||||
'use strict';
|
||||
if(window.CateriumAccountSecurityV1771)return;
|
||||
|
||||
const VERSION='17.7.1';
|
||||
const RELEASE='20260908-v17-7-1-password-security';
|
||||
const $=id=>document.getElementById(id);
|
||||
const cloud=()=>window.SunCloudV2||null;
|
||||
const client=()=>cloud()?.getClient?.()||null;
|
||||
const session=()=>cloud()?.getSession?.()||null;
|
||||
const esc=v=>window.SunSafe?.escapeHTML?window.SunSafe.escapeHTML(String(v??'')):String(v??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
||||
const mustChange=user=>Boolean(user?.app_metadata?.must_change_password||user?.user_metadata?.must_change_password);
|
||||
let forcedOpen=false,checking=false;
|
||||
|
||||
function installStyle(){
|
||||
if($('cateriumAccountSecurityV1771Style'))return;
|
||||
const st=document.createElement('style');st.id='cateriumAccountSecurityV1771Style';st.textContent=`
|
||||
.cat-password-gate-v1771{position:fixed;inset:0;z-index:200500;background:rgba(12,16,14,.72);backdrop-filter:blur(8px);display:grid;place-items:center;padding:18px}
|
||||
.cat-password-gate-v1771-card{width:min(460px,100%);background:#fff;border-radius:20px;padding:22px;box-shadow:0 28px 90px rgba(0,0,0,.32)}
|
||||
.cat-password-gate-v1771-card h2{margin:0 0 6px}.cat-password-gate-v1771-card p{color:#6d746f;line-height:1.45}
|
||||
.cat-password-gate-v1771-card label{display:block;margin-top:12px;font-size:12px;font-weight:800;color:#343a36}.cat-password-gate-v1771-card input{width:100%;box-sizing:border-box;margin-top:6px;padding:11px 12px;border:1px solid #d8ded9;border-radius:10px;font:inherit}
|
||||
.cat-password-gate-v1771-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:16px}.cat-password-gate-v1771-actions button{border-radius:10px;padding:9px 12px;font-weight:850}.cat-password-gate-v1771-actions .primary{background:#1d2a22;color:#fff;border:1px solid #1d2a22}.cat-password-gate-v1771-actions .outline{background:#fff;border:1px solid #d5dad6}
|
||||
.cat-password-gate-v1771-error{min-height:20px;margin-top:10px;color:#9f2d2d;font-size:12px}.cat-password-gate-v1771-success{color:#1e6a3d}
|
||||
.cat-profile-password-v1771{margin-top:10px;padding-top:10px;border-top:1px solid #e6e9e7;display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}.cat-profile-password-v1771 small{display:block;color:#7a807c;margin-top:3px}
|
||||
body.cat-password-required-v1771{overflow:hidden!important}
|
||||
`;document.head.appendChild(st);
|
||||
}
|
||||
|
||||
async function signOut(){try{await cloud()?.signOut?.()}catch(_){try{await client()?.auth.signOut()}catch(__){}}}
|
||||
|
||||
async function updatePassword({currentPassword='',newPassword,clearForced=false}){
|
||||
const c=client(),ss=session();if(!c||!ss?.user)throw new Error('Сессия пользователя недоступна.');
|
||||
const email=String(ss.user.email||'').trim();
|
||||
if(currentPassword){const verify=await c.auth.signInWithPassword({email,password:currentPassword});if(verify.error)throw new Error('Текущий пароль введён неверно.');}
|
||||
const metadata={...(ss.user.user_metadata||{})};if(clearForced)metadata.must_change_password=false;
|
||||
const result=await c.auth.updateUser({password:newPassword,data:metadata});if(result.error)throw result.error;
|
||||
try{await c.auth.refreshSession()}catch(_){}
|
||||
return result.data?.user||null;
|
||||
}
|
||||
|
||||
function openPasswordModal({forced=false}={}){
|
||||
installStyle();$('cateriumPasswordGateV1771')?.remove();
|
||||
const ss=session(),user=ss?.user;if(!user)return false;
|
||||
forcedOpen=forced;
|
||||
const host=document.createElement('div');host.id='cateriumPasswordGateV1771';host.className='cat-password-gate-v1771';
|
||||
host.innerHTML=`<div class="cat-password-gate-v1771-card"><h2>${forced?'Создайте постоянный пароль':'Сменить пароль'}</h2><p>${forced?'Вы вошли по временному паролю. Для продолжения работы задайте свой новый пароль. Закрыть это окно без смены пароля нельзя.':'Пароль меняется только для вашего аккаунта Caterium.'}</p>${forced?'':`<label>Текущий пароль<input id="catCurrentPasswordV1771" type="password" autocomplete="current-password"></label>`}<label>Новый пароль<input id="catNewPasswordV1771" type="password" autocomplete="new-password"></label><label>Повторите новый пароль<input id="catNewPassword2V1771" type="password" autocomplete="new-password"></label><div id="catPasswordErrorV1771" class="cat-password-gate-v1771-error"></div><div class="cat-password-gate-v1771-actions">${forced?'<button class="outline" id="catPasswordSignOutV1771" type="button">Выйти</button>':'<button class="outline" id="catPasswordCancelV1771" type="button">Отмена</button>'}<button class="primary" id="catPasswordSaveV1771" type="button">Сохранить пароль</button></div></div>`;
|
||||
document.body.appendChild(host);if(forced)document.body.classList.add('cat-password-required-v1771');
|
||||
if(!forced)$('catPasswordCancelV1771').onclick=()=>host.remove();else $('catPasswordSignOutV1771').onclick=()=>signOut();
|
||||
const save=$('catPasswordSaveV1771'),err=$('catPasswordErrorV1771');
|
||||
const run=async()=>{
|
||||
const p1=String($('catNewPasswordV1771')?.value||''),p2=String($('catNewPassword2V1771')?.value||''),current=String($('catCurrentPasswordV1771')?.value||'');
|
||||
if(!forced&&!current){err.textContent='Введите текущий пароль.';return}if(p1.length<8){err.textContent='Новый пароль должен содержать минимум 8 символов.';return}if(p1!==p2){err.textContent='Пароли не совпадают.';return}if(!forced&&p1===current){err.textContent='Новый пароль должен отличаться от текущего.';return}
|
||||
save.disabled=true;err.textContent='Сохраняю новый пароль…';err.classList.remove('cat-password-gate-v1771-success');
|
||||
try{await updatePassword({currentPassword:forced?'':current,newPassword:p1,clearForced:forced});err.textContent='Пароль успешно изменён.';err.classList.add('cat-password-gate-v1771-success');document.body.classList.remove('cat-password-required-v1771');forcedOpen=false;setTimeout(()=>{host.remove();ensureForcedGate();decorateProfile()},450)}catch(e){err.textContent=String(e?.message||e||'Не удалось изменить пароль.');save.disabled=false}
|
||||
};
|
||||
save.onclick=run;$('catNewPassword2V1771').addEventListener('keydown',e=>{if(e.key==='Enter')run()});setTimeout(()=>$('catNewPasswordV1771')?.focus(),50);return true;
|
||||
}
|
||||
|
||||
async function latestUser(){
|
||||
const c=client();if(!c)return session()?.user||null;try{const r=await c.auth.getUser();return r.data?.user||session()?.user||null}catch(_){return session()?.user||null}
|
||||
}
|
||||
async function ensureForcedGate(){
|
||||
if(checking)return;checking=true;try{const user=await latestUser();if(!user){$('cateriumPasswordGateV1771')?.remove();document.body.classList.remove('cat-password-required-v1771');forcedOpen=false;return}if(mustChange(user)){if(!$('cateriumPasswordGateV1771')||!forcedOpen)openPasswordModal({forced:true})}else if(forcedOpen){$('cateriumPasswordGateV1771')?.remove();document.body.classList.remove('cat-password-required-v1771');forcedOpen=false}}finally{checking=false}
|
||||
}
|
||||
|
||||
function decorateProfile(){
|
||||
const ss=session();if(!ss?.user)return;
|
||||
const card=$('sunCloudV2Card');if(!card)return;const profile=[...card.querySelectorAll('.sun-cloud-v2-box')].find(x=>x.querySelector('h3')?.textContent.trim()==='Профиль');if(!profile||profile.querySelector('.cat-profile-password-v1771'))return;
|
||||
const row=document.createElement('div');row.className='cat-profile-password-v1771';row.innerHTML=`<div><b>Безопасность аккаунта</b><small>Сменить пароль для ${esc(ss.user.email||'этого аккаунта')}</small></div><button type="button" class="outline" id="catProfilePasswordV1771">Сменить пароль</button>`;profile.appendChild(row);row.querySelector('#catProfilePasswordV1771').onclick=()=>openPasswordModal({forced:false});
|
||||
}
|
||||
|
||||
function maintain(){installStyle();ensureForcedGate();decorateProfile()}
|
||||
const observer=new MutationObserver(()=>{if(document.hidden)return;setTimeout(()=>{decorateProfile();ensureForcedGate()},40)});
|
||||
if(document.documentElement)observer.observe(document.documentElement,{childList:true,subtree:true});
|
||||
window.addEventListener('sun:cloud-state-applied',()=>setTimeout(maintain,80));
|
||||
window.addEventListener('focus',maintain);document.addEventListener('visibilitychange',()=>{if(!document.hidden)maintain()});
|
||||
setInterval(()=>{if(!document.hidden)ensureForcedGate()},5000);
|
||||
|
||||
window.CateriumAccountSecurityV1771={VERSION,RELEASE,mustChange,openPasswordModal,ensureForcedGate,decorateProfile,checks:()=>({version:VERSION,forcedOpen,gate:Boolean($('cateriumPasswordGateV1771')),profileButton:Boolean($('catProfilePasswordV1771'))})};
|
||||
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',maintain,{once:true});else maintain();
|
||||
})();
|
||||
Loading…
Reference in New Issue
Block a user