Skip to content

Commit a04910e

Browse files
committed
Merge branch 'cloaking' into preview
2 parents fd95650 + 7f04052 commit a04910e

3 files changed

Lines changed: 20 additions & 3 deletions

File tree

docs/faqs.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ Set `NUXT_DISABLE_BOT_ACCESS_LOG` to `true`.
5353

5454
## 9. What is Link Cloaking?
5555

56-
Link cloaking masks your destination URL by showing your short link domain in the browser address bar instead of redirecting to the target URL. The destination page loads inside a full-screen iframe.
56+
Link cloaking keeps your short link in the browser address bar instead of redirecting the top-level page to the target URL. The destination page loads inside a full-screen iframe.
57+
58+
It is a simple iframe-based feature. It does not hide the destination URL from page source, browser developer tools, network logs, or users who inspect the page.
5759

5860
### How to enable it
5961

@@ -63,7 +65,8 @@ Toggle **Enable Link Cloaking** in the **Link Settings** section when creating o
6365

6466
- **Sites that block iframes**: Websites with `X-Frame-Options: DENY` or `Content-Security-Policy: frame-ancestors 'none'` will not load inside the iframe. Most major sites (Google, GitHub, Twitter, etc.) block iframe embedding.
6567
- **HTTPS required**: The destination URL must use HTTPS. Mixed content (HTTPS short link → HTTP destination) will be blocked by browsers.
66-
- **Limited interaction**: Some features like OAuth login flows, `window.top` navigation, and certain payment forms may not work correctly inside the iframe.
68+
- **Limited interaction**: Some features like OAuth login flows and certain payment forms may not work correctly inside the iframe. Sink allows user-activated top-level navigation to improve checkout and external redirect compatibility, but it cannot make every embedded site work.
69+
- **No target URL hiding**: Sink does not proxy cloaked links or rewrite destination pages. This keeps cloaking simple and predictable, but the target URL can still be inspected by visitors.
6770
- **Device redirects take priority**: If both cloaking and device redirects (iOS/Android) are configured, device redirects will take precedence on matching devices.
6871

6972
### If the destination site blocks iframes

server/utils/template.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@ import type { Link } from '#shared/schemas/link'
22
import { escape } from 'es-toolkit/string'
33
import { parseURL } from 'ufo'
44

5+
const CLOAKING_IFRAME_SANDBOX = [
6+
'allow-scripts',
7+
'allow-same-origin',
8+
'allow-forms',
9+
'allow-popups',
10+
'allow-popups-to-escape-sandbox',
11+
'allow-top-navigation-by-user-activation',
12+
'allow-downloads',
13+
'allow-modals',
14+
].join(' ')
15+
516
function buildMetaTags(link: Link, baseUrl: string) {
617
const { host: hostname } = parseURL(link.url)
718
const title = link.title || hostname || 'Link'
@@ -39,7 +50,7 @@ export function generateCloakingHtml(link: Link, targetUrl: string, baseUrl: str
3950
${tags}
4051
</head>
4152
<body style="margin:0;overflow:hidden">
42-
<iframe src="${escape(targetUrl)}" style="width:100vw;height:100vh;border:none" sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox" allowfullscreen referrerpolicy="no-referrer"></iframe>
53+
<iframe src="${escape(targetUrl)}" style="width:100%;height:100%;width:100vw;height:100vh;border:none" sandbox="${CLOAKING_IFRAME_SANDBOX}" allowfullscreen referrerpolicy="no-referrer"></iframe>
4354
<noscript><meta http-equiv="refresh" content="0;url=${escape(targetUrl)}"></noscript>
4455
</body>
4556
</html>`

tests/redirect.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ describe('/', () => {
117117
expect(response.status).toBe(200)
118118
expect(html).toContain('<meta name="viewport" content="width=device-width,initial-scale=1">')
119119
expect(html).toContain(`<iframe src="${targetUrl}"`)
120+
expect(html).toContain('allow-top-navigation-by-user-activation')
121+
expect(html).toContain('allow-downloads')
122+
expect(html).toContain('allow-modals')
120123
})
121124

122125
it('prefers device redirect over geo redirect', async () => {

0 commit comments

Comments
 (0)