### Android SDK Project Setup Source: https://github.com/tutao/tutanota/blob/master/tuta-sdk/rust/README.md Guides through setting up the Android SDK project in Android Studio, including module SDK configuration and Gradle synchronization. ```text # setup the sdk project - open tutanota-3/tutasdk/android in Android Studio - Ctrl + A -> Project Structure -> Modules -> SDK -> select the NDK - gradle sync # add sdk/android to the app-android project as a library # sync gradle in Android Studio ``` -------------------------------- ### Install bindgen-cli Source: https://github.com/tutao/tutanota/blob/master/tuta-sdk/rust/README.md Installs the bindgen-cli binary and adds it to the system's PATH. Verify the installation by running the 'bindgen' command. ```bash # install bindgen-cli binary and export it to path car go install --locked bindgen-cli # export installed bindgen binary to $PATH. # verify it works bindgen ``` -------------------------------- ### Setup Songbird SDK Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Initializes and configures the Songbird SDK, handling script loading and potential setup failures. It includes a timeout for the setup process and initiates V1 fallback on failure. ```javascript this.setupSongbird = function (e) { var t = this, r = Date.now(); return this._songbirdPromise || (e = e || {}, this._songbirdPromise = new _, this._v2SetupFailureReason = "reason-unknown", t._loadCardinalScript(e).then(function () { return window.Cardinal ? t._configureCardinalSdk({ setupOptions: e, setupStartTime: r }) : (t._v2SetupFailureReason = "cardinal-global-unavailable", f.reject(new s(l.THREEDS_CARDINAL_SDK_SETUP_FAILED))) }).catch(function (e) { e = a(e, { type: l.THREEDS_CARDINAL_SDK_SETUP_FAILED.type, code: l.THREEDS_CARDINAL_SDK_SETUP_FAILED.code, message: l.THREEDS_CARDINAL_SDK_SETUP_FAILED.message }); t._getDfReferenceIdPromisePlus.reject(e), window.clearTimeout(t._songbirdSetupTimeoutReference), c.sendEvent(t._client, "three-d-secure.cardinal-sdk.init.setup-failed"), t._initiateV1Fallback("cardinal-sdk-setup-failed." + t._v2SetupFailureReason) }), this._songbirdPromise) } ``` -------------------------------- ### Handle Payments Setup Complete Callback Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Callback executed when the Cardinal SDK setup is complete. Resolves the session ID and the main setup promise. ```javascript y.prototype._createPaymentsSetupCompleteCallback = function () { var t = this; return function (e) { t._getDfReferenceIdPromisePlus.resolve(e.sessionId), window.clearTimeout(t._songbirdSetupTimeoutReference), c.sendEvent(t._createPromise, "three-d-secure.cardinal-sdk.init.setup-completed"), t._songbirdPromise.resolve() } } ``` -------------------------------- ### Build Unpacked Desktop Client Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Build the desktop client without packaging the installer, yielding an unpacked directory. ```bash node desktop --custom-desktop-release --unpacked ``` -------------------------------- ### Install Android App Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Install the built Android application on a device using adb. ```bash adb install -r ``` -------------------------------- ### Android NDK and Rust Target Setup Source: https://github.com/tutao/tutanota/blob/master/tuta-sdk/rust/README.md Installs the Android NDK and necessary Rust targets for cross-compilation. Configures environment variables for the NDK and adds its toolchain to the PATH. ```bash # install the android NDK Android Studio -> Android SDK Manager -> SDK Tools -> NDK (Side by Side) -> Install # install the android targets for rust (part of rust-tuta pkg on dev machines) rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android # add ANDROID_NDK to your shell profile (.bashrc). the version depends on your NDK version. export ANDROID_NDK_ROOT=/opt/android-sdk/ndk/28.2.13676358 export ANDROID_NDK_HOME=/opt/android-sdk/ndk/28.2.13676358 # add NDK toolchain to path export PATH=${PATH}:${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/ ``` -------------------------------- ### Install Dependencies Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Install project dependencies using npm ci. ```bash npm ci ``` -------------------------------- ### Configure and Setup Cardinal SDK Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Initializes the Cardinal SDK with JWT for payment processing. Ensure the Cardinal SDK is loaded before calling this. ```javascript window.Cardinal.configure(t), window.Cardinal.setup("init", {jwt: e}), i._clientMetadata.cardinalDeviceDataCollectionTimeElapsed = Date.now() - r, i.setCardinalListener("payments.validated", i._createPaymentsValidatedCallback()) ``` -------------------------------- ### CMake Project Setup Source: https://github.com/tutao/tutanota/blob/master/app-android/tutashared/src/main/cpp/CMakeLists.txt Sets the minimum required CMake version and defines the project name and languages. ```cmake cmake_minimum_required(VERSION 3.18.0) project("tutashared" LANGUAGES C CXX ) ``` -------------------------------- ### Handle inline setup for 3D Secure Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Handles the inline setup for 3D Secure authentication, managing different modes like 'suppress' and 'static'. It creates and appends the necessary iframe element. ```javascript a.prototype._onInlineSetup = function (e, t, r, n) { var i; e && t && "CCA" === t.paymentType && ("suppress" === t.data.mode || "static" === t.data.mode) || (i = !0), i ? n(new o(s.THREEDS_INLINE_IFRAME_DETAILS_INCORRECT)) : ((n = document.createElement("div")).innerHTML = e, "suppress" === t.data.mode ? (n.style.display = "none", document.body.appendChild(n), r()) : "static" === t.data.mode && this._emit(a.events.AUTHENTICATION_IFRAME_AVAILABLE, {element: n}, function () { r() })) } ``` -------------------------------- ### Setup V1 Bus for Authentication Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Sets up the V1 communication bus using a provided lookup response and an assets URL. It initializes a new `p` instance for communication and constructs the URL for the authentication complete frame. ```javascript y.prototype._setupV1Bus = function (e) { var t = window.location.href.split("#")[0], r = e.lookupResponse, n = _(), i = new p({channel: n, verifyDomain: c}), o = this._assetsUrl + "/html/three-d-secure-authentication-complete-frame.html?channel=" + encodeURIComponent(n) + "&"; return i.on(m, functi ``` -------------------------------- ### Clone Tutanota Repository Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Clone the Tutanota repository to start building the client. ```bash git clone https://github.com/tutao/tutanota.git ``` -------------------------------- ### Install Windows Cross-Compilation Target and Tool Source: https://github.com/tutao/tutanota/blob/master/src/app-kit/mimimi/README.md Add the x86_64-pc-windows-msvc target for Rust and install the cargo-xwin tool to enable cross-compilation to Windows from a Linux environment. ```bash rustup target add x86_64-pc-windows-msvc cargo install cargo-xwin ``` -------------------------------- ### Install Emscripten Compiler on Ubuntu Source: https://github.com/tutao/tutanota/blob/master/libs/webassembly/README.md Install the emscripten compiler on Ubuntu systems. This compiler is necessary for building WebAssembly binaries. ```bash sudo apt install emscripten emcc --version ``` -------------------------------- ### Configure Cardinal SDK Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Configures the Cardinal SDK after the client is ready. It retrieves the JWT, creates configuration options, and sets up various event listeners for payments setup completion and other events. ```javascript this._configureCardinalSdk = function (n) { var i = this; return this._waitForClient().then(function () { var e = i._client.getConfiguration().gatewayConfiguration.threeDSecure.cardinalAuthenticationJWT, t = n.setupOptions, r = n.setupStartTime, t = i._createCardinalConfigurationOptions(t); m.forEach(function (e) { i.setCardinalListener(e, function () { i._emit(y.events[e.toUpperCase()]) }) }), i.setCardinalListener("payments.setupComplete", i._createPaymentsSetupComplet ``` -------------------------------- ### iOS Rust Target and Build Script Source: https://github.com/tutao/tutanota/blob/master/tuta-sdk/rust/README.md Installs the required Rust targets for iOS development and executes the build script for the SDK. ```bash # install the iOS targets for rust rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim # build the sdk for iOS ./make_ios.sh ``` -------------------------------- ### Install Linux Cross-Compilation Target Source: https://github.com/tutao/tutanota/blob/master/src/app-kit/mimimi/README.md Add the x86_64-unknown-linux-gnu target for Rust to enable cross-compilation to Linux from a Linux environment. ```bash rustup target add x86_64-unknown-linux-gnu ``` -------------------------------- ### Setup 3D Secure V1 Iframe Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Configures and returns a 3D Secure V1 iframe element. It constructs the iframe source URL with necessary parameters and uses a helper function to create the iframe element. ```javascript y.prototype._setupV1Iframe = function (e) { e = this._assetsUrl + "/html/three-d-secure-bank-frame" + E(this._isDebug) + ".html?showLoader=" + e.showLoader; return d({ src: e, height: 400, width: 400, name: f.LANDING_FRAME_NAME + "_" + this._v1Bus.channel, title: "3D Secure Authorization Frame" }) } ``` -------------------------------- ### Configure Cardinal payment framework Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Configures the payment framework for Cardinal, setting it to 'inline'. This is part of the setup for 3D Secure authentication. ```javascript a.prototype._createCardinalConfigurationOptions = function (e) { e = n.prototype._createCardinalConfigurationOptions.call(this, e); return e.payment.framework = "inline", e } ``` -------------------------------- ### Inline Iframe Framework Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Handles the setup and events for an inline iframe used for Braintree integrations. It extends the Songbird class and defines specific events for iframe availability. ```javascript function a(e) { n.call(this, e) } a.prototype = Object.create(n.prototype, { constructor: n } ); a.events = e(["AUTHENTICATION_IFRAME_AVAILABLE"], "inline-iframe-framework:") ``` -------------------------------- ### Load Cardinal SDK Script Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Dynamically loads the Cardinal SDK script, choosing between sandbox and production sources based on the environment. Includes a timeout for setup and falls back to V1 if loading fails. ```javascript y.prototype._loadCardinalScript = function (t) { var r = this, n = p.CARDINAL_SCRIPT_SOURCE.sandbox; return this._waitForClient().then(function () { var e = "production" === r._client.getConfiguration().gatewayConfiguration.environment; return r._songbirdSetupTimeoutReference = window.setTimeout(function () { c.sendEvent(r._client, "three-d-secure.cardinal-sdk.init.setup-timeout"), r._initiateV1Fallback("cardinal-sdk-setup-timeout") }, t.timeout || h), e && (n = p.CARDINAL_SCRIPT_SOURCE.production), u.loadScript({src: n}) }).catch(function (e) { return r._v2SetupFailureReason = "songbird-js-failed-to-load", f.reject(a(e, l.THREEDS_CARDINAL_SDK_SCRIPT_LOAD_FAILED)) }) } ``` -------------------------------- ### Install MacOS Cross-Compilation Targets Source: https://github.com/tutao/tutanota/blob/master/src/app-kit/mimimi/README.md Add the x86_64-apple-darwin and aarch64-apple-darwin targets for Rust to enable cross-compilation to different macOS architectures from a macOS environment. ```bash rustup target add x86_64-apple-darwin rustup target add aarch64-apple-darwin ``` -------------------------------- ### Run F-Droid Build Container Source: https://github.com/tutao/tutanota/blob/master/ci/containers/README.md Runs the F-Droid build container, mounting the current directory as a repository and the host's Android SDK. The container requires the host to have necessary NDKs installed. ```bash podman run --rm -v $(pwd):/repo -v /opt/android-sdk:/opt/android-sdk -e ANDROID_HOME:/opt/android-sdk fdroid ``` -------------------------------- ### Build and Run SQLCipher for Android Docker Image Source: https://github.com/tutao/tutanota/blob/master/libs/sqlcipher-android/README-android-sqlcipher.md This command sequence builds a Docker image for Android SQLCipher and then runs it to produce the .aar artifact. Ensure you have Podman installed and the necessary Dockerfile. ```shell mkdir build-sqlcipher podman build -t android-sqlcipher --network=host -f android-sqlcipher.dockerfile source android-sqlcipher-ver podman run --rm \ -e SQLCIPHER_VERSION=$SQLCIPHER_VERSION \ -e SQLCIPHER_ANDROID_VERSION=$SQLCIPHER_ANDROID_VERSION \ -v $(pwd):/workspace:ro \ -v $(pwd)/build-sqlcipher:/build-sqlcipher \ -it android-sqlcipher # This will produce the artifact at build-sqlcipher/sqlcipher-android-4.7.2-release.aar # Move it to its final destination mv build-sqlcipher/sqlcipher-android-${SQLCIPHER_ANDROID_VERSION}-release.aar ../../app-android/libs/sqlcipher-android.aar ``` -------------------------------- ### Run Bash Shell in Linux Build Container Source: https://github.com/tutao/tutanota/blob/master/ci/containers/README.md Starts an interactive bash shell within the linux-build container. This allows for manual inspection or execution of commands inside the container. ```bash podman run -ti --name=linux-build linux-build:latest /bin/bash ``` -------------------------------- ### Build Desktop Client for Production Source: https://github.com/tutao/tutanota/blob/master/doc/HACKING.md Build the desktop client to connect against the production server. ```bash node make -d prod ``` -------------------------------- ### Build Web Client for Production Source: https://github.com/tutao/tutanota/blob/master/doc/HACKING.md Build the web client to connect against the production server. ```bash node make prod ``` -------------------------------- ### Serve Web Client Locally Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Run a local server to host the built web client. Use npx serve or python -m SimpleHTTPServer. ```bash npx serve build -s -p 9000 ``` ```bash python -m SimpleHTTPServer 9000 ``` -------------------------------- ### Build Web Client Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Build the production release of the web client. ```bash node webapp prod ``` -------------------------------- ### GET /rest/sys/missednotification/{ID} Source: https://github.com/tutao/tutanota/blob/master/doc/notifications.md Fetches missed notifications for a specific device. This endpoint is used by Desktop/Android clients to retrieve new email alerts after an SSE 'notification' event, and by iOS clients to get notifications triggered by APNS messages. ```APIDOC ## GET /rest/sys/missednotification/{ID} ### Description Fetches missed notifications for a specific device. The ID parameter is the device's PushIdentifier converted to a custom ID via Base64URL encoding. ### Method GET ### Endpoint /rest/sys/missednotification/{ID} ### Parameters #### Path Parameters - **ID** (string) - Required - The custom ID of the device, derived from PushIdentifier. #### Headers - **userIds** (string) - Required - A comma-separated list of user IDs logged into this device. - **lastProcessedNotificationId** (string) - Optional - The ID of the last notification fetched and processed by the client. Used to avoid duplicate data. - **v** (string) - Required - System model version. - **cv** (string) - Required - Client version. ### Response #### Success Response (200) - **MissedNotification** (object) - Contains the missed notification data. The exact structure is defined in the model definition. #### Error Response - **403** - Forbidden: Indicates that the userIds do not match the missed notification, suggesting local data invalidation. - **404** - Not Found: Indicates that there are no missed notifications to fetch. ``` -------------------------------- ### Show All Test Options Source: https://github.com/tutao/tutanota/blob/master/doc/HACKING.md Display all available command-line options for running tests. ```bash npm:run test -- --help ``` -------------------------------- ### Initialize and Update Submodules Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Initialize, synchronize, and update submodules for liboqs and argon2. ```bash git submodule init git submodule sync --recursive git submodule update ``` -------------------------------- ### Build Calendar Web App for Production Source: https://github.com/tutao/tutanota/blob/master/doc/HACKING.md Build the calendar web app specifically for production. ```bash node make prod -a calendar ``` -------------------------------- ### Build Desktop Client Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Build a custom release of the Tuta Mail Desktop client. ```bash node desktop --custom-desktop-release ``` -------------------------------- ### Set up framework-specific listeners for Cardinal Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Sets up framework-specific listeners for Cardinal, specifically for the 'ui.inline.setup' event. This is crucial for handling inline 3D Secure UI interactions. ```javascript a.prototype._setupFrameworkSpecificListeners = function () { this.setCardinalListener("ui.inline.setup", this._onInlineSetup.bind(this)) } ``` -------------------------------- ### Run All SDK and Node Tests Source: https://github.com/tutao/tutanota/blob/master/doc/HACKING.md Execute all tests for the SDK and node mimimi modules. ```bash cargo test --all ``` -------------------------------- ### Present Challenge with V1 Fallback Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Sets up and presents the challenge UI using the V1 fallback mechanism, including a loader and an authentication response handler. ```javascript this._presentChallengeWithV1Fallback = function (e) { var t = this; this._setupV1Elements({ lookupResponse: e, showLoader: !0, handleAuthResponse: function (e) { t._handleAuthResponseFromV1Fallback(e) } }), this._v1Modal = this._createV1IframeModal(this._v1Iframe), this._addV1IframeToPage() } ``` -------------------------------- ### Initialize Braintree SDK Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html This snippet shows the basic initialization of the Braintree SDK, setting up event listeners for UI interactions like closing, rendering, and loading states. ```javascript this.on(y.events["UI.CLOSE"], function () { r("authentication-modal-close") }), this.on(y.events["UI.RENDER"], function () { r("authentication-modal-render") }), this.on(y.events["UI.RENDERHIDDEN"], function () { r("authentication-modal-render-hidden") }), this.on(y.events["UI.LOADING.CLOSE"], function () { r("authentication-modal-loader-close") }), this.on(y.events["UI.LOADING.RENDER"], function () { r("authentication-modal-loader-render") }) ``` -------------------------------- ### Initialize Challenge with Lookup Response Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Initializes the challenge process using the response from a lookup, ensuring Songbird is set up first. ```javascript this.initializeChallengeWithLookupResponse = function (e, t) { return this.setupSongbird().then(function () { return n.prototype.initializeChallengeWithLookupResponse.call(this, e, t) }.bind(this)) } ``` -------------------------------- ### Build Web Client Source: https://github.com/tutao/tutanota/blob/master/doc/HACKING.md Build the web client for development. This will use the browser URL as the API endpoint. ```bash node make ``` -------------------------------- ### Build Linux Build Container Image Source: https://github.com/tutao/tutanota/blob/master/ci/containers/README.md Builds the linux-build container image using Podman. Ensure you are running as root or have rootless containers configured. Uses host network and specifies the Dockerfile. ```bash podman build -t linux-build:latest --network=host -f linux-build.dockerfile --format docker --squash ``` -------------------------------- ### Initialize Promise Polyfill Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Sets up the Promise polyfill for environments that do not natively support Promises. ```javascript var n = e("promise-polyfill"), e = e("@braintree/extended-promise"), n = "undefined" != typeof Promise ? Promise : n; e.suppressUnhandledPromiseMessage = !0, e.setPromise(n), t.exports = n ``` -------------------------------- ### Run SDK and Node Tests with Local HTTP Server Source: https://github.com/tutao/tutanota/blob/master/doc/HACKING.md Run SDK and node mimimi tests that require an actual local HTTP server. This enables tests that do not yet have a mock server. ```bash cargo test --all --features test-with-local-http-server ``` -------------------------------- ### Initialize Songbird framework Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Initializes the Songbird framework, which is used for 3D Secure authentication. It sets up internal properties and event listeners. ```javascript y.prototype.setupSongbird = function(e) { this._useV1Fallback = !1, this._clientMetadata = { requestedThreeDSecureVersion: "2", sdkVersion: E + "/3.69.0" }, this._getDfReferenceIdPromisePlus = new _ , this.setupSongbird(e), this._cardinalEvents = [] } ``` -------------------------------- ### Build Android App Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Build the Android application using node, providing signing details. ```bash APK_SIGN_ALIAS="tutaKey" APK_SIGN_STORE='MyKeystore.jks' APK_SIGN_STORE_PASS="CHANGEME" APK_SIGN_KEY_PASS="CHANGEME" node android ``` -------------------------------- ### Set up event listeners for Songbird framework Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Sets up event listeners for the Songbird framework, specifically for 'lookup-complete' and 'customer-canceled' events. These events are crucial for managing the 3D Secure transaction flow. ```javascript y.prototype.setUpEventListeners = function (r) { this.on(y.events.LOOKUP_COMPLETE, function (e, t) { r("lookup-complete", e, t) }), this.on(y.events.CUSTOMER_CANCELED, fun ``` -------------------------------- ### Initialize and Update Git Submodules Source: https://github.com/tutao/tutanota/blob/master/libs/webassembly/README.md Initialize and update git submodules to fetch C library dependencies. This is typically done only once. ```bash git submodule init # only the first time git submodule update ``` -------------------------------- ### Initialize 3D Secure Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Creates a new 3D Secure component. Requires client authorization and optionally accepts a debug flag and assets URL. ```javascript var threeDSecure = require('braintree-web/three-d-secure'); threeDSecure.create({ client: client }).then(function (instance) { // Use instance to verify cards }).catch(function (err) { console.error(err); }); ``` -------------------------------- ### Generate Android Keystore Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Generate a keystore for signing the Android application. Replace placeholders with your own values. ```bash keytool -genkey -noprompt -keystore MyKeystore.jks -alias tutaKey -keyalg RSA -keysize 2048 -validity 10000 -deststoretype pkcs12 -storepass CHANGEME -keypass CHANGEME -dname "CN=com.example" ``` -------------------------------- ### Create Braintree Client Instance Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Creates a Braintree client instance. It either uses an existing client from the window object or dynamically loads the client script. It also checks for version compatibility. ```javascript t.exports = { create: function (e) { var t = i.resolve(); return e.client ? i.resolve(e.client) : (window.braintree && window.braintree.client || (t = o.loadScript({src: e.assetsUrl + "/web/" + a + "/js/client.min.js"}).catch(function (e) { return i.reject(new n({ type: s.CLIENT_SCRIPT_FAILED_TO_LOAD.type, code: s.CLIENT_SCRIPT_FAILED_TO_LOAD.code, message: s.CLIENT_SCRIPT_FAILED_TO_LOAD.message, details: {originalError: e} })) })), t.then(function () { return window.braintree.client.VERSION !== a ? i.reject(new n({ type: s.INCOMPATIBLE_VERSIONS.type, code: s.INCOMPATIBLE_VERSIONS.code, message: "Client ( ``` -------------------------------- ### Prepare Lookup Request Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Prepares data for a lookup request, including fetching a DF reference ID, triggering a BIN process, and waiting for the client to be ready. It also attaches client metadata and authorization fingerprint. ```javascript this.prepareLookup = function (e) { var t = i({}, e), r = this; return this.getDfReferenceId().then(function (e) { t.dfReferenceId = e }).then(function () { return r._triggerCardinalBinProcess(e.bin) }).catch(function () { }).then(function () { return r._waitForClient() }).then(function () { return t.clientMetadata = r._clientMetadata, t.authorizationFingerprint = r._client.getConfiguration().authorizationFingerprint, t.braintreeLibraryVersion = "braintree/web/3.69.0", t }) } ``` -------------------------------- ### Build a Specific WASM Library Source: https://github.com/tutao/tutanota/blob/master/libs/webassembly/README.md Build a specific WebAssembly (WASM) library by calling its respective makefile. The built WASM binary will be placed in the specified output directory. ```bash make -f ``` -------------------------------- ### Create Cardinal Configuration Options Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Generates configuration options for the Cardinal SDK, including logging and payment display settings. Supports enabling verbose logging if not explicitly disabled. ```javascript y.prototype._createCardinalConfigurationOptions = function (e) { var t = e.cardinalSDKConfig || {}, r = t.payment || {}; return !t.logging && e.loggingEnabled && (t.logging = {level: "verbose"}), t.payment = {}, r.hasOwnProperty("displayLoading") && (t.payment.displayLoading = r.displayLoading), r.hasOwnProperty("displayExitButton") && (t.payment.displayExitButton = r.displayExitButton), t } ``` -------------------------------- ### Initialize 3D Secure Client Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Initializes the 3D Secure client, checking for various configuration requirements and enabling/disabling features based on the environment and authorization type. It returns a promise that resolves with the initialized client or rejects with a Braintree error. ```javascript (function (e) { var t, r = e.getConfiguration(), n = r.gatewayConfiguration; return o.client = e, n.threeDSecureEnabled || (t = p.THREEDS_NOT_ENABLED), "TOKENIZATION_KEY" === r.authorizationType && (t = p.THREEDS_CAN_NOT_USE_TOKENIZATION_KEY), "production" === n.environment && !a() && (t = p.THREEDS_HTTPS_REQUIRED), "legacy" === i || n.threeDSecure && n.threeDSecure.cardinalAuthenticationJWT || (d.sendEvent(o.client, "three-d-secure.initialization.failed.missing-cardinalAuthenticationJWT"), t = p.THREEDS_NOT_ENABLED_FOR_V2), t ? f.reject(new l(t)) : (d.sendEvent(o.client, "three-d-secure.initialized"), e) }), r = new s({ client: o.client, assetsUrl: e, createPromise: t, loggingEnabled: o.loggingEnabled, cardinalSDKConfig: o.cardinalSDKConfig, framework: i }); return o.client ? t.then(function () { return r }) : r }) }), VERSION: "3.69.0" } ``` -------------------------------- ### Initiate V1 Fallback Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Sets a flag to use V1 fallback and sends an event indicating the fallback initiation. ```javascript this._initiateV1Fallback = function (e) { this._useV1Fallback = !0, c.sendEvent(this._createPromise, "three-d-secure.v1-fallback." + e), this._songbirdPromise.resolve() } ``` -------------------------------- ### Create Braintree Client Instance Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Creates a Braintree client instance with the provided authorization and debug settings. ```javascript window.braintree.client.create({authorization: e.authorization, debug: e.debug}) ``` -------------------------------- ### Facade Definition Syntax Source: https://github.com/tutao/tutanota/blob/master/buildSrc/licc/README.md Defines a facade with a name, type, sender/receiver platforms, optional documentation, and methods. ```json5 { name: "BarFacade", type: "facade", senders: [ "web" ], receivers: [ "desktop", "ios" ], doc: "optional doc comment explaining the scope of the facade", methods: { "methodName": { doc: "optional comment explaining the contract and purpose of the method", arg: [ { argName1: "argType1" }, { argName2: "argType2" }, ... ], ret: "returnType" }, ... } } ``` -------------------------------- ### Braintree Client Initialization and Event Handling Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Initializes Braintree client and sets up event listeners. This snippet is part of a larger class structure for managing Braintree interactions. ```javascript function y(e) { u.call(this), this._client = e.client, this._createPromise = e.createPromise, this._createOptions = e, this._client ? (this._isDebug = this._client.getConfiguration().isDebug, this._assetsUrl = this._client.getConfiguration().gatewayConfiguration.assetsUrl) : (this._isDebug = Boolean(e.isDebug), this._assetsUrl = e.assetsUrl), this._assetsUrl = this._assetsUrl + "/web/3.69.0" } u.createChild(y), y.prototype._waitForClient = function () { return this._client ? a.resolve() : this._createPromise.then(function (e) { this._client = e }.bind(this)) }, y.prototype.setUpEventListeners = function () { throw new s(l.THREEDS_FRAMEWORK_METHOD_NOT_IMPLEMENTED) }, y.prototype.verifyCard = function (e, t) { var r, n = this; return t = t || {}, (t = this._checkForVerifyCardError(e, t)) ? a.reject(t) : (this._verifyCardInProgress = !0, r = this._formatVerifyCardOptions(e), this._formatLookupData(r).then(function (e) { return o.sendEvent(n._createPromise, "three-d-secure.verification-flow.started"), n._performLookup(r.nonce, e) }).then(function (e) { retu ``` -------------------------------- ### Checkout Latest Web Release Tag Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Checkout the latest web release tag for building the web client. ```bash git checkout tutanota-release-xxx ``` -------------------------------- ### Event Optimization Scenario Source: https://github.com/tutao/tutanota/blob/master/doc/events.md Illustrates a scenario involving create (C) and update (U) events, highlighting a critical point '!' where an instance event for ownerGroup A occurs, emphasizing the need for prior group existence. ```text C ...... U C ...... _ _ ...!.. C C - create event U - update event ! - create for instance with ownerGroup = A _ - skipped event ``` -------------------------------- ### Initialize Challenge with Lookup Response Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Initializes the 3D Secure challenge flow using a previous lookup response. The response can be provided as a JSON string or an object. ```javascript instance.initializeChallengeWithLookupResponse(lookupResponse); ``` -------------------------------- ### Build Node-Mimimi with napi-rs Source: https://github.com/tutao/tutanota/blob/master/src/app-kit/mimimi/README.md Build the Node-Mimimi module using napi-rs, specifying CommonJS bindings and TypeScript definitions. This command is recommended for compatibility. ```bash napi build --platform . --js binding.cjs --dts binding.d.ts ``` -------------------------------- ### Build MAPIrs Native Dependency Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Build the MAPIrs native dependency for Windows MAPI support. Ensure it's in the correct directory structure relative to tutanota. ```bash parent dir ├── mapirs └── tutanota-3 ``` -------------------------------- ### Framebus Constructor Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Initializes a new Framebus instance with optional origin, channel, and domain verification settings. Defaults are provided for origin and channel if not specified. ```javascript function n(e) { void 0 === e && (e = {}), this.origin = e.origin || "*", this.channel = e.channel || "", this.verifyDomain = e.verifyDomain, this.isDestroyed = !1, this.listeners = []; } ``` -------------------------------- ### Build F-Droid Container Image Source: https://github.com/tutao/tutanota/blob/master/ci/containers/README.md Builds the F-Droid build container image from the specified Dockerfile located in the ci/containers directory. Uses the host network. ```bash podman build -t fdroid --network=host -f ci/containers/fdroid-build.dockerfile ``` -------------------------------- ### Create V1 iframe for authentication Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Creates a V1 iframe for authentication purposes. It sets up event handlers for the authentication response and returns the iframe element. ```javascript o.prototype._createIframe = function (t) { var r = this; return this._setupV1Elements({ lookupResponse: t.lookupResponse, showLoader: t.showLoader, handleAuthResponse: function (e) { r._handleAuthResponse(e, t) } }), this._v1Iframe } ``` -------------------------------- ### Handle Web Build Error Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Delete the include directory if a build error related to wasm-loader or liboqs.wasm occurs. ```bash rm -rf libs/webassembly/include ``` -------------------------------- ### Checkout Latest Android Release Tag Source: https://github.com/tutao/tutanota/blob/master/doc/BUILDING.md Checkout the latest android release tag for building the Android app. ```bash git checkout tutanota-android-release-xxx ``` -------------------------------- ### Format lookup data for V1 Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Formats the lookup data, including transforming the customer's billing address if present. This prepares the data for the V1 integration. ```javascript o.prototype._formatLookupData = function (t) { var r = this; return n.prototype._formatLookupData.call(this, t).then(function (e) { return t.customer && t.customer.billingAddress && (e.customer = r.transformV1CustomerBillingAddress(t.customer)), e }) } ``` -------------------------------- ### Define Library Paths Source: https://github.com/tutao/tutanota/blob/master/app-android/tutashared/src/main/cpp/CMakeLists.txt Sets variables for various library directories used in the project. ```cmake set(TUTAMAIL_PROJECT_DIR "${CMAKE_SOURCE_DIR}/../../../../../") set(WEBASSEMBLY_LIBS_DIR "${TUTAMAIL_PROJECT_DIR}/libs/webassembly") set(ARGON2_DIR "${WEBASSEMBLY_LIBS_DIR}/phc-winner-argon2") set(LIBOQS_DIR "${WEBASSEMBLY_LIBS_DIR}/liboqs") set(C_LIBS_INCLUDE_DIR "${WEBASSEMBLY_LIBS_DIR}/include") ``` -------------------------------- ### Format verify card options for V1 Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Formats the options for the verify card function, adapting them for the V1 integration. It wraps 'addFrame' and 'removeFrame' in promises and sets 'showLoader'. ```javascript o.prototype._formatVerifyCardOptions = function (e) { var t = n.prototype._formatVerifyCardOptions.call(this, e); return t.addFrame = i(e.addFrame), t.removeFrame = i(e.removeFrame), t.showLoader = !1 !== e.showLoader, t } ``` -------------------------------- ### Run All TypeScript Tests Source: https://github.com/tutao/tutanota/blob/master/doc/HACKING.md Execute all tests written in TypeScript. ```bash npm test ``` -------------------------------- ### Cardinal SDK Configuration Constants Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Defines constants for Cardinal's SDK, including landing frame names and script sources for production and sandbox environments. ```javascript t.exports = { LANDING_FRAME_NAME: "braintreethreedsecurelanding", CARDINAL_SCRIPT_SOURCE: { production: "https://songbird.cardinalcommerce.com/edge/v1/songbird.js", sandbox: "https://songbirdstag.cardinalcommerce.com/edge/v1/songbird.js" } } ``` -------------------------------- ### Wrap Prototype Methods with Promise/Callback Support Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Wraps all methods of a given prototype with promise and callback support. This allows methods to be called either with a callback or to return a Promise. ```javascript "use strict"; var i = e("./lib/deferred"), o = e("./lib/once"), s = e("./lib/promise-or-callback"); function a(n) { return function () { for (var e, t = [], r = 0; r < arguments.length; r++) t[r] = arguments[r]; return "function" == typeof t[t.length - 1] && (e = t.pop(), e = o.once(i.deferred(e))), s.promiseOrCallback(n.apply(this, t), e); }; } a.wrapPrototype = function (n, e) { void 0 === e && (e = {}); var i = e.ignoreMethods || [], o = !0 === e.transformPrivateMethods; return Object.getOwnPropertyNames(n.prototype).filter(function (e) { var t = "constructor" !== e && "function" == typeof n.prototype[e], r = -1 === i.indexOf(e), e = o || "_" !== e.charAt(0); return t && e && r; }).forEach(function (e) { var t = n.prototype[e]; n.prototype[e] = a(t); }), n; }, t.exports = a; ``` -------------------------------- ### Initiate 3D Secure Verification Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html This snippet shows how to create a 3D Secure instance and initiate card verification using the Braintree SDK. It handles the lookup process and prepares for payment processing. ```javascript document.addEventListener("DOMContentLoaded", function (event) { let params = parseQueryString(location.hash.substring(1)) document.getElementById("message").textContent = decodeURIComponent(`${params.message}`) const schema = params.app === "mail" ? "tutanota" : "tutacalendar" confirm3ds2(decodeURIComponent(params.clientToken), decodeURIComponent(params.nonce), decodeURIComponent(params.bin), decodeURIComponent(params.price), decodeURIComponent(params.clientType), schema) }); function confirm3ds2(clientToken, nonce, bin, price, clientType, schema) { // see https://braintree.github.io/braintree-web/current/ThreeDSecure.html#verifyCard braintree.threeDSecure.create({ authorization: clientToken, version: 2 }).then(threeDS => { return threeDS.verifyCard({ onLookupComplete: function (data, next) { next() }, amount: price, nonce: nonce, bin: bin, challengeRequested: true, }) }).then((result) => { fetch(`${location.origin}/rest/sys/paymentdataservice`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ "1838": "0", "1839": [{"1834": "lq3tLw", "1835": clientToken, "1836": result.nonce} ] }) // body data type must match "Content-Type" header }).then(response => { document.getElementById("message").textContent = "Your payment details were successfully linked to your Tuta Mail account!" document.getElementById("message2").textContent = "You may close this tab and return to the app." // ClientType.App if (clientType === "2") window.location.href = `${schema}://app`; else window.close(); }).catch(e => { document.getElementById("message").textContent = "Sorry, the verification of your payment details was unsuccessful." document.getElementById("message2").textContent = "You may return to the app to see what went wrong." // ClientType.App if (clientType === "2") window.location.href = `${schema}://app`; else window.close(); }) }).catch(e => { document.getElementById("message").textContent = "Sorry, the verification of your payment details was unsuccessful." document.getElementById("message2").textContent = "You may return to the app to see what went wrong." // ClientType.App if (clientType === "2") window.location.href = `${schema}://app`; else window.close(); }) } ``` -------------------------------- ### Struct Definition Syntax Source: https://github.com/tutao/tutanota/blob/master/buildSrc/licc/README.md Defines a structure with a name, type, optional documentation, and fields. ```json5 { name: "Foo", type: "struct", doc: "optional doc comment that explains the type's purpose", fields: { fieldName: "fieldType", ... } } ``` -------------------------------- ### Custom Promise Implementation Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html A detailed implementation of a Promise object, including methods like then, catch, finally, all, resolve, reject, and race. This serves as a foundational utility for asynchronous operations. ```javascript "use strict"; var n = setTimeout; function c(e) { return Boolean(e && void 0 !== e.length) } function i() { } function o(e) { if (!(this instanceof o)) throw new TypeError("Promises must be constructed via new"); if ("function" != typeof e) throw new TypeError("not a function"); this._state = 0, this._handled = !1, this._value = void 0, this._deferreds = [], p(e, this) } function s(r, n) { for (; 3 === r._state;) r = r._value; 0 !== r._state ? (r._handled = !0, o._immediateFn(function () { var e, t = 1 === r._state ? n.onFulfilled : n.onRejected; null !== t ? (try { e = t(r._value) } catch (e) { return void u(n.promise, e) }, a(n.promise, e)) : (1 === r._state ? a : u)(n.promise, r._value) })) : r._deferreds.push(n) } function a(t, e) { try { if (e === t) throw new TypeError("A promise cannot be resolved with itself."); if (e && ("object" == typeof e || "function" == typeof e)) { var r = e.then; if (e instanceof o) return t._state = 3, t._value = e, void l(t); if ("function" == typeof r) return void p((n = r, i = e, function () { n.apply(i, arguments) }), t) } t._state = 1, t._value = e, l(t) } catch (e) { u(t, e) } var n, i } function u(e, t) { e._state = 2, e._value = t, l(e) } function l(e) { 2 === e._state && 0 === e.length && o._immediateFn(function () { e._handled || o._unhandledRejectionFn(e._value) }); for (var t = 0, r = e._deferreds.length; t < r; t++) s(e, e._deferreds[t]); e._deferreds = null } function d(e, t, r) { this.onFulfilled = "function" == typeof e ? e : null, this.onRejected = "function" == typeof t ? t : null, this.promise = r } function p(e, t) { var r = !1; try { e(function (e) { r || (r = !0, a(t, e)) }, function (e) { r || (r = !0, u(t, e)) }) } catch (e) { if (r) return; r = !0, u(t, e) } } o.prototype.catch = function (e) { return this.then(null, e) }, o.prototype.then = function (e, t) { var r = new this.constructor(i); return s(this, new d(e, t, r)), r }, o.prototype.finally = function (t) { var r = this.constructor; return this.then(function (e) { return r.resolve(t()).then(function () { return e }) }, function (e) { return r.resolve(t()).then(function () { return r.reject(e) }) }) }, o.all = function (t) { return new o(function (i, o) { if (!c(t)) return o(new TypeError("Promise.all accepts an array")); var s = Array.prototype.slice.call(t); if (0 === s.length) return i([]); var a = s.length; for (var e = 0; e < s.length; e++) !function t(r, e) { try { if (e && ("object" == typeof e || "function" == typeof e)) { var n = e.then; if ("function" == typeof n) return void n.call(e, function (e) { t(r, e) }, o) } s[r] = e, 0 == --a && i(s) } catch (e) { o(e) } }(e, s[e]) }) }, o.resolve = function (t) { return t && "object" == typeof t && t.constructor === o ? t : new o(function (e) { e(t) }) }, o.reject = function (r) { return new o(function (e, t) { t(r) }) }, o.race = function (i) { return new o(function (e, t) { if (!c(i)) return t(new TypeError("Promise.race accepts an array")); for (var r = 0, n = i.length; r < n; r++) o.resolve(i[r]).then(e, t) }) }, o._immediateFn = "function" == typeof setImmediate ? function (e) { setImmediate(e) } : function (e) { n(e, 0) }, o._unhandledRejectionFn = function (e) { "undefined" != typeof console && console && console.warn("Possible Unhandled Promise Rejection:", e) }, t.exports = o ``` -------------------------------- ### Set up event listeners for Braintree authentication iframe Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Sets up event listeners for the Braintree authentication iframe, emitting a custom event when the iframe is available. This is useful for managing the authentication flow. ```javascript a.prototype.setUpEventListeners = function (r) { n.prototype.setUpEventListeners.call(this, r), this.on(a.events.AUTHENTICATION_IFRAME_AVAILABLE, function (e, t) { r("authentication-iframe-available", e, t) }) } ``` -------------------------------- ### Prepare Lookup Data Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Prepares data for a 3D Secure lookup, potentially adding challenge or exemption information. ```javascript instance.prepareLookup(lookupData).then(function (formattedLookupData) { // Use formattedLookupData for the lookup return JSON.stringify(formattedLookupData); }); ``` -------------------------------- ### Handle Authentication Response from V1 Fallback Source: https://github.com/tutao/tutanota/blob/master/src/braintree.html Cleans up V1 elements and processes the authentication response received from the V1 fallback. ```javascript this._handleAuthResponseFromV1Fallback = function (e) { this._teardownV1Elements(), this._v1Modal.parentNode.removeChild(this._v1Modal), this._handleV1AuthResponse(e) } ``` -------------------------------- ### Run Specific Tests Without npm Source: https://github.com/tutao/tutanota/blob/master/doc/HACKING.md Execute specific tests directly using Node.js, bypassing the npm test script. ```bash node test -f CalendarModel ```