42 lines
3.8 KiB
HTML
42 lines
3.8 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Yang's 网盘</title>
|
||
<link rel="icon" href="psc.svg" type="image/svg+xml" />
|
||
<style>
|
||
body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;margin:0;padding:0;color:#111}
|
||
.container{max-width:800px;margin:24px auto;padding:0 16px}
|
||
h1{font-size:24px;margin:0 0 12px}
|
||
#statusTop{color:#666;margin-bottom:16px}
|
||
input{padding:8px;border:1px solid #ccc;border-radius:4px}
|
||
button{padding:8px 12px;border:1px solid #999;border-radius:4px;background:#f7f7f7}
|
||
.debugbox{white-space:pre-wrap;border:1px dashed #ccc;border-radius:4px;padding:8px;min-height:120px;margin-top:8px;color:#333}
|
||
</style>
|
||
<script>
|
||
let lines=[]
|
||
function log(){ const t=new Date().toISOString(); const msg=[t].concat([].slice.call(arguments)).join(' '); lines.push(msg); if(lines.length>200) lines.shift(); const el=document.getElementById('debugBottom'); if(el) el.textContent=lines.join('\n') }
|
||
function setStatus(t){ const s=document.getElementById('status'); if(s) s.textContent=t; const top=document.getElementById('statusTop'); if(top) top.textContent='后端: ' + location.origin + ' | ' + t; try{ log('status', t) }catch{} }
|
||
async function calcMasterFp(s){ const material = await window.crypto.subtle.importKey('raw', new TextEncoder().encode(s), 'PBKDF2', false, ['deriveBits']); const bits = await window.crypto.subtle.deriveBits({ name:'PBKDF2', hash:'SHA-256', salt: new TextEncoder().encode('local-fp'), iterations:120000 }, material, 256); const b = new Uint8Array(bits); return btoa(String.fromCharCode(...b)) }
|
||
function init(){ log('app.loaded'); log('backend.origin', location.origin); log('initUi.start'); const btn=document.getElementById('btnLogin'); const inp=document.getElementById('master'); btn.onclick=async function(){ const v=(inp.value||'').trim(); if(!v){ setStatus('请输入18位身份证号'); return } try{ log('login.skip_format_check'); log('login.req', 'id.len', v.length); const r = await fetch('/api/psc/auth/login/plain', { method:'POST', headers:{ 'Content-Type':'application/json' }, body: JSON.stringify({ master_password: v }) }); let j=null; try{ j=await r.json() }catch{}; log('login.status', r.status); log('login.json', JSON.stringify(j)); if(r.ok && j && j.token){ try{ localStorage.setItem('tk_plain', j.token) }catch{}; try{ const fp = await calcMasterFp(v); localStorage.setItem('mfp', fp) }catch{}; setStatus('登录成功,正在跳转...'); setTimeout(()=>{ location.href='index.html' }, 300) } else { if(j && j.error==='not_setup'){ setStatus('未初始化,请先设置登录密码'); return } if(j && j.error==='unauthorized'){ setStatus('身份证号不准确'); return } setStatus('登录失败') } } catch(e){ setStatus('网络错误,登录失败') } }; const cp=document.getElementById('btnCopyDebugBottom'); cp.onclick=async function(){ try{ await navigator.clipboard.writeText((document.getElementById('debugBottom')?.textContent)||''); setStatus('调试信息已复制') } catch{ setStatus('请手动复制调试信息') } } }
|
||
window.addEventListener('DOMContentLoaded', init)
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>Yang's 网盘</h1>
|
||
<div id="statusTop"></div>
|
||
<div id="login">
|
||
<h2>登录</h2>
|
||
<input id="master" placeholder="18位身份证号" type="password" autocomplete="off" autocapitalize="off" spellcheck="false" />
|
||
<button id="btnLogin">登录</button>
|
||
<div style="margin:6px 0"><button id="btnCopyDebugBottom">复制调试信息</button></div>
|
||
<div id="status" style="margin-top:8px"></div>
|
||
<div id="debugBottom" class="debugbox"></div>
|
||
</div>
|
||
</div>
|
||
<script src="auth.js"></script>
|
||
</body>
|
||
</html>
|