用户要求:备案号与域名都应当可配置,仓库内容要脱敏。 功能(不只是替换字面量): - 被代理页面注入的备案号改为读后台「站点信息」的 icp/gongan,**未配置就不注入**; 原先写死具体备案号,等于每个部署者都会把别人的备案信息印到自己页面上 - 注入内容做 nginx 安全处理(去引号/反斜杠/换行/美元符),并有测试覆盖 - auth.go:PORTAL_COOKIE_DOMAIN / PORTAL_HOME_URL 不再预置域名, cookie 默认 host-only、首页默认相对路径 "/" - gateway.go:默认 loginUrl 不再预置域名(受保护路由缺配置会明确报错,不静默生成跳不出去的登录页) - 首装脚本在给了 NAVI_DOMAIN 时自动注入 PORTAL_COOKIE_DOMAIN/PORTAL_HOME_URL, 避免"去掉写死默认值"导致跨子域单点登录失效 脱敏:内网 IP(10.0.0.10)与真实备案号清零;真实域名仅剩门户页内容 8 处(待定); 测试夹具/示例/错误页/脚本/后台占位提示全部通用化。 README:新增「跨子域单点登录需要的两个环境变量」;环境变量表改为 NAVI_HOST 必填。 测试:新增备案号注入三条(用配置、未配置不注入、危险字符清理)。
39 lines
2.5 KiB
JavaScript
39 lines
2.5 KiB
JavaScript
// 目标环境通过环境变量指定,仓库不预置任何真实域名/主机。
|
|
const BASE = process.env.PORTAL_BASE || 'https://dashy.example.com';
|
|
const DOM = process.env.PORTAL_COOKIE_DOMAIN || '.example.com';
|
|
const { chromium }=require('playwright-core');
|
|
function rgb(s){const m=s.match(/[\d.]+/g);return m?m.slice(0,4).map(Number):[]}
|
|
function L(a){return Math.round(.2126*(a[0]||0)+.7152*(a[1]||0)+.0722*(a[2]||0))}
|
|
const C=process.env.PORTAL_COOKIE;
|
|
(async()=>{
|
|
const b=await chromium.connectOverCDP('http://127.0.0.1:9222');
|
|
const ctx=await b.newContext({ignoreHTTPSErrors:true,viewport:{width:1400,height:900}});
|
|
await ctx.addCookies([{name:'portal_session',value:C,domain:DOM,path:'/',httpOnly:true,secure:true,sameSite:'Lax'}]);
|
|
const p=await ctx.newPage(); const errs=[]; p.on('pageerror',e=>errs.push(String(e)));
|
|
await p.emulateMedia({colorScheme:'dark'}); await p.addInitScript(()=>{try{localStorage.removeItem('navi-theme')}catch(e){}});
|
|
await p.goto(BASE+'/workspace',{waitUntil:'networkidle',timeout:90000}); await p.waitForTimeout(3000);
|
|
const n=await p.evaluate(()=>[...document.querySelectorAll('nav.side-bar a,nav.side-bar button,.side-bar-item')].length);
|
|
let modal=null;
|
|
for(let i=0;i<n;i++){
|
|
await p.evaluate(i=>{const e=[...document.querySelectorAll('nav.side-bar a,nav.side-bar button,.side-bar-item')][i];e&&e.click()},i);
|
|
await p.waitForTimeout(3500);
|
|
modal=await p.evaluate(()=>{
|
|
const card=document.querySelector('.navi-ws-modal-card'); if(!card) return null;
|
|
const c=getComputedStyle(card); const t=document.querySelector('.navi-ws-modal-title');
|
|
return {bg:c.backgroundColor, title:t?getComputedStyle(t).color:null, text:(card.textContent||'').trim().slice(0,60)};
|
|
});
|
|
if(modal) break;
|
|
}
|
|
const r=await p.evaluate(()=>{
|
|
const g=s=>{const e=document.querySelector(s);if(!e)return null;const c=getComputedStyle(e);return c.backgroundColor};
|
|
return {ws:(document.querySelector('.work-space')||{dataset:{}}).dataset?.naviWs||null,
|
|
modalCard:g('.navi-ws-modal-card'),modalOk:g('.navi-ws-modal-ok'),webContent:g('.work-space .web-content')};
|
|
});
|
|
console.log(JSON.stringify({sidebarItems:n,modalSeen:!!modal,modal,r,errors:errs},null,1));
|
|
await p.screenshot({path:'/tmp/ws-v50-modal.png',fullPage:true});
|
|
await ctx.close(); await b.close();
|
|
const ok = !modal || (L(rgb(modal.bg))<95 && L(rgb(modal.title||'rgb(255,255,255)'))>190);
|
|
console.log(ok?'MODAL_DARK_OK':'MODAL_STILL_LIGHT');
|
|
if(!ok) process.exitCode=2;
|
|
})().catch(e=>{console.error(e);process.exit(1)});
|