global.window = undefined
function getCspUrls(env) {
// we want to have the following allowed connect-src for a given staticUrl like https://app(.local/.test).tuta.com:
//
// wss://app(.local/.test).tuta.com for websocket
// http(s)://*.api(.local/.test).tuta.com for the web app
// api://app(.local/.test).tuta.com for the mobile apps api protocol (intercepted by native part)
// https://app(.local/.test).tuta.com for the staticUrl itself
// https://(local./test.)tuta.com for the website
if (env.staticUrl) {
const url = new URL(env.staticUrl)
const staticUrlParts = env.staticUrl.split("//")
const apiUrl = staticUrlParts[0] + "//*.api." + staticUrlParts[1]
const webSocketUrl = `ws${env.staticUrl.substring(4)}`
const appApiUrl = `${env.staticUrl.replace(/^https?/, "api")}`
const websiteUrl = env.domainConfigs[url.hostname]?.websiteBaseUrl ?? "https://tuta.com"
return `${env.staticUrl} ${webSocketUrl} ${apiUrl} ${appApiUrl} ${websiteUrl}`
} else {
return ""
}
}
/**
* Renders the initial HTML page to bootstrap Tutanota for different environments
*/
export async function renderHtml(scripts, env) {
return `
${csp(env)}
${scripts.map(renderScriptImport).join("\n\t")}
${env.mode === "App" || env.mode === "Desktop" ? "Tuta Mail" : "Tuta Mail: Login & Sign up for free"}
`
}
function csp(env) {
if (env.dist) {
if (env.mode === "App" || env.mode === "Desktop") {
// differences in comparison to web csp:
// * Content Security Policies delivered via a element may not contain the frame-ancestors directive.
const cspContent =
"default-src 'none';" +
" script-src 'self' 'wasm-unsafe-eval';" +
" worker-src 'self';" +
" frame-src 'none';" +
" font-src 'self';" +
" img-src http: blob: data: *;" +
" media-src blob: data: *;" +
" style-src 'unsafe-inline';" +
"base-uri 'none';" +
` connect-src 'self' ${getCspUrls(env)};`
return ``
} else {
// csp is in the response headers
return ""
}
} else {
const cspContent =
"default-src * 'unsafe-inline';" +
" script-src * 'unsafe-inline' 'wasm-unsafe-eval';" +
" img-src * data: blob: 'unsafe-inline';" +
" media-src * data: blob: 'unsafe-inline';" +
" style-src * 'unsafe-inline';" +
" frame-src *;" +
` connect-src *;`
return ``
}
}
function renderScriptImport({ src, type }) {
const typeString = type ? ` type="${type}"` : ""
return ``
}