Skip to content

Commit 328d3b9

Browse files
authored
xftp-web: use XFTP server domain in share link, verify on download (#1732)
* xftp-web: use XFTP server domain in share link, verify on download Use a random XFTP server host from the file description as the link origin instead of the current page domain. On download, verify that the hosting domain matches one of the servers in the description. * xftp-web: use first description server as link origin * xftp-web: show wrong server error in download UI instead of blank page
1 parent b6b87a6 commit 328d3b9

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

xftp-web/src/protocol/address.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,23 @@ export function parseXFTPServer(address: string): XFTPServer {
5252
export function formatXFTPServer(srv: XFTPServer): string {
5353
return "xftp://" + base64urlEncode(srv.keyHash) + "@" + srv.host + ":" + srv.port
5454
}
55+
56+
// Extract unique XFTP servers referenced in a file description's chunk replicas.
57+
export function getDescriptionServers(fd: {chunks: {replicas: {server: string}[]}[]}): XFTPServer[] {
58+
const seen = new Set<string>()
59+
const servers: XFTPServer[] = []
60+
for (const chunk of fd.chunks) {
61+
for (const replica of chunk.replicas) {
62+
if (!seen.has(replica.server)) {
63+
seen.add(replica.server)
64+
servers.push(parseXFTPServer(replica.server))
65+
}
66+
}
67+
}
68+
return servers
69+
}
70+
71+
// Build an HTTPS origin from an XFTP server address.
72+
export function serverOrigin(server: XFTPServer): string {
73+
return server.port === "443" ? `https://${server.host}` : `https://${server.host}:${server.port}`
74+
}

xftp-web/web/download.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
newXFTPAgent, closeXFTPAgent,
66
decodeDescriptionURI, downloadFileRaw
77
} from '../src/agent.js'
8+
import {getDescriptionServers} from '../src/protocol/address.js'
89
import {XFTPPermanentError} from '../src/client.js'
910

1011
const DECRYPT_WEIGHT = 0.15
@@ -20,6 +21,8 @@ export function initDownload(app: HTMLElement, hash: string) {
2021
return
2122
}
2223

24+
const wrongServer = !getDescriptionServers(fd).map(s => s.host).includes(window.location.hostname)
25+
2326
const size = fd.redirect ? fd.redirect.size : fd.size
2427
app.innerHTML = `
2528
<div class="card">
@@ -62,6 +65,11 @@ export function initDownload(app: HTMLElement, hash: string) {
6265
showStage(errorStage)
6366
}
6467

68+
if (wrongServer) {
69+
readyStage.innerHTML = `<p class="error">${t('wrongServer', 'This file is not hosted on this server.')}</p>`
70+
return
71+
}
72+
6573
dlBtn.addEventListener('click', startDownload)
6674
retryBtn.addEventListener('click', () => showStage(readyStage))
6775

xftp-web/web/upload.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
newXFTPAgent, closeXFTPAgent, uploadFile, encodeDescriptionURI,
77
type EncryptedFileMetadata
88
} from '../src/agent.js'
9+
import {getDescriptionServers, serverOrigin} from '../src/protocol/address.js'
910
import {XFTPPermanentError} from '../src/client.js'
1011

1112
const MAX_SIZE = 100 * 1024 * 1024
@@ -170,7 +171,11 @@ export function initUpload(app: HTMLElement) {
170171
})
171172
if (aborted) return
172173

173-
const url = window.location.origin + window.location.pathname + '#' + result.uri
174+
const descServers = getDescriptionServers(result.rcvDescription)
175+
const origin = descServers.length > 0
176+
? serverOrigin(descServers[0])
177+
: window.location.origin
178+
const url = origin + window.location.pathname + '#' + result.uri
174179
shareLink.value = url
175180
showStage(completeStage)
176181
app.dispatchEvent(new CustomEvent('xftp:upload-complete', {detail: {url}, bubbles: true}))

0 commit comments

Comments
 (0)