From e3a65ab41ef93d9eaedcd6abf09a856161e71beb Mon Sep 17 00:00:00 2001 From: sug Date: Wed, 9 Oct 2024 11:10:42 +0200 Subject: [PATCH] imap import wip --- .../NativeCryptoFacadeReceiveDispatcher.kt | 15 +- .../generated_ipc/PersistedCredentials.kt | 3 +- .../generated_ipc/UnencryptedCredentials.kt | 3 +- buildSrc/DesktopBuilder.js | 15 +- buildSrc/DevBuild.js | 10 +- buildSrc/esbuildUtils.js | 37 +- buildSrc/packageBuilderFunctions.js | 4 +- .../facades/ImapImportSystemFacade.json | 34 + ipc-schema/types/ImapCredentials.json | 7 + ipc-schema/types/MailBundle.json | 2 +- ipc-schema/types/TutaCredentials.json | 7 + package-lock.json | 48 ++ package.json | 2 + packages/node-mimimi/.cargo/config.toml | 2 + packages/node-mimimi/.gitignore | 197 ++++++ packages/node-mimimi/.npmignore | 13 + packages/node-mimimi/Cargo.toml | 37 + packages/node-mimimi/README.md | 34 + packages/node-mimimi/build.rs | 5 + packages/node-mimimi/examples/http_request.rs | 43 ++ packages/node-mimimi/make.js | 41 ++ .../npm/darwin-universal/README.md | 3 + .../npm/darwin-universal/package.json | 15 + .../node-mimimi/npm/linux-x64-gnu/README.md | 3 + .../npm/linux-x64-gnu/package.json | 21 + .../node-mimimi/npm/win32-x64-msvc/README.md | 3 + .../npm/win32-x64-msvc/package.json | 18 + packages/node-mimimi/package.json | 35 + packages/node-mimimi/rustfmt.toml | 16 + packages/node-mimimi/src/imap.rs | 2 + packages/node-mimimi/src/imap/credentials.rs | 12 + .../node-mimimi/src/imap/import_client.rs | 290 ++++++++ packages/node-mimimi/src/importer.rs | 107 +++ packages/node-mimimi/src/lib.rs | 16 + packages/node-mimimi/src/logging.rs | 13 + packages/node-mimimi/src/logging/console.rs | 87 +++ packages/node-mimimi/src/logging/logger.rs | 108 +++ packages/node-mimimi/src/tuta.rs | 1 + packages/node-mimimi/src/tuta/credentials.rs | 48 ++ packages/node-mimimi/test/Suite.ts | 3 + packages/node-mimimi/test/tsconfig.json | 15 + packages/node-mimimi/tsconfig.json | 5 + packages/tuta-imap/.gitignore | 6 + packages/tuta-imap/Cargo.toml | 20 + packages/tuta-imap/build.rs | 29 + packages/tuta-imap/java/build.gradle.kts | 24 + packages/tuta-imap/java/settings.gradle.kts | 24 + .../java/greenmailserver/GreenMailServer.java | 63 ++ packages/tuta-imap/package.json | 15 + packages/tuta-imap/rust-toolchain | 1 + packages/tuta-imap/src/client/mod.rs | 511 ++++++++++++++ packages/tuta-imap/src/client/tls_stream.rs | 111 +++ packages/tuta-imap/src/client/types/mail.rs | 28 + packages/tuta-imap/src/client/types/mod.rs | 6 + packages/tuta-imap/src/lib.rs | 9 + .../tuta-imap/src/testing/jvm_singeleton.rs | 21 + packages/tuta-imap/src/testing/mod.rs | 161 +++++ packages/tuta-imap/src/testing/utils.rs | 5 + packages/tuta-imap/src/utils/mod.rs | 28 + src/calendar-app/calendarLocator.ts | 2 + src/common/api/main/CommonLocator.ts | 2 + .../api/worker/rest/DefaultEntityRestCache.ts | 7 + src/common/desktop/DesktopMain.ts | 8 +- .../DesktopImapImportSystemFacade.ts | 41 ++ src/common/desktop/sse/SseClient.ts | 2 +- src/common/login/PostLoginActions.ts | 24 +- .../generatedipc/DesktopGlobalDispatcher.ts | 7 + .../common/generatedipc/ImapCredentials.ts | 3 + .../generatedipc/ImapImportSystemFacade.ts | 23 + ...ImapImportSystemFacadeReceiveDispatcher.ts | 25 + .../ImapImportSystemFacadeSendDispatcher.ts | 19 + .../common/generatedipc/NativePushFacade.ts | 1 - .../NativePushFacadeReceiveDispatcher.ts | 1 - .../common/generatedipc/TutaCredentials.ts | 3 + .../native/main/NativeInterfaceFactory.ts | 4 + src/mail-app/mailLocator.ts | 3 + .../api/worker/crypto/InstanceMapperTest.ts | 1 + test/types/test.d.ts | 1 + tsconfig.json | 3 + tuta-sdk/rust/sdk/src/crypto/aes.rs | 4 + tuta-sdk/rust/sdk/src/crypto/argon2_id.rs | 1 + tuta-sdk/rust/sdk/src/crypto/crypto_facade.rs | 12 +- tuta-sdk/rust/sdk/src/crypto/hkdf.rs | 1 + tuta-sdk/rust/sdk/src/crypto/key.rs | 2 + .../rust/sdk/src/crypto/randomizer_facade.rs | 2 + tuta-sdk/rust/sdk/src/crypto/sha.rs | 1 + tuta-sdk/rust/sdk/src/crypto/tuta_crypt.rs | 1 + tuta-sdk/rust/sdk/src/custom_id.rs | 3 + tuta-sdk/rust/sdk/src/element_value.rs | 316 ++++----- tuta-sdk/rust/sdk/src/entities/base.rs | 3 - .../rust/sdk/src/entities/entity_facade.rs | 74 +- tuta-sdk/rust/sdk/src/entities/monitor.rs | 24 - tuta-sdk/rust/sdk/src/entities/storage.rs | 39 - tuta-sdk/rust/sdk/src/entities/sys.rs | 666 ------------------ tuta-sdk/rust/sdk/src/entities/tutanota.rs | 345 --------- tuta-sdk/rust/sdk/src/entities/usage.rs | 24 - tuta-sdk/rust/sdk/src/lib.rs | 2 + tuta-sdk/rust/sdk/src/login/credentials.rs | 14 +- .../rust/sdk/src/net/native_rest_client.rs | 2 +- tuta-sdk/rust/sdk/src/net/vec_body.rs | 62 +- tuta-sdk/rust/sdk/src/rest_error.rs | 2 +- tuta-sdk/rust/sdk/src/services/accounting.rs | 15 +- tuta-sdk/rust/sdk/src/services/base.rs | 8 +- tuta-sdk/rust/sdk/src/services/gossip.rs | 8 +- tuta-sdk/rust/sdk/src/services/monitor.rs | 15 +- .../rust/sdk/src/services/service_executor.rs | 51 +- tuta-sdk/rust/sdk/src/services/storage.rs | 41 +- tuta-sdk/rust/sdk/src/services/sys.rs | 465 ++++++++---- .../rust/sdk/src/services/test_services.rs | 141 ++-- tuta-sdk/rust/sdk/src/services/tutanota.rs | 151 ++-- tuta-sdk/rust/sdk/src/services/usage.rs | 48 +- tuta-sdk/rust/sdk/src/type_model_provider.rs | 26 +- tuta-sdk/rust/sdk/src/util/mod.rs | 3 +- tuta-sdk/rust/sdk/tests/test_rest_client.rs | 1 - 114 files changed, 3513 insertions(+), 1682 deletions(-) create mode 100644 ipc-schema/facades/ImapImportSystemFacade.json create mode 100644 ipc-schema/types/ImapCredentials.json create mode 100644 ipc-schema/types/TutaCredentials.json create mode 100644 packages/node-mimimi/.cargo/config.toml create mode 100644 packages/node-mimimi/.gitignore create mode 100644 packages/node-mimimi/.npmignore create mode 100644 packages/node-mimimi/Cargo.toml create mode 100644 packages/node-mimimi/README.md create mode 100644 packages/node-mimimi/build.rs create mode 100644 packages/node-mimimi/examples/http_request.rs create mode 100644 packages/node-mimimi/make.js create mode 100644 packages/node-mimimi/npm/darwin-universal/README.md create mode 100644 packages/node-mimimi/npm/darwin-universal/package.json create mode 100644 packages/node-mimimi/npm/linux-x64-gnu/README.md create mode 100644 packages/node-mimimi/npm/linux-x64-gnu/package.json create mode 100644 packages/node-mimimi/npm/win32-x64-msvc/README.md create mode 100644 packages/node-mimimi/npm/win32-x64-msvc/package.json create mode 100644 packages/node-mimimi/package.json create mode 100644 packages/node-mimimi/rustfmt.toml create mode 100644 packages/node-mimimi/src/imap.rs create mode 100644 packages/node-mimimi/src/imap/credentials.rs create mode 100644 packages/node-mimimi/src/imap/import_client.rs create mode 100644 packages/node-mimimi/src/importer.rs create mode 100644 packages/node-mimimi/src/lib.rs create mode 100644 packages/node-mimimi/src/logging.rs create mode 100644 packages/node-mimimi/src/logging/console.rs create mode 100644 packages/node-mimimi/src/logging/logger.rs create mode 100644 packages/node-mimimi/src/tuta.rs create mode 100644 packages/node-mimimi/src/tuta/credentials.rs create mode 100644 packages/node-mimimi/test/Suite.ts create mode 100644 packages/node-mimimi/test/tsconfig.json create mode 100644 packages/node-mimimi/tsconfig.json create mode 100644 packages/tuta-imap/.gitignore create mode 100644 packages/tuta-imap/Cargo.toml create mode 100644 packages/tuta-imap/build.rs create mode 100644 packages/tuta-imap/java/build.gradle.kts create mode 100644 packages/tuta-imap/java/settings.gradle.kts create mode 100644 packages/tuta-imap/java/src/main/java/greenmailserver/GreenMailServer.java create mode 100644 packages/tuta-imap/package.json create mode 100644 packages/tuta-imap/rust-toolchain create mode 100644 packages/tuta-imap/src/client/mod.rs create mode 100644 packages/tuta-imap/src/client/tls_stream.rs create mode 100644 packages/tuta-imap/src/client/types/mail.rs create mode 100644 packages/tuta-imap/src/client/types/mod.rs create mode 100644 packages/tuta-imap/src/lib.rs create mode 100644 packages/tuta-imap/src/testing/jvm_singeleton.rs create mode 100644 packages/tuta-imap/src/testing/mod.rs create mode 100644 packages/tuta-imap/src/testing/utils.rs create mode 100644 packages/tuta-imap/src/utils/mod.rs create mode 100644 src/common/desktop/imapimport/DesktopImapImportSystemFacade.ts create mode 100644 src/common/native/common/generatedipc/ImapCredentials.ts create mode 100644 src/common/native/common/generatedipc/ImapImportSystemFacade.ts create mode 100644 src/common/native/common/generatedipc/ImapImportSystemFacadeReceiveDispatcher.ts create mode 100644 src/common/native/common/generatedipc/ImapImportSystemFacadeSendDispatcher.ts create mode 100644 src/common/native/common/generatedipc/TutaCredentials.ts diff --git a/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/NativeCryptoFacadeReceiveDispatcher.kt b/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/NativeCryptoFacadeReceiveDispatcher.kt index 27933003084c..733a50f11251 100644 --- a/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/NativeCryptoFacadeReceiveDispatcher.kt +++ b/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/NativeCryptoFacadeReceiveDispatcher.kt @@ -2,17 +2,16 @@ @file:Suppress("NAME_SHADOWING") - package de.tutao.tutashared.ipc -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json +import kotlinx.serialization.* +import kotlinx.serialization.json.* class NativeCryptoFacadeReceiveDispatcher( private val json: Json, private val facade: NativeCryptoFacade, ) { - + suspend fun dispatch(method: String, arg: List): String { when (method) { "rsaEncrypt" -> { @@ -26,7 +25,6 @@ class NativeCryptoFacadeReceiveDispatcher( ) return json.encodeToString(result) } - "rsaDecrypt" -> { val privateKey: RsaPrivateKey = json.decodeFromString(arg[0]) val data: DataWrapper = json.decodeFromString(arg[1]) @@ -36,7 +34,6 @@ class NativeCryptoFacadeReceiveDispatcher( ) return json.encodeToString(result) } - "aesEncryptFile" -> { val key: DataWrapper = json.decodeFromString(arg[0]) val fileUri: String = json.decodeFromString(arg[1]) @@ -48,7 +45,6 @@ class NativeCryptoFacadeReceiveDispatcher( ) return json.encodeToString(result) } - "aesDecryptFile" -> { val key: DataWrapper = json.decodeFromString(arg[0]) val fileUri: String = json.decodeFromString(arg[1]) @@ -58,7 +54,6 @@ class NativeCryptoFacadeReceiveDispatcher( ) return json.encodeToString(result) } - "argon2idGeneratePassphraseKey" -> { val passphrase: String = json.decodeFromString(arg[0]) val salt: DataWrapper = json.decodeFromString(arg[1]) @@ -68,7 +63,6 @@ class NativeCryptoFacadeReceiveDispatcher( ) return json.encodeToString(result) } - "generateKyberKeypair" -> { val seed: DataWrapper = json.decodeFromString(arg[0]) val result: KyberKeyPair = this.facade.generateKyberKeypair( @@ -76,7 +70,6 @@ class NativeCryptoFacadeReceiveDispatcher( ) return json.encodeToString(result) } - "kyberEncapsulate" -> { val publicKey: KyberPublicKey = json.decodeFromString(arg[0]) val seed: DataWrapper = json.decodeFromString(arg[1]) @@ -86,7 +79,6 @@ class NativeCryptoFacadeReceiveDispatcher( ) return json.encodeToString(result) } - "kyberDecapsulate" -> { val privateKey: KyberPrivateKey = json.decodeFromString(arg[0]) val ciphertext: DataWrapper = json.decodeFromString(arg[1]) @@ -96,7 +88,6 @@ class NativeCryptoFacadeReceiveDispatcher( ) return json.encodeToString(result) } - else -> throw Error("unknown method for NativeCryptoFacade: $method") } } diff --git a/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/PersistedCredentials.kt b/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/PersistedCredentials.kt index d53164af8797..4fecd5244436 100644 --- a/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/PersistedCredentials.kt +++ b/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/PersistedCredentials.kt @@ -3,7 +3,8 @@ package de.tutao.tutashared.ipc -import kotlinx.serialization.Serializable +import kotlinx.serialization.* +import kotlinx.serialization.json.* /** diff --git a/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/UnencryptedCredentials.kt b/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/UnencryptedCredentials.kt index c031d4109b73..20170615e6aa 100644 --- a/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/UnencryptedCredentials.kt +++ b/app-android/tutashared/src/main/java/de/tutao/tutashared/generated_ipc/UnencryptedCredentials.kt @@ -3,7 +3,8 @@ package de.tutao.tutashared.ipc -import kotlinx.serialization.Serializable +import kotlinx.serialization.* +import kotlinx.serialization.json.* /** diff --git a/buildSrc/DesktopBuilder.js b/buildSrc/DesktopBuilder.js index 8e720566d072..08c94619ec50 100644 --- a/buildSrc/DesktopBuilder.js +++ b/buildSrc/DesktopBuilder.js @@ -121,7 +121,10 @@ async function rollupDesktop(dirname, outDir, version, platform, architecture, d input: [path.join(dirname, "src/common/desktop/DesktopMain.ts"), path.join(dirname, "src/common/desktop/sqlworker.ts")], // some transitive dep of a transitive dev-dep requires https://www.npmjs.com/package/url // which rollup for some reason won't distinguish from the node builtin. - external: ["url", "util", "path", "fs", "os", "http", "https", "crypto", "child_process", "electron"], + external: (id, parent, isResolved) => { + if (parent != null && parent.endsWith("node-mimimi/dist/binding.cjs")) return true + return ["url", "util", "path", "fs", "os", "http", "https", "crypto", "child_process", "electron"].includes(id) + }, preserveEntrySignatures: false, plugins: [ copyNativeModulePlugin({ @@ -131,6 +134,16 @@ async function rollupDesktop(dirname, outDir, version, platform, architecture, d architecture, nodeModule: "better-sqlite3", }), + { + // todo: this needs to work everywhere + name: "copy-mimimi-plugin", + async buildStart() { + const normalDst = path.join(path.normalize("./build/desktop/"), "node-mimimi.linux-x64-gnu.node") + const dstDir = path.dirname(normalDst) + await fs.promises.mkdir(dstDir, { recursive: true }) + await fs.promises.copyFile("./packages/node-mimimi/dist/node-mimimi.linux-x64-gnu.node", normalDst) + }, + }, typescript({ tsconfig: "tsconfig.json", outDir, diff --git a/buildSrc/DevBuild.js b/buildSrc/DevBuild.js index 298142e7f79e..203a9e6f691f 100644 --- a/buildSrc/DevBuild.js +++ b/buildSrc/DevBuild.js @@ -4,7 +4,7 @@ import { build as esbuild } from "esbuild" import { getTutanotaAppVersion, runStep, writeFile } from "./buildUtils.js" import "zx/globals" import * as env from "./env.js" -import { externalTranslationsPlugin, libDeps, preludeEnvPlugin, sqliteNativePlugin } from "./esbuildUtils.js" +import { externalTranslationsPlugin, libDeps, mimimiNativePlugin, preludeEnvPlugin, sqliteNativePlugin } from "./esbuildUtils.js" import { fileURLToPath } from "node:url" import * as LaunchHtml from "./LaunchHtml.js" import os from "node:os" @@ -173,9 +173,9 @@ async function buildDesktopPart({ version, app }) { format: "cjs", sourcemap: "linked", platform: "node", - external: ["electron"], + external: ["electron", "*.node"], banner: { - js: `globalThis.buildOptions = globalThis.buildOptions ?? {} + js: `globalThis.buildOptions = globalThis.buildOptions ?? {} globalThis.buildOptions.sqliteNativePath = "./better-sqlite3.node";`, }, plugins: [ @@ -187,6 +187,10 @@ globalThis.buildOptions.sqliteNativePath = "./better-sqlite3.node";`, architecture: process.arch, nativeBindingPath: "./better_sqlite3.node", }), + mimimiNativePlugin({ + dstPath: `./${buildDir}/desktop/`, + platform: process.platform, + }), preludeEnvPlugin(env.create({ staticUrl: null, version, mode: "Desktop", dist: false, domainConfigs })), externalTranslationsPlugin(), ], diff --git a/buildSrc/esbuildUtils.js b/buildSrc/esbuildUtils.js index 172d64f864e3..28c61b127c77 100644 --- a/buildSrc/esbuildUtils.js +++ b/buildSrc/esbuildUtils.js @@ -6,7 +6,7 @@ import { aliasPath as esbuildPluginAliasPath } from "esbuild-plugin-alias-path" /** * Little plugin that obtains compiled better-sqlite3, copies it to dstPath and sets the path to nativeBindingPath. - * We do not use default file loader from esbuild, it is much simpler and reliable to do it manually and it doesn't work for dynamic import (like in this case) + * We do not use default file loader from esbuild, it is much simpler and reliable to do it manually, and it doesn't work for dynamic import (like in this case) * anyway. * It will also replace `buildOptions.sqliteNativePath` with the nativeBindingPath */ @@ -37,6 +37,41 @@ export function sqliteNativePlugin({ environment, dstPath, nativeBindingPath, pl } } +export function mimimiNativePlugin({ dstPath, platform }) { + return { + name: "mimimi-native-plugin", + setup(build) { + const options = build.initialOptions + options.define = options.define ?? {} + + build.onStart(async () => { + let nativeBinaryName + switch (platform) { + case "linux": + nativeBinaryName = "node-mimimi.linux-x64-gnu.node" + break + case "win32": + nativeBinaryName = "node-mimimi.win32-x64-msvc.node" + break + case "darwin": + nativeBinaryName = "node-mimimi.darwin-universal.node" + break + default: + throw Error(`could not find node-mimimi binary: platform ${platform} is unknown`) + } + + // Replace mentions of buildOptions.mimimiNativePath with the actual path + options.define["buildOptions.mimimiNativePath"] = `"./${nativeBinaryName}"` + + const nativeBinarySourcePath = path.join(process.cwd(), "./packages/node-mimimi/dist", nativeBinaryName) + + await fs.promises.mkdir(path.dirname(dstPath), { recursive: true }) + await fs.promises.copyFile(nativeBinarySourcePath, path.join(process.cwd(), dstPath, nativeBinaryName)) + }) + }, + } +} + /** Little plugin that replaces imports for libs from dependencyMap with their prebuilt versions in libs directory. */ export function libDeps(prefix = ".") { const absoluteDependencyMap = Object.fromEntries( diff --git a/buildSrc/packageBuilderFunctions.js b/buildSrc/packageBuilderFunctions.js index a8bddf024f7b..917cb9382060 100644 --- a/buildSrc/packageBuilderFunctions.js +++ b/buildSrc/packageBuilderFunctions.js @@ -12,7 +12,7 @@ export async function buildRuntimePackages() { // tsconfig is rather JSON5, if it becomes a problem switch to JSON5 parser here const tsconfig = JSON.parse(await fs.readFile("tsconfig.json", { encoding: "utf-8" })) const packagePaths = tsconfig.references.map((ref) => ref.path) - await $`npx tsc -b ${packagePaths}` + await Promise.all(packagePaths.map((dir) => $`cd ${dir} && npm run build`)) } /** @@ -20,5 +20,5 @@ export async function buildRuntimePackages() { */ export async function buildPackages(pathPrefix = ".") { const packages = await glob(`${pathPrefix}/packages/*`, { deep: 1, onlyDirectories: true }) - await $`npx tsc -b ${packages}` + await Promise.all(packages.map((dir) => $`cd ${dir} && npm run build`)) } diff --git a/ipc-schema/facades/ImapImportSystemFacade.json b/ipc-schema/facades/ImapImportSystemFacade.json new file mode 100644 index 000000000000..e4245a075090 --- /dev/null +++ b/ipc-schema/facades/ImapImportSystemFacade.json @@ -0,0 +1,34 @@ +{ + "name": "ImapImportSystemFacade", + "type": "facade", + "senders": ["web"], + "receivers": ["desktop"], + "doc": "Facade implemented by the native desktop client starting and stopping an IMAP import.", + "methods": { + "setup": { + "doc": "Initializing the IMAP import.", + "arg": [ + { + "apiUrl": "string" + }, + { + "unencryptedTutaCredentials": "UnencryptedCredentials" + }, + { + "imapCredentials": "ImapCredentials" + } + ], + "ret": "void" + }, + "startImport": { + "doc": "Start the IMAP import.", + "arg": [], + "ret": "void" + }, + "stopImport": { + "doc": "Stop a running IMAP import.", + "arg": [], + "ret": "void" + } + } +} diff --git a/ipc-schema/types/ImapCredentials.json b/ipc-schema/types/ImapCredentials.json new file mode 100644 index 000000000000..05c3815c6284 --- /dev/null +++ b/ipc-schema/types/ImapCredentials.json @@ -0,0 +1,7 @@ +{ + "name": "ImapCredentials", + "type": "typeref", + "location": { + "typescript": "../packages/node-mimimi/dist/binding.js" + } +} diff --git a/ipc-schema/types/MailBundle.json b/ipc-schema/types/MailBundle.json index 1b0a4fd50b5b..5339e21ebec0 100644 --- a/ipc-schema/types/MailBundle.json +++ b/ipc-schema/types/MailBundle.json @@ -2,6 +2,6 @@ "name": "MailBundle", "type": "typeref", "location": { - "typescript": "../src/mail-app/mail/export/Bundler.js" + "typescript": "../src/common/mailFunctionality/SharedMailUtils.js" } } diff --git a/ipc-schema/types/TutaCredentials.json b/ipc-schema/types/TutaCredentials.json new file mode 100644 index 000000000000..aa1fbe99c74e --- /dev/null +++ b/ipc-schema/types/TutaCredentials.json @@ -0,0 +1,7 @@ +{ + "name": "TutaCredentials", + "type": "typeref", + "location": { + "typescript": "../packages/node-mimimi/dist/binding.js" + } +} diff --git a/package-lock.json b/package-lock.json index e46865dbb2a2..e206cbafc0c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,8 @@ "./packages/*" ], "dependencies": { + "@napi-rs/cli": "^2.18.4", + "@tutao/node-mimimi": "244.240923.0", "@tutao/oxmsg": "0.0.9-beta.0", "@tutao/tuta-wasm-loader": "247.241007.0", "@tutao/tutanota-crypto": "247.241007.0", @@ -1170,6 +1172,21 @@ "node": ">=10" } }, + "node_modules/@napi-rs/cli": { + "version": "2.18.4", + "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.18.4.tgz", + "integrity": "sha512-SgJeA4df9DE2iAEpr3M2H0OKl/yjtg1BnRI5/JyowS71tUWhrfSu2LT0V3vlHET+g1hBVlrO60PmEXwUEKp8Mg==", + "bin": { + "napi": "scripts/index.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2040,6 +2057,10 @@ "resolved": "packages/licc", "link": true }, + "node_modules/@tutao/node-mimimi": { + "resolved": "packages/node-mimimi", + "link": true + }, "node_modules/@tutao/otest": { "resolved": "packages/otest", "link": true @@ -9272,6 +9293,10 @@ "node": "*" } }, + "node_modules/tuta-imap": { + "resolved": "packages/tuta-imap", + "link": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -10028,6 +10053,26 @@ "node": ">= 16.0.0" } }, + "packages/node-mimimi": { + "name": "@tutao/node-mimimi", + "version": "244.240917.0", + "license": "MIT", + "devDependencies": { + "@napi-rs/cli": "^2.18.4", + "@tutao/otest": "244.240910.0", + "typescript": "5.3.3", + "zx": "8.1.5" + }, + "engines": { + "node": ">= 20" + } + }, + "packages/node-mimimi/node_modules/@tutao/otest": { + "version": "244.240910.0", + "resolved": "https://registry.npmjs.org/@tutao/otest/-/otest-244.240910.0.tgz", + "integrity": "sha512-QYasrO+XMEjO2LcTd/gC+XgiHXJT5wxL4hWhwLtmZWfCMu4pCJGrirHFgrV+cTLkx+9sPCO4eisISAP3Fj7xCA==", + "dev": true + }, "packages/otest": { "name": "@tutao/otest", "version": "247.241007.0", @@ -10036,6 +10081,9 @@ "typescript": "5.3.3" } }, + "packages/tuta-imap": { + "version": "1.0.0" + }, "packages/tuta-wasm-loader": { "name": "@tutao/tuta-wasm-loader", "version": "247.241007.0", diff --git a/package.json b/package.json index 2cdd14c58fb4..afbb093ce1a8 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,8 @@ "fix": "npm run style:fix && npm run lint:fix" }, "dependencies": { + "@napi-rs/cli": "^2.18.4", + "@tutao/node-mimimi": "244.240923.0", "@tutao/oxmsg": "0.0.9-beta.0", "@tutao/tuta-wasm-loader": "247.241007.0", "@tutao/tutanota-crypto": "247.241007.0", diff --git a/packages/node-mimimi/.cargo/config.toml b/packages/node-mimimi/.cargo/config.toml new file mode 100644 index 000000000000..0c17df095caa --- /dev/null +++ b/packages/node-mimimi/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.x86_64-pc-windows-msvc] +rustflags = ["-C", "target-feature=+crt-static"] \ No newline at end of file diff --git a/packages/node-mimimi/.gitignore b/packages/node-mimimi/.gitignore new file mode 100644 index 000000000000..a2b5be15ddfd --- /dev/null +++ b/packages/node-mimimi/.gitignore @@ -0,0 +1,197 @@ +# Created by https://www.toptal.com/developers/gitignore/api/node +# Edit at https://www.toptal.com/developers/gitignore?templates=node + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# End of https://www.toptal.com/developers/gitignore/api/node + +# Created by https://www.toptal.com/developers/gitignore/api/macos +# Edit at https://www.toptal.com/developers/gitignore?templates=macos + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +# End of https://www.toptal.com/developers/gitignore/api/macos + +# Created by https://www.toptal.com/developers/gitignore/api/windows +# Edit at https://www.toptal.com/developers/gitignore?templates=windows + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/windows + +#Added by cargo + +/target +Cargo.lock + +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +*.node diff --git a/packages/node-mimimi/.npmignore b/packages/node-mimimi/.npmignore new file mode 100644 index 000000000000..ec144db2a711 --- /dev/null +++ b/packages/node-mimimi/.npmignore @@ -0,0 +1,13 @@ +target +Cargo.lock +.cargo +.github +npm +.eslintrc +.prettierignore +rustfmt.toml +yarn.lock +*.node +.yarn +__test__ +renovate.json diff --git a/packages/node-mimimi/Cargo.toml b/packages/node-mimimi/Cargo.toml new file mode 100644 index 000000000000..866636d3ac7d --- /dev/null +++ b/packages/node-mimimi/Cargo.toml @@ -0,0 +1,37 @@ +[package] +edition = "2021" +name = "tutao_node-mimimi" +version = "244.240917.0" + +[lib] +# need to have lib to be able to use this from rust examples +crate-type = ["cdylib", "lib"] + +[features] +default = [] +# needed to turn off the autogenerated ffi when using the examples +rust = [] + +[dependencies] +# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix +napi = { version = "2.16.10", default-features = false, features = ["napi9", "async", "tokio_rt"] } +napi-derive = "2.16.12" +tuta-sdk = { path = "../../tuta-sdk/rust/sdk", features = ["net"] } +tuta-imap = { path = "../tuta-imap" } +async-trait = "0.1.83" + +[build-dependencies] +napi-build = "2.1.3" + +[dev-dependencies] +tokio = { version = "1", features = ["full"] } + + +[[example]] +name = "http_request" +path = "examples/http_request.rs" +required-features = ["rust"] + +[profile.release] +lto = true +strip = "symbols" diff --git a/packages/node-mimimi/README.md b/packages/node-mimimi/README.md new file mode 100644 index 000000000000..cc38f5a0e5ea --- /dev/null +++ b/packages/node-mimimi/README.md @@ -0,0 +1,34 @@ +# Node-Mimimi + +**M**ini **IM**AP **IM**porter **I**mplementation + +A native node module enabling the tuta mail desktop client to import mail from IMAP servers into your tuta account. +It's using [napi-rs](https://napi.rs/docs/introduction/getting-started) for project setup and to generate the bindings. + +## Building + +napi-rs by default generates a common js module that is supposed to be compatible with ESM named imports, but we had +problems getting it to import in all cases. One solution was found on +the [napi-rs github](https://github.com/napi-rs/napi-rs/issues/1429#issuecomment-1379743978). It works, but requires us +to build like this: + +`napi build --platform . --js binding.cjs --dts binding.d.ts` + +# Compilation + +See https://napi.rs/docs/cross-build/summary + +### Setup +1. `apt install clang llvm` + +#### Linux (from linux): +1. `rustup target add x86_64-unknown-linux-gnu` + +#### Windows (from linux): +1. `rustup target add x86_64-pc-windows-msvc` +2. `cargo install cargo-xwin` + +#### MacOS (**only** from MacOS): +1. `rustup target add x86_64-apple-darwin` +2. `rustup target add aarch64-apple-darwin` + diff --git a/packages/node-mimimi/build.rs b/packages/node-mimimi/build.rs new file mode 100644 index 000000000000..1f866b6a3c3a --- /dev/null +++ b/packages/node-mimimi/build.rs @@ -0,0 +1,5 @@ +extern crate napi_build; + +fn main() { + napi_build::setup(); +} diff --git a/packages/node-mimimi/examples/http_request.rs b/packages/node-mimimi/examples/http_request.rs new file mode 100644 index 000000000000..a97b1648b468 --- /dev/null +++ b/packages/node-mimimi/examples/http_request.rs @@ -0,0 +1,43 @@ +use tutasdk::net::native_rest_client::NativeRestClient; +use tutasdk::rest_client::{HttpMethod, RestClient, RestClientOptions}; +fn main() -> Result<(), &'static str> { + let mut runtime_builder = napi::tokio::runtime::Builder::new_current_thread(); + let runtime_builder = runtime_builder.enable_all(); + let Ok(runtime) = runtime_builder.build() else { + panic!("could not initialize tokio runtime"); + }; + + runtime.block_on(async_main()) +} + +async fn async_main() -> Result<(), &'static str> { + println!("starting a request"); + + let url = "https://echo.free.beeceptor.com"; + + let rest_client: NativeRestClient = + NativeRestClient::try_new().expect("failed to get rest client"); + let response_pending = rest_client + .request_binary( + url.to_string(), + HttpMethod::GET, + RestClientOptions { + headers: Default::default(), + body: Default::default(), + }, + ) + .await; + + let response = match response_pending { + Ok(res) => res, + Err(err) => panic!("failed to get response: {:?}", err), + }; + + println!("response status is {:?}", response.status); + println!( + "response body is {:?}", + response.body.map(|v| String::from_utf8(v)) + ); + + Ok(()) +} diff --git a/packages/node-mimimi/make.js b/packages/node-mimimi/make.js new file mode 100644 index 000000000000..256b37e03e16 --- /dev/null +++ b/packages/node-mimimi/make.js @@ -0,0 +1,41 @@ +import { Argument, program } from "commander" +import { $ } from "zx" + +await program + .usage("[options] [win|linux|darwin|native]") + .addArgument(new Argument("platform").choices(["win", "linux", "darwin", "native"]).default("native").argOptional()) + .option("-c, --clean", "clean build artifacts") + .option("-r, --release", "run a release build") + .option("-t, --test", "also build the test suite") + .action(run) + .parseAsync(process.argv) + +function getTarget(platform) { + switch (platform) { + case "win": + return "--target=x86_64-pc-windows-msvc" + case "linux": + return "--target=x86_64-unknown-linux-gnu" + case "darwin": + return "--target=x86_64-apple-darwin" + case "native": + return "" + default: + throw new Error(`unknown platform ${platform}`) + } +} + +async function run(platform, { clean, release, test }) { + if (clean) { + $`rm -r -f ./build` + $`rm -r -f ./target` + $`rm -r -f ./dist` + } + + const target = getTarget(platform) + const releaseFlag = release ? "--release" : "" + await $`napi build --platform dist --js binding.cjs --dts binding.d.ts ${target} ${releaseFlag}` + if (test) { + await $`tsc -b test` + } +} diff --git a/packages/node-mimimi/npm/darwin-universal/README.md b/packages/node-mimimi/npm/darwin-universal/README.md new file mode 100644 index 000000000000..71296da77cad --- /dev/null +++ b/packages/node-mimimi/npm/darwin-universal/README.md @@ -0,0 +1,3 @@ +# `@tutao/node-mimimi-darwin-universal` + +This is the **universal-apple-darwin** binary for `@tutao/node-mimimi` diff --git a/packages/node-mimimi/npm/darwin-universal/package.json b/packages/node-mimimi/npm/darwin-universal/package.json new file mode 100644 index 000000000000..d40371e8c5b5 --- /dev/null +++ b/packages/node-mimimi/npm/darwin-universal/package.json @@ -0,0 +1,15 @@ +{ + "name": "@tutao/node-mimimi-darwin-universal", + "version": "0.0.0", + "os": [ + "darwin" + ], + "main": "node-mimimi.darwin-universal.node", + "files": [ + "node-mimimi.darwin-universal.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} diff --git a/packages/node-mimimi/npm/linux-x64-gnu/README.md b/packages/node-mimimi/npm/linux-x64-gnu/README.md new file mode 100644 index 000000000000..a6364039dd45 --- /dev/null +++ b/packages/node-mimimi/npm/linux-x64-gnu/README.md @@ -0,0 +1,3 @@ +# `@tutao/node-mimimi-linux-x64-gnu` + +This is the **x86_64-unknown-linux-gnu** binary for `@tutao/node-mimimi` diff --git a/packages/node-mimimi/npm/linux-x64-gnu/package.json b/packages/node-mimimi/npm/linux-x64-gnu/package.json new file mode 100644 index 000000000000..d7245e81837c --- /dev/null +++ b/packages/node-mimimi/npm/linux-x64-gnu/package.json @@ -0,0 +1,21 @@ +{ + "name": "@tutao/node-mimimi-linux-x64-gnu", + "version": "0.0.0", + "os": [ + "linux" + ], + "cpu": [ + "x64" + ], + "main": "node-mimimi.linux-x64-gnu.node", + "files": [ + "node-mimimi.linux-x64-gnu.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "libc": [ + "glibc" + ] +} diff --git a/packages/node-mimimi/npm/win32-x64-msvc/README.md b/packages/node-mimimi/npm/win32-x64-msvc/README.md new file mode 100644 index 000000000000..0961fd962af8 --- /dev/null +++ b/packages/node-mimimi/npm/win32-x64-msvc/README.md @@ -0,0 +1,3 @@ +# `@tutao/node-mimimi-win32-x64-msvc` + +This is the **x86_64-pc-windows-msvc** binary for `@tutao/node-mimimi` diff --git a/packages/node-mimimi/npm/win32-x64-msvc/package.json b/packages/node-mimimi/npm/win32-x64-msvc/package.json new file mode 100644 index 000000000000..6f50d754ed3e --- /dev/null +++ b/packages/node-mimimi/npm/win32-x64-msvc/package.json @@ -0,0 +1,18 @@ +{ + "name": "@tutao/node-mimimi-win32-x64-msvc", + "version": "0.0.0", + "os": [ + "win32" + ], + "cpu": [ + "x64" + ], + "main": "node-mimimi.win32-x64-msvc.node", + "files": [ + "node-mimimi.win32-x64-msvc.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} diff --git a/packages/node-mimimi/package.json b/packages/node-mimimi/package.json new file mode 100644 index 000000000000..2df9d977326b --- /dev/null +++ b/packages/node-mimimi/package.json @@ -0,0 +1,35 @@ +{ + "name": "@tutao/node-mimimi", + "version": "244.240917.0", + "main": "./dist/binding.cjs", + "types": "./dist/binding.d.ts", + "napi": { + "name": "node-mimimi", + "triples": { + "defaults": false, + "additional": [ + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "universal-apple-darwin" + ] + } + }, + "license": "MIT", + "devDependencies": { + "@tutao/otest": "244.240910.0", + "@napi-rs/cli": "^2.18.4", + "typescript": "5.3.3", + "zx": "8.1.5" + }, + "engines": { + "node": ">= 20" + }, + "type": "module", + "scripts": { + "build": "node make", + "prepublishOnly": "napi prepublish -t npm", + "test": "node make -t && cd build/test && node Suite.js && cargo test", + "universal": "napi universal", + "version": "napi version" + } +} diff --git a/packages/node-mimimi/rustfmt.toml b/packages/node-mimimi/rustfmt.toml new file mode 100644 index 000000000000..c22683acdcd6 --- /dev/null +++ b/packages/node-mimimi/rustfmt.toml @@ -0,0 +1,16 @@ +edition = "2024" + +tab_spaces = 4 +hard_tabs = true +newline_style = "Unix" +max_width = 100 +match_block_trailing_comma = true +use_field_init_shorthand = true + +# TODO: Very nice-to-have, but currently nightly only +#normalize_comments = true +#normalize_doc_attributes = true +#group_imports = "StdExternalCrate" +#reorder_impl_items = true +#combine_control_expr = false +#condense_wildcard_suffixes = true diff --git a/packages/node-mimimi/src/imap.rs b/packages/node-mimimi/src/imap.rs new file mode 100644 index 000000000000..c191e1b0ae7a --- /dev/null +++ b/packages/node-mimimi/src/imap.rs @@ -0,0 +1,2 @@ +pub mod import_client; +pub mod credentials; \ No newline at end of file diff --git a/packages/node-mimimi/src/imap/credentials.rs b/packages/node-mimimi/src/imap/credentials.rs new file mode 100644 index 000000000000..6323c0b61967 --- /dev/null +++ b/packages/node-mimimi/src/imap/credentials.rs @@ -0,0 +1,12 @@ +#[napi(object)] +#[derive(Clone)] +/// passed in from js before being validated and used for logging into the imap server +pub struct ImapCredentials { + /// hostname of the imap server to import mail from + pub host: String, + /// imap port of the imap server to import mail from + pub port: String, + pub username: Option, + pub password: Option, + pub access_token: Option, +} \ No newline at end of file diff --git a/packages/node-mimimi/src/imap/import_client.rs b/packages/node-mimimi/src/imap/import_client.rs new file mode 100644 index 000000000000..e0c324342f40 --- /dev/null +++ b/packages/node-mimimi/src/imap/import_client.rs @@ -0,0 +1,290 @@ +use crate::imap::credentials::ImapCredentials; +use std::collections::HashMap; +use tuta_imap::client::types::mail::ImapMail; +use tuta_imap::client::types::reexports::{Mailbox, StatusKind}; +use tuta_imap::client::TutanotaImapClient; +use tutasdk::crypto::key::GenericAesKey; +use tutasdk::custom_id::CustomId; +use tutasdk::entities::tutanota::{DraftCreateData, DraftCreateReturn, DraftData}; +use tutasdk::services::service_executor::ServiceExecutor; +use tutasdk::services::tutanota::DraftService; +use tutasdk::services::ExtraServiceParams; + +#[napi(object)] +#[derive(Clone)] +pub struct ImapImportParams { + pub root_import_mail_folder_name: String, + pub credentials: ImapCredentials, +} + +/// current state of the imap import for this tuta account +/// requires an initialized SDK! +#[napi] +pub enum ImapImportStatus { + NotInitialized, + Paused, + Running, + Postponed, + Finished, +} + +#[napi(object)] +#[derive(Clone)] +pub struct ImapImportConfig { + pub params: ImapImportParams, +} + +#[napi] +pub struct ImapImport { + pub status: ImapImportStatus, + pub import_config: ImapImportConfig, + + imap_client: TutanotaImapClient, + service_executor: ServiceExecutor, + session_key: GenericAesKey, +} + +#[napi] +impl ImapImport { + #[napi(factory)] + pub fn initialize(imap_import_config: ImapImportConfig) -> Self { + Self::new(imap_import_config, todo!(), todo!()) + } + + #[napi] + pub async unsafe fn continue_import(&mut self) { + let imap_mail = self.get_mail_from_imap(); + let draft_return_data = self.upload_mail_to_tutanota(imap_mail).await; + + // 8. do something with DraftServiceReturnData + eprintln!("====================== yay! ==========================="); + eprintln!("Successfully uploaded imap mail as draft. Data: {draft_return_data:?}"); + eprintln!("========================================================"); + + // 9. everything is completed. update the status + self.status = ImapImportStatus::Finished + } + + #[napi] + pub async fn delete_import(&self) -> ImapImportStatus { + todo!() + } + + #[napi] + pub async fn pause_import(&self) -> ImapImportStatus { + todo!() + } +} + +impl ImapImport { + pub fn new( + import_config: ImapImportConfig, + service_executor: ServiceExecutor, + session_key: GenericAesKey, + ) -> Self { + let imap_client = TutanotaImapClient::start_new_session( + import_config.params.credentials.port.parse().unwrap(), + ); + Self { + status: ImapImportStatus::NotInitialized, + imap_client, + import_config, + service_executor, + session_key, + } + } + + fn get_mail_from_imap(&mut self) -> ImapMail { + // 1. get updated capabilities + self.imap_client + .refresh_capabilities() + .eq(&StatusKind::Ok) + .then_some(()) + .expect("Cannot refresh capabilities"); + + // 2. login + self.imap_client + .login( + self.import_config + .params + .credentials + .username + .as_ref() + .map(String::as_str) + .unwrap_or("test@greenmail.org"), + self.import_config + .params + .credentials + .password + .as_ref() + .map(String::as_str) + .unwrap_or("password"), + ) + .eq(&StatusKind::Ok) + .then_some(()) + .expect("Can not login"); + + // 3. select mailbox + self.imap_client + .select_mailbox(Mailbox::Inbox) + .eq(&StatusKind::Ok) + .then_some(()) + .expect("Cannot select INBOX mailbox"); + + // 4. search for uid and get the first result + self.imap_client + .search_all_uid() + .eq(&StatusKind::Ok) + .then_some(()) + .expect("Cannot search for uid in INBOX"); + let target_mail_id = self + .imap_client + .latest_search_results + .first() + .expect("Empty search result") + .clone(); + + // 5. fetch the mail by uid + self.imap_client + .fetch_mail_by_uid(target_mail_id.clone()) + .eq(&StatusKind::Ok) + .then_some(()) + .expect("Cannot fetch a mail id"); + let fetched_mail = self + .imap_client + .latest_mails + .remove(&target_mail_id) + .expect("No mail was fetched"); + + fetched_mail + } + + async fn upload_mail_to_tutanota(&mut self, fetched_mail: ImapMail) -> DraftCreateReturn { + // 6. convert the fetched mail to tutanota draft data + let create_draft_data = Self::make_tutanota_draft_input(fetched_mail); + + // 7. call DraftService + let service_params = ExtraServiceParams { + session_key: Some(self.session_key.clone()), + ..Default::default() + }; + let draft_return_data = self + .service_executor + .post::(create_draft_data, service_params) + .await + .expect("Cannot execute DraftService"); + + draft_return_data + } + + /// Convert the mail format from imap server to draft mail data + fn make_tutanota_draft_input(imap_mail: ImapMail) -> DraftCreateData { + let ImapMail { subject } = imap_mail; + + DraftCreateData { + _format: 0, + conversationType: 0, + ownerEncSessionKey: vec![], + ownerKeyVersion: 0, + previousMessageId: None, + draftData: DraftData { + subject, // only fill the subject for now + _id: Default::default(), //CustomId::from_custom_string("aaaaaaaaa"), + bodyText: "this is a mail from imap".to_string(), + compressedBodyText: None, + confidential: false, + method: 0, + senderMailAddress: "send@tutao.de".to_string(), + senderName: "ImapImporter".to_string(), + addedAttachments: vec![], + bccRecipients: vec![], + ccRecipients: vec![], + removedAttachments: vec![], + replyTos: vec![], + toRecipients: vec![], + _finalIvs: HashMap::new(), + }, + _errors: None, + _finalIvs: HashMap::new(), + } + } +} + +#[cfg(test)] +mod tests { + use crate::imap::credentials::ImapCredentials; + use std::sync::Arc; + use std::time::Duration; + use tuta_imap::testing::GreenMailTestServer; + use tutasdk::crypto::key::GenericAesKey; + use tutasdk::entities::entity_facade::{EntityFacade as _, EntityFacadeImpl as EntityFacade}; + use tutasdk::net::native_rest_client::NativeRestClient; + use tutasdk::services::service_executor::ServiceExecutor; + use tutasdk::{Sdk, CLIENT_VERSION}; + + async fn init(sdk: Sdk) -> (super::ImapImport, GreenMailTestServer) { + let logged_in_sdk = sdk + .create_session("map-free@tutanota.de", "map") + .await + .unwrap(); + let service_executor = ServiceExecutor::new( + logged_in_sdk + .get_entity_client() + .get_headers_provider() + .clone(), + logged_in_sdk + .get_crypto_entity_client() + .get_crypto_facade() + .clone(), + Arc::new(EntityFacade::new(sdk.get_type_model_provider().clone())), + sdk.get_instance_mapper().clone(), + sdk.get_json_serializer().clone(), + sdk.get_rest_client().clone(), + sdk.get_type_model_provider().clone(), + sdk.get_base_url().to_string(), + ); + + let greenmail = GreenMailTestServer::new(); + let imap_import_config = super::ImapImportConfig { + params: super::ImapImportParams { + root_import_mail_folder_name: "/".to_string(), + credentials: ImapCredentials { + host: "127.0.0.1".to_string(), + port: greenmail.imaps_port.to_string(), + username: Some("sug@example.org".to_string()), + password: Some("sug".to_string()), + access_token: None, + }, + }, + }; + let importer = super::ImapImport::new( + imap_import_config, + service_executor, + GenericAesKey::from_bytes(&[12; 32]).unwrap(), + ); + + (importer, greenmail) + } + + #[tokio::test] + async fn can_upload_to_draft_server() { + let sdk = Sdk::new( + "http://localhost:9000".to_string(), + Arc::new(NativeRestClient::try_new().unwrap()), + CLIENT_VERSION.to_string(), + ); + let (mut importer, greenmail) = init(sdk).await; + + // 1. construct ImapMail + greenmail.store_mail("sug@example.org", "Subject: Find me if you can"); + let imap_mail = importer.get_mail_from_imap(); + + // 2. start local tutadb server? + + // 3. call ImapImp::upload_mail_to_server + let uploaded_draft_id = importer.upload_mail_to_tutanota(imap_mail).await; + + // 4. verify the draft ( with return idTuple ) is present in tutanota + std::thread::sleep(Duration::from_secs(100000)); + } +} diff --git a/packages/node-mimimi/src/importer.rs b/packages/node-mimimi/src/importer.rs new file mode 100644 index 000000000000..346f3717f944 --- /dev/null +++ b/packages/node-mimimi/src/importer.rs @@ -0,0 +1,107 @@ +use crate::imap::credentials::ImapCredentials; +use crate::logging::Console; +use crate::tuta::credentials::TutaCredentials; +use napi::bindgen_prelude::*; +use napi::threadsafe_function::ErrorStrategy::T; +use napi::tokio::sync::Mutex; +use napi::tokio::sync::OnceCell; +use napi::JsObject; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use tuta_imap::client::TutanotaImapClient; +use tutasdk::login::Credentials; +use tutasdk::net::native_rest_client::NativeRestClient; +use tutasdk::rest_client::{ + HttpMethod, RestClient, RestClientError, RestClientOptions, RestResponse, +}; +use tutasdk::{LoggedInSdk, Sdk}; + +const TAG: &'static str = file!(); + +type Handle = Arc>; + +#[cfg(not(feature = "rust"))] +#[napi] +pub struct ImportCredentials { + console: &'static Console, + tuta_credentials: TutaCredentials, + imap_credentials: ImapCredentials, + + /// Represents a fallible async initialization process that + /// results in a logged in importer (tuta and imap) and that can be retried. + handle: Mutex>, +} + +#[cfg(not(feature = "rust"))] +#[napi] +impl ImportCredentials { + #[napi(factory)] + pub fn setup( + env: Env, + tuta_credentials: TutaCredentials, + imap_credentials: ImapCredentials, + ) -> Result { + let console = Console::get(env); + Ok(ImportCredentials { + console, + tuta_credentials, + imap_credentials, + handle: Mutex::new(None), + }) + } + + #[napi(ts_return_type = "Promise")] + /// Log into tuta + imap and return a handle to an object that can be used to control the import process. + pub fn login(&'static self, env: Env) -> Result { + env.execute_tokio_future( + async { self.prepare_inner().await }, + |env: &mut Env, inner: ImporterInner| Ok(Importer::new(inner)), + ) + } + + async fn prepare_inner(&self) -> Result { + let api_url: String = self.tuta_credentials.api_url.clone(); + let rest_client = NativeRestClient::try_new()?; + let client_version = self.tuta_credentials.client_version.clone(); + let sdk = Sdk::new(api_url, Arc::new(rest_client), client_version); + + let credentials: Credentials = self + .tuta_credentials + .clone() + .try_into() + .map_err(|_| napi::Error::from_reason("failed to convert credentials"))?; + let logged_in_sdk = sdk.login(credentials).await.map_err(|e| { + self.console.error(TAG, e.to_string().as_str()); + Error::from_reason("failed to log into tuta") + })?; + + let imap = Arc::new(TutanotaImapClient::start_new_session(42)); + + Ok(ImporterInner { + console: self.console, + sdk: logged_in_sdk, + imap, + }) + } +} + +struct ImporterInner { + console: &'static Console, + sdk: Arc, + imap: Arc, +} + +#[cfg(not(feature = "rust"))] +#[napi] +pub struct Importer { + inner: Handle, +} + +#[cfg(not(feature = "rust"))] +impl Importer { + fn new(inner: ImporterInner) -> Self { + Self { + inner: Arc::new(Mutex::new(inner)), + } + } +} diff --git a/packages/node-mimimi/src/lib.rs b/packages/node-mimimi/src/lib.rs new file mode 100644 index 000000000000..a6778e5372e3 --- /dev/null +++ b/packages/node-mimimi/src/lib.rs @@ -0,0 +1,16 @@ +#![deny(clippy::all)] +#[macro_use] +extern crate napi_derive; +extern crate tutasdk; + +#[cfg(not(feature = "rust"))] +pub mod importer; + +#[cfg(not(feature = "rust"))] +pub mod tuta; + +#[cfg(not(feature = "rust"))] +pub mod imap; + +#[cfg(not(feature = "rust"))] +pub mod logging; diff --git a/packages/node-mimimi/src/logging.rs b/packages/node-mimimi/src/logging.rs new file mode 100644 index 000000000000..f52ea6970eea --- /dev/null +++ b/packages/node-mimimi/src/logging.rs @@ -0,0 +1,13 @@ +use napi::bindgen_prelude::*; + +mod logger; +pub(crate) mod console; + +/// todo: plumb through SDK's log messages? it's currently using simple_logger when not compiled +/// todo: for ios or android. + +pub use crate::logging::console::Console; + + + + diff --git a/packages/node-mimimi/src/logging/console.rs b/packages/node-mimimi/src/logging/console.rs new file mode 100644 index 000000000000..c94861fe8af4 --- /dev/null +++ b/packages/node-mimimi/src/logging/console.rs @@ -0,0 +1,87 @@ +use crate::logging::logger::{LogLevel, LogMessage, Logger}; +use napi::Env; +use std::sync::OnceLock; + +const TAG: &'static str = file!(); + +pub static INSTANCE: OnceLock = OnceLock::new(); + +/// A way for the rust code to log messages to the main applications log files +/// without having to deal with obtaining a reference to console each time. +#[derive(Clone)] +pub struct Console { + tx: std::sync::mpsc::Sender, +} + +impl Console { + pub fn get(env: Env) -> &'static Self { + let (tx, rx) = std::sync::mpsc::channel::(); + let console = Console { tx }; + let logger = Logger::new(rx); + let Ok(()) = INSTANCE.set(console) else { + // some other thread already initialized the cell, we don't need to set up the logger. + return INSTANCE.get().expect("should already have been initialized!"); + }; + + // this may be the instance set by another thread, but that's okay. + let console = INSTANCE.get().expect("not initialized"); + let maybe_async_task = env.spawn(logger); + match maybe_async_task { + Ok(_) => console.log(TAG, "spawned logger"), + Err(e) => eprintln!("failed to spawn logger: {e}"), + }; + set_panic_hook(console); + console + } + + pub fn log(&self, tag: &str, message: &str) { + // todo: this returns Err if the logger closes the channel, what to do in that case? + let _ = self.tx.send(LogMessage { + level: LogLevel::Log, + tag: tag.into(), + message: message.into(), + }); + } + pub fn warn(&self, tag: &str, message: &str) { + let _ = self.tx.send(LogMessage { + level: LogLevel::Warn, + tag: tag.into(), + message: message.into(), + }); + } + + pub fn error(&self, tag: &str, message: &str) { + let _ = self.tx.send(LogMessage { + level: LogLevel::Error, + tag: tag.into(), + message: message.into(), + }); + } +} + +/// set a panic hook that tries to log the panic to the JS side before continuing +/// a normal unwind. should work unless the panicking thread is the main thread. +fn set_panic_hook(console: &'static Console) { + let logger_thread_id = std::thread::current().id(); + let panic_console = console.clone(); + let old_panic_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |panic_info| { + let formatted_info = panic_info.to_string(); + let formatted_stack = std::backtrace::Backtrace::force_capture().to_string(); + if logger_thread_id == std::thread::current().id() { + // logger is (probably) running on the currently panicking thread, + // so we can't use it to log to JS. this at least shows up in stderr. + eprintln!("PANIC MAIN {}", formatted_info); + eprintln!("PANIC MAIN {}", formatted_stack); + } else { + panic_console.error( + "PANIC", format!( + "thread {} {}", + std::thread::current().name().unwrap_or_else(|| ""), + formatted_info + ).as_str()); + panic_console.error("PANIC", formatted_stack.as_str()); + } + old_panic_hook(panic_info) + })); +} \ No newline at end of file diff --git a/packages/node-mimimi/src/logging/logger.rs b/packages/node-mimimi/src/logging/logger.rs new file mode 100644 index 000000000000..2e62e2f455da --- /dev/null +++ b/packages/node-mimimi/src/logging/logger.rs @@ -0,0 +1,108 @@ +use napi::bindgen_prelude::*; +use napi::{Env, JsObject, JsUndefined}; + +/// The part of the logging setup that receives log messages from the rust log +/// {@link struct Console} and forwards them to the node environment to log. +pub struct Logger { + /// This is an option because we need to Option::take it from the old instance before + /// rescheduling the listen job with a new one. + rx: Option>, +} + +impl Logger { + pub fn new(rx: std::sync::mpsc::Receiver) -> Self { + Self { rx: Some(rx) } + } + fn execute_log(&self, env: Env, log_message: LogMessage) { + let globals = env.get_global() + .expect("no globals in env"); + let console: JsObject = globals.get_named_property("console") + .expect("console property not found"); + + let formatted_message = format!("[{} {}] {}", log_message.marker(), log_message.tag, log_message.message); + let js_string: napi::JsString = env.create_string_from_std(formatted_message) + .expect("could not create string"); + + let js_error: JsFunction = console.get_named_property(log_message.method()) + .expect("logging fn not found"); + js_error.call(None, &[js_string]) + .expect("logging failed"); + } +} + +impl Task for Logger { + type Output = LogMessage; + type JsValue = JsUndefined; + + /// runs on the libuv thread pool. + fn compute(&mut self) -> Result { + if let Some(rx) = &self.rx { + Ok(rx.recv().unwrap_or_else(|_| LogMessage { + level: LogLevel::Finish, + tag: "Logger".to_string(), + message: "channel closed, logger finished".to_string(), + })) + } else { + // should not happen - each Logger instance listens for exactly one message and then + // gets dropped and reincarnated. + Ok(LogMessage { + level: LogLevel::Error, + tag: "Logger".to_string(), + message: "rx not available, already moved".to_string(), + }) + } + } + + /// runs on the main thread and receives the output produced by compute + fn resolve(&mut self, env: Env, output: Self::Output) -> Result { + let level = output.level; + self.execute_log(env, output); + if level != LogLevel::Finish { + // we only have a &mut self, so can't revive ourselves directly. + // I guess this is reincarnation. + let rx = self.rx.take(); + let _promise = env.spawn(Logger { rx }); + } + Ok(env.get_undefined()?) + } +} + + +/// determines the urgency and some formatting of the log message +#[derive(Eq, PartialEq, Copy, Clone)] +pub enum LogLevel { + /// used if we want to log the fact that all consoles have been dropped (there will not be any more log messages) + Finish, + Log, + Warn, + Error, +} + +/// a struct containing all information necessary to print the +pub struct LogMessage { + pub level: LogLevel, + pub message: String, + pub tag: String, +} + +impl LogMessage { + /// get a prefix for labeling the log level in cases where it's + /// not obvious from terminal colors or similar + pub fn marker(&self) -> &str { + match self.level { + LogLevel::Finish | LogLevel::Log => "I", + LogLevel::Warn => "W", + LogLevel::Error => "E", + } + } + + /// the name of the logging method to use for each log level. + /// very js-specific. + pub fn method(&self) -> &str { + match self.level { + LogLevel::Finish | LogLevel::Log => "log", + LogLevel::Warn => "warn", + LogLevel::Error => "error", + } + } +} \ No newline at end of file diff --git a/packages/node-mimimi/src/tuta.rs b/packages/node-mimimi/src/tuta.rs new file mode 100644 index 000000000000..48c828e752cc --- /dev/null +++ b/packages/node-mimimi/src/tuta.rs @@ -0,0 +1 @@ +pub mod credentials; \ No newline at end of file diff --git a/packages/node-mimimi/src/tuta/credentials.rs b/packages/node-mimimi/src/tuta/credentials.rs new file mode 100644 index 000000000000..9b5ca14d7b34 --- /dev/null +++ b/packages/node-mimimi/src/tuta/credentials.rs @@ -0,0 +1,48 @@ +use tutasdk::generated_id::GeneratedId; +use tutasdk::login::CredentialType; + + +#[napi(object)] +#[derive(Clone)] +/// Passed in from js-side, will be validated before being converted to proper tuta sdk credentials. +pub struct TutaCredentials { + pub api_url: String, + pub client_version: String, + pub login: String, + pub user_id: String, + pub access_token: String, + // FIXME Buffer type causes TutaCredentials to not being able to share between threads safely + pub encrypted_passphrase_key: Vec, + pub credential_type: TutaCredentialType, +} + +impl TryInto for TutaCredentials { + // todo: proper errors + type Error = (); + + fn try_into(self) -> Result { + // todo: validate! + Ok(tutasdk::login::Credentials { + login: self.login, + user_id: GeneratedId(self.user_id), + access_token: self.access_token, + encrypted_passphrase_key: self.encrypted_passphrase_key.clone().to_vec(), + credential_type: self.credential_type.into(), + }) + } +} + +#[napi(string_enum)] +pub enum TutaCredentialType { + Internal, + External, +} + +impl Into for TutaCredentialType { + fn into(self) -> CredentialType { + match self { + TutaCredentialType::Internal => { CredentialType::Internal } + TutaCredentialType::External => { CredentialType::External } + } + } +} \ No newline at end of file diff --git a/packages/node-mimimi/test/Suite.ts b/packages/node-mimimi/test/Suite.ts new file mode 100644 index 000000000000..14c54784a079 --- /dev/null +++ b/packages/node-mimimi/test/Suite.ts @@ -0,0 +1,3 @@ +import { getIdByteSizePlus } from "../dist/binding.cjs" + +console.log("testing :", getIdByteSizePlus(123)) diff --git a/packages/node-mimimi/test/tsconfig.json b/packages/node-mimimi/test/tsconfig.json new file mode 100644 index 000000000000..e3f614151189 --- /dev/null +++ b/packages/node-mimimi/test/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../tsconfig_common.json", + "include": ["../../../types/*.d.ts"], + "files": ["Suite.ts"], + "compilerOptions": { + "outDir": "../build", + "declaration": false, + "noImplicitAny": false + }, + "references": [ + { + "path": "../../tutanota-test-utils/tsconfig.json" + } + ] +} diff --git a/packages/node-mimimi/tsconfig.json b/packages/node-mimimi/tsconfig.json new file mode 100644 index 000000000000..18c2b4c7c645 --- /dev/null +++ b/packages/node-mimimi/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "composite": true + } +} diff --git a/packages/tuta-imap/.gitignore b/packages/tuta-imap/.gitignore new file mode 100644 index 000000000000..658e291372c2 --- /dev/null +++ b/packages/tuta-imap/.gitignore @@ -0,0 +1,6 @@ +/target +Cargo.lock + +/java/.idea +/java/build +.gradle diff --git a/packages/tuta-imap/Cargo.toml b/packages/tuta-imap/Cargo.toml new file mode 100644 index 000000000000..145be30dce26 --- /dev/null +++ b/packages/tuta-imap/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "tuta-imap" +version = "0.1.0" +edition = "2021" + +[dependencies.imap-codec] +git = "https://github.com/duesee/imap-codec.git" +rev = "16a5c182285c7a895b06276f68a116caf2cb294f" +features = ["serde", "starttls", "ext_id", "ext_metadata"] + +[dependencies] +serde = { version = "1.0.210", features = ["derive"] } +log = { version = "0.4.22" } +rand = { version = "0.8.1" } +rustls = { version = "0.23.13", features = ["std"] } + +# see todo in `mod testing` in lib.rs +# [dev-dependencies] +j4rs = { version = "0.20.0" } +lazy_static = { version = "0.2.11" } \ No newline at end of file diff --git a/packages/tuta-imap/build.rs b/packages/tuta-imap/build.rs new file mode 100644 index 000000000000..b456aa59c157 --- /dev/null +++ b/packages/tuta-imap/build.rs @@ -0,0 +1,29 @@ +use std::process::Command; + +const GREENMAIL_TEST_SERVER_JAR: &str = concat!( +env!("CARGO_MANIFEST_DIR"), +"/java/build/libs/greenmail-test-server.jar" +); +const BUILD_WATCHLIST: &[&str] = &["/java/src/", "/java/build/libs/greenmail-test-server.jar"]; + +pub fn main() { + println!("cargo::rustc-env=GREENMAIL_TEST_SERVER_JAR={GREENMAIL_TEST_SERVER_JAR}", ); + for watch in BUILD_WATCHLIST { + println!("cargo::rerun-if-changed={watch}"); + } + + run_gradle_jar(); +} + +fn run_gradle_jar() { + Command::new("/opt/gradle-8.5/bin/gradle") + .current_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/java")) + .args(["jar"]) + .spawn() + .expect("Cannot spawn gradle command") + .wait() + .expect("Cannot wait for gradle command") + .success() + .then_some(()) + .expect("gradle exited with non-success status code"); +} diff --git a/packages/tuta-imap/java/build.gradle.kts b/packages/tuta-imap/java/build.gradle.kts new file mode 100644 index 000000000000..31ca8eb6be03 --- /dev/null +++ b/packages/tuta-imap/java/build.gradle.kts @@ -0,0 +1,24 @@ +repositories { + mavenLocal() + maven { + credentials(PasswordCredentials::class) + url = uri("https://next.tutao.de/nexus/content/groups/public/") + } +} + +plugins { + java +} + +dependencies { + implementation("com.icegreen:greenmail-standalone:2.0.1") +} + +tasks.jar { + val dependencies = configurations + .runtimeClasspath + .get() + .map(::zipTree) // OR .map { zipTree(it) } + from(dependencies) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} \ No newline at end of file diff --git a/packages/tuta-imap/java/settings.gradle.kts b/packages/tuta-imap/java/settings.gradle.kts new file mode 100644 index 000000000000..a9467e9f9833 --- /dev/null +++ b/packages/tuta-imap/java/settings.gradle.kts @@ -0,0 +1,24 @@ +rootProject.name = "greenmail-test-server" + +pluginManagement { + repositories { + mavenLocal() + maven { + url = uri("https://next.tutao.de/nexus/content/groups/public/") + credentials(PasswordCredentials::class) + } + } +} + +buildscript { + repositories { + mavenLocal() + maven { + credentials(PasswordCredentials::class) + url = uri("https://next.tutao.de/nexus/content/groups/public/") + } + } + dependencies { + classpath(group = "de.tutao.gradle", name = "devDefaults", version = "3.6.2") + } +} \ No newline at end of file diff --git a/packages/tuta-imap/java/src/main/java/greenmailserver/GreenMailServer.java b/packages/tuta-imap/java/src/main/java/greenmailserver/GreenMailServer.java new file mode 100644 index 000000000000..25f7e93d62c5 --- /dev/null +++ b/packages/tuta-imap/java/src/main/java/greenmailserver/GreenMailServer.java @@ -0,0 +1,63 @@ +package greenmailserver; + +import com.icegreen.greenmail.user.GreenMailUser; +import com.icegreen.greenmail.user.UserException; +import com.icegreen.greenmail.util.GreenMail; +import com.icegreen.greenmail.util.ServerSetup; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; + +import java.io.ByteArrayInputStream; + + +public class GreenMailServer { + public static final String imapsHost = "127.0.0.1"; + + private GreenMail greenMail; + + public GreenMailUser userMap; + public GreenMailUser userSug; + + public GreenMailServer(Integer p) { + setSystemClassLoaderForCurrentThreadContext(); + + ServerSetup defaultImapsProps = new ServerSetup(p, imapsHost, "imaps"); + try { + greenMail = new GreenMail(defaultImapsProps); + } catch (Exception e) { + e.printStackTrace(); + } + + greenMail.start(); + + try { + userMap = greenMail.getUserManager().createUser("map@example.org", "map@example.org", "map"); + userSug = greenMail.getUserManager().createUser("sug@example.org", "sug@example.org", "sug"); + } catch (UserException e) { + throw new RuntimeException(e); + } + } + + public void stop() { + greenMail.stop(); + } + + public void store_mail(String recipientAddress, String mimeMsg) throws MessagingException { + var recipient = greenMail.getUserManager().getUserByEmail(recipientAddress); + var mimeMessage = new MimeMessage(null, new ByteArrayInputStream(mimeMsg.getBytes())); + recipient.deliver(mimeMessage); + } + + + // ========= configuration required for (rust) jni interface ================== + + // For the class loaded by jni, .getCurrentThread().getContextClassLoader() will be null + // set it to systemClassLoader + public static void setSystemClassLoaderForCurrentThreadContext() { + if (Thread.currentThread().getContextClassLoader() == null) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + Thread.currentThread().setContextClassLoader(cl); + } + } + +} diff --git a/packages/tuta-imap/package.json b/packages/tuta-imap/package.json new file mode 100644 index 000000000000..7d9882cb2d78 --- /dev/null +++ b/packages/tuta-imap/package.json @@ -0,0 +1,15 @@ +{ + "name": "tuta-imap", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo test done", + "build": "echo done" + }, + "repository": { + "type": "git", + "url": "https://github.com/tutao/tutanota.git" + }, + "private": true +} diff --git a/packages/tuta-imap/rust-toolchain b/packages/tuta-imap/rust-toolchain new file mode 100644 index 000000000000..870bbe4e50e6 --- /dev/null +++ b/packages/tuta-imap/rust-toolchain @@ -0,0 +1 @@ +stable \ No newline at end of file diff --git a/packages/tuta-imap/src/client/mod.rs b/packages/tuta-imap/src/client/mod.rs new file mode 100644 index 000000000000..f99252bb87f1 --- /dev/null +++ b/packages/tuta-imap/src/client/mod.rs @@ -0,0 +1,511 @@ +use crate::client::tls_stream::TlsStream; +use crate::client::types::mail::ImapMail; +use imap_codec::decode::{Decoder, ResponseDecodeError}; +use imap_codec::encode::Encoder; +use imap_codec::imap_types::core::Tag; +use imap_codec::imap_types::mailbox::Mailbox; +use imap_codec::imap_types::response::{ + CommandContinuationRequest, Data, Response, Status, StatusBody, StatusKind, +}; +use imap_codec::imap_types::secret::Secret; +use imap_codec::imap_types::{response, ToStatic}; +use imap_codec::{imap_types, CommandCodec, ResponseCodec}; +use imap_types::state::State as ConnectionState; +use std::collections::HashMap; +use std::num::NonZeroU32; + +// todo: +// what is the intention for this commit: +// https://github.com/duesee/imap-codec/commit/998fa15456fb0b2006c88ba5d523b5e2e115ae86 +pub mod tls_stream; +pub mod types; + +// todo: make a PR for this type alias? +pub type CapabilitiesList<'a> = imap_types::core::Vec1>; + +/// Always return a pre-formatted/sanitised error to client and not the execution details +pub type ApiError = String; +pub type ApiResult = Result; + +pub struct TutanotaImapClient { + pub capabilities: Option>, + pub latest_search_results: Vec, + pub latest_mails: HashMap, + pub unreceived_status: HashMap, StatusBody<'static>>, + + connection_state: ConnectionState<'static>, + + command_codec: CommandCodec, + response_codec: ResponseCodec, + tls_stream: TlsStream, +} + +/// Implement the exposed api +impl TutanotaImapClient { + /// Construct a new client + /// as well as: + /// - listen ( &discard ) the greetings & SSL messages + /// - refresh capabilities once + /// - perform login + pub fn start_new_session(imaps_port: i32) -> Self { + let tls_stream = TlsStream::new("127.0.0.1", imaps_port as u16); + + let mut client = Self { + tls_stream, + capabilities: None, + latest_mails: HashMap::new(), + latest_search_results: Vec::new(), + command_codec: CommandCodec::new(), + response_codec: ResponseCodec::new(), + unreceived_status: HashMap::new(), + connection_state: ConnectionState::NotAuthenticated, + }; + + // start the tls handshake process + client.start_tls().unwrap(); + + // discard any tls & greetings messages + client.read_until_next_untagged_status().unwrap(); + client.connection_state = ConnectionState::Greeting; + + // refresh the capabilities + client.refresh_capabilities(); + + // return the updated client + client + } + + /// try to refresh the capability from server by executing CAPABILITIES command + pub fn refresh_capabilities(&mut self) -> response::StatusKind { + let capability_command = imap_types::command::Command { + tag: self.create_tag(), + body: imap_types::command::CommandBody::Capability, + }; + let capability_response = self + .execute_command_directly(capability_command) + .unwrap() + .unwrap(); + + capability_response.kind + } + + pub fn login(&mut self, username: &str, password: &str) -> response::StatusKind { + let login_command = imap_types::command::Command { + tag: self.create_tag(), + body: imap_types::command::CommandBody::Login { + username: username.try_into().unwrap(), + password: Secret::new(password.try_into().unwrap()), + }, + }; + let login_response = self + .execute_command_directly(login_command) + .unwrap() + .unwrap(); + let status_kind = login_response.kind.clone(); + + if status_kind == response::StatusKind::Ok { + self.connection_state = ConnectionState::Authenticated; + } + + status_kind + } + + /// List all the mailbox available + pub fn list_mailbox(&mut self) {} + + /// Select a mailbox + /// + /// Caller should already invoke `list_mailbox` function before calling this + pub fn select_mailbox(&mut self, mailbox: Mailbox) -> StatusKind { + assert_eq!( + ConnectionState::Authenticated, + self.connection_state, + "must be in authenticated state to select mailbox" + ); + let select_command = imap_types::command::Command { + tag: self.create_tag(), + body: imap_types::command::CommandBody::Select { mailbox }, + }; + + let select_response = self + .execute_command_directly(select_command) + .unwrap() + .unwrap(); + let status_kind = select_response.kind; + if status_kind == response::StatusKind::Ok { + self.connection_state = ConnectionState::Selected(Mailbox::Inbox) + } + status_kind + } + + /// perform a UID search command + pub fn search_all_uid(&mut self) -> StatusKind { + assert_eq!( + ConnectionState::Selected(Mailbox::Inbox), + self.connection_state, + "must be in selected state to search mailbox UIDs" + ); + let search_all_command = imap_types::command::Command { + tag: self.create_tag(), + body: imap_types::command::CommandBody::Search { + charset: None, + uid: true, + criteria: [imap_types::search::SearchKey::All].into(), + }, + }; + + let search_all_command = self + .execute_command_directly(search_all_command) + .unwrap() + .unwrap(); + let status_kind = search_all_command.kind; + status_kind + } + + /// fetch mail with given uid + // todo: + /// & given uidValidity + pub fn fetch_mail_by_uid(&mut self, uid: NonZeroU32) -> StatusKind { + assert_eq!( + ConnectionState::Selected(Mailbox::Inbox), + self.connection_state, + "must be in selected state to fetch mailbox UID" + ); + let fetch_command = imap_types::command::Command { + tag: self.create_tag(), + body: imap_types::command::CommandBody::Fetch { + uid: true, + sequence_set: imap_types::sequence::Sequence::Single(uid.into()).into(), + macro_or_item_names: imap_types::fetch::Macro::All.into(), + }, + }; + + let search_all_command = self + .execute_command_directly(fetch_command) + .unwrap() + .unwrap(); + let status_kind = search_all_command.kind; + status_kind + } +} + +/// Implement direct helper function divisions + +impl TutanotaImapClient { + fn create_tag(&mut self) -> Tag<'static> { + Tag::try_from("tag").unwrap() + } + + fn start_tls(&mut self) -> Result<(), ()> { + Ok(()) + } + + fn read_until_next_untagged_status(&mut self) -> Result { + loop { + let mut response_bytes = self.tls_stream.read_until_crlf().unwrap(); + + let response = self + .parse_response(&mut response_bytes) + .unwrap() + .to_static(); + + match &response { + Response::Status(Status::Untagged(status_body)) + | Response::Status(Status::Tagged(response::Tagged { + tag: _, + body: status_body, + })) => return Ok(status_body.to_owned()), + + Response::Status(_) + | Response::Data(_) + | Response::CommandContinuationRequest(_) => todo!(), + } + } + } + + // Use any untagged data response to update the state + fn process_data_response(&mut self, data_response: Data) { + match data_response { + Data::Capability(list) => self.capabilities = Some(list.to_static()), + Data::Search(list) => self.latest_search_results = list.to_static(), + Data::Fetch { seq, items } => { + self.latest_mails.insert(seq, ImapMail::new(items)); + } + + anything_else => { + log::warn!("Do not know yet how to handle: {anything_else:?}") + } + } + } + + // command continuation request + fn process_cmd_continutation_response( + &self, + cmd_continutation_response: CommandContinuationRequest, + ) -> Result<(), ()> { + Ok(()) + } + + /// Process any response parsed. + fn process_response(&mut self, response: Response) { + match response { + Response::Data(untagged_data) => { + self.process_data_response(untagged_data); + } + Response::Status(status) => match status { + Status::Untagged(untagged_status) => { + log::warn!("Received untagged status: {:?}", untagged_status); + } + Status::Tagged(response::Tagged { tag, body }) => { + self.unreceived_status + .insert(tag.to_static(), body.to_static()); + } + Status::Bye(response_bye) => { + log::warn!("Received bye from server. byeeeee."); + self.connection_state = ConnectionState::Logout; + } + }, + Response::CommandContinuationRequest(cmd_continuation) => { + self.process_cmd_continutation_response(cmd_continuation) + .unwrap(); + } + } + } + + /// returns if response bytes is incomplete + fn parse_response(&mut self, response_bytes: &mut Vec) -> Option { + if response_bytes.is_empty() { + None?; + } + + let response = self.response_codec.decode(response_bytes.as_ref()); + match response { + Ok((_left_over, response)) => { + log::info!("Got response to be: `{:?}`", response); + Some(response.to_static()) + } + + // if this is incomplete, + // save this might have to re-read again once we get remaining of response + Err(ResponseDecodeError::Incomplete) => { + log::warn!( + "Got an incomplete response from server. Saving it: `{}`", + String::from_utf8(response_bytes.to_vec()).unwrap() + ); + None + } + Err(ResponseDecodeError::Failed) => { + log::error!( + "Found a response: {}. But failed to decode. Ignoring...", + String::from_utf8(response_bytes.to_vec()).unwrap() + ); + None + } + Err(ResponseDecodeError::LiteralFound { length }) => { + log::warn!( + "Literal found for response: {}", + String::from_utf8(response_bytes.to_vec()).unwrap() + ); + + // read everything remaining + let mut remaining_literal = Vec::with_capacity(length as usize); + self.tls_stream.read_exact(&mut remaining_literal).unwrap(); + response_bytes.append(&mut remaining_literal); + + // try again + self.parse_response(response_bytes) + } + } + } + + // execute a command in imap + // + // this api is allowed to cache or delay the execution given command: + // example: some other non-overridden-able command is in progress + // example: LOGIN command is in progress. it's better to wait for such command to finish + // so that we can execute following command in correct state context + // + // this api is allowed to block the execution for so reason. If the waiting is not desired, + // todo: + // call another async function which will received the command and put it to queue, + // once the command is executed and the response with tag of this command is received, + // the response ( only the tagged one ) will be passed to the receiving channel + + fn execute_command_directly( + &mut self, + command: imap_types::command::Command, + ) -> Result, ()> { + // only check for logout state, + // calling function should make sure to check for other state + // if that action expects client to be in certain state + assert_ne!( + ConnectionState::Logout, + self.connection_state, + "Cannot execute command after being logged out" + ); + log::info!("Start Executing command: {command:?}"); + + // write the command + let encoded_command = self.command_codec.encode(&command); + self.tls_stream + .write_imap_command(encoded_command.dump().as_slice()) + .unwrap(); + + log::info!("Command written..."); + + loop { + // we assume we get at least one line of response with every command + // otherwise we will wait here forever, + // unless we get any other response ( which is still not ok because we check for this tag later on) + let mut next_line = self.tls_stream.read_until_crlf().unwrap(); + if next_line.is_empty() { + return Ok(None); + } + + let maybe_cmd_status = self.parse_response(&mut next_line).map(|r| r.to_static()); + match maybe_cmd_status { + // if it's the tagged response + // with the same tag as of command + Some(Response::Status(Status::Tagged(response::Tagged { tag, body }))) + if &tag == &command.tag => + { + return Ok(Some(body.to_owned())) + } + + // if response is something else, + // process the command and loop back + Some(response) => self.process_response(response), + + // response was literalFound? Incomplete? + None => { + log::warn!("Cannot get the tagged response from server for.. What to do now?") + } + } + } + } +} + +/// Credentials mechanism to use for authenticating the client +/// +/// LOGIN command will be available in all imap server, +/// but this is the least secure way to authenticate. and simplest. +/// +/// According to server capabilities, we can choose to perform login via any +/// SASL* (RFC 4422) authentication mechanism. +/// +/// Example: +/// Gmail IMAP server support OAUTH2, +/// and provides a custom `Authenticate` Command to do so. +/// this will require CommandContinuationRequests and hence is less +/// simple than LOGIN but this mechanism will be more "secured" +/// +/// todo: +/// For now only care for PLAIN mechanism. +pub enum CredentialsMechanism { + Plain, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::client::{CapabilitiesList, TutanotaImapClient}; + use crate::testing::utils::toNonZeroU32; + use crate::testing::GreenMailTestServer; + use imap_codec::imap_types::response::{Capability, StatusKind}; + + #[test] + fn can_refresh_capabilities() { + let greenmail = GreenMailTestServer::new(); + let mut import_client = TutanotaImapClient::start_new_session(greenmail.imaps_port); + + // refreshing multiple times should still result in same + for _ in 0..3 { + assert_eq!(StatusKind::Ok, import_client.refresh_capabilities()); + assert_eq!( + Some(vec![ + Capability::Imap4Rev1, + Capability::LiteralPlus, + Capability::UidPlus, + Capability::Sort(None), + Capability::Idle, + Capability::Move, + Capability::Quota, + ]), + import_client + .capabilities + .clone() + .map(CapabilitiesList::into_inner) + ); + } + } + + #[test] + fn can_login() { + let greenmail = GreenMailTestServer::new(); + let mut import_client = TutanotaImapClient::start_new_session(greenmail.imaps_port); + + // refreshing multiple times should still result in same + assert_eq!( + StatusKind::Ok, + import_client.login("sug@example.org", "sug") + ); + assert_eq!( + import_client.connection_state, + ConnectionState::Authenticated + ); + } + + #[test] + fn select_inbox() { + let greenmail = GreenMailTestServer::new(); + let mut import_client = TutanotaImapClient::start_new_session(greenmail.imaps_port); + + import_client.login("sug@example.org", "sug"); + + // refreshing multiple times should still result in same + assert_eq!(StatusKind::Ok, import_client.select_mailbox(Mailbox::Inbox)); + assert_eq!( + import_client.connection_state, + ConnectionState::Selected(Mailbox::Inbox) + ); + } + + #[test] + fn search_all_mail() { + let greenmail = GreenMailTestServer::new(); + let mut import_client = TutanotaImapClient::start_new_session(greenmail.imaps_port); + + // should find these two `sug` mails + greenmail.store_mail("sug@example.org", ""); + greenmail.store_mail("sug@example.org", ""); + // should not find this `map` mail + greenmail.store_mail("map@example.org", ""); + + import_client.login("sug@example.org", "sug"); + import_client.select_mailbox(Mailbox::Inbox); + assert_eq!(StatusKind::Ok, import_client.search_all_uid()); + assert_eq!(toNonZeroU32(&[1, 2]), import_client.latest_search_results); + } + + #[test] + fn fetch_mail() { + let greenmail = GreenMailTestServer::new(); + let mut import_client = TutanotaImapClient::start_new_session(greenmail.imaps_port); + + greenmail.store_mail("map@example.org", "Subject: =?UTF-8?B?bWEgdXRmLTgg4oKs?="); + greenmail.store_mail("map@example.org", "Subject: Find me if you can"); + + import_client.login("map@example.org", "map"); + import_client.select_mailbox(Mailbox::Inbox); + import_client.search_all_uid(); + + let message_id = NonZeroU32::new(1).unwrap(); + assert_eq!(StatusKind::Ok, import_client.fetch_mail_by_uid(message_id)); + assert_eq!( + &ImapMail { + subject: "=?UTF-8?B?bWEgdXRmLTgg4oKs?=".to_string() + }, + import_client.latest_mails.get(&message_id).unwrap(), + ); + } +} diff --git a/packages/tuta-imap/src/client/tls_stream.rs b/packages/tuta-imap/src/client/tls_stream.rs new file mode 100644 index 000000000000..e980cf22138a --- /dev/null +++ b/packages/tuta-imap/src/client/tls_stream.rs @@ -0,0 +1,111 @@ +use crate::utils::BufReadExtension; +use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}; +use rustls::pki_types::{CertificateDer, ServerName, UnixTime}; +use rustls::{ClientConfig, ClientConnection, DigitallySignedStruct, Error, SignatureScheme}; +use std::io::{BufReader, Read, Write}; +use std::net::{SocketAddr, SocketAddrV4, TcpStream}; +use std::str::FromStr; +use std::sync::Arc; +use std::time::Duration; + +pub type SecuredStream = rustls::StreamOwned; + +pub struct TlsStream { + buffer_controller: BufReader, +} + +impl TlsStream { + pub fn new(address: &str, port: u16) -> Self { + let tcp_address = SocketAddr::V4(SocketAddrV4::new( + std::net::Ipv4Addr::from_str(address).unwrap(), + port, + )); + + let dangerous_config = ClientConfig::builder() + .dangerous() + .with_custom_certificate_verifier(Arc::new(MockSsl)) + .with_no_client_auth(); + + let tcp_stream = TcpStream::connect_timeout(&tcp_address, Duration::from_secs(10)).unwrap(); + let client_connection = rustls::ClientConnection::new( + Arc::new(dangerous_config), + "localhost".try_into().unwrap(), + ) + .unwrap(); + + let buffer_controller = BufReader::new(SecuredStream::new(client_connection, tcp_stream)); + + TlsStream { buffer_controller } + } + + pub fn write_imap_command(&mut self, encoded_command: &[u8]) -> std::io::Result { + let writer = self.buffer_controller.get_mut(); + let written = writer.write(encoded_command)?; + writer.flush()?; + Ok(written) + } + + pub fn read_until_crlf(&mut self) -> std::io::Result> { + let mut line_until_crlf = Vec::new(); + self.buffer_controller + .read_until_slice(b"\r\n", &mut line_until_crlf)?; + + Ok(line_until_crlf) + } + + pub fn read_exact(&mut self, target: &mut Vec) -> std::io::Result<()> { + self.buffer_controller.read_exact(target) + } +} + +#[derive(Debug)] +pub struct MockSsl; + +impl ServerCertVerifier for MockSsl { + fn verify_server_cert( + &self, + end_entity: &CertificateDer<'_>, + intermediates: &[CertificateDer<'_>], + server_name: &ServerName<'_>, + ocsp_response: &[u8], + now: UnixTime, + ) -> Result { + Ok(ServerCertVerified::assertion()) + } + + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result { + Ok(HandshakeSignatureValid::assertion()) + } + + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result { + Ok(HandshakeSignatureValid::assertion()) + } + + fn supported_verify_schemes(&self) -> Vec { + vec![ + SignatureScheme::RSA_PKCS1_SHA1, + SignatureScheme::ECDSA_SHA1_Legacy, + SignatureScheme::RSA_PKCS1_SHA256, + SignatureScheme::ECDSA_NISTP256_SHA256, + SignatureScheme::RSA_PKCS1_SHA384, + SignatureScheme::ECDSA_NISTP384_SHA384, + SignatureScheme::RSA_PKCS1_SHA512, + SignatureScheme::ECDSA_NISTP521_SHA512, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::ED25519, + SignatureScheme::ED448, + ] + } +} diff --git a/packages/tuta-imap/src/client/types/mail.rs b/packages/tuta-imap/src/client/types/mail.rs new file mode 100644 index 000000000000..23f8fd177074 --- /dev/null +++ b/packages/tuta-imap/src/client/types/mail.rs @@ -0,0 +1,28 @@ +use imap_codec::imap_types::core::Vec1; +use imap_codec::imap_types::fetch::MessageDataItem; + +#[derive(Eq, PartialEq, Debug)] +pub struct ImapMail { + pub subject: String, +} + +impl ImapMail { + pub fn new(items: Vec1) -> Self { + let mut imap_mail = ImapMail { + subject: String::new(), + }; + + for item in items { + match item { + MessageDataItem::Envelope(envelope) => { + imap_mail.subject = + String::from_utf8(envelope.subject.0.unwrap().into_inner().to_vec()) + .unwrap() + } + + _ => (), + } + } + imap_mail + } +} diff --git a/packages/tuta-imap/src/client/types/mod.rs b/packages/tuta-imap/src/client/types/mod.rs new file mode 100644 index 000000000000..996a5d04085f --- /dev/null +++ b/packages/tuta-imap/src/client/types/mod.rs @@ -0,0 +1,6 @@ +pub mod mail; + +pub mod reexports { + pub use imap_codec::imap_types::mailbox::Mailbox; + pub use imap_codec::imap_types::response::StatusKind; +} diff --git a/packages/tuta-imap/src/lib.rs b/packages/tuta-imap/src/lib.rs new file mode 100644 index 000000000000..2c8f944b89b2 --- /dev/null +++ b/packages/tuta-imap/src/lib.rs @@ -0,0 +1,9 @@ +// todo: +// somehow have to guard against another feature flag ( #[cfg(test)] ) will not be forwarded to +// dependency hence, currently cannot use this module with #[cfg(test)] in node-mimimi test +// #[cfg(test)] +pub mod testing; + +pub mod client; + +pub mod utils; diff --git a/packages/tuta-imap/src/testing/jvm_singeleton.rs b/packages/tuta-imap/src/testing/jvm_singeleton.rs new file mode 100644 index 000000000000..bed996435137 --- /dev/null +++ b/packages/tuta-imap/src/testing/jvm_singeleton.rs @@ -0,0 +1,21 @@ +use crate::testing::GREENMAIL_TEST_SERVER_JAR; +use j4rs::{ClasspathEntry, JvmBuilder}; + +static mut START_JVM_INVOCATION_COUNTER: i32 = 0; + +pub fn start_or_attach_to_jvm() -> i32 { + /// todo: SAFETY??? + unsafe { + if START_JVM_INVOCATION_COUNTER == 0 { + // create exactly one jvm and attach to it whenever we create a new IMAP test server + + JvmBuilder::new() + .classpath_entry(ClasspathEntry::new(GREENMAIL_TEST_SERVER_JAR)) + .with_default_classloader() + .build() + .expect("Cannot start jvm"); + } + START_JVM_INVOCATION_COUNTER += 1; + START_JVM_INVOCATION_COUNTER + } +} diff --git a/packages/tuta-imap/src/testing/mod.rs b/packages/tuta-imap/src/testing/mod.rs new file mode 100644 index 000000000000..51a0cf57b6c7 --- /dev/null +++ b/packages/tuta-imap/src/testing/mod.rs @@ -0,0 +1,161 @@ +use j4rs::{Instance, InvocationArg, Jvm}; +use std::collections::HashMap; + +pub mod jvm_singeleton; +pub mod utils; + +pub const GREENMAIL_TEST_SERVER_JAR: &str = env!("GREENMAIL_TEST_SERVER_JAR"); +pub const IMAPS_STARTING_PORT: i32 = 3993; + +pub struct GreenMailTestServer { + pub jvm: Jvm, + pub server: Instance, + + pub imaps_address: (String, u32), + + pub users: HashMap<&'static str, Instance>, + pub imaps_port: i32, +} + +impl GreenMailTestServer { + pub fn new() -> Self { + let this_jvm_id = jvm_singeleton::start_or_attach_to_jvm(); + let imaps_port = this_jvm_id + IMAPS_STARTING_PORT; + let jvm = Jvm::attach_thread().unwrap(); + + let imaps_host = jvm + .static_class_field("greenmailserver.GreenMailServer", "imapsHost") + .map(|v| jvm.to_rust(v)) + .unwrap() + .unwrap(); + let imaps_address = (imaps_host, imaps_port as u32); + + let server = jvm + .create_instance( + "greenmailserver.GreenMailServer", + &[InvocationArg::try_from(imaps_port).unwrap()], + ) + .unwrap(); + + let mut users = HashMap::new(); + users.insert("map", jvm.field(&server, "userMap").unwrap()); + users.insert("sug", jvm.field(&server, "userSug").unwrap()); + + Self { + users, + jvm, + server, + imaps_address, + imaps_port, + } + } + + pub fn stop(self) { + self.stop_greenmail_server(); + } + + fn stop_greenmail_server(&self) { + self.jvm + .invoke(&self.server, "stop", InvocationArg::empty()) + .unwrap(); + } + + pub fn store_mail(&self, receiver: &str, mime_message: &str) { + self.jvm + .invoke( + &self.server, + "store_mail", + &[ + &InvocationArg::try_from(receiver).unwrap(), + &mime_message.try_into().unwrap(), + ], + ) + .unwrap(); + } +} + +impl Drop for GreenMailTestServer { + fn drop(&mut self) { + self.stop_greenmail_server() + } +} + +#[cfg(test)] +pub mod greenmail_interaction { + use super::*; + use std::process::Command; + + #[test] + pub fn ensure_imap_server_running() { + let test_server = GreenMailTestServer::new(); + let (imaps_host, imaps_port) = &test_server.imaps_address; + + let output = Command::new("curl") + .args(&[ + format!("imaps://{imaps_host}:{imaps_port}").as_str(), + "--request", + "CAPABILITY", + "-k", + ]) + .output() + .unwrap(); + + assert!(output.status.success()); + assert_eq!( + b"* CAPABILITY IMAP4rev1 LITERAL+ UIDPLUS SORT IDLE MOVE QUOTA\r\n", + output.stdout.as_slice() + ); + } + + #[test] + pub fn ensure_can_store_mail() { + let test_server = GreenMailTestServer::new(); + let (imaps_host, imaps_port) = &test_server.imaps_address; + + test_server.store_mail( + "sug@example.org", + r#"From: Some One +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="XXXXboundary text" + +This is a multipart message in MIME format. + +--XXXXboundary text +Content-Type: text/plain + +this is the body text + +--XXXXboundary text +Content-Type: text/plain; +Content-Disposition: attachment; + filename="test.txt" + +this is the attachment text + +--XXXXboundary text--"#, + ); + + let output = Command::new("curl") + .args(&[ + format!("imaps://{imaps_host}:{imaps_port}/INBOX").as_str(), + "--request", + "LIST \"\" *", + "--user", + "sug@example.org:sug", + "--request", + "FETCH 1 BODY[HEADER]", + "-k", + ]) + .output() + .unwrap(); + + assert!(output.status.success()); + assert_eq!( + b"* 1 FETCH (FLAGS (\\Seen) BODY[HEADER] {127}\r\n", + output.stdout.as_slice(), + "{}", + String::from_utf8(output.stdout.to_vec()).unwrap() + ); + } +} diff --git a/packages/tuta-imap/src/testing/utils.rs b/packages/tuta-imap/src/testing/utils.rs new file mode 100644 index 000000000000..cde623ffe7b5 --- /dev/null +++ b/packages/tuta-imap/src/testing/utils.rs @@ -0,0 +1,5 @@ +use std::num::NonZeroU32; + +pub fn toNonZeroU32(slice: &[u32]) -> Vec { + slice.iter().map(|s| NonZeroU32::new(*s).unwrap()).collect() +} diff --git a/packages/tuta-imap/src/utils/mod.rs b/packages/tuta-imap/src/utils/mod.rs new file mode 100644 index 000000000000..65011c851b43 --- /dev/null +++ b/packages/tuta-imap/src/utils/mod.rs @@ -0,0 +1,28 @@ +use std::io::BufRead; + +pub trait BufReadExtension { + /// Same as `std::io::BufRead::read_until` + /// instead of accepting a single byte, accept a slice + fn read_until_slice(&mut self, delimiter: &[u8], buf: &mut Vec) -> std::io::Result; +} + +// implement for everything that have BufRead +impl BufReadExtension for T +where + T: BufRead, +{ + fn read_until_slice(&mut self, delimeter: &[u8], buf: &mut Vec) -> std::io::Result { + let mut read_count = 0; + + loop { + let mut one_byte = [0]; + self.read_exact(&mut one_byte)?; + buf.push(one_byte[0]); + + read_count += 1; + if buf.ends_with(delimeter) { + break Ok(read_count); + } + } + } +} diff --git a/src/calendar-app/calendarLocator.ts b/src/calendar-app/calendarLocator.ts index bfe92b34305c..cd132c490a2a 100644 --- a/src/calendar-app/calendarLocator.ts +++ b/src/calendar-app/calendarLocator.ts @@ -110,6 +110,7 @@ import { locator } from "../common/api/main/CommonLocator.js" import { showSnackBar } from "../common/gui/base/SnackBar.js" import { DbError } from "../common/api/common/error/DbError.js" import { WorkerRandomizer } from "../common/api/worker/workerInterfaces.js" +import { ImapImportSystemFacade } from "../common/native/common/generatedipc/ImapImportSystemFacade.js" assertMainOrNode() @@ -150,6 +151,7 @@ class CalendarLocator { searchTextFacade!: SearchTextInAppFacade desktopSettingsFacade!: SettingsFacade desktopSystemFacade!: DesktopSystemFacade + imapImportSystemFacade!: ImapImportSystemFacade webMobileFacade!: WebMobileFacade systemPermissionHandler!: SystemPermissionHandler interWindowEventSender!: InterWindowEventFacadeSendDispatcher diff --git a/src/common/api/main/CommonLocator.ts b/src/common/api/main/CommonLocator.ts index c1414f3ff299..4b4a905f585e 100644 --- a/src/common/api/main/CommonLocator.ts +++ b/src/common/api/main/CommonLocator.ts @@ -67,6 +67,7 @@ import { MobilePaymentsFacade } from "../../native/common/generatedipc/MobilePay import { AppStorePaymentPicker } from "../../misc/AppStorePaymentPicker.js" import { WorkerRandomizer } from "../worker/workerInterfaces.js" import { CommonSearchModel } from "../../search/CommonSearchModel.js" +import { ImapImportSystemFacade } from "../../native/common/generatedipc/ImapImportSystemFacade.js" export interface CommonLocator { worker: WorkerClient @@ -83,6 +84,7 @@ export interface CommonLocator { infoMessageHandler: InfoMessageHandler desktopSettingsFacade: SettingsFacade desktopSystemFacade: DesktopSystemFacade + imapImportSystemFacade: ImapImportSystemFacade themeController: ThemeController entityClient: EntityClient diff --git a/src/common/api/worker/rest/DefaultEntityRestCache.ts b/src/common/api/worker/rest/DefaultEntityRestCache.ts index d43dd5e28bb1..be838da17e3b 100644 --- a/src/common/api/worker/rest/DefaultEntityRestCache.ts +++ b/src/common/api/worker/rest/DefaultEntityRestCache.ts @@ -882,7 +882,14 @@ export class DefaultEntityRestCache implements EntityRestCache { if (oldFolder != null && oldFolder.isMailSet) return const updatedFolder = await this.entityRestClient.load(MailFolderTypeRef, [update.instanceListId, update.instanceId]) if (!updatedFolder.isMailSet) return + let mailsInOffline = await this.storage.getIdsInRange(MailTypeRef, updatedFolder.mails) await this.storage.deleteWholeList(MailTypeRef, updatedFolder.mails) + + await this.storage.lockRangesDbAccess(updatedFolder.mails) + console.log("Loading mails: ", mailsInOffline) + await this.entityRestClient.loadMultiple(MailTypeRef, updatedFolder.mails, mailsInOffline) + await this.storage.unlockRangesDbAccess(updatedFolder.mails) + await this.storage.put(updatedFolder) } } diff --git a/src/common/desktop/DesktopMain.ts b/src/common/desktop/DesktopMain.ts index 916007217ebb..343fb0dcbcce 100644 --- a/src/common/desktop/DesktopMain.ts +++ b/src/common/desktop/DesktopMain.ts @@ -71,6 +71,10 @@ import { DelayedImpls, exposeLocalDelayed } from "../api/common/WorkerProxy.js" import { DefaultDateProvider } from "../calendar/date/CalendarUtils.js" import { AlarmScheduler } from "../calendar/date/AlarmScheduler.js" import { DesktopExternalCalendarFacade } from "./ipc/DesktopExternalCalendarFacade.js" +import { DesktopImapImportSystemFacade } from "./imapimport/DesktopImapImportSystemFacade.js" +import { DomainConfigProvider } from "../api/common/DomainConfigProvider.js" + +mp() /** * Should be injected during build time. @@ -86,7 +90,6 @@ setupAssetProtocol(electron) const TAG = "[DesktopMain]" -mp() type Components = { readonly wm: WindowManager readonly tfs: TempFs @@ -270,6 +273,7 @@ async function createComponents(): Promise { new DesktopExportFacade(tfs, conf, window, dragIcons), new DesktopExternalCalendarFacade(), new DesktopFileFacade(window, conf, dateProvider, desktopNet, electron, tfs, fs), + new DesktopImapImportSystemFacade(window), new DesktopInterWindowEventFacade(window, wm), nativeCredentialsFacade, desktopCrypto, @@ -317,7 +321,7 @@ async function startupInstance(components: Components) { const { wm, sse, tfs } = components if (!(await desktopUtils.cleanupOldInstance())) return sse.connect().catch((e) => log.warn("unable to start sse client", e)) - // The second-instance event fires when we call app.requestSingleInstanceLock inside of DesktopUtils.makeSingleInstance + // The second-instance event fires when we call app.requestSingleInstanceLock inside DesktopUtils.makeSingleInstance app.on("second-instance", async (_ev, args) => desktopUtils.handleSecondInstance(wm, args)) app.on("open-url", (e, url) => { // MacOS mailto handling diff --git a/src/common/desktop/imapimport/DesktopImapImportSystemFacade.ts b/src/common/desktop/imapimport/DesktopImapImportSystemFacade.ts new file mode 100644 index 000000000000..c212d9638be4 --- /dev/null +++ b/src/common/desktop/imapimport/DesktopImapImportSystemFacade.ts @@ -0,0 +1,41 @@ +import { ImapImportSystemFacade } from "../../native/common/generatedipc/ImapImportSystemFacade.js" +import { ImapCredentials, ImportCredentials, TutaCredentials, TutaCredentialType } from "@tutao/node-mimimi" +import { UnencryptedCredentials } from "../../native/common/generatedipc/UnencryptedCredentials.js" +import { CredentialType } from "../../misc/credentials/CredentialType.js" +import { getApiBaseUrl } from "../../api/common/Env.js" +import { ApplicationWindow } from "../ApplicationWindow.js" +import { locator } from "../../api/main/CommonLocator.js" + +export class DesktopImapImportSystemFacade implements ImapImportSystemFacade { + constructor(private readonly win: ApplicationWindow) {} + + async setup(apiUrl: string, unencryptedTutaCredentials: UnencryptedCredentials, imapCredentials: ImapCredentials): Promise { + try { + const tutaCredentials: TutaCredentials = { + accessToken: unencryptedTutaCredentials?.accessToken, + credentialType: + unencryptedTutaCredentials.credentialInfo.type == CredentialType.Internal ? TutaCredentialType.Internal : TutaCredentialType.External, + encryptedPassphraseKey: unencryptedTutaCredentials.encryptedPassphraseKey ? Array.from(unencryptedTutaCredentials.encryptedPassphraseKey) : [], + login: unencryptedTutaCredentials.credentialInfo.login, + userId: unencryptedTutaCredentials.credentialInfo.userId, + apiUrl: apiUrl, + clientVersion: env.versionNumber, + } + + const importCredentials = ImportCredentials.setup(tutaCredentials, imapCredentials) + const importerObj = await importCredentials.login() + + console.log(importerObj) + } catch (e) { + console.log(e) + } + } + + startImport(): Promise { + throw new Error("Method not implemented.") + } + + stopImport(): Promise { + throw new Error("Method not implemented.") + } +} diff --git a/src/common/desktop/sse/SseClient.ts b/src/common/desktop/sse/SseClient.ts index 93d84c511347..01f8de4089a7 100644 --- a/src/common/desktop/sse/SseClient.ts +++ b/src/common/desktop/sse/SseClient.ts @@ -79,7 +79,7 @@ export class SseClient { constructor(private readonly net: DesktopNetworkClient, private readonly delay: SseDelay, private readonly scheduler: Scheduler) {} async connect(options: SseConnectOptions) { - log.debug("connect") + log.debug("connect", options) switch (this.state.state) { case ConnectionState.delayedReconnect: this.scheduler.unscheduleTimeout(this.state.timeout) diff --git a/src/common/login/PostLoginActions.ts b/src/common/login/PostLoginActions.ts index 0803532b206d..ae46d02258bb 100644 --- a/src/common/login/PostLoginActions.ts +++ b/src/common/login/PostLoginActions.ts @@ -1,7 +1,7 @@ import m, { Component } from "mithril" import type { LoggedInEvent, PostLoginAction } from "../api/main/LoginController" import { LoginController } from "../api/main/LoginController" -import { isAdminClient, isApp, isDesktop, LOGIN_TITLE } from "../api/common/Env" +import { getApiBaseUrl, isAdminClient, isApp, isDesktop, LOGIN_TITLE } from "../api/common/Env" import { assertNotNull, defer, delay, neverNull, noOp, ofClass } from "@tutao/tutanota-utils" import { windowFacade } from "../misc/WindowFacade.js" import { checkApprovalStatus } from "../misc/LoginUtils.js" @@ -35,6 +35,7 @@ import { CustomerFacade } from "../api/worker/facades/lazy/CustomerFacade.js" import { deviceConfig } from "../misc/DeviceConfig.js" import { ThemeController } from "../gui/ThemeController.js" import { EntityUpdateData, isUpdateForTypeRef } from "../api/common/utils/EntityUpdateUtils.js" +import { ImapCredentials } from "../native/common/generatedipc/ImapCredentials" /** * This is a collection of all things that need to be initialized/global state to be set after a user has logged in successfully. @@ -195,6 +196,27 @@ export class PostLoginActions implements PostLoginAction { // Needs to be called after UsageTestModel.init() if the UsageOptInNews is live! (its isShown() requires an initialized UsageTestModel) await locator.newsModel.loadNewsIds() + // FIXME + // initialize imap import + if (isDesktop()) { + const userId = locator.logins.getUserController().userId + const unencryptedCredentials = await locator.credentialsProvider.getDecryptedCredentialsByUserId(userId) + + if (unencryptedCredentials) { + const imapCredentials: ImapCredentials = { + password: "imap-password", + username: "imap-user", + host: "mail.gmail.com", + port: "123", + } + + const apiUrl = getApiBaseUrl(locator.domainConfigProvider().getCurrentDomainConfig()) + await locator.imapImportSystemFacade.setup(apiUrl, unencryptedCredentials, imapCredentials) + } else { + console.error(`could not load credentials for user with userId ${userId}`) + } + } + // Redraw to render usage tests and news, among other things that may have changed. m.redraw() } diff --git a/src/common/native/common/generatedipc/DesktopGlobalDispatcher.ts b/src/common/native/common/generatedipc/DesktopGlobalDispatcher.ts index c6473c215ea0..f532745c5517 100644 --- a/src/common/native/common/generatedipc/DesktopGlobalDispatcher.ts +++ b/src/common/native/common/generatedipc/DesktopGlobalDispatcher.ts @@ -10,6 +10,8 @@ import { ExternalCalendarFacade } from "./ExternalCalendarFacade.js" import { ExternalCalendarFacadeReceiveDispatcher } from "./ExternalCalendarFacadeReceiveDispatcher.js" import { FileFacade } from "./FileFacade.js" import { FileFacadeReceiveDispatcher } from "./FileFacadeReceiveDispatcher.js" +import { ImapImportSystemFacade } from "./ImapImportSystemFacade.js" +import { ImapImportSystemFacadeReceiveDispatcher } from "./ImapImportSystemFacadeReceiveDispatcher.js" import { InterWindowEventFacade } from "./InterWindowEventFacade.js" import { InterWindowEventFacadeReceiveDispatcher } from "./InterWindowEventFacadeReceiveDispatcher.js" import { NativeCredentialsFacade } from "./NativeCredentialsFacade.js" @@ -35,6 +37,7 @@ export class DesktopGlobalDispatcher { private readonly exportFacade: ExportFacadeReceiveDispatcher private readonly externalCalendarFacade: ExternalCalendarFacadeReceiveDispatcher private readonly fileFacade: FileFacadeReceiveDispatcher + private readonly imapImportSystemFacade: ImapImportSystemFacadeReceiveDispatcher private readonly interWindowEventFacade: InterWindowEventFacadeReceiveDispatcher private readonly nativeCredentialsFacade: NativeCredentialsFacadeReceiveDispatcher private readonly nativeCryptoFacade: NativeCryptoFacadeReceiveDispatcher @@ -50,6 +53,7 @@ export class DesktopGlobalDispatcher { exportFacade: ExportFacade, externalCalendarFacade: ExternalCalendarFacade, fileFacade: FileFacade, + imapImportSystemFacade: ImapImportSystemFacade, interWindowEventFacade: InterWindowEventFacade, nativeCredentialsFacade: NativeCredentialsFacade, nativeCryptoFacade: NativeCryptoFacade, @@ -65,6 +69,7 @@ export class DesktopGlobalDispatcher { this.exportFacade = new ExportFacadeReceiveDispatcher(exportFacade) this.externalCalendarFacade = new ExternalCalendarFacadeReceiveDispatcher(externalCalendarFacade) this.fileFacade = new FileFacadeReceiveDispatcher(fileFacade) + this.imapImportSystemFacade = new ImapImportSystemFacadeReceiveDispatcher(imapImportSystemFacade) this.interWindowEventFacade = new InterWindowEventFacadeReceiveDispatcher(interWindowEventFacade) this.nativeCredentialsFacade = new NativeCredentialsFacadeReceiveDispatcher(nativeCredentialsFacade) this.nativeCryptoFacade = new NativeCryptoFacadeReceiveDispatcher(nativeCryptoFacade) @@ -88,6 +93,8 @@ export class DesktopGlobalDispatcher { return this.externalCalendarFacade.dispatch(methodName, args) case "FileFacade": return this.fileFacade.dispatch(methodName, args) + case "ImapImportSystemFacade": + return this.imapImportSystemFacade.dispatch(methodName, args) case "InterWindowEventFacade": return this.interWindowEventFacade.dispatch(methodName, args) case "NativeCredentialsFacade": diff --git a/src/common/native/common/generatedipc/ImapCredentials.ts b/src/common/native/common/generatedipc/ImapCredentials.ts new file mode 100644 index 000000000000..373b86d9e1c2 --- /dev/null +++ b/src/common/native/common/generatedipc/ImapCredentials.ts @@ -0,0 +1,3 @@ +/* generated file, don't edit. */ + +export { ImapCredentials } from "../../../../../packages/node-mimimi/dist/binding.js" diff --git a/src/common/native/common/generatedipc/ImapImportSystemFacade.ts b/src/common/native/common/generatedipc/ImapImportSystemFacade.ts new file mode 100644 index 000000000000..f92ddb6bc033 --- /dev/null +++ b/src/common/native/common/generatedipc/ImapImportSystemFacade.ts @@ -0,0 +1,23 @@ +/* generated file, don't edit. */ + +import { UnencryptedCredentials } from "./UnencryptedCredentials.js" +import { ImapCredentials } from "./ImapCredentials.js" +/** + * Facade implemented by the native desktop client starting and stopping an IMAP import. + */ +export interface ImapImportSystemFacade { + /** + * Initializing the IMAP import. + */ + setup(apiUrl: string, unencryptedTutaCredentials: UnencryptedCredentials, imapCredentials: ImapCredentials): Promise + + /** + * Start the IMAP import. + */ + startImport(): Promise + + /** + * Stop a running IMAP import. + */ + stopImport(): Promise +} diff --git a/src/common/native/common/generatedipc/ImapImportSystemFacadeReceiveDispatcher.ts b/src/common/native/common/generatedipc/ImapImportSystemFacadeReceiveDispatcher.ts new file mode 100644 index 000000000000..1307bd8788d1 --- /dev/null +++ b/src/common/native/common/generatedipc/ImapImportSystemFacadeReceiveDispatcher.ts @@ -0,0 +1,25 @@ +/* generated file, don't edit. */ + +import { UnencryptedCredentials } from "./UnencryptedCredentials.js" +import { ImapCredentials } from "./ImapCredentials.js" +import { ImapImportSystemFacade } from "./ImapImportSystemFacade.js" + +export class ImapImportSystemFacadeReceiveDispatcher { + constructor(private readonly facade: ImapImportSystemFacade) {} + async dispatch(method: string, arg: Array): Promise { + switch (method) { + case "setup": { + const apiUrl: string = arg[0] + const unencryptedTutaCredentials: UnencryptedCredentials = arg[1] + const imapCredentials: ImapCredentials = arg[2] + return this.facade.setup(apiUrl, unencryptedTutaCredentials, imapCredentials) + } + case "startImport": { + return this.facade.startImport() + } + case "stopImport": { + return this.facade.stopImport() + } + } + } +} diff --git a/src/common/native/common/generatedipc/ImapImportSystemFacadeSendDispatcher.ts b/src/common/native/common/generatedipc/ImapImportSystemFacadeSendDispatcher.ts new file mode 100644 index 000000000000..867b7a5fb019 --- /dev/null +++ b/src/common/native/common/generatedipc/ImapImportSystemFacadeSendDispatcher.ts @@ -0,0 +1,19 @@ +/* generated file, don't edit. */ + +import { ImapImportSystemFacade } from "./ImapImportSystemFacade.js" + +interface NativeInterface { + invokeNative(requestType: string, args: unknown[]): Promise +} +export class ImapImportSystemFacadeSendDispatcher implements ImapImportSystemFacade { + constructor(private readonly transport: NativeInterface) {} + async setup(...args: Parameters) { + return this.transport.invokeNative("ipc", ["ImapImportSystemFacade", "setup", ...args]) + } + async startImport(...args: Parameters) { + return this.transport.invokeNative("ipc", ["ImapImportSystemFacade", "startImport", ...args]) + } + async stopImport(...args: Parameters) { + return this.transport.invokeNative("ipc", ["ImapImportSystemFacade", "stopImport", ...args]) + } +} diff --git a/src/common/native/common/generatedipc/NativePushFacade.ts b/src/common/native/common/generatedipc/NativePushFacade.ts index dfc13eba0b66..ac0e761bb9ab 100644 --- a/src/common/native/common/generatedipc/NativePushFacade.ts +++ b/src/common/native/common/generatedipc/NativePushFacade.ts @@ -2,7 +2,6 @@ import { EncryptedAlarmNotification } from "./EncryptedAlarmNotification.js" import { ExtendedNotificationMode } from "./ExtendedNotificationMode.js" - /** * Push notifications and alarms operations */ diff --git a/src/common/native/common/generatedipc/NativePushFacadeReceiveDispatcher.ts b/src/common/native/common/generatedipc/NativePushFacadeReceiveDispatcher.ts index b8a452c19172..e6aa61494699 100644 --- a/src/common/native/common/generatedipc/NativePushFacadeReceiveDispatcher.ts +++ b/src/common/native/common/generatedipc/NativePushFacadeReceiveDispatcher.ts @@ -6,7 +6,6 @@ import { NativePushFacade } from "./NativePushFacade.js" export class NativePushFacadeReceiveDispatcher { constructor(private readonly facade: NativePushFacade) {} - async dispatch(method: string, arg: Array): Promise { switch (method) { case "getPushIdentifier": { diff --git a/src/common/native/common/generatedipc/TutaCredentials.ts b/src/common/native/common/generatedipc/TutaCredentials.ts new file mode 100644 index 000000000000..aaff8d8a53c9 --- /dev/null +++ b/src/common/native/common/generatedipc/TutaCredentials.ts @@ -0,0 +1,3 @@ +/* generated file, don't edit. */ + +export { TutaCredentials } from "../../../../../packages/node-mimimi/dist/binding.js" diff --git a/src/common/native/main/NativeInterfaceFactory.ts b/src/common/native/main/NativeInterfaceFactory.ts index 976b876428c0..f4e46770277d 100644 --- a/src/common/native/main/NativeInterfaceFactory.ts +++ b/src/common/native/main/NativeInterfaceFactory.ts @@ -38,6 +38,8 @@ import { MobilePaymentsFacadeSendDispatcher } from "../common/generatedipc/Mobil import { AppType } from "../../misc/ClientConstants.js" import { ExternalCalendarFacade } from "../common/generatedipc/ExternalCalendarFacade.js" import { ExternalCalendarFacadeSendDispatcher } from "../common/generatedipc/ExternalCalendarFacadeSendDispatcher.js" +import { ImapImportSystemFacadeSendDispatcher } from "../common/generatedipc/ImapImportSystemFacadeSendDispatcher.js" +import { ImapImportSystemFacade } from "../common/generatedipc/ImapImportSystemFacade.js" export type NativeInterfaces = { native: NativeInterfaceMain @@ -56,6 +58,7 @@ export type DesktopInterfaces = { searchTextFacade: SearchTextInAppFacade desktopSettingsFacade: SettingsFacadeSendDispatcher desktopSystemFacade: DesktopSystemFacade + imapImportSystemFacade: ImapImportSystemFacade interWindowEventSender: InterWindowEventFacadeSendDispatcher } @@ -113,6 +116,7 @@ export function createDesktopInterfaces(native: NativeInterfaceMain): DesktopInt searchTextFacade: new SearchTextInAppFacadeSendDispatcher(native), desktopSettingsFacade: new SettingsFacadeSendDispatcher(native), desktopSystemFacade: new DesktopSystemFacadeSendDispatcher(native), + imapImportSystemFacade: new ImapImportSystemFacadeSendDispatcher(native), interWindowEventSender: new InterWindowEventFacadeSendDispatcher(native), } } diff --git a/src/mail-app/mailLocator.ts b/src/mail-app/mailLocator.ts index 04f6a8c7a509..87e1e3b0dc4e 100644 --- a/src/mail-app/mailLocator.ts +++ b/src/mail-app/mailLocator.ts @@ -127,6 +127,7 @@ import type { ContactImporter } from "./contacts/ContactImporter.js" import { ExternalCalendarFacade } from "../common/native/common/generatedipc/ExternalCalendarFacade.js" import { AppType } from "../common/misc/ClientConstants.js" import { ParsedEvent } from "../common/calendar/import/CalendarImporter.js" +import { ImapImportSystemFacade } from "../common/native/common/generatedipc/ImapImportSystemFacade.js" assertMainOrNode() @@ -171,6 +172,7 @@ class MailLocator { searchTextFacade!: SearchTextInAppFacade desktopSettingsFacade!: SettingsFacade desktopSystemFacade!: DesktopSystemFacade + imapImportSystemFacade!: ImapImportSystemFacade webMobileFacade!: WebMobileFacade systemPermissionHandler!: SystemPermissionHandler interWindowEventSender!: InterWindowEventFacadeSendDispatcher @@ -805,6 +807,7 @@ class MailLocator { if (isDesktop()) { this.desktopSettingsFacade = desktopInterfaces.desktopSettingsFacade this.desktopSystemFacade = desktopInterfaces.desktopSystemFacade + this.imapImportSystemFacade = desktopInterfaces.imapImportSystemFacade } } else if (isAndroidApp() || isIOSApp()) { const { SystemPermissionHandler } = await import("../common/native/main/SystemPermissionHandler.js") diff --git a/test/tests/api/worker/crypto/InstanceMapperTest.ts b/test/tests/api/worker/crypto/InstanceMapperTest.ts index dc4ec9e7e4a2..bd78c7bdf13e 100644 --- a/test/tests/api/worker/crypto/InstanceMapperTest.ts +++ b/test/tests/api/worker/crypto/InstanceMapperTest.ts @@ -295,6 +295,7 @@ o.spec("InstanceMapper", function () { o(encryptValue("_id", vt, null, null)).equals(null) o(encryptValue("_permissions", vt, null, null)).equals(null) }) + o("throw error on ONE null values (enc String)", makeTestForErrorOnNull(ValueType.String)) o("throw error on ONE null values (enc Date)", makeTestForErrorOnNull(ValueType.Date)) o("throw error on ONE null values (enc Bytes)", makeTestForErrorOnNull(ValueType.Bytes)) diff --git a/test/types/test.d.ts b/test/types/test.d.ts index eb92ac06b6f8..0a153385478c 100644 --- a/test/types/test.d.ts +++ b/test/types/test.d.ts @@ -26,4 +26,5 @@ declare function node(f: F): F */ declare const buildOptions: { readonly sqliteNativePath: string + readonly mimimiNativePath: string } diff --git a/tsconfig.json b/tsconfig.json index 91bb648f77f8..ca3efda30908 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,6 +25,9 @@ }, { "path": "./packages/tuta-wasm-loader" + }, + { + "path": "./packages/node-mimimi" } ] } diff --git a/tuta-sdk/rust/sdk/src/crypto/aes.rs b/tuta-sdk/rust/sdk/src/crypto/aes.rs index a7e1bac6046a..b2ef3cdcea5b 100644 --- a/tuta-sdk/rust/sdk/src/crypto/aes.rs +++ b/tuta-sdk/rust/sdk/src/crypto/aes.rs @@ -52,12 +52,14 @@ macro_rules! aes_key { impl $name { /// Generate an AES key. + #[must_use] pub fn generate(randomizer_facade: &RandomizerFacade) -> Self { let key: [u8; $size] = randomizer_facade.generate_random_array(); Self(key) } /// Get the key represented as bytes. + #[must_use] pub fn as_bytes(&self) -> &[u8; $size] { &self.0 } @@ -154,6 +156,7 @@ impl Clone for Iv { impl Iv { /// Generate an initialisation vector. + #[must_use] pub fn generate(randomizer_facade: &RandomizerFacade) -> Self { Self(randomizer_facade.generate_random_array()) } @@ -166,6 +169,7 @@ impl Iv { Self::from_bytes(slice).ok() } + #[must_use] pub fn get_inner(&self) -> &[u8; IV_BYTE_SIZE] { &self.0 } diff --git a/tuta-sdk/rust/sdk/src/crypto/argon2_id.rs b/tuta-sdk/rust/sdk/src/crypto/argon2_id.rs index e4e5a26ee3dc..cfa03d06a890 100644 --- a/tuta-sdk/rust/sdk/src/crypto/argon2_id.rs +++ b/tuta-sdk/rust/sdk/src/crypto/argon2_id.rs @@ -11,6 +11,7 @@ const ARGON2ID_KEY_LENGTH: usize = 32; /// `pass` The passphrase to use for key generation as utf8 string. /// `salt` 16 bytes of random data /// returns resolved with the key +#[must_use] pub fn generate_key_from_passphrase(password: &str, salt: [u8; 16]) -> Aes256Key { let params = Params::new( ARGON2ID_MEMORY_IN_KIB, diff --git a/tuta-sdk/rust/sdk/src/crypto/crypto_facade.rs b/tuta-sdk/rust/sdk/src/crypto/crypto_facade.rs index 2e9ceabfceba..d6c59b778078 100644 --- a/tuta-sdk/rust/sdk/src/crypto/crypto_facade.rs +++ b/tuta-sdk/rust/sdk/src/crypto/crypto_facade.rs @@ -48,6 +48,7 @@ pub struct ResolvedSessionKey { #[cfg_attr(test, mockall::automock)] impl CryptoFacade { + #[must_use] pub fn new( key_loader_facade: Option>, instance_mapper: Arc, @@ -371,6 +372,12 @@ impl SessionKeyResolutionErrorSubtype for PQError {} impl SessionKeyResolutionErrorSubtype for RSAEncryptionError {} +#[must_use] +pub fn create_auth_verifier(user_passphrase_key: Aes256Key) -> String { + let sha_user_passphrase = crate::crypto::sha::sha256(user_passphrase_key.as_bytes()); + BASE64_URL_SAFE_NO_PAD.encode(sha_user_passphrase) +} + // FIXME: check for returned owner_enc_session_key #[cfg(test)] mod test { @@ -650,8 +657,3 @@ mod test { } } } - -pub fn create_auth_verifier(user_passphrase_key: Aes256Key) -> String { - let sha_user_passphrase = crate::crypto::sha::sha256(user_passphrase_key.as_bytes()); - BASE64_URL_SAFE_NO_PAD.encode(sha_user_passphrase) -} diff --git a/tuta-sdk/rust/sdk/src/crypto/hkdf.rs b/tuta-sdk/rust/sdk/src/crypto/hkdf.rs index eb00db490ebe..9185e4e2ea05 100644 --- a/tuta-sdk/rust/sdk/src/crypto/hkdf.rs +++ b/tuta-sdk/rust/sdk/src/crypto/hkdf.rs @@ -1,4 +1,5 @@ /// Derives a key of a defined length from `salt`, `input_key_material` and `info`. +#[must_use] pub fn hkdf(salt: &[u8], input_key_material: &[u8], info: &[u8], length_bytes: usize) -> Vec { let generator = hkdf::Hkdf::::new(Some(salt), input_key_material); let mut output_buffer = vec![0u8; length_bytes]; diff --git a/tuta-sdk/rust/sdk/src/crypto/key.rs b/tuta-sdk/rust/sdk/src/crypto/key.rs index 77d52e5be79a..17ca03a93818 100644 --- a/tuta-sdk/rust/sdk/src/crypto/key.rs +++ b/tuta-sdk/rust/sdk/src/crypto/key.rs @@ -76,6 +76,7 @@ impl GenericAesKey { } /// Encrypts `key_to_encrypt` with this key. + #[must_use] pub fn encrypt_key(&self, key_to_encrypt: &GenericAesKey, iv: Iv) -> Vec { match self { Self::Aes128(key) => { @@ -111,6 +112,7 @@ impl GenericAesKey { } } + #[must_use] pub fn as_bytes(&self) -> &[u8] { match self { Self::Aes128(n) => n.as_bytes(), diff --git a/tuta-sdk/rust/sdk/src/crypto/randomizer_facade.rs b/tuta-sdk/rust/sdk/src/crypto/randomizer_facade.rs index d4a5a78fe333..0dc6d0fdbfdd 100644 --- a/tuta-sdk/rust/sdk/src/crypto/randomizer_facade.rs +++ b/tuta-sdk/rust/sdk/src/crypto/randomizer_facade.rs @@ -27,6 +27,7 @@ impl RandomizerFacade { } /// Generate a random array of a given size. + #[must_use] pub fn generate_random_array(&self) -> [u8; S] { let mut output = [0u8; S]; self.fill_slice(&mut output); @@ -65,6 +66,7 @@ pub mod test_util { use super::*; /// Used for internal testing using OsRng. + #[must_use] pub fn make_thread_rng_facade() -> RandomizerFacade { RandomizerFacade::from_core(rand::rngs::OsRng {}) } diff --git a/tuta-sdk/rust/sdk/src/crypto/sha.rs b/tuta-sdk/rust/sdk/src/crypto/sha.rs index a0472b45e603..8b54137d5e51 100644 --- a/tuta-sdk/rust/sdk/src/crypto/sha.rs +++ b/tuta-sdk/rust/sdk/src/crypto/sha.rs @@ -2,6 +2,7 @@ use sha2::Digest; /// Generates a SHA256 hash of `data` +#[must_use] pub fn sha256(data: &[u8]) -> Vec { let mut hasher = sha2::Sha256::new(); hasher.update(data); diff --git a/tuta-sdk/rust/sdk/src/crypto/tuta_crypt.rs b/tuta-sdk/rust/sdk/src/crypto/tuta_crypt.rs index 270b6c1d7bf8..10a478f16ef2 100644 --- a/tuta-sdk/rust/sdk/src/crypto/tuta_crypt.rs +++ b/tuta-sdk/rust/sdk/src/crypto/tuta_crypt.rs @@ -175,6 +175,7 @@ pub struct PQKeyPairs { impl PQKeyPairs { /// Generate a keypair with the given random number generator. + #[must_use] pub fn generate(randomizer_facade: &RandomizerFacade) -> Self { let ecc_keys = EccKeyPair::generate(randomizer_facade); let kyber_keys = KyberKeyPair::generate(); diff --git a/tuta-sdk/rust/sdk/src/custom_id.rs b/tuta-sdk/rust/sdk/src/custom_id.rs index 6f324e1eeec4..bd8c1741057f 100644 --- a/tuta-sdk/rust/sdk/src/custom_id.rs +++ b/tuta-sdk/rust/sdk/src/custom_id.rs @@ -11,17 +11,20 @@ pub const CUSTOM_ID_STRUCT_NAME: &str = "CustomId"; pub struct CustomId(pub String); impl CustomId { + #[must_use] pub fn as_str(&self) -> &str { &self.0 } /// Create a CustomId from an arbitrary (unencoded) string + #[must_use] pub fn from_custom_string(custom_string: &str) -> Self { Self(base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(custom_string)) } /// Generates and returns a random `CustomId` #[cfg(test)] + #[must_use] pub fn test_random() -> Self { use crate::util::test_utils::generate_random_string; Self(generate_random_string::<9>()) diff --git a/tuta-sdk/rust/sdk/src/element_value.rs b/tuta-sdk/rust/sdk/src/element_value.rs index 88832e31fb0b..43cdbd48c96d 100644 --- a/tuta-sdk/rust/sdk/src/element_value.rs +++ b/tuta-sdk/rust/sdk/src/element_value.rs @@ -8,199 +8,199 @@ use std::collections::HashMap; /// Primitive value types used by entity/instance types #[derive(uniffi::Enum, Debug, Serialize, Deserialize, PartialEq, Clone)] pub enum ElementValue { - Null, - String(String), - Number(i64), - Bytes(Vec), - Date(DateTime), - Bool(bool), - // Names are prefixed with 'Id' to avoid name collision in Kotlin - IdGeneratedId(GeneratedId), - IdCustomId(CustomId), - IdTupleId(IdTuple), - Dict(HashMap), - Array(Vec), + Null, + String(String), + Number(i64), + Bytes(Vec), + Date(DateTime), + Bool(bool), + // Names are prefixed with 'Id' to avoid name collision in Kotlin + IdGeneratedId(GeneratedId), + IdCustomId(CustomId), + IdTupleId(IdTuple), + Dict(HashMap), + Array(Vec), } pub type ParsedEntity = HashMap; impl ElementValue { - pub fn assert_number(&self) -> i64 { - match self { - ElementValue::Number(number) => *number, - _ => panic!("Invalid type"), - } - } - - pub fn assert_string(&self) -> String { - self.assert_str().to_string() - } - - pub fn assert_array(&self) -> Vec { - match self { - ElementValue::Array(value) => value.clone(), - _ => panic!("Invalid type"), - } - } - - pub fn assert_bytes(&self) -> Vec { - match self { - ElementValue::Bytes(value) => value.clone(), - _ => panic!( - "Invalid type, expected bytes, got: {}", - self.type_variant_name() - ), - } - } - - pub fn assert_dict(&self) -> HashMap { - match self { - ElementValue::Dict(value) => value.clone(), - _ => panic!("Invalid type"), - } - } - - pub fn assert_array_ref(&self) -> &Vec { - match self { - ElementValue::Array(value) => value, - _ => panic!("Invalid type"), - } - } - - pub fn assert_dict_ref(&self) -> &HashMap { - match self { - ElementValue::Dict(value) => value, - _ => panic!("Invalid type"), - } - } - - pub fn assert_dict_mut_ref(&mut self) -> &mut HashMap { - match self { - ElementValue::Dict(value) => value, - _ => panic!("Invalid type"), - } - } - - pub fn assert_str(&self) -> &str { - match self { - ElementValue::String(value) => value, - _ => panic!("Invalid type"), - } - } - - pub fn assert_generated_id(&self) -> &GeneratedId { - match self { - ElementValue::IdGeneratedId(value) => value, - _ => panic!("Invalid type"), - } - } - pub fn assert_tuple_id(&self) -> &IdTuple { - match self { - ElementValue::IdTupleId(value) => value, - _ => panic!("Invalid type"), - } - } - - pub fn assert_custom_id(&self) -> &CustomId { - match self { - ElementValue::IdCustomId(value) => value, - _ => panic!("Invalid type"), - } - } - - pub fn assert_date(&self) -> &DateTime { - match self { - ElementValue::Date(value) => value, - _ => panic!("Invalid type"), - } - } - - pub fn assert_bool(&self) -> bool { - match self { - ElementValue::Bool(value) => *value, - _ => panic!("Invalid type"), - } - } - - pub(crate) fn type_variant_name(&self) -> &'static str { - match self { - Self::Null => "Null", - Self::String(_) => "String", - Self::Number(_) => "Number", - Self::Bytes(_) => "Bytes", - Self::Date(_) => "Date", - Self::Bool(_) => "Bool", - Self::IdGeneratedId(_) => "IdGeneratedId", - Self::IdCustomId(_) => "IdCustomId", - Self::IdTupleId(_) => "IdTupleId", - Self::Dict(_) => "Dict", - Self::Array(_) => "Array", - } - } + pub fn assert_number(&self) -> i64 { + match self { + ElementValue::Number(number) => *number, + _ => panic!("Invalid type"), + } + } + + pub fn assert_string(&self) -> String { + self.assert_str().to_string() + } + + pub fn assert_array(&self) -> Vec { + match self { + ElementValue::Array(value) => value.clone(), + _ => panic!("Invalid type"), + } + } + + pub fn assert_bytes(&self) -> Vec { + match self { + ElementValue::Bytes(value) => value.clone(), + _ => panic!( + "Invalid type, expected bytes, got: {}", + self.type_variant_name() + ), + } + } + + pub fn assert_dict(&self) -> HashMap { + match self { + ElementValue::Dict(value) => value.clone(), + _ => panic!("Invalid type"), + } + } + + pub fn assert_array_ref(&self) -> &Vec { + match self { + ElementValue::Array(value) => value, + _ => panic!("Invalid type"), + } + } + + pub fn assert_dict_ref(&self) -> &HashMap { + match self { + ElementValue::Dict(value) => value, + _ => panic!("Invalid type"), + } + } + + pub fn assert_dict_mut_ref(&mut self) -> &mut HashMap { + match self { + ElementValue::Dict(value) => value, + _ => panic!("Invalid type"), + } + } + + pub fn assert_str(&self) -> &str { + match self { + ElementValue::String(value) => value, + _ => panic!("Invalid type"), + } + } + + pub fn assert_generated_id(&self) -> &GeneratedId { + match self { + ElementValue::IdGeneratedId(value) => value, + _ => panic!("Invalid type"), + } + } + pub fn assert_tuple_id(&self) -> &IdTuple { + match self { + ElementValue::IdTupleId(value) => value, + _ => panic!("Invalid type"), + } + } + + pub fn assert_custom_id(&self) -> &CustomId { + match self { + ElementValue::IdCustomId(value) => value, + _ => panic!("Invalid type"), + } + } + + pub fn assert_date(&self) -> &DateTime { + match self { + ElementValue::Date(value) => value, + _ => panic!("Invalid type"), + } + } + + pub fn assert_bool(&self) -> bool { + match self { + ElementValue::Bool(value) => *value, + _ => panic!("Invalid type"), + } + } + + pub(crate) fn type_variant_name(&self) -> &'static str { + match self { + Self::Null => "Null", + Self::String(_) => "String", + Self::Number(_) => "Number", + Self::Bytes(_) => "Bytes", + Self::Date(_) => "Date", + Self::Bool(_) => "Bool", + Self::IdGeneratedId(_) => "IdGeneratedId", + Self::IdCustomId(_) => "IdCustomId", + Self::IdTupleId(_) => "IdTupleId", + Self::Dict(_) => "Dict", + Self::Array(_) => "Array", + } + } } impl From<()> for ElementValue { - fn from(value: ()) -> Self { - Self::Null - } + fn from(_: ()) -> Self { + Self::Null + } } impl From for ElementValue { - fn from(value: String) -> Self { - Self::String(value) - } + fn from(value: String) -> Self { + Self::String(value) + } } impl From for ElementValue { - fn from(value: i64) -> Self { - Self::Number(value) - } + fn from(value: i64) -> Self { + Self::Number(value) + } } impl From> for ElementValue { - fn from(value: Vec) -> Self { - Self::Bytes(value) - } + fn from(value: Vec) -> Self { + Self::Bytes(value) + } } impl From for ElementValue { - fn from(value: DateTime) -> Self { - Self::Date(value) - } + fn from(value: DateTime) -> Self { + Self::Date(value) + } } impl From for ElementValue { - fn from(value: bool) -> Self { - Self::Bool(value) - } + fn from(value: bool) -> Self { + Self::Bool(value) + } } impl From for ElementValue { - fn from(value: GeneratedId) -> Self { - Self::IdGeneratedId(value) - } + fn from(value: GeneratedId) -> Self { + Self::IdGeneratedId(value) + } } impl From for ElementValue { - fn from(value: CustomId) -> Self { - Self::IdCustomId(value) - } + fn from(value: CustomId) -> Self { + Self::IdCustomId(value) + } } impl From for ElementValue { - fn from(value: IdTuple) -> Self { - Self::IdTupleId(value) - } + fn from(value: IdTuple) -> Self { + Self::IdTupleId(value) + } } impl From> for ElementValue { - fn from(value: HashMap) -> Self { - Self::Dict(value) - } + fn from(value: HashMap) -> Self { + Self::Dict(value) + } } impl From> for ElementValue { - fn from(value: Vec) -> Self { - Self::Array(value) - } -} \ No newline at end of file + fn from(value: Vec) -> Self { + Self::Array(value) + } +} diff --git a/tuta-sdk/rust/sdk/src/entities/base.rs b/tuta-sdk/rust/sdk/src/entities/base.rs index 1a58f2ef4c60..98d86f680f7f 100644 --- a/tuta-sdk/rust/sdk/src/entities/base.rs +++ b/tuta-sdk/rust/sdk/src/entities/base.rs @@ -16,6 +16,3 @@ impl Entity for PersistenceResourcePostReturn { } } } - - - diff --git a/tuta-sdk/rust/sdk/src/entities/entity_facade.rs b/tuta-sdk/rust/sdk/src/entities/entity_facade.rs index 4614e6b73fa3..490ee8e6c401 100644 --- a/tuta-sdk/rust/sdk/src/entities/entity_facade.rs +++ b/tuta-sdk/rust/sdk/src/entities/entity_facade.rs @@ -43,9 +43,9 @@ impl IvProvider { fn provide_iv(&self) -> Iv { match self { IvProvider::Random => Iv::from_bytes( - &RandomizerFacade::from_core(rand_core::OsRng) + RandomizerFacade::from_core(rand_core::OsRng) .generate_random_array::() - .to_vec(), + .as_ref(), ) .unwrap(), @@ -72,6 +72,7 @@ pub trait EntityFacade: Send + Sync { } impl EntityFacadeImpl { + #[must_use] pub fn new(type_model_provider: Arc) -> Self { EntityFacadeImpl { type_model_provider, @@ -115,7 +116,7 @@ impl EntityFacadeImpl { } else if model_value.encrypted { let iv = iv_provider.provide_iv(); let bytes = Self::map_value_to_binary(value_type, instance_value) - .expect(&format!("invalid encrypted value {:?}", instance_value)); + .unwrap_or_else(|| panic!("invalid encrypted value {:?}", instance_value)); let encrypted_data = session_key .as_ref() .ok_or(ApiCallError::internal( @@ -138,19 +139,6 @@ impl EntityFacadeImpl { None } - fn map_value_to_db_type(value_type: &ValueType, value: &ElementValue) -> ElementValue { - match value { - ElementValue::Date(d) => ElementValue::String(d.as_millis().to_string()), - ElementValue::Bool(b) => ElementValue::String(if *b { - String::from("1") - } else { - String::from("0") - }), - ElementValue::Number(n) => ElementValue::String(n.to_string()), - other => other.clone(), - } - } - fn map_value_to_binary(value_type: &ValueType, value: &ElementValue) -> Option> { if >::is_nil(value) { return None; @@ -191,14 +179,14 @@ impl EntityFacadeImpl { } let mut encrypted = ParsedEntity::new(); - for (key, model_value) in type_model.values.iter() { + for (key, model_value) in &type_model.values { let instance_value = instance .get(&key.to_string()) - .expect(format!("Can not find key: {key} in instance: {instance:?}").as_str()); + .unwrap_or_else(|| panic!("Can not find key: {key} in instance: {instance:?}")); let encrypted_value: ElementValue; - if Self::should_restore_default_value(&model_value, instance_value, &instance, &key) { + if Self::should_restore_default_value(model_value, instance_value, instance, key) { // restore the default encrypted value because it has not changed // note: this branch must be checked *before* the one which reuses IVs as this one checks // the length. @@ -233,28 +221,28 @@ impl EntityFacadeImpl { encrypted.insert(key.to_string(), encrypted_value); } - if type_model.element_type == ElementType::Aggregated && encrypted.get("_id").is_none() { + if type_model.element_type == ElementType::Aggregated && !encrypted.contains_key("_id") { let randomizer = RandomizerFacade::from_core(rand_core::OsRng); let new_id = randomizer.generate_random_array::<4>(); encrypted.insert( String::from("_id"), - ElementValue::String( - BASE64_URL_SAFE_NO_PAD.encode(BASE64_STANDARD.encode(&new_id)), - ), + ElementValue::String(BASE64_URL_SAFE_NO_PAD.encode(BASE64_STANDARD.encode(new_id))), ); } - for (association_name, association) in type_model.associations.iter() { + for (association_name, association) in &type_model.associations { if let AssociationType::Aggregation = association.association_type { let dependency = association.dependency.unwrap_or(type_model.app); let aggregated_type_model = self .type_model_provider .get_type_model(dependency, association.ref_type) - .expect(&format!( - "Cannot find type model for: {:?}", - (dependency, association.ref_type) - )); + .unwrap_or_else(|| { + panic!( + "Cannot find type model for: {:?}", + (dependency, association.ref_type) + ) + }); let aggregation = association; let instance_association = instance.get(&association_name.to_string()).unwrap(); if aggregation.cardinality == Cardinality::ZeroOrOne @@ -266,7 +254,7 @@ impl EntityFacadeImpl { } else if aggregation.cardinality == Cardinality::Any { let aggregates = instance_association.assert_array(); let mut encrypted_aggregates = Vec::with_capacity(aggregates.len()); - for aggregate in aggregates.iter() { + for aggregate in &aggregates { let parsed_entity = self.encrypt_and_map_to_literal_with_iv( aggregated_type_model, &aggregate.assert_dict(), @@ -750,7 +738,7 @@ mod tests { .encrypt_data(value.assert_string().as_bytes(), iv) .unwrap(); - assert_eq!(expected, encrypted_value.unwrap().assert_bytes().to_vec()) + assert_eq!(expected, encrypted_value.unwrap().assert_bytes().clone()) } #[test] @@ -775,7 +763,7 @@ mod tests { .unwrap() .encrypt_data("1".as_bytes(), iv.clone()) .unwrap(); - assert_eq!(expected, encrypted_value.unwrap().assert_bytes().to_vec()) + assert_eq!(expected, encrypted_value.unwrap().assert_bytes().clone()) } { @@ -793,7 +781,7 @@ mod tests { .unwrap() .encrypt_data("0".as_bytes(), iv.clone()) .unwrap(); - assert_eq!(expected, encrypted_value.unwrap().assert_bytes().to_vec()) + assert_eq!(expected, encrypted_value.unwrap().assert_bytes().clone()) } } @@ -817,7 +805,7 @@ mod tests { .encrypt_data(value.assert_date().as_millis().to_string().as_bytes(), iv) .unwrap(); - assert_eq!(expected, encrypted_value.unwrap().assert_bytes().to_vec()); + assert_eq!(expected, encrypted_value.unwrap().assert_bytes().clone()); } #[test] @@ -841,7 +829,7 @@ mod tests { .encrypt_data(value.assert_bytes().as_slice(), iv) .unwrap(); - assert_eq!(expected, encrypted_value.unwrap().assert_bytes().to_vec()); + assert_eq!(expected, encrypted_value.unwrap().assert_bytes().clone()); } #[test] @@ -1163,7 +1151,7 @@ mod tests { .unwrap(); } - let mut encrypted_mail = entity_facade.encrypt_and_map_to_literal_with_iv( + let encrypted_mail = entity_facade.encrypt_and_map_to_literal_with_iv( type_model, &raw_mail, Some(sk.clone()), @@ -1174,8 +1162,8 @@ mod tests { // verify every data is preserved as is after decryption { - let mut original_mail = raw_mail; - let mut encrypted_mail = encrypted_mail.unwrap(); + let original_mail = raw_mail; + let encrypted_mail = encrypted_mail.unwrap(); let instance_mapper = InstanceMapper::new(); let mut decrypted_mail = entity_facade @@ -1237,7 +1225,7 @@ mod tests { let instance = json_serializer.parse(&type_ref, instance).unwrap(); let encrypted_instance = - entity_facade.encrypt_and_map_to_literal(&type_model, &instance, Some(sk.clone())); + entity_facade.encrypt_and_map_to_literal(type_model, &instance, Some(sk.clone())); // unencrypted value should be kept as-is assert_eq!(Ok(instance), encrypted_instance); @@ -1259,7 +1247,7 @@ mod tests { // use two seperate iv assert_ne!(original_iv.get_inner(), new_iv.get_inner()); - let (mut encrypted_mail, mut unencrypted_mail) = generate_email_entity( + let (encrypted_mail, mut unencrypted_mail) = generate_email_entity( &sk, &original_iv, true, @@ -1281,7 +1269,7 @@ mod tests { ElementValue::Dict(final_iv_for_subject), ); - let mut encrypted_mail = entity_facade + let encrypted_mail = entity_facade .encrypt_and_map_to_literal_with_iv( type_model, &unencrypted_mail, @@ -1328,7 +1316,7 @@ mod tests { let iv = Iv::from_bytes(&rand::random::<[u8; 16]>()).unwrap(); let default_subject = String::from(""); - let (mut encrypted_mail, mut unencrypted_mail) = generate_email_entity( + let (encrypted_mail, unencrypted_mail) = generate_email_entity( &sk, &iv, true, @@ -1337,7 +1325,7 @@ mod tests { String::from("Munich"), ); - let mut encrypted_mail = entity_facade + let encrypted_mail = entity_facade .encrypt_and_map_to_literal_with_iv( type_model, &unencrypted_mail, @@ -1353,7 +1341,7 @@ mod tests { fn map_to_string(map: &HashMap) -> String { let mut out = String::new(); let sorted_map: BTreeMap = map.clone().into_iter().collect(); - for (key, value) in sorted_map.iter() { + for (key, value) in &sorted_map { match value { ElementValue::Dict(aggregate) => { out.push_str(&format!("{}: {}\n", key, map_to_string(aggregate))) diff --git a/tuta-sdk/rust/sdk/src/entities/monitor.rs b/tuta-sdk/rust/sdk/src/entities/monitor.rs index fcb946d0ad9a..7105985a9b60 100644 --- a/tuta-sdk/rust/sdk/src/entities/monitor.rs +++ b/tuta-sdk/rust/sdk/src/entities/monitor.rs @@ -22,9 +22,6 @@ impl Entity for ApprovalMail { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CounterValue { pub _id: CustomId, @@ -40,9 +37,6 @@ impl Entity for CounterValue { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ErrorReportData { pub _id: CustomId, @@ -65,9 +59,6 @@ impl Entity for ErrorReportData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ErrorReportFile { pub _id: CustomId, @@ -83,9 +74,6 @@ impl Entity for ErrorReportFile { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ReadCounterData { pub _format: i64, @@ -102,9 +90,6 @@ impl Entity for ReadCounterData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ReadCounterReturn { pub _format: i64, @@ -120,9 +105,6 @@ impl Entity for ReadCounterReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ReportErrorIn { pub _format: i64, @@ -138,9 +120,6 @@ impl Entity for ReportErrorIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct WriteCounterData { pub _format: i64, @@ -157,6 +136,3 @@ impl Entity for WriteCounterData { } } } - - - diff --git a/tuta-sdk/rust/sdk/src/entities/storage.rs b/tuta-sdk/rust/sdk/src/entities/storage.rs index 358d4020042d..5a643fb103b6 100644 --- a/tuta-sdk/rust/sdk/src/entities/storage.rs +++ b/tuta-sdk/rust/sdk/src/entities/storage.rs @@ -18,9 +18,6 @@ impl Entity for BlobAccessTokenPostIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobAccessTokenPostOut { pub _format: i64, @@ -35,9 +32,6 @@ impl Entity for BlobAccessTokenPostOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobArchiveRef { pub _format: i64, @@ -55,9 +49,6 @@ impl Entity for BlobArchiveRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobGetIn { pub _format: i64, @@ -74,9 +65,6 @@ impl Entity for BlobGetIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobId { pub _id: CustomId, @@ -91,9 +79,6 @@ impl Entity for BlobId { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobPostOut { pub _format: i64, @@ -108,9 +93,6 @@ impl Entity for BlobPostOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobReadData { pub _id: CustomId, @@ -127,9 +109,6 @@ impl Entity for BlobReadData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobReferenceDeleteIn { pub _format: i64, @@ -147,9 +126,6 @@ impl Entity for BlobReferenceDeleteIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobReferencePutIn { pub _format: i64, @@ -167,9 +143,6 @@ impl Entity for BlobReferencePutIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobServerAccessInfo { pub _id: CustomId, @@ -186,9 +159,6 @@ impl Entity for BlobServerAccessInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobServerUrl { pub _id: CustomId, @@ -203,9 +173,6 @@ impl Entity for BlobServerUrl { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobWriteData { pub _id: CustomId, @@ -220,9 +187,6 @@ impl Entity for BlobWriteData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct InstanceId { pub _id: CustomId, @@ -236,6 +200,3 @@ impl Entity for InstanceId { } } } - - - diff --git a/tuta-sdk/rust/sdk/src/entities/sys.rs b/tuta-sdk/rust/sdk/src/entities/sys.rs index e125ad7a01fd..25331b137db2 100644 --- a/tuta-sdk/rust/sdk/src/entities/sys.rs +++ b/tuta-sdk/rust/sdk/src/entities/sys.rs @@ -39,9 +39,6 @@ impl Entity for AccountingInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AdminGroupKeyAuthenticationData { pub _id: CustomId, @@ -59,9 +56,6 @@ impl Entity for AdminGroupKeyAuthenticationData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AdminGroupKeyRotationPostIn { pub _format: i64, @@ -78,9 +72,6 @@ impl Entity for AdminGroupKeyRotationPostIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AdministratedGroupsRef { pub _id: CustomId, @@ -95,9 +86,6 @@ impl Entity for AdministratedGroupsRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AffiliatePartnerKpiMonthSummary { pub _id: CustomId, @@ -117,9 +105,6 @@ impl Entity for AffiliatePartnerKpiMonthSummary { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AffiliatePartnerKpiServiceGetOut { pub _format: i64, @@ -137,9 +122,6 @@ impl Entity for AffiliatePartnerKpiServiceGetOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AlarmInfo { pub _id: CustomId, @@ -157,9 +139,6 @@ impl Entity for AlarmInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AlarmNotification { pub _id: CustomId, @@ -182,9 +161,6 @@ impl Entity for AlarmNotification { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AlarmServicePost { pub _format: i64, @@ -201,9 +177,6 @@ impl Entity for AlarmServicePost { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ArchiveRef { pub _id: CustomId, @@ -218,9 +191,6 @@ impl Entity for ArchiveRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ArchiveType { pub _id: CustomId, @@ -238,9 +208,6 @@ impl Entity for ArchiveType { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AuditLogEntry { pub _format: i64, @@ -269,9 +236,6 @@ impl Entity for AuditLogEntry { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AuditLogRef { pub _id: CustomId, @@ -286,9 +250,6 @@ impl Entity for AuditLogRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AuthenticatedDevice { pub _id: CustomId, @@ -306,9 +267,6 @@ impl Entity for AuthenticatedDevice { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Authentication { pub _id: CustomId, @@ -326,9 +284,6 @@ impl Entity for Authentication { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AutoLoginDataDelete { pub _format: i64, @@ -343,9 +298,6 @@ impl Entity for AutoLoginDataDelete { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AutoLoginDataGet { pub _format: i64, @@ -361,9 +313,6 @@ impl Entity for AutoLoginDataGet { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AutoLoginDataReturn { pub _format: i64, @@ -379,9 +328,6 @@ impl Entity for AutoLoginDataReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AutoLoginPostReturn { pub _format: i64, @@ -396,9 +342,6 @@ impl Entity for AutoLoginPostReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Blob { pub _id: CustomId, @@ -415,9 +358,6 @@ impl Entity for Blob { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BlobReferenceTokenWrapper { pub _id: CustomId, @@ -432,9 +372,6 @@ impl Entity for BlobReferenceTokenWrapper { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Booking { pub _area: i64, @@ -459,9 +396,6 @@ impl Entity for Booking { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BookingItem { pub _id: CustomId, @@ -482,9 +416,6 @@ impl Entity for BookingItem { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BookingsRef { pub _id: CustomId, @@ -499,9 +430,6 @@ impl Entity for BookingsRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BootstrapFeature { pub _id: CustomId, @@ -516,9 +444,6 @@ impl Entity for BootstrapFeature { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Braintree3ds2Request { pub _id: CustomId, @@ -535,9 +460,6 @@ impl Entity for Braintree3ds2Request { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Braintree3ds2Response { pub _id: CustomId, @@ -553,9 +475,6 @@ impl Entity for Braintree3ds2Response { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BrandingDomainData { pub _format: i64, @@ -578,9 +497,6 @@ impl Entity for BrandingDomainData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BrandingDomainDeleteData { pub _format: i64, @@ -595,9 +511,6 @@ impl Entity for BrandingDomainDeleteData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BrandingDomainGetReturn { pub _format: i64, @@ -612,9 +525,6 @@ impl Entity for BrandingDomainGetReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Bucket { pub _id: CustomId, @@ -629,9 +539,6 @@ impl Entity for Bucket { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BucketKey { pub _id: CustomId, @@ -654,9 +561,6 @@ impl Entity for BucketKey { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct BucketPermission { pub _format: i64, @@ -687,9 +591,6 @@ impl Entity for BucketPermission { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CalendarEventRef { pub _id: CustomId, @@ -705,9 +606,6 @@ impl Entity for CalendarEventRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CertificateInfo { pub _id: CustomId, @@ -726,9 +624,6 @@ impl Entity for CertificateInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Challenge { pub _id: CustomId, @@ -746,9 +641,6 @@ impl Entity for Challenge { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ChangeKdfPostIn { pub _format: i64, @@ -772,9 +664,6 @@ impl Entity for ChangeKdfPostIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ChangePasswordPostIn { pub _format: i64, @@ -801,9 +690,6 @@ impl Entity for ChangePasswordPostIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Chat { pub _id: CustomId, @@ -820,9 +706,6 @@ impl Entity for Chat { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CloseSessionServicePost { pub _format: i64, @@ -838,9 +721,6 @@ impl Entity for CloseSessionServicePost { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CreateCustomerServerPropertiesData { pub _format: i64, @@ -857,9 +737,6 @@ impl Entity for CreateCustomerServerPropertiesData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CreateCustomerServerPropertiesReturn { pub _format: i64, @@ -874,9 +751,6 @@ impl Entity for CreateCustomerServerPropertiesReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CreateSessionData { pub _format: i64, @@ -898,9 +772,6 @@ impl Entity for CreateSessionData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CreateSessionReturn { pub _format: i64, @@ -917,9 +788,6 @@ impl Entity for CreateSessionReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CreditCard { pub _id: CustomId, @@ -939,9 +807,6 @@ impl Entity for CreditCard { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CustomDomainCheckGetIn { pub _format: i64, @@ -957,9 +822,6 @@ impl Entity for CustomDomainCheckGetIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CustomDomainCheckGetOut { pub _format: i64, @@ -977,9 +839,6 @@ impl Entity for CustomDomainCheckGetOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CustomDomainData { pub _format: i64, @@ -995,9 +854,6 @@ impl Entity for CustomDomainData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CustomDomainReturn { pub _format: i64, @@ -1013,9 +869,6 @@ impl Entity for CustomDomainReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Customer { pub _format: i64, @@ -1054,9 +907,6 @@ impl Entity for Customer { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CustomerAccountTerminationPostIn { pub _format: i64, @@ -1072,9 +922,6 @@ impl Entity for CustomerAccountTerminationPostIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CustomerAccountTerminationPostOut { pub _format: i64, @@ -1089,9 +936,6 @@ impl Entity for CustomerAccountTerminationPostOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CustomerAccountTerminationRequest { pub _format: i64, @@ -1111,9 +955,6 @@ impl Entity for CustomerAccountTerminationRequest { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CustomerInfo { pub _format: i64, @@ -1158,9 +999,6 @@ impl Entity for CustomerInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CustomerProperties { pub _format: i64, @@ -1183,9 +1021,6 @@ impl Entity for CustomerProperties { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CustomerServerProperties { pub _format: i64, @@ -1213,9 +1048,6 @@ impl Entity for CustomerServerProperties { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DateWrapper { pub _id: CustomId, @@ -1231,9 +1063,6 @@ impl Entity for DateWrapper { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DebitServicePutData { pub _format: i64, @@ -1248,9 +1077,6 @@ impl Entity for DebitServicePutData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DeleteCustomerData { pub _format: i64, @@ -1271,9 +1097,6 @@ impl Entity for DeleteCustomerData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DnsRecord { pub _id: CustomId, @@ -1291,9 +1114,6 @@ impl Entity for DnsRecord { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DomainInfo { pub _id: CustomId, @@ -1311,9 +1131,6 @@ impl Entity for DomainInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DomainMailAddressAvailabilityData { pub _format: i64, @@ -1328,9 +1145,6 @@ impl Entity for DomainMailAddressAvailabilityData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DomainMailAddressAvailabilityReturn { pub _format: i64, @@ -1345,9 +1159,6 @@ impl Entity for DomainMailAddressAvailabilityReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DomainsRef { pub _id: CustomId, @@ -1362,9 +1173,6 @@ impl Entity for DomainsRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct EmailSenderListElement { pub _id: CustomId, @@ -1384,9 +1192,6 @@ impl Entity for EmailSenderListElement { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct EntityEventBatch { pub _format: i64, @@ -1404,9 +1209,6 @@ impl Entity for EntityEventBatch { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct EntityUpdate { pub _id: CustomId, @@ -1426,9 +1228,6 @@ impl Entity for EntityUpdate { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SysException { pub _id: CustomId, @@ -1445,9 +1244,6 @@ impl Entity for SysException { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ExternalPropertiesReturn { pub _format: i64, @@ -1465,9 +1261,6 @@ impl Entity for ExternalPropertiesReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ExternalUserReference { pub _format: i64, @@ -1486,9 +1279,6 @@ impl Entity for ExternalUserReference { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Feature { pub _id: CustomId, @@ -1503,9 +1293,6 @@ impl Entity for Feature { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct File { pub _id: CustomId, @@ -1523,9 +1310,6 @@ impl Entity for File { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GeneratedIdWrapper { pub _id: CustomId, @@ -1540,9 +1324,6 @@ impl Entity for GeneratedIdWrapper { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GiftCard { pub _format: i64, @@ -1569,9 +1350,6 @@ impl Entity for GiftCard { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GiftCardCreateData { pub _format: i64, @@ -1594,9 +1372,6 @@ impl Entity for GiftCardCreateData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GiftCardCreateReturn { pub _format: i64, @@ -1611,9 +1386,6 @@ impl Entity for GiftCardCreateReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GiftCardDeleteData { pub _format: i64, @@ -1628,9 +1400,6 @@ impl Entity for GiftCardDeleteData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GiftCardGetReturn { pub _format: i64, @@ -1647,9 +1416,6 @@ impl Entity for GiftCardGetReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GiftCardOption { pub _id: CustomId, @@ -1664,9 +1430,6 @@ impl Entity for GiftCardOption { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GiftCardRedeemData { pub _format: i64, @@ -1684,9 +1447,6 @@ impl Entity for GiftCardRedeemData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GiftCardRedeemGetReturn { pub _format: i64, @@ -1705,9 +1465,6 @@ impl Entity for GiftCardRedeemGetReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GiftCardsRef { pub _id: CustomId, @@ -1722,9 +1479,6 @@ impl Entity for GiftCardsRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Group { pub _format: i64, @@ -1761,9 +1515,6 @@ impl Entity for Group { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupInfo { pub _format: i64, @@ -1795,9 +1546,6 @@ impl Entity for GroupInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupKey { pub _format: i64, @@ -1822,9 +1570,6 @@ impl Entity for GroupKey { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupKeyRotationData { pub _id: CustomId, @@ -1848,9 +1593,6 @@ impl Entity for GroupKeyRotationData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupKeyRotationInfoGetOut { pub _format: i64, @@ -1866,9 +1608,6 @@ impl Entity for GroupKeyRotationInfoGetOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupKeyRotationPostIn { pub _format: i64, @@ -1883,9 +1622,6 @@ impl Entity for GroupKeyRotationPostIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupKeyUpdate { pub _format: i64, @@ -1911,9 +1647,6 @@ impl Entity for GroupKeyUpdate { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupKeyUpdateData { pub _id: CustomId, @@ -1933,9 +1666,6 @@ impl Entity for GroupKeyUpdateData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupKeyUpdatesRef { pub _id: CustomId, @@ -1950,9 +1680,6 @@ impl Entity for GroupKeyUpdatesRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupKeysRef { pub _id: CustomId, @@ -1967,9 +1694,6 @@ impl Entity for GroupKeysRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupMember { pub _format: i64, @@ -1990,9 +1714,6 @@ impl Entity for GroupMember { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupMembership { pub _id: CustomId, @@ -2016,9 +1737,6 @@ impl Entity for GroupMembership { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupMembershipKeyData { pub _id: CustomId, @@ -2037,9 +1755,6 @@ impl Entity for GroupMembershipKeyData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupMembershipUpdateData { pub _id: CustomId, @@ -2057,9 +1772,6 @@ impl Entity for GroupMembershipUpdateData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupRoot { pub _format: i64, @@ -2079,9 +1791,6 @@ impl Entity for GroupRoot { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct IdTupleWrapper { pub _id: CustomId, @@ -2097,9 +1806,6 @@ impl Entity for IdTupleWrapper { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct InstanceSessionKey { pub _id: CustomId, @@ -2121,9 +1827,6 @@ impl Entity for InstanceSessionKey { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Invoice { pub _format: i64, @@ -2162,9 +1865,6 @@ impl Entity for Invoice { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct InvoiceDataGetIn { pub _format: i64, @@ -2179,9 +1879,6 @@ impl Entity for InvoiceDataGetIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct InvoiceDataGetOut { pub _format: i64, @@ -2208,9 +1905,6 @@ impl Entity for InvoiceDataGetOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct InvoiceDataItem { pub _id: CustomId, @@ -2230,9 +1924,6 @@ impl Entity for InvoiceDataItem { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct InvoiceInfo { pub _format: i64, @@ -2263,9 +1954,6 @@ impl Entity for InvoiceInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct InvoiceItem { pub _id: CustomId, @@ -2288,9 +1976,6 @@ impl Entity for InvoiceItem { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct KeyPair { pub _id: CustomId, @@ -2316,9 +2001,6 @@ impl Entity for KeyPair { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct KeyRotation { pub _format: i64, @@ -2338,9 +2020,6 @@ impl Entity for KeyRotation { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct KeyRotationsRef { pub _id: CustomId, @@ -2355,9 +2034,6 @@ impl Entity for KeyRotationsRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct LocationServiceGetReturn { pub _format: i64, @@ -2372,9 +2048,6 @@ impl Entity for LocationServiceGetReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Login { pub _format: i64, @@ -2392,9 +2065,6 @@ impl Entity for Login { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailAddressAlias { pub _id: CustomId, @@ -2410,9 +2080,6 @@ impl Entity for MailAddressAlias { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailAddressAliasGetIn { pub _format: i64, @@ -2427,9 +2094,6 @@ impl Entity for MailAddressAliasGetIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailAddressAliasServiceData { pub _format: i64, @@ -2445,9 +2109,6 @@ impl Entity for MailAddressAliasServiceData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailAddressAliasServiceDataDelete { pub _format: i64, @@ -2464,9 +2125,6 @@ impl Entity for MailAddressAliasServiceDataDelete { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailAddressAliasServiceReturn { pub _format: i64, @@ -2484,9 +2142,6 @@ impl Entity for MailAddressAliasServiceReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailAddressAvailability { pub _id: CustomId, @@ -2502,9 +2157,6 @@ impl Entity for MailAddressAvailability { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailAddressToGroup { pub _format: i64, @@ -2522,9 +2174,6 @@ impl Entity for MailAddressToGroup { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MembershipAddData { pub _format: i64, @@ -2544,9 +2193,6 @@ impl Entity for MembershipAddData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MembershipPutIn { pub _format: i64, @@ -2561,9 +2207,6 @@ impl Entity for MembershipPutIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MembershipRemoveData { pub _format: i64, @@ -2579,9 +2222,6 @@ impl Entity for MembershipRemoveData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MissedNotification { pub _format: i64, @@ -2608,9 +2248,6 @@ impl Entity for MissedNotification { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MultipleMailAddressAvailabilityData { pub _format: i64, @@ -2625,9 +2262,6 @@ impl Entity for MultipleMailAddressAvailabilityData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MultipleMailAddressAvailabilityReturn { pub _format: i64, @@ -2642,9 +2276,6 @@ impl Entity for MultipleMailAddressAvailabilityReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct NotificationInfo { pub _id: CustomId, @@ -2661,9 +2292,6 @@ impl Entity for NotificationInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct NotificationMailTemplate { pub _id: CustomId, @@ -2680,9 +2308,6 @@ impl Entity for NotificationMailTemplate { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct NotificationSessionKey { pub _id: CustomId, @@ -2699,9 +2324,6 @@ impl Entity for NotificationSessionKey { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct OrderProcessingAgreement { pub _format: i64, @@ -2728,9 +2350,6 @@ impl Entity for OrderProcessingAgreement { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct OtpChallenge { pub _id: CustomId, @@ -2745,9 +2364,6 @@ impl Entity for OtpChallenge { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PaymentDataServiceGetData { pub _format: i64, @@ -2762,9 +2378,6 @@ impl Entity for PaymentDataServiceGetData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PaymentDataServiceGetReturn { pub _format: i64, @@ -2779,9 +2392,6 @@ impl Entity for PaymentDataServiceGetReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PaymentDataServicePostData { pub _format: i64, @@ -2796,9 +2406,6 @@ impl Entity for PaymentDataServicePostData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PaymentDataServicePutData { pub _format: i64, @@ -2824,9 +2431,6 @@ impl Entity for PaymentDataServicePutData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PaymentDataServicePutReturn { pub _format: i64, @@ -2842,9 +2446,6 @@ impl Entity for PaymentDataServicePutReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PaymentErrorInfo { pub _id: CustomId, @@ -2861,9 +2462,6 @@ impl Entity for PaymentErrorInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Permission { pub _format: i64, @@ -2895,9 +2493,6 @@ impl Entity for Permission { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PlanConfiguration { pub _id: CustomId, @@ -2921,9 +2516,6 @@ impl Entity for PlanConfiguration { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PlanPrices { pub _id: CustomId, @@ -2950,9 +2542,6 @@ impl Entity for PlanPrices { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PlanServiceGetOut { pub _format: i64, @@ -2967,9 +2556,6 @@ impl Entity for PlanServiceGetOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PriceData { pub _id: CustomId, @@ -2987,9 +2573,6 @@ impl Entity for PriceData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PriceItemData { pub _id: CustomId, @@ -3007,9 +2590,6 @@ impl Entity for PriceItemData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PriceRequestData { pub _id: CustomId, @@ -3029,9 +2609,6 @@ impl Entity for PriceRequestData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PriceServiceData { pub _format: i64, @@ -3047,9 +2624,6 @@ impl Entity for PriceServiceData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PriceServiceReturn { pub _format: i64, @@ -3068,9 +2642,6 @@ impl Entity for PriceServiceReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PubEncKeyData { pub _id: CustomId, @@ -3091,9 +2662,6 @@ impl Entity for PubEncKeyData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PublicKeyGetIn { pub _format: i64, @@ -3110,9 +2678,6 @@ impl Entity for PublicKeyGetIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PublicKeyGetOut { pub _format: i64, @@ -3133,9 +2698,6 @@ impl Entity for PublicKeyGetOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PublicKeyPutIn { pub _format: i64, @@ -3154,9 +2716,6 @@ impl Entity for PublicKeyPutIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PushIdentifier { pub _area: i64, @@ -3188,9 +2747,6 @@ impl Entity for PushIdentifier { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PushIdentifierList { pub _id: CustomId, @@ -3205,9 +2761,6 @@ impl Entity for PushIdentifierList { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ReceivedGroupInvitation { pub _format: i64, @@ -3240,9 +2793,6 @@ impl Entity for ReceivedGroupInvitation { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RecoverCode { pub _format: i64, @@ -3266,9 +2816,6 @@ impl Entity for RecoverCode { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RecoverCodeData { pub _id: CustomId, @@ -3289,9 +2836,6 @@ impl Entity for RecoverCodeData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ReferralCodeGetIn { pub _format: i64, @@ -3306,9 +2850,6 @@ impl Entity for ReferralCodeGetIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ReferralCodePostIn { pub _format: i64, @@ -3322,9 +2863,6 @@ impl Entity for ReferralCodePostIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ReferralCodePostOut { pub _format: i64, @@ -3339,9 +2877,6 @@ impl Entity for ReferralCodePostOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RegistrationCaptchaServiceData { pub _format: i64, @@ -3357,9 +2892,6 @@ impl Entity for RegistrationCaptchaServiceData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RegistrationCaptchaServiceGetData { pub _format: i64, @@ -3378,9 +2910,6 @@ impl Entity for RegistrationCaptchaServiceGetData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RegistrationCaptchaServiceReturn { pub _format: i64, @@ -3397,9 +2926,6 @@ impl Entity for RegistrationCaptchaServiceReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RegistrationReturn { pub _format: i64, @@ -3414,9 +2940,6 @@ impl Entity for RegistrationReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RegistrationServiceData { pub _format: i64, @@ -3433,9 +2956,6 @@ impl Entity for RegistrationServiceData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RejectedSender { pub _format: i64, @@ -3457,9 +2977,6 @@ impl Entity for RejectedSender { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RejectedSendersRef { pub _id: CustomId, @@ -3474,9 +2991,6 @@ impl Entity for RejectedSendersRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RepeatRule { pub _id: CustomId, @@ -3497,9 +3011,6 @@ impl Entity for RepeatRule { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ResetFactorsDeleteData { pub _format: i64, @@ -3516,9 +3027,6 @@ impl Entity for ResetFactorsDeleteData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ResetPasswordPostIn { pub _format: i64, @@ -3541,9 +3049,6 @@ impl Entity for ResetPasswordPostIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RootInstance { pub _format: i64, @@ -3561,9 +3066,6 @@ impl Entity for RootInstance { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SaltData { pub _format: i64, @@ -3578,9 +3080,6 @@ impl Entity for SaltData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SaltReturn { pub _format: i64, @@ -3597,9 +3096,6 @@ impl Entity for SaltReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SecondFactor { pub _format: i64, @@ -3622,9 +3118,6 @@ impl Entity for SecondFactor { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SecondFactorAuthAllowedReturn { pub _format: i64, @@ -3639,9 +3132,6 @@ impl Entity for SecondFactorAuthAllowedReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SecondFactorAuthData { pub _format: i64, @@ -3661,9 +3151,6 @@ impl Entity for SecondFactorAuthData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SecondFactorAuthDeleteData { pub _format: i64, @@ -3678,9 +3165,6 @@ impl Entity for SecondFactorAuthDeleteData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SecondFactorAuthGetData { pub _format: i64, @@ -3695,9 +3179,6 @@ impl Entity for SecondFactorAuthGetData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SecondFactorAuthGetReturn { pub _format: i64, @@ -3712,9 +3193,6 @@ impl Entity for SecondFactorAuthGetReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SecondFactorAuthentication { pub _format: i64, @@ -3735,9 +3213,6 @@ impl Entity for SecondFactorAuthentication { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SendRegistrationCodeData { pub _format: i64, @@ -3755,9 +3230,6 @@ impl Entity for SendRegistrationCodeData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SendRegistrationCodeReturn { pub _format: i64, @@ -3772,9 +3244,6 @@ impl Entity for SendRegistrationCodeReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SentGroupInvitation { pub _format: i64, @@ -3795,9 +3264,6 @@ impl Entity for SentGroupInvitation { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Session { pub _format: i64, @@ -3828,9 +3294,6 @@ impl Entity for Session { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SignOrderProcessingAgreementData { pub _format: i64, @@ -3846,9 +3309,6 @@ impl Entity for SignOrderProcessingAgreementData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SseConnectData { pub _format: i64, @@ -3864,9 +3324,6 @@ impl Entity for SseConnectData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct StringConfigValue { pub _id: CustomId, @@ -3882,9 +3339,6 @@ impl Entity for StringConfigValue { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct StringWrapper { pub _id: CustomId, @@ -3899,9 +3353,6 @@ impl Entity for StringWrapper { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SurveyData { pub _id: CustomId, @@ -3919,9 +3370,6 @@ impl Entity for SurveyData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SwitchAccountTypePostIn { pub _format: i64, @@ -3942,9 +3390,6 @@ impl Entity for SwitchAccountTypePostIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SystemKeysReturn { pub _format: i64, @@ -3973,9 +3418,6 @@ impl Entity for SystemKeysReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct TakeOverDeletedAddressData { pub _format: i64, @@ -3993,9 +3435,6 @@ impl Entity for TakeOverDeletedAddressData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct TypeInfo { pub _id: CustomId, @@ -4011,9 +3450,6 @@ impl Entity for TypeInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct U2fChallenge { pub _id: CustomId, @@ -4030,9 +3466,6 @@ impl Entity for U2fChallenge { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct U2fKey { pub _id: CustomId, @@ -4050,9 +3483,6 @@ impl Entity for U2fKey { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct U2fRegisteredDevice { pub _id: CustomId, @@ -4073,9 +3503,6 @@ impl Entity for U2fRegisteredDevice { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct U2fResponseData { pub _id: CustomId, @@ -4092,9 +3519,6 @@ impl Entity for U2fResponseData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UpdatePermissionKeyData { pub _format: i64, @@ -4113,9 +3537,6 @@ impl Entity for UpdatePermissionKeyData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UpdateSessionKeysPostIn { pub _format: i64, @@ -4130,9 +3551,6 @@ impl Entity for UpdateSessionKeysPostIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UpgradePriceServiceData { pub _format: i64, @@ -4149,9 +3567,6 @@ impl Entity for UpgradePriceServiceData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UpgradePriceServiceReturn { pub _format: i64, @@ -4180,9 +3595,6 @@ impl Entity for UpgradePriceServiceReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct User { pub _format: i64, @@ -4218,9 +3630,6 @@ impl Entity for User { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserAlarmInfo { pub _format: i64, @@ -4243,9 +3652,6 @@ impl Entity for UserAlarmInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserAlarmInfoListType { pub _id: CustomId, @@ -4260,9 +3666,6 @@ impl Entity for UserAlarmInfoListType { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserAreaGroups { pub _id: CustomId, @@ -4277,9 +3680,6 @@ impl Entity for UserAreaGroups { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserAuthentication { pub _id: CustomId, @@ -4296,9 +3696,6 @@ impl Entity for UserAuthentication { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserDataDelete { pub _format: i64, @@ -4315,9 +3712,6 @@ impl Entity for UserDataDelete { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserExternalAuthInfo { pub _id: CustomId, @@ -4337,9 +3731,6 @@ impl Entity for UserExternalAuthInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserGroupKeyDistribution { pub _format: i64, @@ -4359,9 +3750,6 @@ impl Entity for UserGroupKeyDistribution { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserGroupKeyRotationData { pub _id: CustomId, @@ -4391,9 +3779,6 @@ impl Entity for UserGroupKeyRotationData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserGroupKeyRotationPostIn { pub _format: i64, @@ -4408,9 +3793,6 @@ impl Entity for UserGroupKeyRotationPostIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserGroupRoot { pub _format: i64, @@ -4430,9 +3812,6 @@ impl Entity for UserGroupRoot { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct VariableExternalAuthInfo { pub _format: i64, @@ -4457,9 +3836,6 @@ impl Entity for VariableExternalAuthInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct VerifyRegistrationCodeData { pub _format: i64, @@ -4475,9 +3851,6 @@ impl Entity for VerifyRegistrationCodeData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Version { pub _id: CustomId, @@ -4496,9 +3869,6 @@ impl Entity for Version { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct VersionData { pub _format: i64, @@ -4516,9 +3886,6 @@ impl Entity for VersionData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct VersionInfo { pub _format: i64, @@ -4545,9 +3912,6 @@ impl Entity for VersionInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct VersionReturn { pub _format: i64, @@ -4562,9 +3926,6 @@ impl Entity for VersionReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct WebauthnResponseData { pub _id: CustomId, @@ -4586,9 +3947,6 @@ impl Entity for WebauthnResponseData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct WebsocketCounterData { pub _format: i64, @@ -4604,9 +3962,6 @@ impl Entity for WebsocketCounterData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct WebsocketCounterValue { pub _id: CustomId, @@ -4622,9 +3977,6 @@ impl Entity for WebsocketCounterValue { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct WebsocketEntityData { pub _format: i64, @@ -4641,9 +3993,6 @@ impl Entity for WebsocketEntityData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct WebsocketLeaderStatus { pub _format: i64, @@ -4658,9 +4007,6 @@ impl Entity for WebsocketLeaderStatus { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct WhitelabelChild { pub _format: i64, @@ -4687,9 +4033,6 @@ impl Entity for WhitelabelChild { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct WhitelabelChildrenRef { pub _id: CustomId, @@ -4704,9 +4047,6 @@ impl Entity for WhitelabelChildrenRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct WhitelabelConfig { pub _format: i64, @@ -4732,9 +4072,6 @@ impl Entity for WhitelabelConfig { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct WhitelabelParent { pub _id: CustomId, @@ -4749,6 +4086,3 @@ impl Entity for WhitelabelParent { } } } - - - diff --git a/tuta-sdk/rust/sdk/src/entities/tutanota.rs b/tuta-sdk/rust/sdk/src/entities/tutanota.rs index c3661696e98f..7a8a21a37fad 100644 --- a/tuta-sdk/rust/sdk/src/entities/tutanota.rs +++ b/tuta-sdk/rust/sdk/src/entities/tutanota.rs @@ -20,9 +20,6 @@ impl Entity for AttachmentKeyData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Birthday { pub _id: CustomId, @@ -39,9 +36,6 @@ impl Entity for Birthday { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Body { pub _id: CustomId, @@ -58,9 +52,6 @@ impl Entity for Body { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CalendarDeleteData { pub _format: i64, @@ -75,9 +66,6 @@ impl Entity for CalendarDeleteData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CalendarEvent { pub _format: i64, @@ -114,9 +102,6 @@ impl Entity for CalendarEvent { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CalendarEventAttendee { pub _id: CustomId, @@ -133,9 +118,6 @@ impl Entity for CalendarEventAttendee { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CalendarEventIndexRef { pub _id: CustomId, @@ -150,9 +132,6 @@ impl Entity for CalendarEventIndexRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CalendarEventUidIndex { pub _format: i64, @@ -171,9 +150,6 @@ impl Entity for CalendarEventUidIndex { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CalendarEventUpdate { pub _format: i64, @@ -197,9 +173,6 @@ impl Entity for CalendarEventUpdate { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CalendarEventUpdateList { pub _id: CustomId, @@ -214,9 +187,6 @@ impl Entity for CalendarEventUpdateList { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CalendarGroupRoot { pub _format: i64, @@ -241,9 +211,6 @@ impl Entity for CalendarGroupRoot { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CalendarRepeatRule { pub _id: CustomId, @@ -264,9 +231,6 @@ impl Entity for CalendarRepeatRule { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Contact { pub _format: i64, @@ -315,9 +279,6 @@ impl Entity for Contact { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactAddress { pub _id: CustomId, @@ -336,9 +297,6 @@ impl Entity for ContactAddress { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactCustomDate { pub _id: CustomId, @@ -357,9 +315,6 @@ impl Entity for ContactCustomDate { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactList { pub _format: i64, @@ -383,9 +338,6 @@ impl Entity for ContactList { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactListEntry { pub _format: i64, @@ -408,9 +360,6 @@ impl Entity for ContactListEntry { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactListGroupRoot { pub _format: i64, @@ -433,9 +382,6 @@ impl Entity for ContactListGroupRoot { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactMailAddress { pub _id: CustomId, @@ -454,9 +400,6 @@ impl Entity for ContactMailAddress { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactMessengerHandle { pub _id: CustomId, @@ -475,9 +418,6 @@ impl Entity for ContactMessengerHandle { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactPhoneNumber { pub _id: CustomId, @@ -496,9 +436,6 @@ impl Entity for ContactPhoneNumber { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactPronouns { pub _id: CustomId, @@ -515,9 +452,6 @@ impl Entity for ContactPronouns { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactRelationship { pub _id: CustomId, @@ -536,9 +470,6 @@ impl Entity for ContactRelationship { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactSocialId { pub _id: CustomId, @@ -557,9 +488,6 @@ impl Entity for ContactSocialId { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ContactWebsite { pub _id: CustomId, @@ -578,9 +506,6 @@ impl Entity for ContactWebsite { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ConversationEntry { pub _format: i64, @@ -601,9 +526,6 @@ impl Entity for ConversationEntry { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CreateExternalUserGroupData { pub _id: CustomId, @@ -623,9 +545,6 @@ impl Entity for CreateExternalUserGroupData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CreateGroupPostReturn { pub _format: i64, @@ -642,9 +561,6 @@ impl Entity for CreateGroupPostReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CreateMailFolderData { pub _format: i64, @@ -666,9 +582,6 @@ impl Entity for CreateMailFolderData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CreateMailFolderReturn { pub _format: i64, @@ -685,9 +598,6 @@ impl Entity for CreateMailFolderReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CreateMailGroupData { pub _format: i64, @@ -707,9 +617,6 @@ impl Entity for CreateMailGroupData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct CustomerAccountCreateData { pub _format: i64, @@ -744,9 +651,6 @@ impl Entity for CustomerAccountCreateData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DefaultAlarmInfo { pub _id: CustomId, @@ -762,9 +666,6 @@ impl Entity for DefaultAlarmInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DeleteGroupData { pub _format: i64, @@ -780,9 +681,6 @@ impl Entity for DeleteGroupData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DeleteMailData { pub _format: i64, @@ -798,9 +696,6 @@ impl Entity for DeleteMailData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DeleteMailFolderData { pub _format: i64, @@ -817,9 +712,6 @@ impl Entity for DeleteMailFolderData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DraftAttachment { pub _id: CustomId, @@ -838,9 +730,6 @@ impl Entity for DraftAttachment { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DraftCreateData { pub _format: i64, @@ -862,9 +751,6 @@ impl Entity for DraftCreateData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DraftCreateReturn { pub _format: i64, @@ -879,9 +765,6 @@ impl Entity for DraftCreateReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DraftData { pub _id: CustomId, @@ -909,9 +792,6 @@ impl Entity for DraftData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DraftRecipient { pub _id: CustomId, @@ -928,9 +808,6 @@ impl Entity for DraftRecipient { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DraftUpdateData { pub _format: i64, @@ -948,9 +825,6 @@ impl Entity for DraftUpdateData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct DraftUpdateReturn { pub _format: i64, @@ -967,9 +841,6 @@ impl Entity for DraftUpdateReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct EmailTemplate { pub _format: i64, @@ -994,9 +865,6 @@ impl Entity for EmailTemplate { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct EmailTemplateContent { pub _id: CustomId, @@ -1013,9 +881,6 @@ impl Entity for EmailTemplateContent { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct EncryptTutanotaPropertiesData { pub _format: i64, @@ -1033,9 +898,6 @@ impl Entity for EncryptTutanotaPropertiesData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct EncryptedMailAddress { pub _id: CustomId, @@ -1052,9 +914,6 @@ impl Entity for EncryptedMailAddress { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct EntropyData { pub _format: i64, @@ -1071,9 +930,6 @@ impl Entity for EntropyData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ExternalUserData { pub _format: i64, @@ -1108,9 +964,6 @@ impl Entity for ExternalUserData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct TutanotaFile { pub _format: i64, @@ -1139,9 +992,6 @@ impl Entity for TutanotaFile { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct FileSystem { pub _format: i64, @@ -1164,9 +1014,6 @@ impl Entity for FileSystem { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupInvitationDeleteData { pub _format: i64, @@ -1181,9 +1028,6 @@ impl Entity for GroupInvitationDeleteData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupInvitationPostData { pub _format: i64, @@ -1199,9 +1043,6 @@ impl Entity for GroupInvitationPostData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupInvitationPostReturn { pub _format: i64, @@ -1218,9 +1059,6 @@ impl Entity for GroupInvitationPostReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupInvitationPutData { pub _format: i64, @@ -1241,9 +1079,6 @@ impl Entity for GroupInvitationPutData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct GroupSettings { pub _id: CustomId, @@ -1263,9 +1098,6 @@ impl Entity for GroupSettings { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Header { pub _id: CustomId, @@ -1282,9 +1114,6 @@ impl Entity for Header { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ImapFolder { pub _id: CustomId, @@ -1302,9 +1131,6 @@ impl Entity for ImapFolder { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ImapSyncConfiguration { pub _id: CustomId, @@ -1323,9 +1149,6 @@ impl Entity for ImapSyncConfiguration { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ImapSyncState { pub _format: i64, @@ -1343,9 +1166,6 @@ impl Entity for ImapSyncState { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct InboxRule { pub _id: CustomId, @@ -1364,9 +1184,6 @@ impl Entity for InboxRule { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct InternalGroupData { pub _id: CustomId, @@ -1399,9 +1216,6 @@ impl Entity for InternalGroupData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct InternalRecipientKeyData { pub _id: CustomId, @@ -1421,9 +1235,6 @@ impl Entity for InternalRecipientKeyData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct KnowledgeBaseEntry { pub _format: i64, @@ -1448,9 +1259,6 @@ impl Entity for KnowledgeBaseEntry { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct KnowledgeBaseEntryKeyword { pub _id: CustomId, @@ -1466,9 +1274,6 @@ impl Entity for KnowledgeBaseEntryKeyword { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ListUnsubscribeData { pub _format: i64, @@ -1485,9 +1290,6 @@ impl Entity for ListUnsubscribeData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Mail { pub _format: i64, @@ -1531,9 +1333,6 @@ impl Entity for Mail { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailAddress { pub _id: CustomId, @@ -1551,9 +1350,6 @@ impl Entity for MailAddress { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailAddressProperties { pub _id: CustomId, @@ -1570,9 +1366,6 @@ impl Entity for MailAddressProperties { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailBag { pub _id: CustomId, @@ -1587,9 +1380,6 @@ impl Entity for MailBag { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailBox { pub _format: i64, @@ -1619,9 +1409,6 @@ impl Entity for MailBox { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailDetails { pub _id: CustomId, @@ -1641,9 +1428,6 @@ impl Entity for MailDetails { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailDetailsBlob { pub _format: i64, @@ -1666,9 +1450,6 @@ impl Entity for MailDetailsBlob { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailDetailsDraft { pub _format: i64, @@ -1691,9 +1472,6 @@ impl Entity for MailDetailsDraft { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailDetailsDraftsRef { pub _id: CustomId, @@ -1708,9 +1486,6 @@ impl Entity for MailDetailsDraftsRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailFolder { pub _format: i64, @@ -1739,9 +1514,6 @@ impl Entity for MailFolder { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailFolderRef { pub _id: CustomId, @@ -1756,9 +1528,6 @@ impl Entity for MailFolderRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailSetEntry { pub _format: i64, @@ -1776,9 +1545,6 @@ impl Entity for MailSetEntry { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailboxGroupRoot { pub _format: i64, @@ -1802,9 +1568,6 @@ impl Entity for MailboxGroupRoot { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailboxProperties { pub _format: i64, @@ -1828,9 +1591,6 @@ impl Entity for MailboxProperties { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MailboxServerProperties { pub _format: i64, @@ -1848,9 +1608,6 @@ impl Entity for MailboxServerProperties { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct MoveMailData { pub _format: i64, @@ -1867,9 +1624,6 @@ impl Entity for MoveMailData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct NewDraftAttachment { pub _id: CustomId, @@ -1890,9 +1644,6 @@ impl Entity for NewDraftAttachment { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct NewsId { pub _id: CustomId, @@ -1908,9 +1659,6 @@ impl Entity for NewsId { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct NewsIn { pub _format: i64, @@ -1925,9 +1673,6 @@ impl Entity for NewsIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct NewsOut { pub _format: i64, @@ -1942,9 +1687,6 @@ impl Entity for NewsOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct NotificationMail { pub _id: CustomId, @@ -1963,9 +1705,6 @@ impl Entity for NotificationMail { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct OutOfOfficeNotification { pub _format: i64, @@ -1986,9 +1725,6 @@ impl Entity for OutOfOfficeNotification { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct OutOfOfficeNotificationMessage { pub _id: CustomId, @@ -2006,9 +1742,6 @@ impl Entity for OutOfOfficeNotificationMessage { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct OutOfOfficeNotificationRecipientList { pub _id: CustomId, @@ -2023,9 +1756,6 @@ impl Entity for OutOfOfficeNotificationRecipientList { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PhishingMarkerWebsocketData { pub _format: i64, @@ -2041,9 +1771,6 @@ impl Entity for PhishingMarkerWebsocketData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct PhotosRef { pub _id: CustomId, @@ -2058,9 +1785,6 @@ impl Entity for PhotosRef { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ReceiveInfoServiceData { pub _format: i64, @@ -2075,9 +1799,6 @@ impl Entity for ReceiveInfoServiceData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Recipients { pub _id: CustomId, @@ -2094,9 +1815,6 @@ impl Entity for Recipients { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct RemoteImapSyncInfo { pub _format: i64, @@ -2115,9 +1833,6 @@ impl Entity for RemoteImapSyncInfo { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ReportMailPostData { pub _format: i64, @@ -2135,9 +1850,6 @@ impl Entity for ReportMailPostData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ReportedMailFieldMarker { pub _id: CustomId, @@ -2153,9 +1865,6 @@ impl Entity for ReportedMailFieldMarker { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SecureExternalRecipientKeyData { pub _id: CustomId, @@ -2183,9 +1892,6 @@ impl Entity for SecureExternalRecipientKeyData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SendDraftData { pub _format: i64, @@ -2214,9 +1920,6 @@ impl Entity for SendDraftData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SendDraftReturn { pub _format: i64, @@ -2234,9 +1937,6 @@ impl Entity for SendDraftReturn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SharedGroupData { pub _id: CustomId, @@ -2265,9 +1965,6 @@ impl Entity for SharedGroupData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SpamResults { pub _id: CustomId, @@ -2282,9 +1979,6 @@ impl Entity for SpamResults { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Subfiles { pub _id: CustomId, @@ -2299,9 +1993,6 @@ impl Entity for Subfiles { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SymEncInternalRecipientKeyData { pub _id: CustomId, @@ -2320,9 +2011,6 @@ impl Entity for SymEncInternalRecipientKeyData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct TemplateGroupRoot { pub _format: i64, @@ -2346,9 +2034,6 @@ impl Entity for TemplateGroupRoot { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct TranslationGetIn { pub _format: i64, @@ -2363,9 +2048,6 @@ impl Entity for TranslationGetIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct TranslationGetOut { pub _format: i64, @@ -2381,9 +2063,6 @@ impl Entity for TranslationGetOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct TutanotaProperties { pub _format: i64, @@ -2419,9 +2098,6 @@ impl Entity for TutanotaProperties { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UpdateMailFolderData { pub _format: i64, @@ -2437,9 +2113,6 @@ impl Entity for UpdateMailFolderData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserAccountCreateData { pub _format: i64, @@ -2456,9 +2129,6 @@ impl Entity for UserAccountCreateData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserAccountUserData { pub _id: CustomId, @@ -2513,9 +2183,6 @@ impl Entity for UserAccountUserData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserAreaGroupData { pub _id: CustomId, @@ -2543,9 +2210,6 @@ impl Entity for UserAreaGroupData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserAreaGroupDeleteData { pub _format: i64, @@ -2560,9 +2224,6 @@ impl Entity for UserAreaGroupDeleteData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserAreaGroupPostData { pub _format: i64, @@ -2577,9 +2238,6 @@ impl Entity for UserAreaGroupPostData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UserSettingsGroupRoot { pub _format: i64, @@ -2604,6 +2262,3 @@ impl Entity for UserSettingsGroupRoot { } } } - - - diff --git a/tuta-sdk/rust/sdk/src/entities/usage.rs b/tuta-sdk/rust/sdk/src/entities/usage.rs index 29498be13e2e..4ca0fe279dcf 100644 --- a/tuta-sdk/rust/sdk/src/entities/usage.rs +++ b/tuta-sdk/rust/sdk/src/entities/usage.rs @@ -20,9 +20,6 @@ impl Entity for UsageTestAssignment { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UsageTestAssignmentIn { pub _format: i64, @@ -37,9 +34,6 @@ impl Entity for UsageTestAssignmentIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UsageTestAssignmentOut { pub _format: i64, @@ -55,9 +49,6 @@ impl Entity for UsageTestAssignmentOut { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UsageTestMetricConfig { pub _id: CustomId, @@ -75,9 +66,6 @@ impl Entity for UsageTestMetricConfig { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UsageTestMetricConfigValue { pub _id: CustomId, @@ -93,9 +81,6 @@ impl Entity for UsageTestMetricConfigValue { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UsageTestMetricData { pub _id: CustomId, @@ -111,9 +96,6 @@ impl Entity for UsageTestMetricData { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UsageTestParticipationIn { pub _format: i64, @@ -131,9 +113,6 @@ impl Entity for UsageTestParticipationIn { } } - - - #[derive(uniffi::Record, Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct UsageTestStage { pub _id: CustomId, @@ -150,6 +129,3 @@ impl Entity for UsageTestStage { } } } - - - diff --git a/tuta-sdk/rust/sdk/src/lib.rs b/tuta-sdk/rust/sdk/src/lib.rs index 005c51355dda..ac579a80dc1e 100644 --- a/tuta-sdk/rust/sdk/src/lib.rs +++ b/tuta-sdk/rust/sdk/src/lib.rs @@ -112,6 +112,7 @@ pub struct HeadersProvider { } impl HeadersProvider { + #[must_use] pub fn new(client_version: String, access_token: Option) -> Self { Self { client_version, @@ -355,6 +356,7 @@ pub enum ApiCallError { } impl ApiCallError { + #[must_use] pub fn internal(message: String) -> ApiCallError { ApiCallError::InternalSdkError { error_message: message, diff --git a/tuta-sdk/rust/sdk/src/login/credentials.rs b/tuta-sdk/rust/sdk/src/login/credentials.rs index 8871d1fce638..c087f85252b7 100644 --- a/tuta-sdk/rust/sdk/src/login/credentials.rs +++ b/tuta-sdk/rust/sdk/src/login/credentials.rs @@ -2,15 +2,15 @@ use crate::generated_id::GeneratedId; #[derive(uniffi::Record, Clone)] pub struct Credentials { - pub login: String, - pub user_id: GeneratedId, - pub access_token: String, - pub encrypted_passphrase_key: Vec, - pub credential_type: CredentialType, + pub login: String, + pub user_id: GeneratedId, + pub access_token: String, + pub encrypted_passphrase_key: Vec, + pub credential_type: CredentialType, } #[derive(uniffi::Enum, Debug, PartialEq, Clone)] pub enum CredentialType { - Internal, - External, + Internal, + External, } diff --git a/tuta-sdk/rust/sdk/src/net/native_rest_client.rs b/tuta-sdk/rust/sdk/src/net/native_rest_client.rs index 08336beea795..8268973d7959 100644 --- a/tuta-sdk/rust/sdk/src/net/native_rest_client.rs +++ b/tuta-sdk/rust/sdk/src/net/native_rest_client.rs @@ -88,7 +88,7 @@ fn read_headers( header_map: &HeaderMap, ) -> Result, RestClientError> { let mut headers = HashMap::new(); - for (name, values) in header_map.iter() { + for (name, values) in header_map { let name_str = name.as_str(); let value_str = values .to_str() diff --git a/tuta-sdk/rust/sdk/src/net/vec_body.rs b/tuta-sdk/rust/sdk/src/net/vec_body.rs index f4af2537378a..b79cfa607ab8 100644 --- a/tuta-sdk/rust/sdk/src/net/vec_body.rs +++ b/tuta-sdk/rust/sdk/src/net/vec_body.rs @@ -3,49 +3,49 @@ use hyper::body::Buf; pub type VecBody = Full; pub struct VecBuf(pub Vec); -impl Into for VecBuf { - fn into(self) -> VecBody { - Full::new(self) - } +impl From for VecBody { + fn from(val: VecBuf) -> Self { + Full::new(val) + } } /// somewhat stolen from impl Buf for &[u8] /// also don't know why impl Buf for Vec doesn't come with hyper impl Buf for VecBuf { - #[inline] - fn remaining(&self) -> usize { - self.0.len() - } + #[inline] + fn remaining(&self) -> usize { + self.0.len() + } - #[inline] - fn chunk(&self) -> &[u8] { - self.0.as_slice() - } + #[inline] + fn chunk(&self) -> &[u8] { + self.0.as_slice() + } - #[inline] - fn advance(&mut self, cnt: usize) { - if self.0.len() < cnt { - panic_advance(cnt, self.0.len()); - } - self.0.drain(..cnt); - } + #[inline] + fn advance(&mut self, cnt: usize) { + if self.0.len() < cnt { + panic_advance(cnt, self.0.len()); + } + self.0.drain(..cnt); + } - #[inline] - fn copy_to_slice(&mut self, dst: &mut [u8]) { - if self.0.len() < dst.len() { - panic_advance(dst.len(), self.0.len()); - } + #[inline] + fn copy_to_slice(&mut self, dst: &mut [u8]) { + if self.0.len() < dst.len() { + panic_advance(dst.len(), self.0.len()); + } - dst.copy_from_slice(&self.0[..dst.len()]); - self.advance(dst.len()); - } + dst.copy_from_slice(&self.0[..dst.len()]); + self.advance(dst.len()); + } } /// Panic with a nice error message. #[cold] fn panic_advance(idx: usize, len: usize) -> ! { - panic!( - "advance out of bounds: the len is {} but advancing by {}", - len, idx - ); + panic!( + "advance out of bounds: the len is {} but advancing by {}", + len, idx + ); } diff --git a/tuta-sdk/rust/sdk/src/rest_error.rs b/tuta-sdk/rust/sdk/src/rest_error.rs index 45ffbed257f4..15e2e1d8b9ab 100644 --- a/tuta-sdk/rust/sdk/src/rest_error.rs +++ b/tuta-sdk/rust/sdk/src/rest_error.rs @@ -416,7 +416,7 @@ mod tests { result.expect("An error occurred while testing precondition_failed!") } - /** + /* Asserts `from_http_response` returns the reason `reason` given `precondition` for a `PreconditionFailedError` */ diff --git a/tuta-sdk/rust/sdk/src/services/accounting.rs b/tuta-sdk/rust/sdk/src/services/accounting.rs index 2c9647d516c6..dcdb1f6b3b43 100644 --- a/tuta-sdk/rust/sdk/src/services/accounting.rs +++ b/tuta-sdk/rust/sdk/src/services/accounting.rs @@ -1,11 +1,18 @@ #![allow(unused_imports, dead_code, unused_variables)] -use crate::ApiCallError; +use crate::entities::accounting::CustomerAccountReturn; use crate::entities::Entity; -use crate::services::{PostService, GetService, PutService, DeleteService, Service, Executor, ExtraServiceParams}; use crate::rest_client::HttpMethod; use crate::services::hidden::Nothing; -use crate::entities::accounting::CustomerAccountReturn; +use crate::services::{ + DeleteService, Executor, ExtraServiceParams, GetService, PostService, PutService, Service, +}; +use crate::ApiCallError; pub struct CustomerAccountService; -crate::service_impl!(base, CustomerAccountService, "accounting/customeraccountservice", 7); +crate::service_impl!( + base, + CustomerAccountService, + "accounting/customeraccountservice", + 7 +); crate::service_impl!(GET, CustomerAccountService, (), CustomerAccountReturn); diff --git a/tuta-sdk/rust/sdk/src/services/base.rs b/tuta-sdk/rust/sdk/src/services/base.rs index 213f090e5f55..95816926713d 100644 --- a/tuta-sdk/rust/sdk/src/services/base.rs +++ b/tuta-sdk/rust/sdk/src/services/base.rs @@ -1,6 +1,8 @@ #![allow(unused_imports, dead_code, unused_variables)] -use crate::ApiCallError; use crate::entities::Entity; -use crate::services::{PostService, GetService, PutService, DeleteService, Service, Executor, ExtraServiceParams}; use crate::rest_client::HttpMethod; -use crate::services::hidden::Nothing; \ No newline at end of file +use crate::services::hidden::Nothing; +use crate::services::{ + DeleteService, Executor, ExtraServiceParams, GetService, PostService, PutService, Service, +}; +use crate::ApiCallError; diff --git a/tuta-sdk/rust/sdk/src/services/gossip.rs b/tuta-sdk/rust/sdk/src/services/gossip.rs index 213f090e5f55..95816926713d 100644 --- a/tuta-sdk/rust/sdk/src/services/gossip.rs +++ b/tuta-sdk/rust/sdk/src/services/gossip.rs @@ -1,6 +1,8 @@ #![allow(unused_imports, dead_code, unused_variables)] -use crate::ApiCallError; use crate::entities::Entity; -use crate::services::{PostService, GetService, PutService, DeleteService, Service, Executor, ExtraServiceParams}; use crate::rest_client::HttpMethod; -use crate::services::hidden::Nothing; \ No newline at end of file +use crate::services::hidden::Nothing; +use crate::services::{ + DeleteService, Executor, ExtraServiceParams, GetService, PostService, PutService, Service, +}; +use crate::ApiCallError; diff --git a/tuta-sdk/rust/sdk/src/services/monitor.rs b/tuta-sdk/rust/sdk/src/services/monitor.rs index 8e21549ed79d..923d9bb95ef1 100644 --- a/tuta-sdk/rust/sdk/src/services/monitor.rs +++ b/tuta-sdk/rust/sdk/src/services/monitor.rs @@ -1,20 +1,21 @@ #![allow(unused_imports, dead_code, unused_variables)] -use crate::ApiCallError; -use crate::entities::Entity; -use crate::services::{PostService, GetService, PutService, DeleteService, Service, Executor, ExtraServiceParams}; -use crate::rest_client::HttpMethod; -use crate::services::hidden::Nothing; -use crate::entities::monitor::WriteCounterData; use crate::entities::monitor::ReadCounterData; use crate::entities::monitor::ReadCounterReturn; use crate::entities::monitor::ReportErrorIn; +use crate::entities::monitor::WriteCounterData; +use crate::entities::Entity; +use crate::rest_client::HttpMethod; +use crate::services::hidden::Nothing; +use crate::services::{ + DeleteService, Executor, ExtraServiceParams, GetService, PostService, PutService, Service, +}; +use crate::ApiCallError; pub struct CounterService; crate::service_impl!(base, CounterService, "monitor/counterservice", 28); crate::service_impl!(POST, CounterService, WriteCounterData, ()); crate::service_impl!(GET, CounterService, ReadCounterData, ReadCounterReturn); - pub struct ReportErrorService; crate::service_impl!(base, ReportErrorService, "monitor/reporterrorservice", 28); diff --git a/tuta-sdk/rust/sdk/src/services/service_executor.rs b/tuta-sdk/rust/sdk/src/services/service_executor.rs index 3493d958caeb..24d8397b5d25 100644 --- a/tuta-sdk/rust/sdk/src/services/service_executor.rs +++ b/tuta-sdk/rust/sdk/src/services/service_executor.rs @@ -257,7 +257,7 @@ mod tests { HelloEncInput, HelloEncOutput, HelloEncryptedService, HelloUnEncInput, HelloUnEncOutput, HelloUnEncryptedService, APP_VERSION_STR, }; - use crate::services::{test_services, ExtraServiceParams, GetService}; + use crate::services::{test_services, ExtraServiceParams}; use crate::type_model_provider::TypeModelProvider; use crate::HeadersProvider; use base64::prelude::BASE64_STANDARD; @@ -270,7 +270,7 @@ mod tests { let hello_input_data = HelloUnEncInput { message: "Something".to_string(), }; - let executor = maps_unencrypted_data_and_response(HttpMethod::POST).await; + let executor = maps_unencrypted_data_and_response(HttpMethod::POST); let result = executor .post::(hello_input_data, ExtraServiceParams::default()) .await; @@ -289,7 +289,7 @@ mod tests { let hello_input_data = HelloUnEncInput { message: "Something".to_string(), }; - let executor = maps_unencrypted_data_and_response(HttpMethod::PUT).await; + let executor = maps_unencrypted_data_and_response(HttpMethod::PUT); let result = executor .put::(hello_input_data, ExtraServiceParams::default()) .await; @@ -308,7 +308,7 @@ mod tests { let hello_input_data = HelloUnEncInput { message: "Something".to_string(), }; - let executor = maps_unencrypted_data_and_response(HttpMethod::GET).await; + let executor = maps_unencrypted_data_and_response(HttpMethod::GET); let result = executor .get::(hello_input_data, ExtraServiceParams::default()) .await; @@ -327,7 +327,7 @@ mod tests { let hello_input_data = HelloUnEncInput { message: "Something".to_string(), }; - let executor = maps_unencrypted_data_and_response(HttpMethod::DELETE).await; + let executor = maps_unencrypted_data_and_response(HttpMethod::DELETE); let result = executor .delete::(hello_input_data, ExtraServiceParams::default()) .await; @@ -345,11 +345,12 @@ mod tests { pub async fn post_should_decrypt_map_encrypted_data_and_response() { let session_key = GenericAesKey::from_bytes(&rand::random::<[u8; AES_256_KEY_SIZE]>()).unwrap(); - let executor = - maps_encrypted_data_and_response_data(HttpMethod::POST, session_key.clone()).await; + let executor = maps_encrypted_data_and_response_data(HttpMethod::POST, session_key.clone()); - let mut params = ExtraServiceParams::default(); - params.session_key = Some(session_key.clone()); + let params = ExtraServiceParams { + session_key: Some(session_key.clone()), + ..Default::default() + }; let input_entity = HelloEncInput { message: "my encrypted request".to_string(), }; @@ -371,11 +372,12 @@ mod tests { pub async fn put_should_decrypt_map_encrypted_data_and_response() { let session_key = GenericAesKey::from_bytes(&rand::random::<[u8; AES_256_KEY_SIZE]>()).unwrap(); - let executor = - maps_encrypted_data_and_response_data(HttpMethod::PUT, session_key.clone()).await; + let executor = maps_encrypted_data_and_response_data(HttpMethod::PUT, session_key.clone()); - let mut params = ExtraServiceParams::default(); - params.session_key = Some(session_key.clone()); + let params = ExtraServiceParams { + session_key: Some(session_key.clone()), + ..Default::default() + }; let input_entity = HelloEncInput { message: "my encrypted request".to_string(), }; @@ -397,11 +399,12 @@ mod tests { pub async fn get_should_decrypt_map_encrypted_data_and_response() { let session_key = GenericAesKey::from_bytes(&rand::random::<[u8; AES_256_KEY_SIZE]>()).unwrap(); - let executor = - maps_encrypted_data_and_response_data(HttpMethod::GET, session_key.clone()).await; + let executor = maps_encrypted_data_and_response_data(HttpMethod::GET, session_key.clone()); - let mut params = ExtraServiceParams::default(); - params.session_key = Some(session_key.clone()); + let params = ExtraServiceParams { + session_key: Some(session_key.clone()), + ..Default::default() + }; let input_entity = HelloEncInput { message: "my encrypted request".to_string(), }; @@ -424,10 +427,12 @@ mod tests { let session_key = GenericAesKey::from_bytes(&rand::random::<[u8; AES_256_KEY_SIZE]>()).unwrap(); let executor = - maps_encrypted_data_and_response_data(HttpMethod::DELETE, session_key.clone()).await; + maps_encrypted_data_and_response_data(HttpMethod::DELETE, session_key.clone()); - let mut params = ExtraServiceParams::default(); - params.session_key = Some(session_key.clone()); + let params = ExtraServiceParams { + session_key: Some(session_key.clone()), + ..Default::default() + }; let input_entity = HelloEncInput { message: "my encrypted request".to_string(), }; @@ -473,7 +478,7 @@ mod tests { ) } - async fn maps_unencrypted_data_and_response(http_method: HttpMethod) -> ServiceExecutor { + fn maps_unencrypted_data_and_response(http_method: HttpMethod) -> ServiceExecutor { let executor = setup(); let rest_client; let entity_facade; @@ -533,7 +538,7 @@ mod tests { executor } - pub async fn maps_encrypted_data_and_response_data( + pub fn maps_encrypted_data_and_response_data( http_method: HttpMethod, session_key: GenericAesKey, ) -> ServiceExecutor { @@ -599,7 +604,7 @@ mod tests { .expect_resolve_session_key() .returning(move |_entity, model| { assert_eq!(("test", "HelloEncOutput"), (model.app, model.name)); - assert_eq!(true, model.marked_encrypted()); + assert!(model.marked_encrypted()); Ok(Some(ResolvedSessionKey { session_key: session_key_clone.clone(), diff --git a/tuta-sdk/rust/sdk/src/services/storage.rs b/tuta-sdk/rust/sdk/src/services/storage.rs index 03a8713cfce8..71613f9c474f 100644 --- a/tuta-sdk/rust/sdk/src/services/storage.rs +++ b/tuta-sdk/rust/sdk/src/services/storage.rs @@ -1,28 +1,43 @@ #![allow(unused_imports, dead_code, unused_variables)] -use crate::ApiCallError; -use crate::entities::Entity; -use crate::services::{PostService, GetService, PutService, DeleteService, Service, Executor, ExtraServiceParams}; -use crate::rest_client::HttpMethod; -use crate::services::hidden::Nothing; use crate::entities::storage::BlobAccessTokenPostIn; use crate::entities::storage::BlobAccessTokenPostOut; -use crate::entities::storage::BlobReferencePutIn; -use crate::entities::storage::BlobReferenceDeleteIn; -use crate::entities::storage::BlobPostOut; use crate::entities::storage::BlobGetIn; +use crate::entities::storage::BlobPostOut; +use crate::entities::storage::BlobReferenceDeleteIn; +use crate::entities::storage::BlobReferencePutIn; +use crate::entities::Entity; +use crate::rest_client::HttpMethod; +use crate::services::hidden::Nothing; +use crate::services::{ + DeleteService, Executor, ExtraServiceParams, GetService, PostService, PutService, Service, +}; +use crate::ApiCallError; pub struct BlobAccessTokenService; -crate::service_impl!(base, BlobAccessTokenService, "storage/blobaccesstokenservice", 9); -crate::service_impl!(POST, BlobAccessTokenService, BlobAccessTokenPostIn, BlobAccessTokenPostOut); - +crate::service_impl!( + base, + BlobAccessTokenService, + "storage/blobaccesstokenservice", + 9 +); +crate::service_impl!( + POST, + BlobAccessTokenService, + BlobAccessTokenPostIn, + BlobAccessTokenPostOut +); pub struct BlobReferenceService; -crate::service_impl!(base, BlobReferenceService, "storage/blobreferenceservice", 9); +crate::service_impl!( + base, + BlobReferenceService, + "storage/blobreferenceservice", + 9 +); crate::service_impl!(PUT, BlobReferenceService, BlobReferencePutIn, ()); crate::service_impl!(DELETE, BlobReferenceService, BlobReferenceDeleteIn, ()); - pub struct BlobService; crate::service_impl!(base, BlobService, "storage/blobservice", 9); diff --git a/tuta-sdk/rust/sdk/src/services/sys.rs b/tuta-sdk/rust/sdk/src/services/sys.rs index 2479973fc3cd..3812cb22f6b1 100644 --- a/tuta-sdk/rust/sdk/src/services/sys.rs +++ b/tuta-sdk/rust/sdk/src/services/sys.rs @@ -1,85 +1,80 @@ #![allow(unused_imports, dead_code, unused_variables)] -use crate::ApiCallError; -use crate::entities::Entity; -use crate::services::{PostService, GetService, PutService, DeleteService, Service, Executor, ExtraServiceParams}; -use crate::rest_client::HttpMethod; -use crate::services::hidden::Nothing; use crate::entities::sys::AdminGroupKeyRotationPostIn; use crate::entities::sys::AffiliatePartnerKpiServiceGetOut; use crate::entities::sys::AlarmServicePost; +use crate::entities::sys::AutoLoginDataDelete; +use crate::entities::sys::AutoLoginDataGet; use crate::entities::sys::AutoLoginDataReturn; use crate::entities::sys::AutoLoginPostReturn; -use crate::entities::sys::AutoLoginDataGet; -use crate::entities::sys::AutoLoginDataDelete; use crate::entities::sys::BrandingDomainData; -use crate::entities::sys::BrandingDomainGetReturn; use crate::entities::sys::BrandingDomainDeleteData; +use crate::entities::sys::BrandingDomainGetReturn; use crate::entities::sys::ChangeKdfPostIn; use crate::entities::sys::ChangePasswordPostIn; use crate::entities::sys::CloseSessionServicePost; use crate::entities::sys::CreateCustomerServerPropertiesData; use crate::entities::sys::CreateCustomerServerPropertiesReturn; +use crate::entities::sys::CreateSessionData; +use crate::entities::sys::CreateSessionReturn; use crate::entities::sys::CustomDomainCheckGetIn; use crate::entities::sys::CustomDomainCheckGetOut; use crate::entities::sys::CustomDomainData; use crate::entities::sys::CustomDomainReturn; use crate::entities::sys::CustomerAccountTerminationPostIn; use crate::entities::sys::CustomerAccountTerminationPostOut; -use crate::entities::sys::PublicKeyGetOut; -use crate::entities::sys::DeleteCustomerData; use crate::entities::sys::DebitServicePutData; +use crate::entities::sys::DeleteCustomerData; use crate::entities::sys::DomainMailAddressAvailabilityData; use crate::entities::sys::DomainMailAddressAvailabilityReturn; use crate::entities::sys::ExternalPropertiesReturn; -use crate::entities::sys::GiftCardRedeemData; -use crate::entities::sys::GiftCardRedeemGetReturn; use crate::entities::sys::GiftCardCreateData; use crate::entities::sys::GiftCardCreateReturn; -use crate::entities::sys::GiftCardGetReturn; use crate::entities::sys::GiftCardDeleteData; +use crate::entities::sys::GiftCardGetReturn; +use crate::entities::sys::GiftCardRedeemData; +use crate::entities::sys::GiftCardRedeemGetReturn; use crate::entities::sys::GroupKeyRotationInfoGetOut; use crate::entities::sys::GroupKeyRotationPostIn; use crate::entities::sys::InvoiceDataGetIn; use crate::entities::sys::InvoiceDataGetOut; use crate::entities::sys::LocationServiceGetReturn; -use crate::entities::sys::MailAddressAliasServiceData; use crate::entities::sys::MailAddressAliasGetIn; -use crate::entities::sys::MailAddressAliasServiceReturn; +use crate::entities::sys::MailAddressAliasServiceData; use crate::entities::sys::MailAddressAliasServiceDataDelete; +use crate::entities::sys::MailAddressAliasServiceReturn; use crate::entities::sys::MembershipAddData; use crate::entities::sys::MembershipPutIn; use crate::entities::sys::MembershipRemoveData; use crate::entities::sys::MultipleMailAddressAvailabilityData; use crate::entities::sys::MultipleMailAddressAvailabilityReturn; -use crate::entities::sys::PaymentDataServicePostData; use crate::entities::sys::PaymentDataServiceGetData; use crate::entities::sys::PaymentDataServiceGetReturn; +use crate::entities::sys::PaymentDataServicePostData; use crate::entities::sys::PaymentDataServicePutData; use crate::entities::sys::PaymentDataServicePutReturn; use crate::entities::sys::PlanServiceGetOut; use crate::entities::sys::PriceServiceData; use crate::entities::sys::PriceServiceReturn; use crate::entities::sys::PublicKeyGetIn; +use crate::entities::sys::PublicKeyGetOut; use crate::entities::sys::PublicKeyPutIn; +use crate::entities::sys::ReferralCodeGetIn; use crate::entities::sys::ReferralCodePostIn; use crate::entities::sys::ReferralCodePostOut; -use crate::entities::sys::ReferralCodeGetIn; use crate::entities::sys::RegistrationCaptchaServiceData; use crate::entities::sys::RegistrationCaptchaServiceGetData; use crate::entities::sys::RegistrationCaptchaServiceReturn; -use crate::entities::sys::RegistrationServiceData; use crate::entities::sys::RegistrationReturn; +use crate::entities::sys::RegistrationServiceData; use crate::entities::sys::ResetFactorsDeleteData; use crate::entities::sys::ResetPasswordPostIn; use crate::entities::sys::SaltData; use crate::entities::sys::SaltReturn; use crate::entities::sys::SecondFactorAuthAllowedReturn; use crate::entities::sys::SecondFactorAuthData; +use crate::entities::sys::SecondFactorAuthDeleteData; use crate::entities::sys::SecondFactorAuthGetData; use crate::entities::sys::SecondFactorAuthGetReturn; -use crate::entities::sys::SecondFactorAuthDeleteData; -use crate::entities::sys::CreateSessionData; -use crate::entities::sys::CreateSessionReturn; use crate::entities::sys::SignOrderProcessingAgreementData; use crate::entities::sys::SwitchAccountTypePostIn; use crate::entities::sys::SystemKeysReturn; @@ -88,165 +83,288 @@ use crate::entities::sys::UpdatePermissionKeyData; use crate::entities::sys::UpdateSessionKeysPostIn; use crate::entities::sys::UpgradePriceServiceData; use crate::entities::sys::UpgradePriceServiceReturn; -use crate::entities::sys::UserGroupKeyRotationPostIn; use crate::entities::sys::UserDataDelete; +use crate::entities::sys::UserGroupKeyRotationPostIn; use crate::entities::sys::VersionData; use crate::entities::sys::VersionReturn; +use crate::entities::Entity; +use crate::rest_client::HttpMethod; +use crate::services::hidden::Nothing; +use crate::services::{ + DeleteService, Executor, ExtraServiceParams, GetService, PostService, PutService, Service, +}; +use crate::ApiCallError; pub struct AdminGroupKeyRotationService; -crate::service_impl!(base, AdminGroupKeyRotationService, "sys/admingroupkeyrotationservice", 111); -crate::service_impl!(POST, AdminGroupKeyRotationService, AdminGroupKeyRotationPostIn, ()); - +crate::service_impl!( + base, + AdminGroupKeyRotationService, + "sys/admingroupkeyrotationservice", + 111 +); +crate::service_impl!( + POST, + AdminGroupKeyRotationService, + AdminGroupKeyRotationPostIn, + () +); pub struct AffiliatePartnerKpiService; -crate::service_impl!(base, AffiliatePartnerKpiService, "sys/affiliatepartnerkpiservice", 111); -crate::service_impl!(GET, AffiliatePartnerKpiService, (), AffiliatePartnerKpiServiceGetOut); - +crate::service_impl!( + base, + AffiliatePartnerKpiService, + "sys/affiliatepartnerkpiservice", + 111 +); +crate::service_impl!( + GET, + AffiliatePartnerKpiService, + (), + AffiliatePartnerKpiServiceGetOut +); pub struct AlarmService; crate::service_impl!(base, AlarmService, "sys/alarmservice", 111); crate::service_impl!(POST, AlarmService, AlarmServicePost, ()); - pub struct AutoLoginService; crate::service_impl!(base, AutoLoginService, "sys/autologinservice", 111); -crate::service_impl!(POST, AutoLoginService, AutoLoginDataReturn, AutoLoginPostReturn); +crate::service_impl!( + POST, + AutoLoginService, + AutoLoginDataReturn, + AutoLoginPostReturn +); crate::service_impl!(GET, AutoLoginService, AutoLoginDataGet, AutoLoginDataReturn); crate::service_impl!(DELETE, AutoLoginService, AutoLoginDataDelete, ()); - pub struct BrandingDomainService; -crate::service_impl!(base, BrandingDomainService, "sys/brandingdomainservice", 111); +crate::service_impl!( + base, + BrandingDomainService, + "sys/brandingdomainservice", + 111 +); crate::service_impl!(POST, BrandingDomainService, BrandingDomainData, ()); crate::service_impl!(GET, BrandingDomainService, (), BrandingDomainGetReturn); crate::service_impl!(PUT, BrandingDomainService, BrandingDomainData, ()); crate::service_impl!(DELETE, BrandingDomainService, BrandingDomainDeleteData, ()); - pub struct ChangeKdfService; crate::service_impl!(base, ChangeKdfService, "sys/changekdfservice", 111); crate::service_impl!(POST, ChangeKdfService, ChangeKdfPostIn, ()); - pub struct ChangePasswordService; -crate::service_impl!(base, ChangePasswordService, "sys/changepasswordservice", 111); +crate::service_impl!( + base, + ChangePasswordService, + "sys/changepasswordservice", + 111 +); crate::service_impl!(POST, ChangePasswordService, ChangePasswordPostIn, ()); - pub struct CloseSessionService; crate::service_impl!(base, CloseSessionService, "sys/closesessionservice", 111); crate::service_impl!(POST, CloseSessionService, CloseSessionServicePost, ()); - pub struct CreateCustomerServerProperties; -crate::service_impl!(base, CreateCustomerServerProperties, "sys/createcustomerserverproperties", 111); -crate::service_impl!(POST, CreateCustomerServerProperties, CreateCustomerServerPropertiesData, CreateCustomerServerPropertiesReturn); - +crate::service_impl!( + base, + CreateCustomerServerProperties, + "sys/createcustomerserverproperties", + 111 +); +crate::service_impl!( + POST, + CreateCustomerServerProperties, + CreateCustomerServerPropertiesData, + CreateCustomerServerPropertiesReturn +); pub struct CustomDomainCheckService; -crate::service_impl!(base, CustomDomainCheckService, "sys/customdomaincheckservice", 111); -crate::service_impl!(GET, CustomDomainCheckService, CustomDomainCheckGetIn, CustomDomainCheckGetOut); - +crate::service_impl!( + base, + CustomDomainCheckService, + "sys/customdomaincheckservice", + 111 +); +crate::service_impl!( + GET, + CustomDomainCheckService, + CustomDomainCheckGetIn, + CustomDomainCheckGetOut +); pub struct CustomDomainService; crate::service_impl!(base, CustomDomainService, "sys/customdomainservice", 111); -crate::service_impl!(POST, CustomDomainService, CustomDomainData, CustomDomainReturn); +crate::service_impl!( + POST, + CustomDomainService, + CustomDomainData, + CustomDomainReturn +); crate::service_impl!(PUT, CustomDomainService, CustomDomainData, ()); crate::service_impl!(DELETE, CustomDomainService, CustomDomainData, ()); - pub struct CustomerAccountTerminationService; -crate::service_impl!(base, CustomerAccountTerminationService, "sys/customeraccountterminationservice", 111); -crate::service_impl!(POST, CustomerAccountTerminationService, CustomerAccountTerminationPostIn, CustomerAccountTerminationPostOut); - +crate::service_impl!( + base, + CustomerAccountTerminationService, + "sys/customeraccountterminationservice", + 111 +); +crate::service_impl!( + POST, + CustomerAccountTerminationService, + CustomerAccountTerminationPostIn, + CustomerAccountTerminationPostOut +); pub struct CustomerPublicKeyService; -crate::service_impl!(base, CustomerPublicKeyService, "sys/customerpublickeyservice", 111); +crate::service_impl!( + base, + CustomerPublicKeyService, + "sys/customerpublickeyservice", + 111 +); crate::service_impl!(GET, CustomerPublicKeyService, (), PublicKeyGetOut); - pub struct CustomerService; crate::service_impl!(base, CustomerService, "sys/customerservice", 111); crate::service_impl!(DELETE, CustomerService, DeleteCustomerData, ()); - pub struct DebitService; crate::service_impl!(base, DebitService, "sys/debitservice", 111); crate::service_impl!(PUT, DebitService, DebitServicePutData, ()); - pub struct DomainMailAddressAvailabilityService; -crate::service_impl!(base, DomainMailAddressAvailabilityService, "sys/domainmailaddressavailabilityservice", 111); -crate::service_impl!(GET, DomainMailAddressAvailabilityService, DomainMailAddressAvailabilityData, DomainMailAddressAvailabilityReturn); - +crate::service_impl!( + base, + DomainMailAddressAvailabilityService, + "sys/domainmailaddressavailabilityservice", + 111 +); +crate::service_impl!( + GET, + DomainMailAddressAvailabilityService, + DomainMailAddressAvailabilityData, + DomainMailAddressAvailabilityReturn +); pub struct ExternalPropertiesService; -crate::service_impl!(base, ExternalPropertiesService, "sys/externalpropertiesservice", 111); +crate::service_impl!( + base, + ExternalPropertiesService, + "sys/externalpropertiesservice", + 111 +); crate::service_impl!(GET, ExternalPropertiesService, (), ExternalPropertiesReturn); - pub struct GiftCardRedeemService; -crate::service_impl!(base, GiftCardRedeemService, "sys/giftcardredeemservice", 111); +crate::service_impl!( + base, + GiftCardRedeemService, + "sys/giftcardredeemservice", + 111 +); crate::service_impl!(POST, GiftCardRedeemService, GiftCardRedeemData, ()); -crate::service_impl!(GET, GiftCardRedeemService, GiftCardRedeemData, GiftCardRedeemGetReturn); - +crate::service_impl!( + GET, + GiftCardRedeemService, + GiftCardRedeemData, + GiftCardRedeemGetReturn +); pub struct GiftCardService; crate::service_impl!(base, GiftCardService, "sys/giftcardservice", 111); -crate::service_impl!(POST, GiftCardService, GiftCardCreateData, GiftCardCreateReturn); +crate::service_impl!( + POST, + GiftCardService, + GiftCardCreateData, + GiftCardCreateReturn +); crate::service_impl!(GET, GiftCardService, (), GiftCardGetReturn); crate::service_impl!(DELETE, GiftCardService, GiftCardDeleteData, ()); - pub struct GroupKeyRotationInfoService; -crate::service_impl!(base, GroupKeyRotationInfoService, "sys/groupkeyrotationinfoservice", 111); -crate::service_impl!(GET, GroupKeyRotationInfoService, (), GroupKeyRotationInfoGetOut); - +crate::service_impl!( + base, + GroupKeyRotationInfoService, + "sys/groupkeyrotationinfoservice", + 111 +); +crate::service_impl!( + GET, + GroupKeyRotationInfoService, + (), + GroupKeyRotationInfoGetOut +); pub struct GroupKeyRotationService; -crate::service_impl!(base, GroupKeyRotationService, "sys/groupkeyrotationservice", 111); +crate::service_impl!( + base, + GroupKeyRotationService, + "sys/groupkeyrotationservice", + 111 +); crate::service_impl!(POST, GroupKeyRotationService, GroupKeyRotationPostIn, ()); - pub struct InvoiceDataService; crate::service_impl!(base, InvoiceDataService, "sys/invoicedataservice", 111); crate::service_impl!(GET, InvoiceDataService, InvoiceDataGetIn, InvoiceDataGetOut); - pub struct LocationService; crate::service_impl!(base, LocationService, "sys/locationservice", 111); crate::service_impl!(GET, LocationService, (), LocationServiceGetReturn); - pub struct MailAddressAliasService; -crate::service_impl!(base, MailAddressAliasService, "sys/mailaddressaliasservice", 111); -crate::service_impl!(POST, MailAddressAliasService, MailAddressAliasServiceData, ()); -crate::service_impl!(GET, MailAddressAliasService, MailAddressAliasGetIn, MailAddressAliasServiceReturn); -crate::service_impl!(DELETE, MailAddressAliasService, MailAddressAliasServiceDataDelete, ()); - +crate::service_impl!( + base, + MailAddressAliasService, + "sys/mailaddressaliasservice", + 111 +); +crate::service_impl!( + POST, + MailAddressAliasService, + MailAddressAliasServiceData, + () +); +crate::service_impl!( + GET, + MailAddressAliasService, + MailAddressAliasGetIn, + MailAddressAliasServiceReturn +); +crate::service_impl!( + DELETE, + MailAddressAliasService, + MailAddressAliasServiceDataDelete, + () +); pub struct MembershipService; @@ -255,153 +373,254 @@ crate::service_impl!(POST, MembershipService, MembershipAddData, ()); crate::service_impl!(PUT, MembershipService, MembershipPutIn, ()); crate::service_impl!(DELETE, MembershipService, MembershipRemoveData, ()); - pub struct MultipleMailAddressAvailabilityService; -crate::service_impl!(base, MultipleMailAddressAvailabilityService, "sys/multiplemailaddressavailabilityservice", 111); -crate::service_impl!(GET, MultipleMailAddressAvailabilityService, MultipleMailAddressAvailabilityData, MultipleMailAddressAvailabilityReturn); - +crate::service_impl!( + base, + MultipleMailAddressAvailabilityService, + "sys/multiplemailaddressavailabilityservice", + 111 +); +crate::service_impl!( + GET, + MultipleMailAddressAvailabilityService, + MultipleMailAddressAvailabilityData, + MultipleMailAddressAvailabilityReturn +); pub struct PaymentDataService; crate::service_impl!(base, PaymentDataService, "sys/paymentdataservice", 111); crate::service_impl!(POST, PaymentDataService, PaymentDataServicePostData, ()); -crate::service_impl!(GET, PaymentDataService, PaymentDataServiceGetData, PaymentDataServiceGetReturn); -crate::service_impl!(PUT, PaymentDataService, PaymentDataServicePutData, PaymentDataServicePutReturn); - +crate::service_impl!( + GET, + PaymentDataService, + PaymentDataServiceGetData, + PaymentDataServiceGetReturn +); +crate::service_impl!( + PUT, + PaymentDataService, + PaymentDataServicePutData, + PaymentDataServicePutReturn +); pub struct PlanService; crate::service_impl!(base, PlanService, "sys/planservice", 111); crate::service_impl!(GET, PlanService, (), PlanServiceGetOut); - pub struct PriceService; crate::service_impl!(base, PriceService, "sys/priceservice", 111); crate::service_impl!(GET, PriceService, PriceServiceData, PriceServiceReturn); - pub struct PublicKeyService; crate::service_impl!(base, PublicKeyService, "sys/publickeyservice", 111); crate::service_impl!(GET, PublicKeyService, PublicKeyGetIn, PublicKeyGetOut); crate::service_impl!(PUT, PublicKeyService, PublicKeyPutIn, ()); - pub struct ReferralCodeService; crate::service_impl!(base, ReferralCodeService, "sys/referralcodeservice", 111); -crate::service_impl!(POST, ReferralCodeService, ReferralCodePostIn, ReferralCodePostOut); +crate::service_impl!( + POST, + ReferralCodeService, + ReferralCodePostIn, + ReferralCodePostOut +); crate::service_impl!(GET, ReferralCodeService, ReferralCodeGetIn, ()); - pub struct RegistrationCaptchaService; -crate::service_impl!(base, RegistrationCaptchaService, "sys/registrationcaptchaservice", 111); -crate::service_impl!(POST, RegistrationCaptchaService, RegistrationCaptchaServiceData, ()); -crate::service_impl!(GET, RegistrationCaptchaService, RegistrationCaptchaServiceGetData, RegistrationCaptchaServiceReturn); - +crate::service_impl!( + base, + RegistrationCaptchaService, + "sys/registrationcaptchaservice", + 111 +); +crate::service_impl!( + POST, + RegistrationCaptchaService, + RegistrationCaptchaServiceData, + () +); +crate::service_impl!( + GET, + RegistrationCaptchaService, + RegistrationCaptchaServiceGetData, + RegistrationCaptchaServiceReturn +); pub struct RegistrationService; crate::service_impl!(base, RegistrationService, "sys/registrationservice", 111); -crate::service_impl!(POST, RegistrationService, RegistrationServiceData, RegistrationReturn); +crate::service_impl!( + POST, + RegistrationService, + RegistrationServiceData, + RegistrationReturn +); crate::service_impl!(GET, RegistrationService, (), RegistrationServiceData); - pub struct ResetFactorsService; crate::service_impl!(base, ResetFactorsService, "sys/resetfactorsservice", 111); crate::service_impl!(DELETE, ResetFactorsService, ResetFactorsDeleteData, ()); - pub struct ResetPasswordService; crate::service_impl!(base, ResetPasswordService, "sys/resetpasswordservice", 111); crate::service_impl!(POST, ResetPasswordService, ResetPasswordPostIn, ()); - pub struct SaltService; crate::service_impl!(base, SaltService, "sys/saltservice", 111); crate::service_impl!(GET, SaltService, SaltData, SaltReturn); - pub struct SecondFactorAuthAllowedService; -crate::service_impl!(base, SecondFactorAuthAllowedService, "sys/secondfactorauthallowedservice", 111); -crate::service_impl!(GET, SecondFactorAuthAllowedService, (), SecondFactorAuthAllowedReturn); - +crate::service_impl!( + base, + SecondFactorAuthAllowedService, + "sys/secondfactorauthallowedservice", + 111 +); +crate::service_impl!( + GET, + SecondFactorAuthAllowedService, + (), + SecondFactorAuthAllowedReturn +); pub struct SecondFactorAuthService; -crate::service_impl!(base, SecondFactorAuthService, "sys/secondfactorauthservice", 111); +crate::service_impl!( + base, + SecondFactorAuthService, + "sys/secondfactorauthservice", + 111 +); crate::service_impl!(POST, SecondFactorAuthService, SecondFactorAuthData, ()); -crate::service_impl!(GET, SecondFactorAuthService, SecondFactorAuthGetData, SecondFactorAuthGetReturn); -crate::service_impl!(DELETE, SecondFactorAuthService, SecondFactorAuthDeleteData, ()); - +crate::service_impl!( + GET, + SecondFactorAuthService, + SecondFactorAuthGetData, + SecondFactorAuthGetReturn +); +crate::service_impl!( + DELETE, + SecondFactorAuthService, + SecondFactorAuthDeleteData, + () +); pub struct SessionService; crate::service_impl!(base, SessionService, "sys/sessionservice", 111); crate::service_impl!(POST, SessionService, CreateSessionData, CreateSessionReturn); - pub struct SignOrderProcessingAgreementService; -crate::service_impl!(base, SignOrderProcessingAgreementService, "sys/signorderprocessingagreementservice", 111); -crate::service_impl!(POST, SignOrderProcessingAgreementService, SignOrderProcessingAgreementData, ()); - +crate::service_impl!( + base, + SignOrderProcessingAgreementService, + "sys/signorderprocessingagreementservice", + 111 +); +crate::service_impl!( + POST, + SignOrderProcessingAgreementService, + SignOrderProcessingAgreementData, + () +); pub struct SwitchAccountTypeService; -crate::service_impl!(base, SwitchAccountTypeService, "sys/switchaccounttypeservice", 111); +crate::service_impl!( + base, + SwitchAccountTypeService, + "sys/switchaccounttypeservice", + 111 +); crate::service_impl!(POST, SwitchAccountTypeService, SwitchAccountTypePostIn, ()); - pub struct SystemKeysService; crate::service_impl!(base, SystemKeysService, "sys/systemkeysservice", 111); crate::service_impl!(GET, SystemKeysService, (), SystemKeysReturn); - pub struct TakeOverDeletedAddressService; -crate::service_impl!(base, TakeOverDeletedAddressService, "sys/takeoverdeletedaddressservice", 111); -crate::service_impl!(POST, TakeOverDeletedAddressService, TakeOverDeletedAddressData, ()); - +crate::service_impl!( + base, + TakeOverDeletedAddressService, + "sys/takeoverdeletedaddressservice", + 111 +); +crate::service_impl!( + POST, + TakeOverDeletedAddressService, + TakeOverDeletedAddressData, + () +); pub struct UpdatePermissionKeyService; -crate::service_impl!(base, UpdatePermissionKeyService, "sys/updatepermissionkeyservice", 111); -crate::service_impl!(POST, UpdatePermissionKeyService, UpdatePermissionKeyData, ()); - +crate::service_impl!( + base, + UpdatePermissionKeyService, + "sys/updatepermissionkeyservice", + 111 +); +crate::service_impl!( + POST, + UpdatePermissionKeyService, + UpdatePermissionKeyData, + () +); pub struct UpdateSessionKeysService; -crate::service_impl!(base, UpdateSessionKeysService, "sys/updatesessionkeysservice", 111); +crate::service_impl!( + base, + UpdateSessionKeysService, + "sys/updatesessionkeysservice", + 111 +); crate::service_impl!(POST, UpdateSessionKeysService, UpdateSessionKeysPostIn, ()); - pub struct UpgradePriceService; crate::service_impl!(base, UpgradePriceService, "sys/upgradepriceservice", 111); -crate::service_impl!(GET, UpgradePriceService, UpgradePriceServiceData, UpgradePriceServiceReturn); - +crate::service_impl!( + GET, + UpgradePriceService, + UpgradePriceServiceData, + UpgradePriceServiceReturn +); pub struct UserGroupKeyRotationService; -crate::service_impl!(base, UserGroupKeyRotationService, "sys/usergroupkeyrotationservice", 111); -crate::service_impl!(POST, UserGroupKeyRotationService, UserGroupKeyRotationPostIn, ()); - +crate::service_impl!( + base, + UserGroupKeyRotationService, + "sys/usergroupkeyrotationservice", + 111 +); +crate::service_impl!( + POST, + UserGroupKeyRotationService, + UserGroupKeyRotationPostIn, + () +); pub struct UserService; crate::service_impl!(base, UserService, "sys/userservice", 111); crate::service_impl!(DELETE, UserService, UserDataDelete, ()); - pub struct VersionService; crate::service_impl!(base, VersionService, "sys/versionservice", 111); diff --git a/tuta-sdk/rust/sdk/src/services/test_services.rs b/tuta-sdk/rust/sdk/src/services/test_services.rs index 0e0d46937b07..cef691a6cabe 100644 --- a/tuta-sdk/rust/sdk/src/services/test_services.rs +++ b/tuta-sdk/rust/sdk/src/services/test_services.rs @@ -1,7 +1,6 @@ use crate::date::DateTime; use crate::entities::{Entity, FinalIv}; use crate::metamodel::TypeModel; -use crate::services::GetService; use crate::type_model_provider::{AppName, TypeName}; use crate::{service_impl, TypeRef}; use serde::{Deserialize, Serialize}; @@ -124,93 +123,125 @@ pub const HELLO_INPUT_UNENCRYPTED: &str = r#"{ }"#; pub fn extend_model_resolver(model_resolver: &mut HashMap>) { - assert!(model_resolver.get("test").is_none()); - - let enc_input_type_model = serde_json::from_str::(HELLO_INPUT_ENCRYPTED).unwrap(); - let enc_output_type_model = serde_json::from_str::(HELLO_OUTPUT_ENCRYPTED).unwrap(); - let unenc_input_type_model = serde_json::from_str::(HELLO_INPUT_UNENCRYPTED).unwrap(); - let unenc_output_type_model = serde_json::from_str::(HELLO_OUTPUT_UNENCRYPTED).unwrap(); - - let test_types = [ - ("HelloEncInput", enc_input_type_model), - ("HelloEncOutput", enc_output_type_model), - ("HelloUnEncInput", unenc_input_type_model), - ("HelloUnEncOutput", unenc_output_type_model) - ].into_iter().collect(); - model_resolver.insert("test", test_types); + assert!(model_resolver.get("test").is_none()); + + let enc_input_type_model = serde_json::from_str::(HELLO_INPUT_ENCRYPTED).unwrap(); + let enc_output_type_model = serde_json::from_str::(HELLO_OUTPUT_ENCRYPTED).unwrap(); + let unenc_input_type_model = + serde_json::from_str::(HELLO_INPUT_UNENCRYPTED).unwrap(); + let unenc_output_type_model = + serde_json::from_str::(HELLO_OUTPUT_UNENCRYPTED).unwrap(); + + let test_types = [ + ("HelloEncInput", enc_input_type_model), + ("HelloEncOutput", enc_output_type_model), + ("HelloUnEncInput", unenc_input_type_model), + ("HelloUnEncOutput", unenc_output_type_model), + ] + .into_iter() + .collect(); + model_resolver.insert("test", test_types); } - pub struct HelloEncryptedService; pub struct HelloUnEncryptedService; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct HelloEncInput { - pub message: String, + pub message: String, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct HelloEncOutput { - pub answer: String, - pub timestamp: DateTime, - pub _finalIvs: HashMap, + pub answer: String, + pub timestamp: DateTime, + #[allow(non_snake_case)] + pub _finalIvs: HashMap, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct HelloUnEncInput { - pub message: String, + pub message: String, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct HelloUnEncOutput { - pub answer: String, - pub timestamp: DateTime, + pub answer: String, + pub timestamp: DateTime, } impl Entity for HelloEncInput { - fn type_ref() -> TypeRef { - TypeRef { - app: "test", - type_: "HelloEncInput", - } - } + fn type_ref() -> TypeRef { + TypeRef { + app: "test", + type_: "HelloEncInput", + } + } } - impl Entity for HelloEncOutput { - fn type_ref() -> TypeRef { - TypeRef { - app: "test", - type_: "HelloEncOutput", - } - } + fn type_ref() -> TypeRef { + TypeRef { + app: "test", + type_: "HelloEncOutput", + } + } } impl Entity for HelloUnEncInput { - fn type_ref() -> TypeRef { - TypeRef { - app: "test", - type_: "HelloUnEncInput", - } - } + fn type_ref() -> TypeRef { + TypeRef { + app: "test", + type_: "HelloUnEncInput", + } + } } - impl Entity for HelloUnEncOutput { - fn type_ref() -> TypeRef { - TypeRef { - app: "test", - type_: "HelloUnEncOutput", - } - } + fn type_ref() -> TypeRef { + TypeRef { + app: "test", + type_: "HelloUnEncOutput", + } + } } -service_impl!(base, HelloEncryptedService, "test/encrypted-hello", APP_VERSION_NUMBER); +service_impl!( + base, + HelloEncryptedService, + "test/encrypted-hello", + APP_VERSION_NUMBER +); service_impl!(POST, HelloEncryptedService, HelloEncInput, HelloEncOutput); service_impl!(PUT, HelloEncryptedService, HelloEncInput, HelloEncOutput); service_impl!(GET, HelloEncryptedService, HelloEncInput, HelloEncOutput); service_impl!(DELETE, HelloEncryptedService, HelloEncInput, HelloEncOutput); -service_impl!(base, HelloUnEncryptedService, "test/unencrypted-hello", APP_VERSION_NUMBER); -service_impl!(POST, HelloUnEncryptedService, HelloUnEncInput, HelloUnEncOutput); -service_impl!(PUT, HelloUnEncryptedService, HelloUnEncInput, HelloUnEncOutput); -service_impl!(GET, HelloUnEncryptedService, HelloUnEncInput, HelloUnEncOutput); -service_impl!(DELETE, HelloUnEncryptedService, HelloUnEncInput, HelloUnEncOutput); \ No newline at end of file +service_impl!( + base, + HelloUnEncryptedService, + "test/unencrypted-hello", + APP_VERSION_NUMBER +); +service_impl!( + POST, + HelloUnEncryptedService, + HelloUnEncInput, + HelloUnEncOutput +); +service_impl!( + PUT, + HelloUnEncryptedService, + HelloUnEncInput, + HelloUnEncOutput +); +service_impl!( + GET, + HelloUnEncryptedService, + HelloUnEncInput, + HelloUnEncOutput +); +service_impl!( + DELETE, + HelloUnEncryptedService, + HelloUnEncInput, + HelloUnEncOutput +); diff --git a/tuta-sdk/rust/sdk/src/services/tutanota.rs b/tuta-sdk/rust/sdk/src/services/tutanota.rs index 6a369eb9636e..fabd84c17a1d 100644 --- a/tuta-sdk/rust/sdk/src/services/tutanota.rs +++ b/tuta-sdk/rust/sdk/src/services/tutanota.rs @@ -1,14 +1,13 @@ #![allow(unused_imports, dead_code, unused_variables)] -use crate::ApiCallError; -use crate::entities::Entity; -use crate::services::{PostService, GetService, PutService, DeleteService, Service, Executor, ExtraServiceParams}; -use crate::rest_client::HttpMethod; -use crate::services::hidden::Nothing; -use crate::entities::tutanota::UserAreaGroupPostData; -use crate::entities::tutanota::CreateGroupPostReturn; use crate::entities::tutanota::CalendarDeleteData; -use crate::entities::tutanota::UserAreaGroupDeleteData; +use crate::entities::tutanota::CreateGroupPostReturn; +use crate::entities::tutanota::CreateMailFolderData; +use crate::entities::tutanota::CreateMailFolderReturn; +use crate::entities::tutanota::CreateMailGroupData; use crate::entities::tutanota::CustomerAccountCreateData; +use crate::entities::tutanota::DeleteGroupData; +use crate::entities::tutanota::DeleteMailData; +use crate::entities::tutanota::DeleteMailFolderData; use crate::entities::tutanota::DraftCreateData; use crate::entities::tutanota::DraftCreateReturn; use crate::entities::tutanota::DraftUpdateData; @@ -16,18 +15,11 @@ use crate::entities::tutanota::DraftUpdateReturn; use crate::entities::tutanota::EncryptTutanotaPropertiesData; use crate::entities::tutanota::EntropyData; use crate::entities::tutanota::ExternalUserData; +use crate::entities::tutanota::GroupInvitationDeleteData; use crate::entities::tutanota::GroupInvitationPostData; use crate::entities::tutanota::GroupInvitationPostReturn; use crate::entities::tutanota::GroupInvitationPutData; -use crate::entities::tutanota::GroupInvitationDeleteData; use crate::entities::tutanota::ListUnsubscribeData; -use crate::entities::tutanota::CreateMailFolderData; -use crate::entities::tutanota::CreateMailFolderReturn; -use crate::entities::tutanota::UpdateMailFolderData; -use crate::entities::tutanota::DeleteMailFolderData; -use crate::entities::tutanota::CreateMailGroupData; -use crate::entities::tutanota::DeleteGroupData; -use crate::entities::tutanota::DeleteMailData; use crate::entities::tutanota::MoveMailData; use crate::entities::tutanota::NewsIn; use crate::entities::tutanota::NewsOut; @@ -37,131 +29,192 @@ use crate::entities::tutanota::SendDraftData; use crate::entities::tutanota::SendDraftReturn; use crate::entities::tutanota::TranslationGetIn; use crate::entities::tutanota::TranslationGetOut; +use crate::entities::tutanota::UpdateMailFolderData; use crate::entities::tutanota::UserAccountCreateData; +use crate::entities::tutanota::UserAreaGroupDeleteData; +use crate::entities::tutanota::UserAreaGroupPostData; +use crate::entities::Entity; +use crate::rest_client::HttpMethod; +use crate::services::hidden::Nothing; +use crate::services::{ + DeleteService, Executor, ExtraServiceParams, GetService, PostService, PutService, Service, +}; +use crate::ApiCallError; pub struct CalendarService; crate::service_impl!(base, CalendarService, "tutanota/calendarservice", 75); -crate::service_impl!(POST, CalendarService, UserAreaGroupPostData, CreateGroupPostReturn); +crate::service_impl!( + POST, + CalendarService, + UserAreaGroupPostData, + CreateGroupPostReturn +); crate::service_impl!(DELETE, CalendarService, CalendarDeleteData, ()); - pub struct ContactListGroupService; -crate::service_impl!(base, ContactListGroupService, "tutanota/contactlistgroupservice", 75); -crate::service_impl!(POST, ContactListGroupService, UserAreaGroupPostData, CreateGroupPostReturn); +crate::service_impl!( + base, + ContactListGroupService, + "tutanota/contactlistgroupservice", + 75 +); +crate::service_impl!( + POST, + ContactListGroupService, + UserAreaGroupPostData, + CreateGroupPostReturn +); crate::service_impl!(DELETE, ContactListGroupService, UserAreaGroupDeleteData, ()); - pub struct CustomerAccountService; -crate::service_impl!(base, CustomerAccountService, "tutanota/customeraccountservice", 75); +crate::service_impl!( + base, + CustomerAccountService, + "tutanota/customeraccountservice", + 75 +); crate::service_impl!(POST, CustomerAccountService, CustomerAccountCreateData, ()); - pub struct DraftService; crate::service_impl!(base, DraftService, "tutanota/draftservice", 75); crate::service_impl!(POST, DraftService, DraftCreateData, DraftCreateReturn); crate::service_impl!(PUT, DraftService, DraftUpdateData, DraftUpdateReturn); - pub struct EncryptTutanotaPropertiesService; -crate::service_impl!(base, EncryptTutanotaPropertiesService, "tutanota/encrypttutanotapropertiesservice", 75); -crate::service_impl!(POST, EncryptTutanotaPropertiesService, EncryptTutanotaPropertiesData, ()); - +crate::service_impl!( + base, + EncryptTutanotaPropertiesService, + "tutanota/encrypttutanotapropertiesservice", + 75 +); +crate::service_impl!( + POST, + EncryptTutanotaPropertiesService, + EncryptTutanotaPropertiesData, + () +); pub struct EntropyService; crate::service_impl!(base, EntropyService, "tutanota/entropyservice", 75); crate::service_impl!(PUT, EntropyService, EntropyData, ()); - pub struct ExternalUserService; -crate::service_impl!(base, ExternalUserService, "tutanota/externaluserservice", 75); +crate::service_impl!( + base, + ExternalUserService, + "tutanota/externaluserservice", + 75 +); crate::service_impl!(POST, ExternalUserService, ExternalUserData, ()); - pub struct GroupInvitationService; -crate::service_impl!(base, GroupInvitationService, "tutanota/groupinvitationservice", 75); -crate::service_impl!(POST, GroupInvitationService, GroupInvitationPostData, GroupInvitationPostReturn); +crate::service_impl!( + base, + GroupInvitationService, + "tutanota/groupinvitationservice", + 75 +); +crate::service_impl!( + POST, + GroupInvitationService, + GroupInvitationPostData, + GroupInvitationPostReturn +); crate::service_impl!(PUT, GroupInvitationService, GroupInvitationPutData, ()); -crate::service_impl!(DELETE, GroupInvitationService, GroupInvitationDeleteData, ()); - +crate::service_impl!( + DELETE, + GroupInvitationService, + GroupInvitationDeleteData, + () +); pub struct ListUnsubscribeService; -crate::service_impl!(base, ListUnsubscribeService, "tutanota/listunsubscribeservice", 75); +crate::service_impl!( + base, + ListUnsubscribeService, + "tutanota/listunsubscribeservice", + 75 +); crate::service_impl!(POST, ListUnsubscribeService, ListUnsubscribeData, ()); - pub struct MailFolderService; crate::service_impl!(base, MailFolderService, "tutanota/mailfolderservice", 75); -crate::service_impl!(POST, MailFolderService, CreateMailFolderData, CreateMailFolderReturn); +crate::service_impl!( + POST, + MailFolderService, + CreateMailFolderData, + CreateMailFolderReturn +); crate::service_impl!(PUT, MailFolderService, UpdateMailFolderData, ()); crate::service_impl!(DELETE, MailFolderService, DeleteMailFolderData, ()); - pub struct MailGroupService; crate::service_impl!(base, MailGroupService, "tutanota/mailgroupservice", 75); crate::service_impl!(POST, MailGroupService, CreateMailGroupData, ()); crate::service_impl!(DELETE, MailGroupService, DeleteGroupData, ()); - pub struct MailService; crate::service_impl!(base, MailService, "tutanota/mailservice", 75); crate::service_impl!(DELETE, MailService, DeleteMailData, ()); - pub struct MoveMailService; crate::service_impl!(base, MoveMailService, "tutanota/movemailservice", 75); crate::service_impl!(POST, MoveMailService, MoveMailData, ()); - pub struct NewsService; crate::service_impl!(base, NewsService, "tutanota/newsservice", 75); crate::service_impl!(POST, NewsService, NewsIn, ()); crate::service_impl!(GET, NewsService, (), NewsOut); - pub struct ReceiveInfoService; crate::service_impl!(base, ReceiveInfoService, "tutanota/receiveinfoservice", 75); crate::service_impl!(POST, ReceiveInfoService, ReceiveInfoServiceData, ()); - pub struct ReportMailService; crate::service_impl!(base, ReportMailService, "tutanota/reportmailservice", 75); crate::service_impl!(POST, ReportMailService, ReportMailPostData, ()); - pub struct SendDraftService; crate::service_impl!(base, SendDraftService, "tutanota/senddraftservice", 75); crate::service_impl!(POST, SendDraftService, SendDraftData, SendDraftReturn); - pub struct TemplateGroupService; -crate::service_impl!(base, TemplateGroupService, "tutanota/templategroupservice", 75); -crate::service_impl!(POST, TemplateGroupService, UserAreaGroupPostData, CreateGroupPostReturn); +crate::service_impl!( + base, + TemplateGroupService, + "tutanota/templategroupservice", + 75 +); +crate::service_impl!( + POST, + TemplateGroupService, + UserAreaGroupPostData, + CreateGroupPostReturn +); crate::service_impl!(DELETE, TemplateGroupService, UserAreaGroupDeleteData, ()); - pub struct TranslationService; crate::service_impl!(base, TranslationService, "tutanota/translationservice", 75); crate::service_impl!(GET, TranslationService, TranslationGetIn, TranslationGetOut); - pub struct UserAccountService; crate::service_impl!(base, UserAccountService, "tutanota/useraccountservice", 75); diff --git a/tuta-sdk/rust/sdk/src/services/usage.rs b/tuta-sdk/rust/sdk/src/services/usage.rs index 0218931627c2..d99b8621fe59 100644 --- a/tuta-sdk/rust/sdk/src/services/usage.rs +++ b/tuta-sdk/rust/sdk/src/services/usage.rs @@ -1,20 +1,46 @@ #![allow(unused_imports, dead_code, unused_variables)] -use crate::ApiCallError; -use crate::entities::Entity; -use crate::services::{PostService, GetService, PutService, DeleteService, Service, Executor, ExtraServiceParams}; -use crate::rest_client::HttpMethod; -use crate::services::hidden::Nothing; use crate::entities::usage::UsageTestAssignmentIn; use crate::entities::usage::UsageTestAssignmentOut; use crate::entities::usage::UsageTestParticipationIn; +use crate::entities::Entity; +use crate::rest_client::HttpMethod; +use crate::services::hidden::Nothing; +use crate::services::{ + DeleteService, Executor, ExtraServiceParams, GetService, PostService, PutService, Service, +}; +use crate::ApiCallError; pub struct UsageTestAssignmentService; -crate::service_impl!(base, UsageTestAssignmentService, "usage/usagetestassignmentservice", 2); -crate::service_impl!(POST, UsageTestAssignmentService, UsageTestAssignmentIn, UsageTestAssignmentOut); -crate::service_impl!(PUT, UsageTestAssignmentService, UsageTestAssignmentIn, UsageTestAssignmentOut); - +crate::service_impl!( + base, + UsageTestAssignmentService, + "usage/usagetestassignmentservice", + 2 +); +crate::service_impl!( + POST, + UsageTestAssignmentService, + UsageTestAssignmentIn, + UsageTestAssignmentOut +); +crate::service_impl!( + PUT, + UsageTestAssignmentService, + UsageTestAssignmentIn, + UsageTestAssignmentOut +); pub struct UsageTestParticipationService; -crate::service_impl!(base, UsageTestParticipationService, "usage/usagetestparticipationservice", 2); -crate::service_impl!(POST, UsageTestParticipationService, UsageTestParticipationIn, ()); +crate::service_impl!( + base, + UsageTestParticipationService, + "usage/usagetestparticipationservice", + 2 +); +crate::service_impl!( + POST, + UsageTestParticipationService, + UsageTestParticipationIn, + () +); diff --git a/tuta-sdk/rust/sdk/src/type_model_provider.rs b/tuta-sdk/rust/sdk/src/type_model_provider.rs index cab77d38f4c5..73e8b695d04f 100644 --- a/tuta-sdk/rust/sdk/src/type_model_provider.rs +++ b/tuta-sdk/rust/sdk/src/type_model_provider.rs @@ -10,19 +10,19 @@ pub type TypeName = &'static str; /// Contains a map between backend apps and entity/instance types within them pub struct TypeModelProvider { - app_models: HashMap>, + app_models: HashMap>, } impl TypeModelProvider { - pub fn new(app_models: HashMap>) -> TypeModelProvider { - TypeModelProvider { app_models } - } - - /// Gets an entity/instance type with a specified name in a backend app - pub fn get_type_model(&self, app_name: &str, entity_name: &str) -> Option<&TypeModel> { - let app_map = self.app_models.get(app_name)?; - app_map.get(entity_name) - } + pub fn new(app_models: HashMap>) -> TypeModelProvider { + TypeModelProvider { app_models } + } + + /// Gets an entity/instance type with a specified name in a backend app + pub fn get_type_model(&self, app_name: &str, entity_name: &str) -> Option<&TypeModel> { + let app_map = self.app_models.get(app_name)?; + app_map.get(entity_name) + } } // Reads all provided type models into a map. @@ -46,7 +46,7 @@ macro_rules! read_type_models { /// Creates a new `TypeModelProvider` populated with the type models from the JSON type model files pub fn init_type_model_provider() -> TypeModelProvider { - let type_model_map = read_type_models![ + let type_model_map = read_type_models![ "accounting", "base", "gossip", @@ -56,6 +56,6 @@ pub fn init_type_model_provider() -> TypeModelProvider { "tutanota", "usage" ]; - let type_model_provider = TypeModelProvider::new(type_model_map); - type_model_provider + let type_model_provider = TypeModelProvider::new(type_model_map); + type_model_provider } diff --git a/tuta-sdk/rust/sdk/src/util/mod.rs b/tuta-sdk/rust/sdk/src/util/mod.rs index 9365cfee5849..cf6852043bc9 100644 --- a/tuta-sdk/rust/sdk/src/util/mod.rs +++ b/tuta-sdk/rust/sdk/src/util/mod.rs @@ -1,5 +1,4 @@ -use base64::alphabet::{Alphabet, URL_SAFE}; -use base64::engine::general_purpose::NO_PAD; +use base64::alphabet::Alphabet; use base64::engine::GeneralPurpose; #[cfg(test)] diff --git a/tuta-sdk/rust/sdk/tests/test_rest_client.rs b/tuta-sdk/rust/sdk/tests/test_rest_client.rs index 6e48459a31cc..81ecafd2555a 100644 --- a/tuta-sdk/rust/sdk/tests/test_rest_client.rs +++ b/tuta-sdk/rust/sdk/tests/test_rest_client.rs @@ -36,7 +36,6 @@ pub struct TestRestRequest { pub method: HttpMethod, } - #[async_trait::async_trait] impl RestClient for TestRestClient { async fn request_binary(