Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Import in desktop #7555

Draft
wants to merge 32 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
fa6b424
[tutasdk] move id-related code to its own module
ganthern Nov 7, 2024
7dc10d8
add tutanota model V77
ganthern Nov 7, 2024
958353d
eml import wip
ganthern Nov 7, 2024
272f7cb
started adding compatibility tests for mime conversion
mpfau Nov 7, 2024
5ce9583
wip
tuta-sudipg Nov 7, 2024
1019161
wip improve size_estimator docs
ganthern Nov 8, 2024
1898816
wip
tuta-sudipg Nov 8, 2024
e8be7dd
wip: porting test from java
tuta-sudipg Nov 8, 2024
7a3c866
wip: porting test from java 2
tuta-sudipg Nov 8, 2024
f4f0938
prepared train ride
mpfau Nov 8, 2024
94b33e4
add reduce_to_chunks utility
ganthern Nov 11, 2024
e920d75
further iteration improvements for multi mail import
ganthern Nov 11, 2024
2ce1248
multimail import
ganthern Nov 12, 2024
6075ec7
improved mime handling
mpfau Nov 13, 2024
0f74d04
fmt
ganthern Nov 13, 2024
94bfe14
enable multi mail import
ganthern Nov 13, 2024
4301cbb
fix imap example
ganthern Nov 13, 2024
c86a44e
add example to cargo.toml
ganthern Nov 13, 2024
8145478
improved mime handling part 2
mpfau Nov 13, 2024
d805382
improved mime handling part 3
mpfau Nov 13, 2024
5186747
change TutanotaModelV77 (should be merged with other commit)
jomapp Nov 13, 2024
35ab92e
wip import attachments
jomapp Nov 13, 2024
3ffcd6e
make ChunkingIterator thread-safe
jomapp Nov 13, 2024
636d5e6
use typeRef from dependency if available on association
jomapp Nov 13, 2024
81355ff
use ParsedEntity type alias where appropriate
ganthern Nov 13, 2024
040ac51
Test against ImportMailData and not ImportableMail in compatibility_test
mpfau Nov 14, 2024
97eb93a
use ParsedEntity type alias where appropriate
ganthern Nov 13, 2024
c54b003
fix entity_facade test for aggregate id
ganthern Nov 14, 2024
f937c19
wip
mpfau Nov 15, 2024
180d82d
WIP: add test for import without server running
jomapp Nov 15, 2024
ff5d638
Revert "WIP: add test for import without server running"
mpfau Nov 15, 2024
248a066
wip
mpfau Nov 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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>): String {
when (method) {
"rsaEncrypt" -> {
Expand All @@ -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])
Expand All @@ -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])
Expand All @@ -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])
Expand All @@ -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])
Expand All @@ -68,15 +63,13 @@ class NativeCryptoFacadeReceiveDispatcher(
)
return json.encodeToString(result)
}

"generateKyberKeypair" -> {
val seed: DataWrapper = json.decodeFromString(arg[0])
val result: KyberKeyPair = this.facade.generateKyberKeypair(
seed,
)
return json.encodeToString(result)
}

"kyberEncapsulate" -> {
val publicKey: KyberPublicKey = json.decodeFromString(arg[0])
val seed: DataWrapper = json.decodeFromString(arg[1])
Expand All @@ -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])
Expand All @@ -96,7 +88,6 @@ class NativeCryptoFacadeReceiveDispatcher(
)
return json.encodeToString(result)
}

else -> throw Error("unknown method for NativeCryptoFacade: $method")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

package de.tutao.tutashared.ipc

import kotlinx.serialization.Serializable
import kotlinx.serialization.*
import kotlinx.serialization.json.*


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

package de.tutao.tutashared.ipc

import kotlinx.serialization.Serializable
import kotlinx.serialization.*
import kotlinx.serialization.json.*


/**
Expand Down
15 changes: 14 additions & 1 deletion buildSrc/DesktopBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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,
Expand Down
10 changes: 7 additions & 3 deletions buildSrc/DevBuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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: [
Expand All @@ -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(),
],
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/RustGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { AssociationType, Type, ValueType } from "../src/common/api/common/Entit
export function generateRustType({ type, modelName }) {
let typeName = mapTypeName(type.name, modelName)
let buf = `#[derive(uniffi::Record, Clone, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq, Debug))]
#[cfg_attr(any(test, feature = "testing"), derive(PartialEq, Debug))]
pub struct ${typeName} {\n`
for (let [valueName, valueProperties] of Object.entries(type.values)) {
const rustType = rustValueType(valueName, type, valueProperties)
Expand Down
37 changes: 36 additions & 1 deletion buildSrc/esbuildUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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(
Expand Down
4 changes: 2 additions & 2 deletions buildSrc/packageBuilderFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ 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`))
}

/**
* Build all packages in packages directory.
*/
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`))
}
52 changes: 52 additions & 0 deletions ipc-schema/facades/MailImportFacade.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "MailImportFacade",
"type": "facade",
"senders": ["web"],
"receivers": ["desktop"],
"doc": "Facade implemented by the native desktop client enabling mail imports, both from files, and via IMAP.",
"methods": {
"setupImapImport": {
"doc": "Initializing an IMAP import.",
"arg": [
{
"apiUrl": "string"
},
{
"unencryptedTutaCredentials": "UnencryptedCredentials"
}
],
"ret": "void"
},
"startImapImport": {
"doc": "Start an IMAP import.",
"arg": [],
"ret": "void"
},
"stopImapImport": {
"doc": "Stop a running IMAP import.",
"arg": [],
"ret": "void"
},
"importFromFiles": {
"doc": "Import multiple mails from .eml or .mbox files.",
"arg": [
{
"apiUrl": "string"
},
{
"unencryptedTutaCredentials": "UnencryptedCredentials"
},
{
"targetOwnerGroup": "string"
},
{
"targetFolder": "List<string>"
},
{
"filePaths": "List<string>"
}
],
"ret": "string"
}
}
}
2 changes: 1 addition & 1 deletion ipc-schema/types/MailBundle.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
"name": "MailBundle",
"type": "typeref",
"location": {
"typescript": "../src/mail-app/mail/export/Bundler.js"
"typescript": "../src/common/mailFunctionality/SharedMailUtils.js"
}
}
7 changes: 7 additions & 0 deletions ipc-schema/types/TutaCredentials.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "TutaCredentials",
"type": "typeref",
"location": {
"typescript": "../packages/node-mimimi/dist/binding.cjs"
}
}
Loading
Loading