Files
apes-sidebar/tests/browser-probe.spec.ts
T
Menghuan1918 302c20109f feat: 内置 HTML 预览器 + 沙箱浏览器 tab(v0.5.0)
- html viewer:.html/.htm 沙箱 iframe 预览(相对资源经 /sidebar/html 路径编码路由加载,CSP sandbox + 信任围栏 + cwd 边界),预览/编辑切换
- browser tab:+ 菜单多开(browser:<n>),地址栏后退/前进/刷新/在浏览器中打开(15px 图标),URL 与标题按会话持久化(patchTab + nextBrowser)
- 安全:iframe 一律不透明源沙箱(无 allow-same-origin/top-navigation、no-referrer、权限策略全禁、禁 srcdoc);地址栏仅 http(s)、拒绝 localhost 等本机地址;界面实时沙箱状态(关闭红色警示)+ 临时解锁/恢复
- 设置:htmlViewerNoSandbox / htmlViewerDefaultUnsafe / browserNoSandbox / browserInterceptLinks 四个声明式二级设置(默认安全)
- 外链拦截:聊天/界面 http(s) 外链默认在侧边栏打开(openTab seed.url),Ctrl/Cmd 点击放行
- 嵌入拒绝面板:browser.probe 路由探测 X-Frame-Options/frame-ancestors,被拒站点显示原因 + 在浏览器中打开/仍然加载
- 设置页可滚动;内置 7 tab + 9 viewer;新增设计文档;268 个测试全绿
2026-08-11 19:28:48 +08:00

51 lines
2.6 KiB
TypeScript

/**
* browser.probe helpers: the CSP frame-ancestors parser (host side) and the
* embeddability verdict (client side). Together they turn the target's
* response headers into the "refused to be embedded" explanation the
* sidebar browser shows instead of the browser's cryptic blank frame.
*/
import { describe, expect, it } from 'vitest'
import { extractFrameAncestors } from '../src/browser-probe.ts'
import { embeddabilityOf } from '../src/client/browser.ts'
describe('extractFrameAncestors', () => {
it('extracts a frame-ancestors source list from a CSP header', () => {
expect(extractFrameAncestors("default-src 'self'; frame-ancestors 'none'"))
.toEqual(["'none'"])
expect(extractFrameAncestors("frame-ancestors 'self' https://example.com"))
.toEqual(["'self'", 'https://example.com'])
expect(extractFrameAncestors('frame-ancestors *')).toEqual(['*'])
})
it('is undefined when the directive is absent or empty', () => {
expect(extractFrameAncestors(null)).toBeUndefined()
expect(extractFrameAncestors("default-src 'self'")).toBeUndefined()
expect(extractFrameAncestors('frame-ancestors')).toBeUndefined()
expect(extractFrameAncestors('frame-ancestors ; default-src *')).toBeUndefined()
})
})
describe('embeddabilityOf', () => {
it('blocks X-Frame-Options DENY / SAMEORIGIN', () => {
expect(embeddabilityOf({ reachable: true, status: 200, xFrameOptions: 'DENY' })).toBe('blocked')
expect(embeddabilityOf({ reachable: true, status: 200, xFrameOptions: 'SAMEORIGIN' })).toBe('blocked')
expect(embeddabilityOf({ reachable: true, status: 200, xFrameOptions: 'sameorigin' })).toBe('blocked')
})
it('blocks a frame-ancestors list that does not allow * ("self" means the SITE origin, never ours)', () => {
expect(embeddabilityOf({ reachable: true, frameAncestors: ["'none'"] })).toBe('blocked')
expect(embeddabilityOf({ reachable: true, frameAncestors: ["'self'"] })).toBe('blocked')
expect(embeddabilityOf({ reachable: true, frameAncestors: ["'self'", 'https://x.dev'] })).toBe('blocked')
})
it('allows a wildcard frame-ancestors and absent anti-framing headers', () => {
expect(embeddabilityOf({ reachable: true, status: 200, frameAncestors: ['*'] })).toBe('embeddable')
expect(embeddabilityOf({ reachable: true, status: 200 })).toBe('embeddable')
expect(embeddabilityOf({ reachable: true, status: 200, xFrameOptions: 'ALLOW-FROM https://x' })).toBe('embeddable')
})
it('is unknown when the target is unreachable (plain iframe stays)', () => {
expect(embeddabilityOf({ reachable: false })).toBe('unknown')
})
})