Password check before adding or deleting SecondFactorAuthentication

Add SystemModel 117

Close #5986

Co-authored-by: Willow <ivk@tutao.de>
This commit is contained in:
wrd 2024-11-12 17:47:35 +01:00
parent ff2ca8aeae
commit ddb27867df
25 changed files with 1265 additions and 835 deletions

View file

@ -530,6 +530,21 @@
"info": "AddValue TutanotaProperties/defaultLabelCreated/1510."
}
]
},
{
"version": 79,
"changes": [
{
"name": "AddAssociation",
"sourceType": "MailBox",
"info": "AddAssociation MailBox/importedAttachments/LIST_ASSOCIATION/1512."
},
{
"name": "AddAssociation",
"sourceType": "MailBox",
"info": "AddAssociation MailBox/mailImportStates/LIST_ASSOCIATION/1578."
}
]
}
]
}

View file

@ -1,4 +1,5 @@
import {
EntityRestClientEraseOptions,
EntityRestClientLoadOptions,
EntityRestClientSetupOptions,
EntityRestClientUpdateOptions,
@ -112,8 +113,8 @@ export class EntityClient {
return this._target.update(instance, options)
}
erase<T extends SomeEntity>(instance: T): Promise<void> {
return this._target.erase(instance)
erase<T extends SomeEntity>(instance: T, options?: EntityRestClientEraseOptions): Promise<void> {
return this._target.erase(instance, options)
}
async loadRoot<T extends ElementEntity>(typeRef: TypeRef<T>, groupId: Id, opts: EntityRestClientLoadOptions = {}): Promise<T> {

View file

@ -1,5 +1,5 @@
const modelInfo = {
version: 115,
version: 117,
compatibleSince: 114,
}

View file

@ -87,6 +87,8 @@ import { UpgradePriceServiceDataTypeRef } from "./TypeRefs.js"
import { UpgradePriceServiceReturnTypeRef } from "./TypeRefs.js"
import { UserGroupKeyRotationPostInTypeRef } from "./TypeRefs.js"
import { UserDataDeleteTypeRef } from "./TypeRefs.js"
import { VerifierTokenServiceInTypeRef } from "./TypeRefs.js"
import { VerifierTokenServiceOutTypeRef } from "./TypeRefs.js"
import { VersionDataTypeRef } from "./TypeRefs.js"
import { VersionReturnTypeRef } from "./TypeRefs.js"
@ -540,6 +542,15 @@ export const UserService = Object.freeze({
delete: { data: UserDataDeleteTypeRef, return: null },
} as const)
export const VerifierTokenService = Object.freeze({
app: "sys",
name: "VerifierTokenService",
get: null,
post: { data: VerifierTokenServiceInTypeRef, return: VerifierTokenServiceOutTypeRef },
put: null,
delete: null,
} as const)
export const VersionService = Object.freeze({
app: "sys",
name: "VersionService",

File diff suppressed because it is too large Load diff

View file

@ -3460,6 +3460,30 @@ export type VariableExternalAuthInfo = {
loggedInVerifier: null | Uint8Array;
sentCount: NumberString;
}
export const VerifierTokenServiceInTypeRef: TypeRef<VerifierTokenServiceIn> = new TypeRef("sys", "VerifierTokenServiceIn")
export function createVerifierTokenServiceIn(values: StrippedEntity<VerifierTokenServiceIn>): VerifierTokenServiceIn {
return Object.assign(create(typeModels.VerifierTokenServiceIn, VerifierTokenServiceInTypeRef), values)
}
export type VerifierTokenServiceIn = {
_type: TypeRef<VerifierTokenServiceIn>;
_format: NumberString;
authVerifier: Uint8Array;
}
export const VerifierTokenServiceOutTypeRef: TypeRef<VerifierTokenServiceOut> = new TypeRef("sys", "VerifierTokenServiceOut")
export function createVerifierTokenServiceOut(values: StrippedEntity<VerifierTokenServiceOut>): VerifierTokenServiceOut {
return Object.assign(create(typeModels.VerifierTokenServiceOut, VerifierTokenServiceOutTypeRef), values)
}
export type VerifierTokenServiceOut = {
_type: TypeRef<VerifierTokenServiceOut>;
_format: NumberString;
token: string;
}
export const VerifyRegistrationCodeDataTypeRef: TypeRef<VerifyRegistrationCodeData> = new TypeRef("sys", "VerifyRegistrationCodeData")
export function createVerifyRegistrationCodeData(values: StrippedEntity<VerifyRegistrationCodeData>): VerifyRegistrationCodeData {

View file

@ -1,6 +1,6 @@
const modelInfo = {
version: 78,
compatibleSince: 77,
version: 79,
compatibleSince: 79,
}
export default modelInfo

File diff suppressed because it is too large Load diff

View file

@ -1229,7 +1229,9 @@ export type MailBox = {
archivedMailBags: MailBag[];
currentMailBag: null | MailBag;
folders: null | MailFolderRef;
importedAttachments: Id;
mailDetailsDrafts: null | MailDetailsDraftsRef;
mailImportStates: Id;
receivedAttachments: Id;
sentAttachments: Id;
spamResults: null | SpamResults;

View file

@ -26,6 +26,7 @@ import {
SecondFactorAuthService,
SessionService,
TakeOverDeletedAddressService,
VerifierTokenService,
} from "../../entities/sys/Services"
import { AccountType, asKdfType, CloseEventBusOption, Const, DEFAULT_KDF_TYPE, KdfType } from "../../common/TutanotaConstants"
import {
@ -40,6 +41,7 @@ import {
createSecondFactorAuthGetData,
CreateSessionReturn,
createTakeOverDeletedAddressData,
createVerifierTokenServiceIn,
GroupInfo,
GroupInfoTypeRef,
RecoverCodeTypeRef,
@ -136,7 +138,14 @@ type ResumeSessionSuccess = { type: "success"; data: ResumeSessionResultData }
type ResumeSessionFailure = { type: "error"; reason: ResumeSessionErrorReason }
type ResumeSessionResult = ResumeSessionSuccess | ResumeSessionFailure
type AsyncLoginState = { state: "idle" } | { state: "running" } | { state: "failed"; credentials: Credentials; cacheInfo: CacheInfo }
type AsyncLoginState =
| { state: "idle" }
| { state: "running" }
| {
state: "failed"
credentials: Credentials
cacheInfo: CacheInfo
}
/**
* All attributes that are required to derive the passphrase key.
@ -759,7 +768,16 @@ export class LoginFacade {
*/
private async initCache({ userId, databaseKey, timeRangeDays, forceNewDatabase }: InitCacheOptions): Promise<CacheInfo> {
if (databaseKey != null) {
return { databaseKey, ...(await this.cacheInitializer.initialize({ type: "offline", userId, databaseKey, timeRangeDays, forceNewDatabase })) }
return {
databaseKey,
...(await this.cacheInitializer.initialize({
type: "offline",
userId,
databaseKey,
timeRangeDays,
forceNewDatabase,
})),
}
} else {
return { databaseKey: null, ...(await this.cacheInitializer.initialize({ type: "ephemeral", userId })) }
}
@ -809,7 +827,13 @@ export class LoginFacade {
}
}
private async loadUserPassphraseKey(mailAddress: string, passphrase: string): Promise<{ kdfType: KdfType; userPassphraseKey: AesKey }> {
private async loadUserPassphraseKey(
mailAddress: string,
passphrase: string,
): Promise<{
kdfType: KdfType
userPassphraseKey: AesKey
}> {
mailAddress = mailAddress.toLowerCase().trim()
const saltRequest = createSaltData({ mailAddress })
const saltReturn = await this.serviceExecutor.get(SaltService, saltRequest)
@ -1104,4 +1128,21 @@ export class LoginFacade {
throw new Error("credentials went missing")
}
}
/**
* Returns a verifier token, which is proof of password authentication and is valid for a limited time.
* This token will have to be passed back to the server with the appropriate call.
*/
async getVerifierToken(passphrase: string): Promise<string> {
const user = this.userFacade.getLoggedInUser()
const passphraseKey = await this.deriveUserPassphraseKey({
kdfType: asKdfType(user.kdfVersion),
passphrase,
salt: assertNotNull(user.salt),
})
const authVerifier = createAuthVerifier(passphraseKey)
const out = await this.serviceExecutor.post(VerifierTokenService, createVerifierTokenServiceIn({ authVerifier }))
return out.token
}
}

View file

@ -1,6 +1,7 @@
import {
CacheMode,
EntityRestClient,
EntityRestClientEraseOptions,
EntityRestClientLoadOptions,
EntityRestClientSetupOptions,
EntityRestInterface,
@ -312,8 +313,8 @@ export class DefaultEntityRestCache implements EntityRestCache {
return this.entityRestClient.update(instance)
}
erase<T extends SomeEntity>(instance: T): Promise<void> {
return this.entityRestClient.erase(instance)
erase<T extends SomeEntity>(instance: T, options?: EntityRestClientEraseOptions): Promise<void> {
return this.entityRestClient.erase(instance, options)
}
getLastEntityEventBatchForGroup(groupId: Id): Promise<Id | null> {

View file

@ -48,6 +48,10 @@ export interface EntityRestClientUpdateOptions {
ownerKeyProvider?: OwnerKeyProvider
}
export interface EntityRestClientEraseOptions {
extraHeaders?: Dict
}
/**
* Whether to use the cache to fetch the entity
*/
@ -121,7 +125,7 @@ export interface EntityRestInterface {
/**
* Deletes a single element on the server.
*/
erase<T extends SomeEntity>(instance: T): Promise<void>
erase<T extends SomeEntity>(instance: T, options?: EntityRestClientEraseOptions): Promise<void>
/**
* Must be called when entity events are received.
@ -445,9 +449,16 @@ export class EntityRestClient implements EntityRestInterface {
})
}
async erase<T extends SomeEntity>(instance: T): Promise<void> {
async erase<T extends SomeEntity>(instance: T, options?: EntityRestClientEraseOptions): Promise<void> {
const { listId, elementId } = expandId(instance._id)
const { path, queryParams, headers } = await this._validateAndPrepareRestRequest(instance._type, listId, elementId, undefined, undefined, undefined)
const { path, queryParams, headers } = await this._validateAndPrepareRestRequest(
instance._type,
listId,
elementId,
undefined,
options?.extraHeaders,
undefined,
)
await this.restClient.request(path, HttpMethod.DELETE, {
queryParams,
headers,

View file

@ -14,6 +14,7 @@ import { BootIcons } from "../../gui/base/icons/BootIcons.js"
export function showRequestPasswordDialog(props: {
title?: string
messageText?: string
action: (pw: string) => Promise<string>
cancel: {
textId: TranslationKey
@ -36,21 +37,24 @@ export function showRequestPasswordDialog(props: {
view: () => {
const savedState = state
return savedState.type == "idle"
? m(PasswordField, {
label: title,
helpLabel: () => savedState.message,
value: value,
oninput: (newValue) => (value = newValue),
autocompleteAs: Autocomplete.off,
keyHandler: (key: KeyPress) => {
if (isKeyPressed(key.key, Keys.RETURN)) {
doAction()
return false
}
? m("", [
props.messageText ? m(".pt", props.messageText) : null,
m(PasswordField, {
label: title,
helpLabel: () => savedState.message,
value: value,
oninput: (newValue) => (value = newValue),
autocompleteAs: Autocomplete.off,
keyHandler: (key: KeyPress) => {
if (isKeyPressed(key.key, Keys.RETURN)) {
doAction()
return false
}
return true
},
} satisfies PasswordFieldAttrs)
return true
},
} satisfies PasswordFieldAttrs),
])
: m(Icon, {
icon: BootIcons.Progress,
class: "icon-xl icon-progress block mt mb",

View file

@ -51,7 +51,13 @@ export class UserViewer implements UpdatableSettingsDetailsViewer {
this.mailAddressTableExpanded = false
this.secondFactorsForm = new SecondFactorsEditForm(this.user, locator.domainConfigProvider())
this.secondFactorsForm = new SecondFactorsEditForm(
this.user,
locator.domainConfigProvider(),
locator.loginFacade,
this.isAdmin,
!!this.userGroupInfo.deleted,
)
this.teamGroupInfos.getAsync().then(async (availableTeamGroupInfos) => {
if (availableTeamGroupInfos.length > 0) {
@ -157,10 +163,17 @@ export class UserViewer implements UpdatableSettingsDetailsViewer {
}
private onChangeName(name: string) {
Dialog.showProcessTextInputDialog({ title: "edit_action", label: "name_label", defaultValue: name }, (newName) => {
this.userGroupInfo.name = newName
return locator.entityClient.update(this.userGroupInfo)
})
Dialog.showProcessTextInputDialog(
{
title: "edit_action",
label: "name_label",
defaultValue: name,
},
(newName) => {
this.userGroupInfo.name = newName
return locator.entityClient.update(this.userGroupInfo)
},
)
}
private renderAdminStatusSelector(): Children {

View file

@ -44,6 +44,9 @@ export class LoginSettingsViewer implements UpdatableSettingsViewer {
private readonly _secondFactorsForm = new SecondFactorsEditForm(
new LazyLoaded(() => Promise.resolve(locator.logins.getUserController().user)),
locator.domainConfigProvider(),
locator.loginFacade,
true,
false,
)
private readonly _usageTestModel: UsageTestModel
private credentialEncryptionMode: CredentialEncryptionMode | null = null

View file

@ -23,6 +23,7 @@ import { ButtonSize } from "../../../gui/base/ButtonSize.js"
import { NameValidationStatus, SecondFactorEditModel, SecondFactorTypeToNameTextId, VerificationStatus } from "./SecondFactorEditModel.js"
import { UserError } from "../../../api/main/UserError.js"
import { LoginButton } from "../../../gui/base/buttons/LoginButton.js"
import { NotAuthorizedError } from "../../../api/common/error/RestError"
export class SecondFactorEditDialog {
private readonly dialog: Dialog
@ -50,6 +51,12 @@ export class SecondFactorEditDialog {
if (e instanceof UserError) {
// noinspection ES6MissingAwait
Dialog.message(() => e.message)
} else if (e instanceof NotAuthorizedError) {
this.dialog.close()
Dialog.message("contactFormSubmitError_msg")
return
} else {
throw e
}
}
}
@ -59,8 +66,8 @@ export class SecondFactorEditDialog {
RecoverCodeDialog.showRecoverCodeDialogAfterPasswordVerificationAndInfoDialog(user)
}
static async loadAndShow(entityClient: EntityClient, lazyUser: LazyLoaded<User>, mailAddress: string): Promise<void> {
const dialog: SecondFactorEditDialog = await showProgressDialog("pleaseWait_msg", this.loadWebauthnClient(entityClient, lazyUser, mailAddress))
static async loadAndShow(entityClient: EntityClient, lazyUser: LazyLoaded<User>, token?: string): Promise<void> {
const dialog: SecondFactorEditDialog = await showProgressDialog("pleaseWait_msg", this.loadWebauthnClient(entityClient, lazyUser, token))
dialog.dialog.show()
}
@ -167,22 +174,21 @@ export class SecondFactorEditDialog {
}
}
private static async loadWebauthnClient(entityClient: EntityClient, lazyUser: LazyLoaded<User>, mailAddress: string): Promise<SecondFactorEditDialog> {
private static async loadWebauthnClient(entityClient: EntityClient, lazyUser: LazyLoaded<User>, token?: string): Promise<SecondFactorEditDialog> {
const totpKeys = await locator.loginFacade.generateTotpSecret()
const user = await lazyUser.getAsync()
const webauthnSupported = await locator.webAuthn.isSupported()
const model = new SecondFactorEditModel(
entityClient,
user,
mailAddress,
locator.webAuthn,
totpKeys,
webauthnSupported,
lang,
locator.loginFacade,
location.hostname,
locator.domainConfigProvider().getCurrentDomainConfig(),
m.redraw,
token,
)
return new SecondFactorEditDialog(model)
}

View file

@ -48,15 +48,14 @@ export class SecondFactorEditModel {
constructor(
private readonly entityClient: EntityClient,
private readonly user: User,
private readonly mailAddress: string,
private readonly webauthnClient: WebauthnClient,
readonly totpKeys: TotpSecret,
private readonly webauthnSupported: boolean,
private readonly lang: LanguageViewModel,
private readonly loginFacade: LoginFacade,
private readonly hostname: string,
private readonly domainConfig: DomainConfig,
private readonly updateViewCallback: () => void,
private readonly token?: string,
) {
this.selectedType = webauthnSupported ? SecondFactorType.webauthn : SecondFactorType.totp
this.setDefaultNameIfNeeded()
@ -209,7 +208,7 @@ export class SecondFactorEditModel {
sf.otpSecret = this.totpKeys.key
}
}
await this.entityClient.setup(assertNotNull(this.user.auth).secondFactors, sf)
await this.entityClient.setup(assertNotNull(this.user.auth).secondFactors, sf, this.token ? { token: this.token } : undefined)
return this.user
}

View file

@ -2,15 +2,13 @@ import m, { Children } from "mithril"
import { assertMainOrNode } from "../../../api/common/Env.js"
import type { SecondFactor, User } from "../../../api/entities/sys/TypeRefs.js"
import { SecondFactorTypeRef } from "../../../api/entities/sys/TypeRefs.js"
import { assertNotNull, LazyLoaded, neverNull, ofClass } from "@tutao/tutanota-utils"
import { assertNotNull, LazyLoaded, neverNull, noOp } from "@tutao/tutanota-utils"
import { Icons } from "../../../gui/base/icons/Icons.js"
import { Dialog } from "../../../gui/base/Dialog.js"
import { InfoLink, lang } from "../../../misc/LanguageViewModel.js"
import { assertEnumValue, SecondFactorType } from "../../../api/common/TutanotaConstants.js"
import { showProgressDialog } from "../../../gui/dialogs/ProgressDialog.js"
import type { TableAttrs, TableLineAttrs } from "../../../gui/base/Table.js"
import { ColumnWidth, Table } from "../../../gui/base/Table.js"
import { NotFoundError } from "../../../api/common/error/RestError.js"
import { NotAuthorizedError, NotFoundError } from "../../../api/common/error/RestError.js"
import { ifAllowedTutaLinks } from "../../../gui/base/GuiUtils.js"
import { locator } from "../../../api/main/CommonLocator.js"
import { SecondFactorEditDialog } from "./SecondFactorEditDialog.js"
@ -21,16 +19,28 @@ import { appIdToLoginUrl } from "../../../misc/2fa/SecondFactorUtils.js"
import { DomainConfigProvider } from "../../../api/common/DomainConfigProvider.js"
import { EntityUpdateData, isUpdateForTypeRef } from "../../../api/common/utils/EntityUpdateUtils.js"
import { MoreInfoLink } from "../../../misc/news/MoreInfoLink.js"
import { showRequestPasswordDialog } from "../../../misc/passwords/PasswordRequestDialog"
import { LoginFacade } from "../../../api/worker/facades/LoginFacade"
import { showProgressDialog } from "../../../gui/dialogs/ProgressDialog"
import { Dialog } from "../../../gui/base/Dialog"
assertMainOrNode()
export class SecondFactorsEditForm {
_2FALineAttrs: TableLineAttrs[]
constructor(private readonly user: LazyLoaded<User>, private readonly domainConfigProvider: DomainConfigProvider) {
constructor(
private readonly user: LazyLoaded<User>,
private readonly domainConfigProvider: DomainConfigProvider,
private readonly loginFacade: LoginFacade,
private askForPassword: boolean,
private isDeactivated: boolean,
) {
this._2FALineAttrs = []
this._updateSecondFactors()
this.view = this.view.bind(this)
}
view(): Children {
@ -41,7 +51,15 @@ export class SecondFactorsEditForm {
showActionButtonColumn: true,
addButtonAttrs: {
title: "addSecondFactor_action",
click: () => this._showAddSecondFactorDialog(),
click: () => {
if (this.isDeactivated) {
Dialog.message("userAccountDeactivated_msg")
} else if (this.askForPassword) {
this.showAddSecondFactorDialogWithPasswordCheck()
} else {
this.showAddSecondFactorDialog()
}
},
icon: Icons.Add,
size: ButtonSize.Compact,
},
@ -50,7 +68,14 @@ export class SecondFactorsEditForm {
m(".h4.mt-l", lang.get("secondFactorAuthentication_label")),
m(Table, secondFactorTableAttrs),
this.domainConfigProvider.getCurrentDomainConfig().firstPartyDomain
? [ifAllowedTutaLinks(locator.logins, InfoLink.SecondFactor, (link) => m(MoreInfoLink, { link: link, isSmall: true }))]
? [
ifAllowedTutaLinks(locator.logins, InfoLink.SecondFactor, (link) =>
m(MoreInfoLink, {
link: link,
isSmall: true,
}),
),
]
: null,
]
}
@ -73,10 +98,15 @@ export class SecondFactorsEditForm {
this._2FALineAttrs = factors.map((f) => {
const removeButtonAttrs: IconButtonAttrs = {
title: "remove_action",
click: () =>
Dialog.confirm("confirmDeleteSecondFactor_msg")
.then((res) => (res ? showProgressDialog("pleaseWait_msg", locator.entityClient.erase(f)) : Promise.resolve()))
.catch(ofClass(NotFoundError, (e) => console.log("could not delete second factor (already deleted)", e))),
click: () => {
if (this.isDeactivated) {
Dialog.message("userAccountDeactivated_msg")
} else if (this.askForPassword) {
this.removeSecondFactorWithPasswordCheck(f)
} else {
this.removeSecondFactor(f)
}
},
icon: Icons.Cancel,
size: ButtonSize.Compact,
}
@ -106,9 +136,72 @@ export class SecondFactorsEditForm {
}
}
_showAddSecondFactorDialog() {
const mailAddress = assertNotNull(locator.logins.getUserController().userGroupInfo.mailAddress)
SecondFactorEditDialog.loadAndShow(locator.entityClient, this.user, mailAddress)
private showAddSecondFactorDialogWithPasswordCheck() {
const dialog = showRequestPasswordDialog({
action: async (passphrase) => {
try {
const token = await this.loginFacade.getVerifierToken(passphrase)
this.showAddSecondFactorDialog(token)
} catch (e) {
if (e instanceof NotAuthorizedError) {
return lang.get("invalidPassword_msg")
} else {
throw e
}
}
dialog.close()
return ""
},
cancel: {
textId: "cancel_action",
action: noOp,
},
})
}
private showAddSecondFactorDialog(token?: string) {
SecondFactorEditDialog.loadAndShow(locator.entityClient, this.user, token)
}
private removeSecondFactorWithPasswordCheck(secondFactorToRemove: SecondFactor) {
const dialog = showRequestPasswordDialog({
action: async (passphrase) => {
let token = undefined
try {
token = await this.loginFacade.getVerifierToken(passphrase)
} catch (e) {
if (e instanceof NotAuthorizedError) {
return lang.get("invalidPassword_msg")
} else {
throw e
}
}
this.removeSecondFactor(secondFactorToRemove, token)
dialog.close()
return ""
},
messageText: lang.get("confirmDeleteSecondFactor_msg"),
cancel: {
textId: "cancel_action",
action: noOp,
},
})
}
private removeSecondFactor(secondFactorToRemove: SecondFactor, token?: string) {
try {
let options = undefined
if (token) {
options = { extraHeaders: { token } }
}
showProgressDialog("pleaseWait_msg", locator.entityClient.erase(secondFactorToRemove, options))
} catch (e) {
if (e instanceof NotFoundError) {
console.log("could not delete second factor (already deleted)")
} else {
throw e
}
}
}
entityEventReceived(update: EntityUpdateData): Promise<void> {

View file

@ -11,7 +11,6 @@ import { WebauthnClient } from "../../../../../src/common/misc/2fa/webauthn/Weba
import { GroupInfoTypeRef, User } from "../../../../../src/common/api/entities/sys/TypeRefs.js"
import { TotpSecret, TotpVerifier } from "@tutao/tutanota-crypto"
import { noOp } from "@tutao/tutanota-utils"
import { LanguageViewModel } from "../../../../../src/common/misc/LanguageViewModel.js"
import { LoginFacade } from "../../../../../src/common/api/worker/facades/LoginFacade.js"
import { SecondFactorType } from "../../../../../src/common/api/common/TutanotaConstants.js"
import { createTestEntity, domainConfigStub } from "../../../TestUtils.js"
@ -29,8 +28,6 @@ o.spec("SecondFactorEditModel", function () {
let loginFacadeMock: LoginFacade
const totpKeys = createTotpKeys()
const validName = "myU2Fkey"
const langMock: LanguageViewModel = object()
when(langMock.get(matchers.anything())).thenReturn("hello there")
// this is too long if you convert it to bytes
const invalidName = "🏳️‍🌈🏳️‍🌈🏳️‍🌈🏳️‍🌈🏴‍☠️🏴‍☠️🏴‍☠️🏴‍☠️🏴‍☠️"
const hostname = "testhostname"
@ -39,11 +36,9 @@ o.spec("SecondFactorEditModel", function () {
const model = new SecondFactorEditModel(
params.entityClient ?? entityClientMock,
params.user ?? userMock,
"testaddress@tutanota.de",
params.webAuthnClient ?? webAuthnClientMock,
totpKeys,
params.webauthnSupported ?? true,
langMock,
loginFacadeMock,
hostname,
domainConfigStub,
@ -128,7 +123,7 @@ o.spec("SecondFactorEditModel", function () {
o.spec("saving a second factor", function () {
o("saving a u2f key, happy path", async function () {
const redrawMock = tdfn("redrawMock")
when(entityClientMock.setup(matchers.anything(), matchers.anything())).thenResolve("randomID")
when(entityClientMock.setup(matchers.anything(), matchers.anything(), matchers.anything())).thenResolve("randomID")
when(webAuthnClientMock.register(matchers.anything(), matchers.anything())).thenResolve({})
const model = await createSecondFactorModel({ updateView: redrawMock })
@ -138,12 +133,12 @@ o.spec("SecondFactorEditModel", function () {
o(user).deepEquals(userMock)
verify(redrawMock(), { times: 2 })
verify(entityClientMock.setup(matchers.anything(), matchers.anything()), { times: 1 })
verify(entityClientMock.setup(matchers.anything(), matchers.anything(), matchers.anything()), { times: 1 })
})
o("saving a totp key, happy path", async function () {
const redrawMock = tdfn("redrawMock")
when(entityClientMock.setup(matchers.anything(), matchers.anything())).thenResolve("randomID")
when(entityClientMock.setup(matchers.anything(), matchers.anything(), matchers.anything())).thenResolve("randomID")
when(webAuthnClientMock.register(matchers.anything(), matchers.anything())).thenResolve({})
when(loginFacadeMock.generateTotpCode(matchers.anything(), matchers.anything())).thenResolve(123456)
const model = await createSecondFactorModel({ updateView: redrawMock })
@ -155,7 +150,7 @@ o.spec("SecondFactorEditModel", function () {
o(user).deepEquals(userMock)
verify(redrawMock(), { times: 3 })
verify(entityClientMock.setup(matchers.anything(), matchers.anything()), { times: 1 })
verify(entityClientMock.setup(matchers.anything(), matchers.anything(), matchers.anything()), { times: 1 })
})
})

View file

@ -4328,6 +4328,39 @@ impl Entity for VariableExternalAuthInfo {
}
}
#[derive(uniffi::Record, Clone, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq, Debug))]
pub struct VerifierTokenServiceIn {
pub _format: i64,
#[serde(with = "serde_bytes")]
pub authVerifier: Vec<u8>,
}
impl Entity for VerifierTokenServiceIn {
fn type_ref() -> TypeRef {
TypeRef {
app: "sys",
type_: "VerifierTokenServiceIn",
}
}
}
#[derive(uniffi::Record, Clone, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq, Debug))]
pub struct VerifierTokenServiceOut {
pub _format: i64,
pub token: String,
}
impl Entity for VerifierTokenServiceOut {
fn type_ref() -> TypeRef {
TypeRef {
app: "sys",
type_: "VerifierTokenServiceOut",
}
}
}
#[derive(uniffi::Record, Clone, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq, Debug))]
pub struct VerifyRegistrationCodeData {

View file

@ -1555,7 +1555,9 @@ pub struct MailBox {
pub archivedMailBags: Vec<MailBag>,
pub currentMailBag: Option<MailBag>,
pub folders: Option<MailFolderRef>,
pub importedAttachments: GeneratedId,
pub mailDetailsDrafts: Option<MailDetailsDraftsRef>,
pub mailImportStates: GeneratedId,
pub receivedAttachments: GeneratedId,
pub sentAttachments: GeneratedId,
pub spamResults: Option<SpamResults>,

View file

@ -94,35 +94,37 @@ use crate::entities::generated::sys::UpgradePriceServiceData;
use crate::entities::generated::sys::UpgradePriceServiceReturn;
use crate::entities::generated::sys::UserGroupKeyRotationPostIn;
use crate::entities::generated::sys::UserDataDelete;
use crate::entities::generated::sys::VerifierTokenServiceIn;
use crate::entities::generated::sys::VerifierTokenServiceOut;
use crate::entities::generated::sys::VersionData;
use crate::entities::generated::sys::VersionReturn;
pub struct AdminGroupKeyRotationService;
crate::service_impl!(declare, AdminGroupKeyRotationService, "sys/admingroupkeyrotationservice", 115);
crate::service_impl!(declare, AdminGroupKeyRotationService, "sys/admingroupkeyrotationservice", 117);
crate::service_impl!(POST, AdminGroupKeyRotationService, AdminGroupKeyRotationPostIn, ());
pub struct AffiliatePartnerKpiService;
crate::service_impl!(declare, AffiliatePartnerKpiService, "sys/affiliatepartnerkpiservice", 115);
crate::service_impl!(declare, AffiliatePartnerKpiService, "sys/affiliatepartnerkpiservice", 117);
crate::service_impl!(GET, AffiliatePartnerKpiService, (), AffiliatePartnerKpiServiceGetOut);
pub struct AlarmService;
crate::service_impl!(declare, AlarmService, "sys/alarmservice", 115);
crate::service_impl!(declare, AlarmService, "sys/alarmservice", 117);
crate::service_impl!(POST, AlarmService, AlarmServicePost, ());
pub struct AppStoreSubscriptionService;
crate::service_impl!(declare, AppStoreSubscriptionService, "sys/appstoresubscriptionservice", 115);
crate::service_impl!(declare, AppStoreSubscriptionService, "sys/appstoresubscriptionservice", 117);
crate::service_impl!(GET, AppStoreSubscriptionService, AppStoreSubscriptionGetIn, AppStoreSubscriptionGetOut);
pub struct AutoLoginService;
crate::service_impl!(declare, AutoLoginService, "sys/autologinservice", 115);
crate::service_impl!(declare, AutoLoginService, "sys/autologinservice", 117);
crate::service_impl!(POST, AutoLoginService, AutoLoginDataReturn, AutoLoginPostReturn);
crate::service_impl!(GET, AutoLoginService, AutoLoginDataGet, AutoLoginDataReturn);
crate::service_impl!(DELETE, AutoLoginService, AutoLoginDataDelete, ());
@ -130,7 +132,7 @@ crate::service_impl!(DELETE, AutoLoginService, AutoLoginDataDelete, ());
pub struct BrandingDomainService;
crate::service_impl!(declare, BrandingDomainService, "sys/brandingdomainservice", 115);
crate::service_impl!(declare, BrandingDomainService, "sys/brandingdomainservice", 117);
crate::service_impl!(POST, BrandingDomainService, BrandingDomainData, ());
crate::service_impl!(GET, BrandingDomainService, (), BrandingDomainGetReturn);
crate::service_impl!(PUT, BrandingDomainService, BrandingDomainData, ());
@ -139,37 +141,37 @@ crate::service_impl!(DELETE, BrandingDomainService, BrandingDomainDeleteData, ()
pub struct ChangeKdfService;
crate::service_impl!(declare, ChangeKdfService, "sys/changekdfservice", 115);
crate::service_impl!(declare, ChangeKdfService, "sys/changekdfservice", 117);
crate::service_impl!(POST, ChangeKdfService, ChangeKdfPostIn, ());
pub struct ChangePasswordService;
crate::service_impl!(declare, ChangePasswordService, "sys/changepasswordservice", 115);
crate::service_impl!(declare, ChangePasswordService, "sys/changepasswordservice", 117);
crate::service_impl!(POST, ChangePasswordService, ChangePasswordPostIn, ());
pub struct CloseSessionService;
crate::service_impl!(declare, CloseSessionService, "sys/closesessionservice", 115);
crate::service_impl!(declare, CloseSessionService, "sys/closesessionservice", 117);
crate::service_impl!(POST, CloseSessionService, CloseSessionServicePost, ());
pub struct CreateCustomerServerProperties;
crate::service_impl!(declare, CreateCustomerServerProperties, "sys/createcustomerserverproperties", 115);
crate::service_impl!(declare, CreateCustomerServerProperties, "sys/createcustomerserverproperties", 117);
crate::service_impl!(POST, CreateCustomerServerProperties, CreateCustomerServerPropertiesData, CreateCustomerServerPropertiesReturn);
pub struct CustomDomainCheckService;
crate::service_impl!(declare, CustomDomainCheckService, "sys/customdomaincheckservice", 115);
crate::service_impl!(declare, CustomDomainCheckService, "sys/customdomaincheckservice", 117);
crate::service_impl!(GET, CustomDomainCheckService, CustomDomainCheckGetIn, CustomDomainCheckGetOut);
pub struct CustomDomainService;
crate::service_impl!(declare, CustomDomainService, "sys/customdomainservice", 115);
crate::service_impl!(declare, CustomDomainService, "sys/customdomainservice", 117);
crate::service_impl!(POST, CustomDomainService, CustomDomainData, CustomDomainReturn);
crate::service_impl!(PUT, CustomDomainService, CustomDomainData, ());
crate::service_impl!(DELETE, CustomDomainService, CustomDomainData, ());
@ -177,50 +179,50 @@ crate::service_impl!(DELETE, CustomDomainService, CustomDomainData, ());
pub struct CustomerAccountTerminationService;
crate::service_impl!(declare, CustomerAccountTerminationService, "sys/customeraccountterminationservice", 115);
crate::service_impl!(declare, CustomerAccountTerminationService, "sys/customeraccountterminationservice", 117);
crate::service_impl!(POST, CustomerAccountTerminationService, CustomerAccountTerminationPostIn, CustomerAccountTerminationPostOut);
pub struct CustomerPublicKeyService;
crate::service_impl!(declare, CustomerPublicKeyService, "sys/customerpublickeyservice", 115);
crate::service_impl!(declare, CustomerPublicKeyService, "sys/customerpublickeyservice", 117);
crate::service_impl!(GET, CustomerPublicKeyService, (), PublicKeyGetOut);
pub struct CustomerService;
crate::service_impl!(declare, CustomerService, "sys/customerservice", 115);
crate::service_impl!(declare, CustomerService, "sys/customerservice", 117);
crate::service_impl!(DELETE, CustomerService, DeleteCustomerData, ());
pub struct DebitService;
crate::service_impl!(declare, DebitService, "sys/debitservice", 115);
crate::service_impl!(declare, DebitService, "sys/debitservice", 117);
crate::service_impl!(PUT, DebitService, DebitServicePutData, ());
pub struct DomainMailAddressAvailabilityService;
crate::service_impl!(declare, DomainMailAddressAvailabilityService, "sys/domainmailaddressavailabilityservice", 115);
crate::service_impl!(declare, DomainMailAddressAvailabilityService, "sys/domainmailaddressavailabilityservice", 117);
crate::service_impl!(GET, DomainMailAddressAvailabilityService, DomainMailAddressAvailabilityData, DomainMailAddressAvailabilityReturn);
pub struct ExternalPropertiesService;
crate::service_impl!(declare, ExternalPropertiesService, "sys/externalpropertiesservice", 115);
crate::service_impl!(declare, ExternalPropertiesService, "sys/externalpropertiesservice", 117);
crate::service_impl!(GET, ExternalPropertiesService, (), ExternalPropertiesReturn);
pub struct GiftCardRedeemService;
crate::service_impl!(declare, GiftCardRedeemService, "sys/giftcardredeemservice", 115);
crate::service_impl!(declare, GiftCardRedeemService, "sys/giftcardredeemservice", 117);
crate::service_impl!(POST, GiftCardRedeemService, GiftCardRedeemData, ());
crate::service_impl!(GET, GiftCardRedeemService, GiftCardRedeemData, GiftCardRedeemGetReturn);
pub struct GiftCardService;
crate::service_impl!(declare, GiftCardService, "sys/giftcardservice", 115);
crate::service_impl!(declare, GiftCardService, "sys/giftcardservice", 117);
crate::service_impl!(POST, GiftCardService, GiftCardCreateData, GiftCardCreateReturn);
crate::service_impl!(GET, GiftCardService, (), GiftCardGetReturn);
crate::service_impl!(DELETE, GiftCardService, GiftCardDeleteData, ());
@ -228,37 +230,37 @@ crate::service_impl!(DELETE, GiftCardService, GiftCardDeleteData, ());
pub struct GroupKeyRotationInfoService;
crate::service_impl!(declare, GroupKeyRotationInfoService, "sys/groupkeyrotationinfoservice", 115);
crate::service_impl!(declare, GroupKeyRotationInfoService, "sys/groupkeyrotationinfoservice", 117);
crate::service_impl!(GET, GroupKeyRotationInfoService, (), GroupKeyRotationInfoGetOut);
pub struct GroupKeyRotationService;
crate::service_impl!(declare, GroupKeyRotationService, "sys/groupkeyrotationservice", 115);
crate::service_impl!(declare, GroupKeyRotationService, "sys/groupkeyrotationservice", 117);
crate::service_impl!(POST, GroupKeyRotationService, GroupKeyRotationPostIn, ());
pub struct InvoiceDataService;
crate::service_impl!(declare, InvoiceDataService, "sys/invoicedataservice", 115);
crate::service_impl!(declare, InvoiceDataService, "sys/invoicedataservice", 117);
crate::service_impl!(GET, InvoiceDataService, InvoiceDataGetIn, InvoiceDataGetOut);
pub struct LocalAdminRemovalService;
crate::service_impl!(declare, LocalAdminRemovalService, "sys/localadminremovalservice", 115);
crate::service_impl!(declare, LocalAdminRemovalService, "sys/localadminremovalservice", 117);
crate::service_impl!(POST, LocalAdminRemovalService, LocalAdminRemovalPostIn, ());
pub struct LocationService;
crate::service_impl!(declare, LocationService, "sys/locationservice", 115);
crate::service_impl!(declare, LocationService, "sys/locationservice", 117);
crate::service_impl!(GET, LocationService, (), LocationServiceGetReturn);
pub struct MailAddressAliasService;
crate::service_impl!(declare, MailAddressAliasService, "sys/mailaddressaliasservice", 115);
crate::service_impl!(declare, MailAddressAliasService, "sys/mailaddressaliasservice", 117);
crate::service_impl!(POST, MailAddressAliasService, MailAddressAliasServiceData, ());
crate::service_impl!(GET, MailAddressAliasService, MailAddressAliasGetIn, MailAddressAliasServiceReturn);
crate::service_impl!(DELETE, MailAddressAliasService, MailAddressAliasServiceDataDelete, ());
@ -266,7 +268,7 @@ crate::service_impl!(DELETE, MailAddressAliasService, MailAddressAliasServiceDat
pub struct MembershipService;
crate::service_impl!(declare, MembershipService, "sys/membershipservice", 115);
crate::service_impl!(declare, MembershipService, "sys/membershipservice", 117);
crate::service_impl!(POST, MembershipService, MembershipAddData, ());
crate::service_impl!(PUT, MembershipService, MembershipPutIn, ());
crate::service_impl!(DELETE, MembershipService, MembershipRemoveData, ());
@ -274,13 +276,13 @@ crate::service_impl!(DELETE, MembershipService, MembershipRemoveData, ());
pub struct MultipleMailAddressAvailabilityService;
crate::service_impl!(declare, MultipleMailAddressAvailabilityService, "sys/multiplemailaddressavailabilityservice", 115);
crate::service_impl!(declare, MultipleMailAddressAvailabilityService, "sys/multiplemailaddressavailabilityservice", 117);
crate::service_impl!(GET, MultipleMailAddressAvailabilityService, MultipleMailAddressAvailabilityData, MultipleMailAddressAvailabilityReturn);
pub struct PaymentDataService;
crate::service_impl!(declare, PaymentDataService, "sys/paymentdataservice", 115);
crate::service_impl!(declare, PaymentDataService, "sys/paymentdataservice", 117);
crate::service_impl!(POST, PaymentDataService, PaymentDataServicePostData, ());
crate::service_impl!(GET, PaymentDataService, PaymentDataServiceGetData, PaymentDataServiceGetReturn);
crate::service_impl!(PUT, PaymentDataService, PaymentDataServicePutData, PaymentDataServicePutReturn);
@ -288,71 +290,71 @@ crate::service_impl!(PUT, PaymentDataService, PaymentDataServicePutData, Payment
pub struct PlanService;
crate::service_impl!(declare, PlanService, "sys/planservice", 115);
crate::service_impl!(declare, PlanService, "sys/planservice", 117);
crate::service_impl!(GET, PlanService, (), PlanServiceGetOut);
pub struct PriceService;
crate::service_impl!(declare, PriceService, "sys/priceservice", 115);
crate::service_impl!(declare, PriceService, "sys/priceservice", 117);
crate::service_impl!(GET, PriceService, PriceServiceData, PriceServiceReturn);
pub struct PublicKeyService;
crate::service_impl!(declare, PublicKeyService, "sys/publickeyservice", 115);
crate::service_impl!(declare, PublicKeyService, "sys/publickeyservice", 117);
crate::service_impl!(GET, PublicKeyService, PublicKeyGetIn, PublicKeyGetOut);
crate::service_impl!(PUT, PublicKeyService, PublicKeyPutIn, ());
pub struct ReferralCodeService;
crate::service_impl!(declare, ReferralCodeService, "sys/referralcodeservice", 115);
crate::service_impl!(declare, ReferralCodeService, "sys/referralcodeservice", 117);
crate::service_impl!(POST, ReferralCodeService, ReferralCodePostIn, ReferralCodePostOut);
crate::service_impl!(GET, ReferralCodeService, ReferralCodeGetIn, ());
pub struct RegistrationCaptchaService;
crate::service_impl!(declare, RegistrationCaptchaService, "sys/registrationcaptchaservice", 115);
crate::service_impl!(declare, RegistrationCaptchaService, "sys/registrationcaptchaservice", 117);
crate::service_impl!(POST, RegistrationCaptchaService, RegistrationCaptchaServiceData, ());
crate::service_impl!(GET, RegistrationCaptchaService, RegistrationCaptchaServiceGetData, RegistrationCaptchaServiceReturn);
pub struct RegistrationService;
crate::service_impl!(declare, RegistrationService, "sys/registrationservice", 115);
crate::service_impl!(declare, RegistrationService, "sys/registrationservice", 117);
crate::service_impl!(POST, RegistrationService, RegistrationServiceData, RegistrationReturn);
crate::service_impl!(GET, RegistrationService, (), RegistrationServiceData);
pub struct ResetFactorsService;
crate::service_impl!(declare, ResetFactorsService, "sys/resetfactorsservice", 115);
crate::service_impl!(declare, ResetFactorsService, "sys/resetfactorsservice", 117);
crate::service_impl!(DELETE, ResetFactorsService, ResetFactorsDeleteData, ());
pub struct ResetPasswordService;
crate::service_impl!(declare, ResetPasswordService, "sys/resetpasswordservice", 115);
crate::service_impl!(declare, ResetPasswordService, "sys/resetpasswordservice", 117);
crate::service_impl!(POST, ResetPasswordService, ResetPasswordPostIn, ());
pub struct SaltService;
crate::service_impl!(declare, SaltService, "sys/saltservice", 115);
crate::service_impl!(declare, SaltService, "sys/saltservice", 117);
crate::service_impl!(GET, SaltService, SaltData, SaltReturn);
pub struct SecondFactorAuthAllowedService;
crate::service_impl!(declare, SecondFactorAuthAllowedService, "sys/secondfactorauthallowedservice", 115);
crate::service_impl!(declare, SecondFactorAuthAllowedService, "sys/secondfactorauthallowedservice", 117);
crate::service_impl!(GET, SecondFactorAuthAllowedService, (), SecondFactorAuthAllowedReturn);
pub struct SecondFactorAuthService;
crate::service_impl!(declare, SecondFactorAuthService, "sys/secondfactorauthservice", 115);
crate::service_impl!(declare, SecondFactorAuthService, "sys/secondfactorauthservice", 117);
crate::service_impl!(POST, SecondFactorAuthService, SecondFactorAuthData, ());
crate::service_impl!(GET, SecondFactorAuthService, SecondFactorAuthGetData, SecondFactorAuthGetReturn);
crate::service_impl!(DELETE, SecondFactorAuthService, SecondFactorAuthDeleteData, ());
@ -360,65 +362,71 @@ crate::service_impl!(DELETE, SecondFactorAuthService, SecondFactorAuthDeleteData
pub struct SessionService;
crate::service_impl!(declare, SessionService, "sys/sessionservice", 115);
crate::service_impl!(declare, SessionService, "sys/sessionservice", 117);
crate::service_impl!(POST, SessionService, CreateSessionData, CreateSessionReturn);
pub struct SignOrderProcessingAgreementService;
crate::service_impl!(declare, SignOrderProcessingAgreementService, "sys/signorderprocessingagreementservice", 115);
crate::service_impl!(declare, SignOrderProcessingAgreementService, "sys/signorderprocessingagreementservice", 117);
crate::service_impl!(POST, SignOrderProcessingAgreementService, SignOrderProcessingAgreementData, ());
pub struct SwitchAccountTypeService;
crate::service_impl!(declare, SwitchAccountTypeService, "sys/switchaccounttypeservice", 115);
crate::service_impl!(declare, SwitchAccountTypeService, "sys/switchaccounttypeservice", 117);
crate::service_impl!(POST, SwitchAccountTypeService, SwitchAccountTypePostIn, ());
pub struct SystemKeysService;
crate::service_impl!(declare, SystemKeysService, "sys/systemkeysservice", 115);
crate::service_impl!(declare, SystemKeysService, "sys/systemkeysservice", 117);
crate::service_impl!(GET, SystemKeysService, (), SystemKeysReturn);
pub struct TakeOverDeletedAddressService;
crate::service_impl!(declare, TakeOverDeletedAddressService, "sys/takeoverdeletedaddressservice", 115);
crate::service_impl!(declare, TakeOverDeletedAddressService, "sys/takeoverdeletedaddressservice", 117);
crate::service_impl!(POST, TakeOverDeletedAddressService, TakeOverDeletedAddressData, ());
pub struct UpdatePermissionKeyService;
crate::service_impl!(declare, UpdatePermissionKeyService, "sys/updatepermissionkeyservice", 115);
crate::service_impl!(declare, UpdatePermissionKeyService, "sys/updatepermissionkeyservice", 117);
crate::service_impl!(POST, UpdatePermissionKeyService, UpdatePermissionKeyData, ());
pub struct UpdateSessionKeysService;
crate::service_impl!(declare, UpdateSessionKeysService, "sys/updatesessionkeysservice", 115);
crate::service_impl!(declare, UpdateSessionKeysService, "sys/updatesessionkeysservice", 117);
crate::service_impl!(POST, UpdateSessionKeysService, UpdateSessionKeysPostIn, ());
pub struct UpgradePriceService;
crate::service_impl!(declare, UpgradePriceService, "sys/upgradepriceservice", 115);
crate::service_impl!(declare, UpgradePriceService, "sys/upgradepriceservice", 117);
crate::service_impl!(GET, UpgradePriceService, UpgradePriceServiceData, UpgradePriceServiceReturn);
pub struct UserGroupKeyRotationService;
crate::service_impl!(declare, UserGroupKeyRotationService, "sys/usergroupkeyrotationservice", 115);
crate::service_impl!(declare, UserGroupKeyRotationService, "sys/usergroupkeyrotationservice", 117);
crate::service_impl!(POST, UserGroupKeyRotationService, UserGroupKeyRotationPostIn, ());
pub struct UserService;
crate::service_impl!(declare, UserService, "sys/userservice", 115);
crate::service_impl!(declare, UserService, "sys/userservice", 117);
crate::service_impl!(DELETE, UserService, UserDataDelete, ());
pub struct VerifierTokenService;
crate::service_impl!(declare, VerifierTokenService, "sys/verifiertokenservice", 117);
crate::service_impl!(POST, VerifierTokenService, VerifierTokenServiceIn, VerifierTokenServiceOut);
pub struct VersionService;
crate::service_impl!(declare, VersionService, "sys/versionservice", 115);
crate::service_impl!(declare, VersionService, "sys/versionservice", 117);
crate::service_impl!(GET, VersionService, VersionData, VersionReturn);

View file

@ -46,58 +46,58 @@ use crate::entities::generated::tutanota::UnreadMailStatePostIn;
use crate::entities::generated::tutanota::UserAccountCreateData;
pub struct ApplyLabelService;
crate::service_impl!(declare, ApplyLabelService, "tutanota/applylabelservice", 78);
crate::service_impl!(declare, ApplyLabelService, "tutanota/applylabelservice", 79);
crate::service_impl!(POST, ApplyLabelService, ApplyLabelServicePostIn, ());
pub struct CalendarService;
crate::service_impl!(declare, CalendarService, "tutanota/calendarservice", 78);
crate::service_impl!(declare, CalendarService, "tutanota/calendarservice", 79);
crate::service_impl!(POST, CalendarService, UserAreaGroupPostData, CreateGroupPostReturn);
crate::service_impl!(DELETE, CalendarService, CalendarDeleteData, ());
pub struct ContactListGroupService;
crate::service_impl!(declare, ContactListGroupService, "tutanota/contactlistgroupservice", 78);
crate::service_impl!(declare, ContactListGroupService, "tutanota/contactlistgroupservice", 79);
crate::service_impl!(POST, ContactListGroupService, UserAreaGroupPostData, CreateGroupPostReturn);
crate::service_impl!(DELETE, ContactListGroupService, UserAreaGroupDeleteData, ());
pub struct CustomerAccountService;
crate::service_impl!(declare, CustomerAccountService, "tutanota/customeraccountservice", 78);
crate::service_impl!(declare, CustomerAccountService, "tutanota/customeraccountservice", 79);
crate::service_impl!(POST, CustomerAccountService, CustomerAccountCreateData, ());
pub struct DraftService;
crate::service_impl!(declare, DraftService, "tutanota/draftservice", 78);
crate::service_impl!(declare, DraftService, "tutanota/draftservice", 79);
crate::service_impl!(POST, DraftService, DraftCreateData, DraftCreateReturn);
crate::service_impl!(PUT, DraftService, DraftUpdateData, DraftUpdateReturn);
pub struct EncryptTutanotaPropertiesService;
crate::service_impl!(declare, EncryptTutanotaPropertiesService, "tutanota/encrypttutanotapropertiesservice", 78);
crate::service_impl!(declare, EncryptTutanotaPropertiesService, "tutanota/encrypttutanotapropertiesservice", 79);
crate::service_impl!(POST, EncryptTutanotaPropertiesService, EncryptTutanotaPropertiesData, ());
pub struct EntropyService;
crate::service_impl!(declare, EntropyService, "tutanota/entropyservice", 78);
crate::service_impl!(declare, EntropyService, "tutanota/entropyservice", 79);
crate::service_impl!(PUT, EntropyService, EntropyData, ());
pub struct ExternalUserService;
crate::service_impl!(declare, ExternalUserService, "tutanota/externaluserservice", 78);
crate::service_impl!(declare, ExternalUserService, "tutanota/externaluserservice", 79);
crate::service_impl!(POST, ExternalUserService, ExternalUserData, ());
pub struct GroupInvitationService;
crate::service_impl!(declare, GroupInvitationService, "tutanota/groupinvitationservice", 78);
crate::service_impl!(declare, GroupInvitationService, "tutanota/groupinvitationservice", 79);
crate::service_impl!(POST, GroupInvitationService, GroupInvitationPostData, GroupInvitationPostReturn);
crate::service_impl!(PUT, GroupInvitationService, GroupInvitationPutData, ());
crate::service_impl!(DELETE, GroupInvitationService, GroupInvitationDeleteData, ());
@ -105,13 +105,13 @@ crate::service_impl!(DELETE, GroupInvitationService, GroupInvitationDeleteData,
pub struct ListUnsubscribeService;
crate::service_impl!(declare, ListUnsubscribeService, "tutanota/listunsubscribeservice", 78);
crate::service_impl!(declare, ListUnsubscribeService, "tutanota/listunsubscribeservice", 79);
crate::service_impl!(POST, ListUnsubscribeService, ListUnsubscribeData, ());
pub struct MailFolderService;
crate::service_impl!(declare, MailFolderService, "tutanota/mailfolderservice", 78);
crate::service_impl!(declare, MailFolderService, "tutanota/mailfolderservice", 79);
crate::service_impl!(POST, MailFolderService, CreateMailFolderData, CreateMailFolderReturn);
crate::service_impl!(PUT, MailFolderService, UpdateMailFolderData, ());
crate::service_impl!(DELETE, MailFolderService, DeleteMailFolderData, ());
@ -119,81 +119,81 @@ crate::service_impl!(DELETE, MailFolderService, DeleteMailFolderData, ());
pub struct MailGroupService;
crate::service_impl!(declare, MailGroupService, "tutanota/mailgroupservice", 78);
crate::service_impl!(declare, MailGroupService, "tutanota/mailgroupservice", 79);
crate::service_impl!(POST, MailGroupService, CreateMailGroupData, ());
crate::service_impl!(DELETE, MailGroupService, DeleteGroupData, ());
pub struct MailService;
crate::service_impl!(declare, MailService, "tutanota/mailservice", 78);
crate::service_impl!(declare, MailService, "tutanota/mailservice", 79);
crate::service_impl!(DELETE, MailService, DeleteMailData, ());
pub struct ManageLabelService;
crate::service_impl!(declare, ManageLabelService, "tutanota/managelabelservice", 78);
crate::service_impl!(declare, ManageLabelService, "tutanota/managelabelservice", 79);
crate::service_impl!(POST, ManageLabelService, ManageLabelServicePostIn, ());
crate::service_impl!(DELETE, ManageLabelService, ManageLabelServiceDeleteIn, ());
pub struct MoveMailService;
crate::service_impl!(declare, MoveMailService, "tutanota/movemailservice", 78);
crate::service_impl!(declare, MoveMailService, "tutanota/movemailservice", 79);
crate::service_impl!(POST, MoveMailService, MoveMailData, ());
pub struct NewsService;
crate::service_impl!(declare, NewsService, "tutanota/newsservice", 78);
crate::service_impl!(declare, NewsService, "tutanota/newsservice", 79);
crate::service_impl!(POST, NewsService, NewsIn, ());
crate::service_impl!(GET, NewsService, (), NewsOut);
pub struct ReceiveInfoService;
crate::service_impl!(declare, ReceiveInfoService, "tutanota/receiveinfoservice", 78);
crate::service_impl!(declare, ReceiveInfoService, "tutanota/receiveinfoservice", 79);
crate::service_impl!(POST, ReceiveInfoService, ReceiveInfoServiceData, ());
pub struct ReportMailService;
crate::service_impl!(declare, ReportMailService, "tutanota/reportmailservice", 78);
crate::service_impl!(declare, ReportMailService, "tutanota/reportmailservice", 79);
crate::service_impl!(POST, ReportMailService, ReportMailPostData, ());
pub struct SendDraftService;
crate::service_impl!(declare, SendDraftService, "tutanota/senddraftservice", 78);
crate::service_impl!(declare, SendDraftService, "tutanota/senddraftservice", 79);
crate::service_impl!(POST, SendDraftService, SendDraftData, SendDraftReturn);
pub struct SimpleMoveMailService;
crate::service_impl!(declare, SimpleMoveMailService, "tutanota/simplemovemailservice", 78);
crate::service_impl!(declare, SimpleMoveMailService, "tutanota/simplemovemailservice", 79);
crate::service_impl!(POST, SimpleMoveMailService, SimpleMoveMailPostIn, ());
pub struct TemplateGroupService;
crate::service_impl!(declare, TemplateGroupService, "tutanota/templategroupservice", 78);
crate::service_impl!(declare, TemplateGroupService, "tutanota/templategroupservice", 79);
crate::service_impl!(POST, TemplateGroupService, UserAreaGroupPostData, CreateGroupPostReturn);
crate::service_impl!(DELETE, TemplateGroupService, UserAreaGroupDeleteData, ());
pub struct TranslationService;
crate::service_impl!(declare, TranslationService, "tutanota/translationservice", 78);
crate::service_impl!(declare, TranslationService, "tutanota/translationservice", 79);
crate::service_impl!(GET, TranslationService, TranslationGetIn, TranslationGetOut);
pub struct UnreadMailStateService;
crate::service_impl!(declare, UnreadMailStateService, "tutanota/unreadmailstateservice", 78);
crate::service_impl!(declare, UnreadMailStateService, "tutanota/unreadmailstateservice", 79);
crate::service_impl!(POST, UnreadMailStateService, UnreadMailStatePostIn, ());
pub struct UserAccountService;
crate::service_impl!(declare, UserAccountService, "tutanota/useraccountservice", 78);
crate::service_impl!(declare, UserAccountService, "tutanota/useraccountservice", 79);
crate::service_impl!(POST, UserAccountService, UserAccountCreateData, ());

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff