2017-08-15 13:54:22 +02:00
global . window = undefined
2022-07-15 10:01:02 +02:00
function getCspUrls ( env ) {
2023-10-19 16:26:43 +02:00
// 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
2017-08-15 13:54:22 +02:00
if ( env . staticUrl ) {
2023-10-27 11:27:04 +02:00
const url = new URL ( env . staticUrl )
2022-04-20 11:00:52 +02:00
const staticUrlParts = env . staticUrl . split ( "//" )
const apiUrl = staticUrlParts [ 0 ] + "//*.api." + staticUrlParts [ 1 ]
2023-10-19 16:26:43 +02:00
const webSocketUrl = ` ws ${ env . staticUrl . substring ( 4 ) } `
const appApiUrl = ` ${ env . staticUrl . replace ( /^https?/ , "api" ) } `
2023-10-27 11:27:04 +02:00
const websiteUrl = env . domainConfigs [ url . hostname ] ? . websiteBaseUrl ? ? "https://tuta.com"
2023-10-19 16:26:43 +02:00
return ` ${ env . staticUrl } ${ webSocketUrl } ${ apiUrl } ${ appApiUrl } ${ websiteUrl } `
2017-08-15 13:54:22 +02:00
} else {
return ""
}
}
/ * *
* Renders the initial HTML page to bootstrap Tutanota for different environments
* /
2019-09-13 13:49:11 +02:00
export async function renderHtml ( scripts , env ) {
2022-03-02 13:49:49 +01:00
return ` <!DOCTYPE html>
< html >
< head >
< meta charset = "utf-8" >
$ { csp ( env ) }
< meta name = "apple-mobile-web-app-capable" content = "yes" >
< meta name = "mobile-web-app-capable" content = "yes" >
< meta name = "referrer" content = "no-referrer" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" >
2022-03-14 17:52:03 +01:00
$ { scripts . map ( renderScriptImport ) . join ( "\n\t" ) }
2022-03-02 13:49:49 +01:00
<!-- TutanotaTags -- >
2025-01-16 14:54:23 +01:00
< title > $ { env . mode === "App" || env . mode === "Desktop" ? "Tuta Mail" : "Tuta Mail: Login & Sign up for free" } < / t i t l e >
2024-10-28 11:35:18 +01:00
< meta name = "description" content = "Sign-up for Tuta Mail: Get a free email account with quantum-safe encryption and best privacy for all your emails, calendars and contacts." >
2023-11-03 17:01:47 +01:00
< meta name = "application-name" content = "Tuta Mail" >
2025-02-19 11:49:36 +01:00
< link rel = "apple-touch-icon" href = "images/apple-touch-icon.png" >
2022-03-02 13:49:49 +01:00
< link rel = "icon" sizes = "192x192" href = "/images/logo-favicon-192.png" >
2023-08-23 11:48:45 +02:00
< meta name = "twitter:card" content = "summary_large_image" >
2023-11-09 14:04:10 +01:00
< meta name = "twitter:site" content = "@TutaPrivacy" >
2023-10-19 16:26:43 +02:00
< meta name = "twitter:domain" content = "tuta.com" >
< meta name = "twitter:image" content = "https://tuta.com/resources/images/share-tutanota-twitter-thumbnail.png" >
2023-08-23 11:48:45 +02:00
< meta property = "og:type" content = "website" >
2023-11-03 17:01:47 +01:00
< meta property = "og:site_name" content = "Tuta Mail" >
2024-10-15 13:23:20 +02:00
< meta property = "og:title" content = "Turn ON Privacy" >
2023-08-23 11:48:45 +02:00
< meta property = "og:description"
2024-10-15 13:23:20 +02:00
content = "Get a free email account with quantum-safe encryption and best privacy on all your devices. Green, secure & no ads!" >
2023-08-23 11:48:45 +02:00
< meta property = "og:locale" content = "en" >
2023-10-19 16:26:43 +02:00
< meta property = "og:url" content = "https://tuta.com/" >
< meta property = "og:image" content = "https://tuta.com/resources/images/share-tutanota-fb-thumbnail.png" >
2023-08-23 11:48:45 +02:00
< meta property = "article:publisher" content = "https://www.facebook.com/tutanota" >
2024-10-15 13:23:20 +02:00
< meta itemprop = "name" content = "Turn ON Privacy" >
< meta itemprop = "description" content = "Get a free email account with quantum-safe encryption and best privacy on all your devices. Green, secure & no ads!" >
2023-10-19 16:26:43 +02:00
< meta itemprop = "image" content = "https://tuta.com/images/share_image.png" >
2024-11-25 08:44:08 +01:00
< meta name = "apple-itunes-app" content = "app-id=922429609, app-argument=https://app.tuta.com" >
2025-01-08 14:05:44 +01:00
< link rel = "canonical" href = "https://app.tuta.com/" >
2022-03-02 13:49:49 +01:00
< / h e a d >
< body style = "background-color:transparent" >
< noscript > This site requires javascript to be enabled . Please activate it in the settings of your browser . < / n o s c r i p t >
< / b o d y >
< / h t m l > `
2017-08-15 13:54:22 +02:00
}
2022-03-02 13:49:49 +01:00
function csp ( env ) {
2019-09-13 13:49:11 +02:00
if ( env . dist ) {
if ( env . mode === "App" || env . mode === "Desktop" ) {
// differences in comparison to web csp:
// * Content Security Policies delivered via a <meta> element may not contain the frame-ancestors directive.
2022-12-27 15:37:40 +01:00
const cspContent =
"default-src 'none';" +
2023-07-17 11:42:02 +02:00
" script-src 'self' 'wasm-unsafe-eval';" +
2023-09-27 17:22:36 +02:00
" worker-src 'self';" +
2023-10-19 16:26:43 +02:00
" frame-src 'none';" +
2022-12-27 15:37:40 +01:00
" font-src 'self';" +
" img-src http: blob: data: *;" +
2025-07-14 14:10:39 +02:00
" media-src blob: data: *;" +
2022-12-27 15:37:40 +01:00
" style-src 'unsafe-inline';" +
"base-uri 'none';" +
2023-10-19 16:26:43 +02:00
` connect-src 'self' ${ getCspUrls ( env ) } ; `
2022-03-02 13:49:49 +01:00
return ` <meta http-equiv="Content-Security-Policy" content=" ${ cspContent } "> `
2019-09-13 13:49:11 +02:00
} else {
2023-09-25 13:28:09 +02:00
// csp is in the response headers
2022-03-14 17:52:03 +01:00
return ""
2019-09-13 13:49:11 +02:00
}
2018-07-18 16:07:25 +02:00
} else {
2022-12-27 15:37:40 +01:00
const cspContent =
"default-src * 'unsafe-inline';" +
2023-07-17 11:42:02 +02:00
" script-src * 'unsafe-inline' 'wasm-unsafe-eval';" +
2022-12-27 15:37:40 +01:00
" img-src * data: blob: 'unsafe-inline';" +
" media-src * data: blob: 'unsafe-inline';" +
" style-src * 'unsafe-inline';" +
" frame-src *;" +
2023-11-03 17:09:42 +01:00
` connect-src *; `
2022-03-02 13:49:49 +01:00
return ` <meta http-equiv="Content-Security-Policy" content=" ${ cspContent } "> `
2018-07-18 16:07:25 +02:00
}
}
2022-12-27 15:37:40 +01:00
function renderScriptImport ( { src , type } ) {
2022-05-03 13:38:19 +02:00
const typeString = type ? ` type=" ${ type } " ` : ""
2022-03-14 17:52:03 +01:00
return ` <script src=" ${ src } " ${ typeString } defer></script> `
2022-12-27 15:37:40 +01:00
}