From d8d5991977af81a30f9a3be5f9843cb4ca74f995 Mon Sep 17 00:00:00 2001 From: neo773 <62795688+neo773@users.noreply.github.com> Date: Tue, 16 Jun 2026 21:39:04 +0530 Subject: [PATCH] fix(messaging): honor IMAP/SMTP encryption setting instead of inferring it from the port (#21562) This pull request makes the IMAP and SMTP encryption setting actually honor what the user selects. As per spec there's 3 modes: SSL/TLS (implicit TLS from the start), STARTTLS (it will attempt TLS but if the server doesn't support it, it gracefully falls back to plaintext), NONE (plaintext) Current implementation had a boolean flag for this, this replaces it with the 3 modes Upgrade command to migrate all existing accounts, to not risk breaking anyone's existing account in production we map each account to the mode that matches its current behavior, so nothing changes on the wire /closes #21300 Review in cubic --------- Co-authored-by: Charles Bochet --- .../src/metadata/generated/schema.graphql | 12 +- .../src/metadata/generated/schema.ts | 18 +- .../src/metadata/generated/types.ts | 708 +++++++++--------- .../src/generated-metadata/graphql.ts | 20 +- .../SettingsAccountsConnectionForm.tsx | 22 +- .../getConnectedImapSmtpCaldavAccount.ts | 6 +- .../graphql/queries/getMyConnectedAccounts.ts | 4 +- .../hooks/useImapSmtpCaldavConnectionForm.ts | 23 +- .../connectionImapSmtpCalDav.ts | 4 +- ...1461753981-backfill-connection-security.ts | 65 ++ .../instance-commands.constant.ts | 2 + .../imap-smtp-caldav-connected-account.dto.ts | 6 +- .../dtos/imap-smtp-caldav-connection.input.ts | 12 +- .../enums/email-connection-security.enum.ts | 5 + .../schemas/connection-parameters.schema.ts | 5 +- ...map-smtp-caldav-connection.service.spec.ts | 63 +- .../imap-smtp-caldav-connection.service.ts | 5 +- .../types/imap-smtp-caldav-connection.type.ts | 2 + .../build-imap-tls-options.util.spec.ts | 23 + .../build-smtp-tls-options.util.spec.ts | 23 + .../utils/build-imap-tls-options.util.ts | 19 + ...build-public-connection-parameters.util.ts | 7 +- .../utils/build-smtp-tls-options.util.ts | 19 + .../dtos/connected-account-public.dto.ts | 5 +- .../imap-smtp-caldav-apis.service.spec.ts | 22 +- .../imap/providers/imap-client.provider.ts | 3 +- .../smtp/providers/smtp-client.provider.ts | 2 + ...ap-smtp-caldav-account.integration-spec.ts | 46 +- ...ap-smtp-caldav-account.integration-spec.ts | 34 +- ...connected-imap-smtp-caldav-account.util.ts | 6 +- .../save-imap-smtp-caldav-account.util.ts | 34 +- ...on-parameters-rotation.integration-spec.ts | 16 +- ...ll-connection-security.integration-spec.ts | 189 +++++ 33 files changed, 943 insertions(+), 487 deletions(-) create mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/2-15/2-15-instance-command-slow-1781461753981-backfill-connection-security.ts create mode 100644 packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum.ts create mode 100644 packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/__tests__/build-imap-tls-options.util.spec.ts create mode 100644 packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/__tests__/build-smtp-tls-options.util.spec.ts create mode 100644 packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-imap-tls-options.util.ts create mode 100644 packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-smtp-tls-options.util.ts create mode 100644 packages/twenty-server/test/integration/upgrade/suites/2-15-instance-command-slow-1781461753981-backfill-connection-security.integration-spec.ts diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql index 165fcdf631..4c2e06ea2b 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql @@ -2234,7 +2234,13 @@ type PublicConnectionParametersOutput { host: String! port: Float! username: String - secure: Boolean + connectionSecurity: EmailConnectionSecurity +} + +enum EmailConnectionSecurity { + NONE + STARTTLS + SSL_TLS } type PublicImapSmtpCaldavConnectionParameters { @@ -2589,7 +2595,7 @@ type ImapSmtpCaldavPublicConnectionParams { host: String! port: Float! username: String - secure: Boolean + connectionSecurity: EmailConnectionSecurity } type ImapSmtpCaldavPublicConnectionParameters { @@ -4546,7 +4552,7 @@ input ConnectionParametersInput { port: Float! username: String password: String - secure: Boolean + connectionSecurity: EmailConnectionSecurity } input UpdateLabPublicFeatureFlagInput { diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.ts b/packages/twenty-client-sdk/src/metadata/generated/schema.ts index 1801d53bfe..6f0727d870 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.ts @@ -1878,10 +1878,12 @@ export interface PublicConnectionParametersOutput { host: Scalars['String'] port: Scalars['Float'] username?: Scalars['String'] - secure?: Scalars['Boolean'] + connectionSecurity?: EmailConnectionSecurity __typename: 'PublicConnectionParametersOutput' } +export type EmailConnectionSecurity = 'NONE' | 'STARTTLS' | 'SSL_TLS' + export interface PublicImapSmtpCaldavConnectionParameters { IMAP?: PublicConnectionParametersOutput SMTP?: PublicConnectionParametersOutput @@ -2235,7 +2237,7 @@ export interface ImapSmtpCaldavPublicConnectionParams { host: Scalars['String'] port: Scalars['Float'] username?: Scalars['String'] - secure?: Scalars['Boolean'] + connectionSecurity?: EmailConnectionSecurity __typename: 'ImapSmtpCaldavPublicConnectionParams' } @@ -4934,7 +4936,7 @@ export interface PublicConnectionParametersOutputGenqlSelection{ host?: boolean | number port?: boolean | number username?: boolean | number - secure?: boolean | number + connectionSecurity?: boolean | number __typename?: boolean | number __scalar?: boolean | number } @@ -5317,7 +5319,7 @@ export interface ImapSmtpCaldavPublicConnectionParamsGenqlSelection{ host?: boolean | number port?: boolean | number username?: boolean | number - secure?: boolean | number + connectionSecurity?: boolean | number __typename?: boolean | number __scalar?: boolean | number } @@ -6476,7 +6478,7 @@ export interface SendEmailAttachmentInput {id: Scalars['String'],name: Scalars[' export interface EmailAccountConnectionParameters {IMAP?: (ConnectionParametersInput | null),SMTP?: (ConnectionParametersInput | null),CALDAV?: (ConnectionParametersInput | null)} -export interface ConnectionParametersInput {host: Scalars['String'],port: Scalars['Float'],username?: (Scalars['String'] | null),password?: (Scalars['String'] | null),secure?: (Scalars['Boolean'] | null)} +export interface ConnectionParametersInput {host: Scalars['String'],port: Scalars['Float'],username?: (Scalars['String'] | null),password?: (Scalars['String'] | null),connectionSecurity?: (EmailConnectionSecurity | null)} export interface UpdateLabPublicFeatureFlagInput {publicFeatureFlag: Scalars['String'],value: Scalars['Boolean']} @@ -9027,6 +9029,12 @@ export const enumBillingEntitlementKey = { AUDIT_LOGS: 'AUDIT_LOGS' as const } +export const enumEmailConnectionSecurity = { + NONE: 'NONE' as const, + STARTTLS: 'STARTTLS' as const, + SSL_TLS: 'SSL_TLS' as const +} + export const enumEmailingDomainStatus = { PENDING: 'PENDING' as const, VERIFIED: 'VERIFIED' as const, diff --git a/packages/twenty-client-sdk/src/metadata/generated/types.ts b/packages/twenty-client-sdk/src/metadata/generated/types.ts index 37c4461820..06d7741a98 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/types.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/types.ts @@ -61,27 +61,28 @@ export default { 202, 217, 229, - 268, - 270, + 235, + 269, 271, 272, 273, 274, 275, 276, - 283, - 321, + 277, + 284, 322, 323, 324, - 326, - 328, - 339, - 346, - 353, - 475, - 480, - 488 + 325, + 327, + 329, + 340, + 347, + 354, + 476, + 481, + 489 ], "types": { "BillingProductDTO": { @@ -4348,13 +4349,14 @@ export default { "username": [ 1 ], - "secure": [ - 6 + "connectionSecurity": [ + 235 ], "__typename": [ 1 ] }, + "EmailConnectionSecurity": {}, "PublicImapSmtpCaldavConnectionParameters": { "IMAP": [ 234 @@ -4419,7 +4421,7 @@ export default { 4 ], "connectionParameters": [ - 235 + 236 ], "__typename": [ 1 @@ -4470,7 +4472,7 @@ export default { }, "AvailableWorkspacesAndAccessTokens": { "tokens": [ - 241 + 242 ], "availableWorkspaces": [ 226 @@ -4525,7 +4527,7 @@ export default { 32 ], "workspace": [ - 246 + 247 ], "__typename": [ 1 @@ -4574,7 +4576,7 @@ export default { }, "AuthTokens": { "tokens": [ - 241 + 242 ], "__typename": [ 1 @@ -4615,7 +4617,7 @@ export default { 32 ], "workspace": [ - 246 + 247 ], "__typename": [ 1 @@ -4637,7 +4639,7 @@ export default { 1 ], "dailyUsage": [ - 257 + 258 ], "__typename": [ 1 @@ -4654,7 +4656,7 @@ export default { 195 ], "timeSeries": [ - 257 + 258 ], "periodStart": [ 4 @@ -4663,7 +4665,7 @@ export default { 4 ], "userDailyUsage": [ - 258 + 259 ], "__typename": [ 1 @@ -4820,10 +4822,10 @@ export default { 1 ], "status": [ - 268 + 269 ], "verificationRecords": [ - 266 + 267 ], "verifiedAt": [ 4 @@ -4838,22 +4840,22 @@ export default { 3 ], "visibility": [ - 270 + 271 ], "handle": [ 1 ], "type": [ - 271 + 272 ], "isContactAutoCreationEnabled": [ 6 ], "contactAutoCreationPolicy": [ - 272 + 273 ], "messageFolderImportPolicy": [ - 273 + 274 ], "excludeNonProfessionalEmails": [ 6 @@ -4862,7 +4864,7 @@ export default { 6 ], "pendingGroupEmailsAction": [ - 274 + 275 ], "isSyncEnabled": [ 6 @@ -4871,10 +4873,10 @@ export default { 4 ], "syncStatus": [ - 275 + 276 ], "syncStage": [ - 276 + 277 ], "syncStageStartedAt": [ 4 @@ -4895,7 +4897,7 @@ export default { 4 ], "connectedAccount": [ - 236 + 237 ], "__typename": [ 1 @@ -4910,7 +4912,7 @@ export default { "MessageChannelSyncStage": {}, "CreateEmailGroupChannelOutput": { "messageChannel": [ - 269 + 270 ], "forwardingAddress": [ 1 @@ -4972,7 +4974,7 @@ export default { 21 ], "skipped": [ - 280 + 281 ], "__typename": [ 1 @@ -4995,7 +4997,7 @@ export default { 1 ], "visibility": [ - 283 + 284 ], "__typename": [ 1 @@ -5041,7 +5043,7 @@ export default { 1 ], "location": [ - 285 + 286 ], "__typename": [ 1 @@ -5057,8 +5059,8 @@ export default { "username": [ 1 ], - "secure": [ - 6 + "connectionSecurity": [ + 235 ], "__typename": [ 1 @@ -5066,13 +5068,13 @@ export default { }, "ImapSmtpCaldavPublicConnectionParameters": { "IMAP": [ - 287 + 288 ], "SMTP": [ - 287 + 288 ], "CALDAV": [ - 287 + 288 ], "__typename": [ 1 @@ -5092,7 +5094,7 @@ export default { 3 ], "connectionParameters": [ - 288 + 289 ], "__typename": [ 1 @@ -5294,7 +5296,7 @@ export default { 1 ], "series": [ - 296 + 297 ], "xAxisLabel": [ 1 @@ -5343,7 +5345,7 @@ export default { 1 ], "data": [ - 298 + 299 ], "__typename": [ 1 @@ -5351,7 +5353,7 @@ export default { }, "LineChartData": { "series": [ - 299 + 300 ], "xAxisLabel": [ 1 @@ -5388,7 +5390,7 @@ export default { }, "PieChartData": { "data": [ - 301 + 302 ], "showLegend": [ 6 @@ -5490,13 +5492,13 @@ export default { }, "EventLogQueryResult": { "records": [ - 306 + 307 ], "totalCount": [ 21 ], "pageInfo": [ - 307 + 308 ], "__typename": [ 1 @@ -5560,7 +5562,7 @@ export default { 1 ], "parts": [ - 293 + 294 ], "processedAt": [ 4 @@ -5629,7 +5631,7 @@ export default { }, "AiSystemPromptPreview": { "sections": [ - 312 + 313 ], "estimatedTokenCount": [ 21 @@ -5705,10 +5707,10 @@ export default { 3 ], "evaluations": [ - 317 + 318 ], "messages": [ - 310 + 311 ], "createdAt": [ 4 @@ -5739,19 +5741,19 @@ export default { 1 ], "syncStatus": [ - 321 - ], - "syncStage": [ 322 ], - "visibility": [ + "syncStage": [ 323 ], + "visibility": [ + 324 + ], "isContactAutoCreationEnabled": [ 6 ], "contactAutoCreationPolicy": [ - 324 + 325 ], "isSyncEnabled": [ 6 @@ -5802,7 +5804,7 @@ export default { 1 ], "pendingSyncAction": [ - 326 + 327 ], "messageChannelId": [ 3 @@ -5820,7 +5822,7 @@ export default { "MessageFolderPendingSyncAction": {}, "CollectionHash": { "collectionName": [ - 328 + 329 ], "hash": [ 1 @@ -5887,13 +5889,13 @@ export default { }, "MinimalMetadata": { "objectMetadataItems": [ - 329 - ], - "views": [ 330 ], + "views": [ + 331 + ], "collectionHashes": [ - 327 + 328 ], "__typename": [ 1 @@ -6046,7 +6048,7 @@ export default { 2, { "input": [ - 333, + 334, "GetApiKeyInput!" ] } @@ -6143,7 +6145,7 @@ export default { 41, { "input": [ - 334, + 335, "LogicFunctionIdInput!" ] } @@ -6155,7 +6157,7 @@ export default { 15, { "input": [ - 334, + 335, "LogicFunctionIdInput!" ] } @@ -6164,7 +6166,7 @@ export default { 1, { "input": [ - 334, + 335, "LogicFunctionIdInput!" ] } @@ -6247,28 +6249,28 @@ export default { 25, { "input": [ - 335, + 336, "AgentIdInput!" ] } ], "previewMessageCampaignAudience": [ - 278, + 279, { "input": [ - 336, + 337, "PreviewMessageCampaignAudienceInput!" ] } ], "unsubscribeTopics": [ - 282 + 283 ], "unsubscribePagePreviewUrl": [ 1 ], "myMessageChannels": [ - 269, + 270, { "connectedAccountId": [ 3 @@ -6276,16 +6278,16 @@ export default { } ], "getEmailingDomains": [ - 267 + 268 ], "myConnectedAccounts": [ - 236 + 237 ], "getRoles": [ 29 ], "getToolIndex": [ - 292 + 293 ], "getToolInputSchema": [ 15, @@ -6297,10 +6299,10 @@ export default { } ], "webhooks": [ - 291 + 292 ], "webhook": [ - 291, + 292, { "id": [ 3, @@ -6348,7 +6350,7 @@ export default { } ], "myMessageFolders": [ - 325, + 326, { "messageChannelId": [ 3 @@ -6356,7 +6358,7 @@ export default { } ], "myCalendarChannels": [ - 320, + 321, { "connectedAccountId": [ 3 @@ -6364,13 +6366,13 @@ export default { } ], "minimalMetadata": [ - 331 + 332 ], "appConnections": [ 216, { "filter": [ - 337 + 338 ] } ], @@ -6384,13 +6386,13 @@ export default { } ], "findWorkspaceAiStats": [ - 319 + 320 ], "chatThreads": [ - 311 + 312 ], "chatThread": [ - 311, + 312, { "id": [ 3, @@ -6399,7 +6401,7 @@ export default { } ], "chatMessages": [ - 310, + 311, { "threadId": [ 3, @@ -6408,7 +6410,7 @@ export default { } ], "chatStreamCatchupChunks": [ - 314, + 315, { "threadId": [ 3, @@ -6417,13 +6419,13 @@ export default { } ], "getAiSystemPromptPreview": [ - 313 + 314 ], "skills": [ - 309 + 310 ], "skill": [ - 309, + 310, { "id": [ 3, @@ -6432,7 +6434,7 @@ export default { } ], "agentTurns": [ - 318, + 319, { "agentId": [ 3, @@ -6441,7 +6443,7 @@ export default { } ], "checkUserExists": [ - 254, + 255, { "email": [ 1, @@ -6453,7 +6455,7 @@ export default { } ], "checkWorkspaceInviteHashIsValid": [ - 255, + 256, { "inviteHash": [ 1, @@ -6471,7 +6473,7 @@ export default { } ], "validatePasswordResetToken": [ - 249, + 250, { "passwordResetToken": [ 1, @@ -6577,43 +6579,43 @@ export default { 222 ], "eventLogs": [ - 308, + 309, { "input": [ - 338, + 339, "EventLogQueryInput!" ] } ], "pieChartData": [ - 302, + 303, { "input": [ - 342, + 343, "PieChartDataInput!" ] } ], "lineChartData": [ - 300, + 301, { "input": [ - 343, + 344, "LineChartDataInput!" ] } ], "barChartData": [ - 297, + 298, { "input": [ - 344, + 345, "BarChartDataInput!" ] } ], "getConnectedImapSmtpCaldavAccount": [ - 289, + 290, { "id": [ 3, @@ -6622,7 +6624,7 @@ export default { } ], "getAutoCompleteAddress": [ - 284, + 285, { "address": [ 1, @@ -6641,7 +6643,7 @@ export default { } ], "getAddressDetails": [ - 286, + 287, { "placeId": [ 1, @@ -6654,21 +6656,21 @@ export default { } ], "getUsageAnalytics": [ - 259, + 260, { "input": [ - 345 + 346 ] } ], "findManyPublicDomains": [ - 265 + 266 ], "findManyMarketplaceApps": [ - 263 + 264 ], "findMarketplaceAppDetail": [ - 264, + 265, { "universalIdentifier": [ 1, @@ -6731,10 +6733,10 @@ export default { }, "EventLogQueryInput": { "table": [ - 339 + 340 ], "filters": [ - 340 + 341 ], "first": [ 21 @@ -6755,7 +6757,7 @@ export default { 1 ], "dateRange": [ - 341 + 342 ], "recordId": [ 1 @@ -6822,7 +6824,7 @@ export default { 1 ], "operationTypes": [ - 346 + 347 ], "__typename": [ 1 @@ -6834,7 +6836,7 @@ export default { 6, { "input": [ - 348, + 349, "AddQuerySubscriptionInput!" ] } @@ -6843,7 +6845,7 @@ export default { 6, { "input": [ - 349, + 350, "RemoveQueryFromEventStreamInput!" ] } @@ -6852,7 +6854,7 @@ export default { 158, { "inputs": [ - 350, + 351, "[CreateNavigationMenuItemInput!]!" ] } @@ -6861,7 +6863,7 @@ export default { 158, { "input": [ - 350, + 351, "CreateNavigationMenuItemInput!" ] } @@ -6870,7 +6872,7 @@ export default { 158, { "inputs": [ - 351, + 352, "[UpdateOneNavigationMenuItemInput!]!" ] } @@ -6879,7 +6881,7 @@ export default { 158, { "input": [ - 351, + 352, "UpdateOneNavigationMenuItemInput!" ] } @@ -6906,7 +6908,7 @@ export default { 131, { "file": [ - 353, + 354, "Upload!" ] } @@ -6927,7 +6929,7 @@ export default { 131, { "file": [ - 353, + 354, "Upload!" ] } @@ -6936,7 +6938,7 @@ export default { 131, { "file": [ - 353, + 354, "Upload!" ] } @@ -6945,7 +6947,7 @@ export default { 131, { "file": [ - 353, + 354, "Upload!" ] } @@ -6954,7 +6956,7 @@ export default { 131, { "file": [ - 353, + 354, "Upload!" ] } @@ -6963,7 +6965,7 @@ export default { 131, { "file": [ - 353, + 354, "Upload!" ], "fieldMetadataId": [ @@ -6976,7 +6978,7 @@ export default { 131, { "file": [ - 353, + 354, "Upload!" ], "fieldMetadataUniversalIdentifier": [ @@ -6989,7 +6991,7 @@ export default { 62, { "input": [ - 354, + 355, "CreateViewFilterGroupInput!" ] } @@ -7002,7 +7004,7 @@ export default { "String!" ], "input": [ - 355, + 356, "UpdateViewFilterGroupInput!" ] } @@ -7029,7 +7031,7 @@ export default { 64, { "input": [ - 356, + 357, "CreateViewFilterInput!" ] } @@ -7038,7 +7040,7 @@ export default { 64, { "input": [ - 357, + 358, "UpdateViewFilterInput!" ] } @@ -7047,7 +7049,7 @@ export default { 64, { "input": [ - 359, + 360, "DeleteViewFilterInput!" ] } @@ -7056,7 +7058,7 @@ export default { 64, { "input": [ - 360, + 361, "DestroyViewFilterInput!" ] } @@ -7065,7 +7067,7 @@ export default { 70, { "input": [ - 361, + 362, "CreateViewInput!" ] } @@ -7078,7 +7080,7 @@ export default { "String!" ], "input": [ - 362, + 363, "UpdateViewInput!" ] } @@ -7105,7 +7107,7 @@ export default { 70, { "input": [ - 363, + 364, "UpsertViewWidgetInput!" ] } @@ -7114,7 +7116,7 @@ export default { 67, { "input": [ - 368, + 369, "CreateViewSortInput!" ] } @@ -7123,7 +7125,7 @@ export default { 67, { "input": [ - 369, + 370, "UpdateViewSortInput!" ] } @@ -7132,7 +7134,7 @@ export default { 6, { "input": [ - 371, + 372, "DeleteViewSortInput!" ] } @@ -7141,7 +7143,7 @@ export default { 6, { "input": [ - 372, + 373, "DestroyViewSortInput!" ] } @@ -7150,7 +7152,7 @@ export default { 60, { "input": [ - 373, + 374, "UpdateViewFieldInput!" ] } @@ -7159,7 +7161,7 @@ export default { 60, { "input": [ - 375, + 376, "CreateViewFieldInput!" ] } @@ -7168,7 +7170,7 @@ export default { 60, { "inputs": [ - 375, + 376, "[CreateViewFieldInput!]!" ] } @@ -7177,7 +7179,7 @@ export default { 60, { "input": [ - 376, + 377, "DeleteViewFieldInput!" ] } @@ -7186,7 +7188,7 @@ export default { 60, { "input": [ - 377, + 378, "DestroyViewFieldInput!" ] } @@ -7195,7 +7197,7 @@ export default { 69, { "input": [ - 378, + 379, "UpdateViewFieldGroupInput!" ] } @@ -7204,7 +7206,7 @@ export default { 69, { "input": [ - 380, + 381, "CreateViewFieldGroupInput!" ] } @@ -7213,7 +7215,7 @@ export default { 69, { "inputs": [ - 380, + 381, "[CreateViewFieldGroupInput!]!" ] } @@ -7222,7 +7224,7 @@ export default { 69, { "input": [ - 381, + 382, "DeleteViewFieldGroupInput!" ] } @@ -7231,7 +7233,7 @@ export default { 69, { "input": [ - 382, + 383, "DestroyViewFieldGroupInput!" ] } @@ -7240,7 +7242,7 @@ export default { 70, { "input": [ - 383, + 384, "UpsertFieldsWidgetInput!" ] } @@ -7249,7 +7251,7 @@ export default { 2, { "input": [ - 386, + 387, "CreateApiKeyInput!" ] } @@ -7258,7 +7260,7 @@ export default { 2, { "input": [ - 387, + 388, "UpdateApiKeyInput!" ] } @@ -7267,7 +7269,7 @@ export default { 2, { "input": [ - 388, + 389, "RevokeApiKeyInput!" ] } @@ -7389,7 +7391,7 @@ export default { 130, { "input": [ - 389, + 390, "CreateApprovedAccessDomainInput!" ] } @@ -7398,7 +7400,7 @@ export default { 6, { "input": [ - 390, + 391, "DeleteApprovedAccessDomainInput!" ] } @@ -7407,7 +7409,7 @@ export default { 130, { "input": [ - 391, + 392, "ValidateApprovedAccessDomainInput!" ] } @@ -7416,7 +7418,7 @@ export default { 123, { "input": [ - 392, + 393, "CreatePageLayoutTabInput!" ] } @@ -7429,7 +7431,7 @@ export default { "String!" ], "input": [ - 393, + 394, "UpdatePageLayoutTabInput!" ] } @@ -7447,7 +7449,7 @@ export default { 124, { "input": [ - 394, + 395, "CreatePageLayoutInput!" ] } @@ -7460,7 +7462,7 @@ export default { "String!" ], "input": [ - 395, + 396, "UpdatePageLayoutInput!" ] } @@ -7482,7 +7484,7 @@ export default { "String!" ], "input": [ - 396, + 397, "UpdatePageLayoutWithTabsInput!" ] } @@ -7518,7 +7520,7 @@ export default { 85, { "input": [ - 400, + 401, "CreatePageLayoutWidgetInput!" ] } @@ -7531,7 +7533,7 @@ export default { "String!" ], "input": [ - 401, + 402, "UpdatePageLayoutWidgetInput!" ] } @@ -7549,7 +7551,7 @@ export default { 41, { "input": [ - 334, + 335, "LogicFunctionIdInput!" ] } @@ -7558,7 +7560,7 @@ export default { 41, { "input": [ - 402, + 403, "CreateLogicFunctionFromSourceInput!" ] } @@ -7567,7 +7569,7 @@ export default { 167, { "input": [ - 403, + 404, "ExecuteOneLogicFunctionInput!" ] } @@ -7576,7 +7578,7 @@ export default { 6, { "input": [ - 404, + 405, "UpdateLogicFunctionFromSourceInput!" ] } @@ -7585,7 +7587,7 @@ export default { 35, { "input": [ - 406, + 407, "CreateCommandMenuItemInput!" ] } @@ -7594,7 +7596,7 @@ export default { 35, { "input": [ - 407, + 408, "UpdateCommandMenuItemInput!" ] } @@ -7621,7 +7623,7 @@ export default { 34, { "input": [ - 408, + 409, "CreateFrontComponentInput!" ] } @@ -7630,7 +7632,7 @@ export default { 34, { "input": [ - 409, + 410, "UpdateFrontComponentInput!" ] } @@ -7648,7 +7650,7 @@ export default { 56, { "input": [ - 411, + 412, "CreateOneObjectInput!" ] } @@ -7657,7 +7659,7 @@ export default { 56, { "input": [ - 413, + 414, "DeleteOneObjectInput!" ] } @@ -7666,7 +7668,7 @@ export default { 56, { "input": [ - 414, + 415, "UpdateOneObjectInput!" ] } @@ -7675,7 +7677,7 @@ export default { 47, { "input": [ - 416, + 417, "CreateOneIndexInput!" ] } @@ -7684,7 +7686,7 @@ export default { 47, { "input": [ - 419, + 420, "DeleteOneIndexInput!" ] } @@ -7693,7 +7695,7 @@ export default { 25, { "input": [ - 420, + 421, "CreateAgentInput!" ] } @@ -7702,7 +7704,7 @@ export default { 25, { "input": [ - 421, + 422, "UpdateAgentInput!" ] } @@ -7711,43 +7713,43 @@ export default { 25, { "input": [ - 335, + 336, "AgentIdInput!" ] } ], "sendEmailViaEmailingDomain": [ - 279, + 280, { "input": [ - 422, + 423, "SendEmailViaDomainInput!" ] } ], "sendMessageCampaign": [ - 281, + 282, { "input": [ - 423, + 424, "SendMessageCampaignInput!" ] } ], "createUnsubscribeTopic": [ - 282, + 283, { "input": [ - 424, + 425, "CreateUnsubscribeTopicInput!" ] } ], "updateUnsubscribeTopic": [ - 282, + 283, { "input": [ - 425, + 426, "UpdateUnsubscribeTopicInput!" ] } @@ -7762,25 +7764,25 @@ export default { } ], "updateMessageChannel": [ - 269, + 270, { "input": [ - 426, + 427, "UpdateMessageChannelInput!" ] } ], "createEmailGroupChannel": [ - 277, + 278, { "input": [ - 428, + 429, "CreateEmailGroupChannelInput!" ] } ], "deleteEmailGroupChannel": [ - 269, + 270, { "id": [ 3, @@ -7789,10 +7791,10 @@ export default { } ], "createEmailingDomain": [ - 267, + 268, { "input": [ - 429, + 430, "CreateEmailingDomainInput!" ] } @@ -7807,7 +7809,7 @@ export default { } ], "verifyEmailingDomain": [ - 267, + 268, { "id": [ 1, @@ -7816,7 +7818,7 @@ export default { } ], "deleteConnectedAccount": [ - 236, + 237, { "id": [ 3, @@ -7841,7 +7843,7 @@ export default { 29, { "createRoleInput": [ - 430, + 431, "CreateRoleInput!" ] } @@ -7850,7 +7852,7 @@ export default { 29, { "updateRoleInput": [ - 431, + 432, "UpdateRoleInput!" ] } @@ -7868,7 +7870,7 @@ export default { 16, { "upsertObjectPermissionsInput": [ - 433, + 434, "UpsertObjectPermissionsInput!" ] } @@ -7877,7 +7879,7 @@ export default { 27, { "upsertPermissionFlagsInput": [ - 435, + 436, "UpsertPermissionFlagsInput!" ] } @@ -7886,7 +7888,7 @@ export default { 26, { "upsertFieldPermissionsInput": [ - 436, + 437, "UpsertFieldPermissionsInput!" ] } @@ -7895,7 +7897,7 @@ export default { 232, { "input": [ - 438, + 439, "UpsertRowLevelPermissionPredicatesInput!" ] } @@ -7923,34 +7925,34 @@ export default { } ], "runAgent": [ - 294, + 295, { "input": [ - 441, + 442, "RunAgentInput!" ] } ], "createWebhook": [ - 291, + 292, { "input": [ - 442, + 443, "CreateWebhookInput!" ] } ], "updateWebhook": [ - 291, + 292, { "input": [ - 443, + 444, "UpdateWebhookInput!" ] } ], "deleteWebhook": [ - 291, + 292, { "id": [ 3, @@ -7962,7 +7964,7 @@ export default { 44, { "input": [ - 445, + 446, "CreateOneFieldMetadataInput!" ] } @@ -7971,7 +7973,7 @@ export default { 44, { "input": [ - 447, + 448, "UpdateOneFieldMetadataInput!" ] } @@ -7980,7 +7982,7 @@ export default { 44, { "input": [ - 449, + 450, "DeleteOneFieldInput!" ] } @@ -7989,7 +7991,7 @@ export default { 66, { "input": [ - 450, + 451, "CreateViewGroupInput!" ] } @@ -7998,7 +8000,7 @@ export default { 66, { "inputs": [ - 450, + 451, "[CreateViewGroupInput!]!" ] } @@ -8007,7 +8009,7 @@ export default { 66, { "input": [ - 451, + 452, "UpdateViewGroupInput!" ] } @@ -8016,7 +8018,7 @@ export default { 66, { "inputs": [ - 451, + 452, "[UpdateViewGroupInput!]!" ] } @@ -8025,7 +8027,7 @@ export default { 66, { "input": [ - 453, + 454, "DeleteViewGroupInput!" ] } @@ -8034,43 +8036,43 @@ export default { 66, { "input": [ - 454, + 455, "DestroyViewGroupInput!" ] } ], "updateMessageFolder": [ - 325, + 326, { "input": [ - 455, + 456, "UpdateMessageFolderInput!" ] } ], "updateMessageFolders": [ - 325, + 326, { "input": [ - 457, + 458, "UpdateMessageFoldersInput!" ] } ], "updateCalendarChannel": [ - 320, + 321, { "input": [ - 458, + 459, "UpdateCalendarChannelInput!" ] } ], "createChatThread": [ - 311 + 312 ], "sendChatMessage": [ - 315, + 316, { "threadId": [ 3, @@ -8091,7 +8093,7 @@ export default { 1 ], "fileAttachments": [ - 460, + 461, "[FileAttachmentInput!]" ] } @@ -8106,7 +8108,7 @@ export default { } ], "renameChatThread": [ - 311, + 312, { "id": [ 3, @@ -8119,7 +8121,7 @@ export default { } ], "archiveChatThread": [ - 311, + 312, { "id": [ 3, @@ -8128,7 +8130,7 @@ export default { } ], "unarchiveChatThread": [ - 311, + 312, { "id": [ 3, @@ -8155,25 +8157,25 @@ export default { } ], "createSkill": [ - 309, + 310, { "input": [ - 461, + 462, "CreateSkillInput!" ] } ], "updateSkill": [ - 309, + 310, { "input": [ - 462, + 463, "UpdateSkillInput!" ] } ], "deleteSkill": [ - 309, + 310, { "id": [ 3, @@ -8182,7 +8184,7 @@ export default { } ], "activateSkill": [ - 309, + 310, { "id": [ 3, @@ -8191,7 +8193,7 @@ export default { } ], "deactivateSkill": [ - 309, + 310, { "id": [ 3, @@ -8200,7 +8202,7 @@ export default { } ], "evaluateAgentTurn": [ - 317, + 318, { "turnId": [ 3, @@ -8209,7 +8211,7 @@ export default { } ], "runEvaluationInput": [ - 318, + 319, { "agentId": [ 3, @@ -8222,16 +8224,16 @@ export default { } ], "getAuthorizationUrlForSSO": [ - 244, + 245, { "input": [ - 463, + 464, "GetAuthorizationUrlForSSOInput!" ] } ], "getLoginTokenFromCredentials": [ - 253, + 254, { "email": [ 1, @@ -8257,7 +8259,7 @@ export default { } ], "signIn": [ - 242, + 243, { "email": [ 1, @@ -8279,7 +8281,7 @@ export default { } ], "verifyEmailAndGetLoginToken": [ - 250, + 251, { "emailVerificationToken": [ 1, @@ -8299,7 +8301,7 @@ export default { } ], "verifyEmailAndGetWorkspaceAgnosticToken": [ - 242, + 243, { "emailVerificationToken": [ 1, @@ -8315,7 +8317,7 @@ export default { } ], "getAuthTokensFromOTP": [ - 252, + 253, { "otp": [ 1, @@ -8335,7 +8337,7 @@ export default { } ], "signUp": [ - 242, + 243, { "email": [ 1, @@ -8357,7 +8359,7 @@ export default { } ], "signUpInWorkspace": [ - 247, + 248, { "email": [ 1, @@ -8388,13 +8390,13 @@ export default { } ], "signUpInNewWorkspace": [ - 247 - ], - "generateTransientToken": [ 248 ], + "generateTransientToken": [ + 249 + ], "getAuthTokensFromLoginToken": [ - 252, + 253, { "loginToken": [ 1, @@ -8407,7 +8409,7 @@ export default { } ], "authorizeApp": [ - 240, + 241, { "clientId": [ 1, @@ -8429,7 +8431,7 @@ export default { } ], "renewToken": [ - 252, + 253, { "appToken": [ 1, @@ -8438,7 +8440,7 @@ export default { } ], "generateApiKeyToken": [ - 251, + 252, { "apiKeyId": [ 3, @@ -8454,7 +8456,7 @@ export default { 32 ], "emailPasswordResetLink": [ - 243, + 244, { "email": [ 1, @@ -8466,7 +8468,7 @@ export default { } ], "updatePasswordViaResetToken": [ - 245, + 246, { "passwordResetToken": [ 1, @@ -8482,7 +8484,7 @@ export default { 198, { "input": [ - 464, + 465, "CreateApplicationRegistrationInput!" ] } @@ -8491,7 +8493,7 @@ export default { 7, { "input": [ - 465, + 466, "UpdateApplicationRegistrationInput!" ] } @@ -8518,7 +8520,7 @@ export default { 5, { "input": [ - 467, + 468, "CreateApplicationRegistrationVariableInput!" ] } @@ -8527,7 +8529,7 @@ export default { 5, { "input": [ - 468, + 469, "UpdateApplicationRegistrationVariableInput!" ] } @@ -8545,7 +8547,7 @@ export default { 7, { "file": [ - 353, + 354, "Upload!" ], "universalIdentifier": [ @@ -8567,7 +8569,7 @@ export default { } ], "initiateOTPProvisioning": [ - 238, + 239, { "loginToken": [ 1, @@ -8580,10 +8582,10 @@ export default { } ], "initiateOTPProvisioningForAuthenticatedUser": [ - 238 + 239 ], "deleteTwoFactorAuthenticationMethod": [ - 237, + 238, { "twoFactorAuthenticationMethodId": [ 3, @@ -8592,7 +8594,7 @@ export default { } ], "verifyTwoFactorAuthenticationMethodForAuthenticatedUser": [ - 239, + 240, { "otp": [ 1, @@ -8616,7 +8618,7 @@ export default { 6, { "input": [ - 470, + 471, "UpdateWorkspaceMemberSettingsInput!" ] } @@ -8650,7 +8652,7 @@ export default { 76, { "data": [ - 471, + 472, "ActivateWorkspaceInput!" ] } @@ -8659,7 +8661,7 @@ export default { 76, { "data": [ - 472, + 473, "UpdateWorkspaceInput!" ] } @@ -8674,7 +8676,7 @@ export default { 6, { "workspaceMigration": [ - 473, + 474, "WorkspaceMigrationInput!" ] } @@ -8692,7 +8694,7 @@ export default { 223, { "input": [ - 476, + 477, "SetupOIDCSsoInput!" ] } @@ -8701,7 +8703,7 @@ export default { 223, { "input": [ - 477, + 478, "SetupSAMLSsoInput!" ] } @@ -8710,7 +8712,7 @@ export default { 219, { "input": [ - 478, + 479, "DeleteSsoInput!" ] } @@ -8719,13 +8721,13 @@ export default { 220, { "input": [ - 479, + 480, "EditSsoInput!" ] } ], "createObjectEvent": [ - 305, + 306, { "event": [ 1, @@ -8745,10 +8747,10 @@ export default { } ], "trackAnalytics": [ - 305, + 306, { "type": [ - 480, + 481, "AnalyticsType!" ], "name": [ @@ -8763,7 +8765,7 @@ export default { } ], "duplicateDashboard": [ - 303, + 304, { "id": [ 3, @@ -8772,7 +8774,7 @@ export default { } ], "impersonate": [ - 256, + 257, { "userId": [ 3, @@ -8785,16 +8787,16 @@ export default { } ], "sendEmail": [ - 304, + 305, { "input": [ - 481, + 482, "SendEmailInput!" ] } ], "startChannelSync": [ - 295, + 296, { "connectedAccountId": [ 3, @@ -8803,14 +8805,14 @@ export default { } ], "saveImapSmtpCaldavAccount": [ - 290, + 291, { "handle": [ 1, "String!" ], "connectionParameters": [ - 483, + 484, "EmailAccountConnectionParameters!" ], "id": [ @@ -8822,13 +8824,13 @@ export default { 169, { "input": [ - 485, + 486, "UpdateLabPublicFeatureFlagInput!" ] } ], "createPublicDomain": [ - 265, + 266, { "domain": [ 1, @@ -8840,7 +8842,7 @@ export default { } ], "updatePublicDomain": [ - 265, + 266, { "domain": [ 1, @@ -8873,7 +8875,7 @@ export default { 78, { "input": [ - 486, + 487, "CreateOneAppTokenInput!" ] } @@ -8906,7 +8908,7 @@ export default { 6 ], "createDevelopmentApplication": [ - 260, + 261, { "universalIdentifier": [ 1, @@ -8928,7 +8930,7 @@ export default { } ], "syncApplication": [ - 261, + 262, { "manifest": [ 15, @@ -8940,10 +8942,10 @@ export default { } ], "uploadApplicationFile": [ - 262, + 263, { "file": [ - 353, + 354, "Upload!" ], "applicationUniversalIdentifier": [ @@ -8951,7 +8953,7 @@ export default { "String!" ], "fileFolder": [ - 488, + 489, "FileFolder!" ], "filePath": [ @@ -9060,7 +9062,7 @@ export default { 3 ], "update": [ - 352 + 353 ], "__typename": [ 1 @@ -9170,7 +9172,7 @@ export default { 3 ], "update": [ - 358 + 359 ], "__typename": [ 1 @@ -9329,17 +9331,17 @@ export default { 3 ], "viewFields": [ - 364 - ], - "viewFilters": [ 365 ], - "viewFilterGroups": [ + "viewFilters": [ 366 ], - "viewSorts": [ + "viewFilterGroups": [ 367 ], + "viewSorts": [ + 368 + ], "__typename": [ 1 ] @@ -9449,7 +9451,7 @@ export default { 3 ], "update": [ - 370 + 371 ], "__typename": [ 1 @@ -9487,7 +9489,7 @@ export default { 3 ], "update": [ - 374 + 375 ], "__typename": [ 1 @@ -9563,7 +9565,7 @@ export default { 3 ], "update": [ - 379 + 380 ], "__typename": [ 1 @@ -9627,10 +9629,10 @@ export default { 3 ], "groups": [ - 384 + 385 ], "fields": [ - 385 + 386 ], "__typename": [ 1 @@ -9650,7 +9652,7 @@ export default { 6 ], "fields": [ - 385 + 386 ], "__typename": [ 1 @@ -9818,7 +9820,7 @@ export default { 3 ], "tabs": [ - 397 + 398 ], "__typename": [ 1 @@ -9841,7 +9843,7 @@ export default { 89 ], "widgets": [ - 398 + 399 ], "__typename": [ 1 @@ -9864,7 +9866,7 @@ export default { 3 ], "gridPosition": [ - 399 + 400 ], "position": [ 15 @@ -9913,7 +9915,7 @@ export default { 3 ], "gridPosition": [ - 399 + 400 ], "position": [ 15 @@ -9939,7 +9941,7 @@ export default { 3 ], "gridPosition": [ - 399 + 400 ], "position": [ 15 @@ -10011,7 +10013,7 @@ export default { 3 ], "update": [ - 405 + 406 ], "__typename": [ 1 @@ -10171,7 +10173,7 @@ export default { 3 ], "update": [ - 410 + 411 ], "__typename": [ 1 @@ -10190,7 +10192,7 @@ export default { }, "CreateOneObjectInput": { "object": [ - 412 + 413 ], "__typename": [ 1 @@ -10250,7 +10252,7 @@ export default { }, "UpdateOneObjectInput": { "update": [ - 415 + 416 ], "id": [ 3 @@ -10305,7 +10307,7 @@ export default { }, "CreateOneIndexInput": { "index": [ - 417 + 418 ], "__typename": [ 1 @@ -10316,7 +10318,7 @@ export default { 3 ], "fields": [ - 418 + 419 ], "indexType": [ 48 @@ -10477,7 +10479,7 @@ export default { 1 ], "visibility": [ - 283 + 284 ], "__typename": [ 1 @@ -10494,7 +10496,7 @@ export default { 1 ], "visibility": [ - 283 + 284 ], "__typename": [ 1 @@ -10505,7 +10507,7 @@ export default { 3 ], "update": [ - 427 + 428 ], "__typename": [ 1 @@ -10513,16 +10515,16 @@ export default { }, "UpdateMessageChannelInputUpdates": { "visibility": [ - 270 + 271 ], "isContactAutoCreationEnabled": [ 6 ], "contactAutoCreationPolicy": [ - 272 + 273 ], "messageFolderImportPolicy": [ - 273 + 274 ], "isSyncEnabled": [ 6 @@ -10599,7 +10601,7 @@ export default { }, "UpdateRoleInput": { "update": [ - 432 + 433 ], "id": [ 3 @@ -10654,7 +10656,7 @@ export default { 3 ], "objectPermissions": [ - 434 + 435 ], "__typename": [ 1 @@ -10696,7 +10698,7 @@ export default { 3 ], "fieldPermissions": [ - 437 + 438 ], "__typename": [ 1 @@ -10727,10 +10729,10 @@ export default { 3 ], "predicates": [ - 439 + 440 ], "predicateGroups": [ - 440 + 441 ], "__typename": [ 1 @@ -10824,7 +10826,7 @@ export default { 3 ], "update": [ - 444 + 445 ], "__typename": [ 1 @@ -10849,7 +10851,7 @@ export default { }, "CreateOneFieldMetadataInput": { "field": [ - 446 + 447 ], "__typename": [ 1 @@ -10925,7 +10927,7 @@ export default { 3 ], "update": [ - 448 + 449 ], "__typename": [ 1 @@ -11020,7 +11022,7 @@ export default { 3 ], "update": [ - 452 + 453 ], "__typename": [ 1 @@ -11064,7 +11066,7 @@ export default { 3 ], "update": [ - 456 + 457 ], "__typename": [ 1 @@ -11083,7 +11085,7 @@ export default { 3 ], "update": [ - 456 + 457 ], "__typename": [ 1 @@ -11094,7 +11096,7 @@ export default { 3 ], "update": [ - 459 + 460 ], "__typename": [ 1 @@ -11102,13 +11104,13 @@ export default { }, "UpdateCalendarChannelInputUpdates": { "visibility": [ - 323 + 324 ], "isContactAutoCreationEnabled": [ 6 ], "contactAutoCreationPolicy": [ - 324 + 325 ], "isSyncEnabled": [ 6 @@ -11210,7 +11212,7 @@ export default { 1 ], "update": [ - 466 + 467 ], "__typename": [ 1 @@ -11258,7 +11260,7 @@ export default { 1 ], "update": [ - 469 + 470 ], "__typename": [ 1 @@ -11376,7 +11378,7 @@ export default { }, "WorkspaceMigrationInput": { "actions": [ - 474 + 475 ], "__typename": [ 1 @@ -11384,10 +11386,10 @@ export default { }, "WorkspaceMigrationDeleteActionInput": { "type": [ - 475 + 476 ], "metadataName": [ - 328 + 329 ], "universalIdentifier": [ 1 @@ -11480,7 +11482,7 @@ export default { 1 ], "files": [ - 482 + 483 ], "__typename": [ 1 @@ -11499,13 +11501,13 @@ export default { }, "EmailAccountConnectionParameters": { "IMAP": [ - 484 + 485 ], "SMTP": [ - 484 + 485 ], "CALDAV": [ - 484 + 485 ], "__typename": [ 1 @@ -11524,8 +11526,8 @@ export default { "password": [ 1 ], - "secure": [ - 6 + "connectionSecurity": [ + 235 ], "__typename": [ 1 @@ -11544,7 +11546,7 @@ export default { }, "CreateOneAppTokenInput": { "appToken": [ - 487 + 488 ], "__typename": [ 1 @@ -11573,13 +11575,13 @@ export default { 233, { "input": [ - 490, + 491, "LogicFunctionLogsInput!" ] } ], "onAgentChatEvent": [ - 316, + 317, { "threadId": [ 3, @@ -11588,10 +11590,10 @@ export default { } ], "eventLogsLive": [ - 306, + 307, { "table": [ - 339, + 340, "EventLogTable!" ] } diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 999fa66196..2e329d8f5b 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -986,10 +986,10 @@ export type ConnectedImapSmtpCaldavAccount = { }; export type ConnectionParametersInput = { + connectionSecurity?: InputMaybe; host: Scalars['String']['input']; password?: InputMaybe; port: Scalars['Float']['input']; - secure?: InputMaybe; username?: InputMaybe; }; @@ -1487,6 +1487,12 @@ export type EmailAccountConnectionParameters = { SMTP?: InputMaybe; }; +export enum EmailConnectionSecurity { + NONE = 'NONE', + SSL_TLS = 'SSL_TLS', + STARTTLS = 'STARTTLS' +} + export type EmailPasswordResetLink = { __typename?: 'EmailPasswordResetLink'; /** Boolean that confirms query was dispatched */ @@ -1987,9 +1993,9 @@ export type ImapSmtpCaldavPublicConnectionParameters = { export type ImapSmtpCaldavPublicConnectionParams = { __typename?: 'ImapSmtpCaldavPublicConnectionParams'; + connectionSecurity?: Maybe; host: Scalars['String']['output']; port: Scalars['Float']['output']; - secure?: Maybe; username?: Maybe; }; @@ -4166,9 +4172,9 @@ export type PublicApplicationRegistration = { export type PublicConnectionParametersOutput = { __typename?: 'PublicConnectionParametersOutput'; + connectionSecurity?: Maybe; host: Scalars['String']['output']; port: Scalars['Float']['output']; - secure?: Maybe; username?: Maybe; }; @@ -7482,7 +7488,7 @@ export type GetConnectedImapSmtpCaldavAccountQueryVariables = Exact<{ }>; -export type GetConnectedImapSmtpCaldavAccountQuery = { __typename?: 'Query', getConnectedImapSmtpCaldavAccount: { __typename?: 'ConnectedImapSmtpCaldavAccount', id: string, handle: string, provider: string, userWorkspaceId: string, connectionParameters?: { __typename?: 'ImapSmtpCaldavPublicConnectionParameters', IMAP?: { __typename?: 'ImapSmtpCaldavPublicConnectionParams', host: string, port: number, secure?: boolean | null, username?: string | null } | null, SMTP?: { __typename?: 'ImapSmtpCaldavPublicConnectionParams', host: string, username?: string | null, port: number, secure?: boolean | null } | null, CALDAV?: { __typename?: 'ImapSmtpCaldavPublicConnectionParams', host: string, port: number, secure?: boolean | null, username?: string | null } | null } | null } }; +export type GetConnectedImapSmtpCaldavAccountQuery = { __typename?: 'Query', getConnectedImapSmtpCaldavAccount: { __typename?: 'ConnectedImapSmtpCaldavAccount', id: string, handle: string, provider: string, userWorkspaceId: string, connectionParameters?: { __typename?: 'ImapSmtpCaldavPublicConnectionParameters', IMAP?: { __typename?: 'ImapSmtpCaldavPublicConnectionParams', host: string, port: number, connectionSecurity?: EmailConnectionSecurity | null, username?: string | null } | null, SMTP?: { __typename?: 'ImapSmtpCaldavPublicConnectionParams', host: string, username?: string | null, port: number, connectionSecurity?: EmailConnectionSecurity | null } | null, CALDAV?: { __typename?: 'ImapSmtpCaldavPublicConnectionParams', host: string, port: number, connectionSecurity?: EmailConnectionSecurity | null, username?: string | null } | null } | null } }; export type MyCalendarChannelsQueryVariables = Exact<{ connectedAccountId?: InputMaybe; @@ -7494,7 +7500,7 @@ export type MyCalendarChannelsQuery = { __typename?: 'Query', myCalendarChannels export type MyConnectedAccountsQueryVariables = Exact<{ [key: string]: never; }>; -export type MyConnectedAccountsQuery = { __typename?: 'Query', myConnectedAccounts: Array<{ __typename?: 'ConnectedAccountPublicDTO', id: string, handle: string, provider: string, authFailedAt?: string | null, archivedAt?: string | null, scopes?: Array | null, handleAliases?: Array | null, lastSignedInAt?: string | null, userWorkspaceId: string, connectionProviderId?: string | null, name?: string | null, visibility: string, lastCredentialsRefreshedAt?: string | null, createdAt: string, updatedAt: string, connectionParameters?: { __typename?: 'PublicImapSmtpCaldavConnectionParameters', IMAP?: { __typename?: 'PublicConnectionParametersOutput', host: string, port: number, secure?: boolean | null, username?: string | null } | null, SMTP?: { __typename?: 'PublicConnectionParametersOutput', host: string, port: number, secure?: boolean | null, username?: string | null } | null, CALDAV?: { __typename?: 'PublicConnectionParametersOutput', host: string, username?: string | null } | null } | null }> }; +export type MyConnectedAccountsQuery = { __typename?: 'Query', myConnectedAccounts: Array<{ __typename?: 'ConnectedAccountPublicDTO', id: string, handle: string, provider: string, authFailedAt?: string | null, archivedAt?: string | null, scopes?: Array | null, handleAliases?: Array | null, lastSignedInAt?: string | null, userWorkspaceId: string, connectionProviderId?: string | null, name?: string | null, visibility: string, lastCredentialsRefreshedAt?: string | null, createdAt: string, updatedAt: string, connectionParameters?: { __typename?: 'PublicImapSmtpCaldavConnectionParameters', IMAP?: { __typename?: 'PublicConnectionParametersOutput', host: string, port: number, connectionSecurity?: EmailConnectionSecurity | null, username?: string | null } | null, SMTP?: { __typename?: 'PublicConnectionParametersOutput', host: string, port: number, connectionSecurity?: EmailConnectionSecurity | null, username?: string | null } | null, CALDAV?: { __typename?: 'PublicConnectionParametersOutput', host: string, username?: string | null } | null } | null }> }; export type MyMessageChannelsQueryVariables = Exact<{ connectedAccountId?: InputMaybe; @@ -8706,9 +8712,9 @@ export const UpdateCalendarChannelDocument = {"kind":"Document","definitions":[{ export const UpdateMessageChannelDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateMessageChannel"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateMessageChannelInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateMessageChannel"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"contactAutoCreationPolicy"}},{"kind":"Field","name":{"kind":"Name","value":"excludeNonProfessionalEmails"}},{"kind":"Field","name":{"kind":"Name","value":"excludeGroupEmails"}},{"kind":"Field","name":{"kind":"Name","value":"messageFolderImportPolicy"}}]}}]}}]} as unknown as DocumentNode; export const UpdateMessageFolderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateMessageFolder"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateMessageFolderInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateMessageFolder"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isSynced"}}]}}]}}]} as unknown as DocumentNode; export const UpdateMessageFoldersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateMessageFolders"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateMessageFoldersInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateMessageFolders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isSynced"}}]}}]}}]} as unknown as DocumentNode; -export const GetConnectedImapSmtpCaldavAccountDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetConnectedImapSmtpCaldavAccount"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getConnectedImapSmtpCaldavAccount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"userWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"connectionParameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"IMAP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"SMTP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}}]}},{"kind":"Field","name":{"kind":"Name","value":"CALDAV"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetConnectedImapSmtpCaldavAccountDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetConnectedImapSmtpCaldavAccount"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getConnectedImapSmtpCaldavAccount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"userWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"connectionParameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"IMAP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"connectionSecurity"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"SMTP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"connectionSecurity"}}]}},{"kind":"Field","name":{"kind":"Name","value":"CALDAV"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"connectionSecurity"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const MyCalendarChannelsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyCalendarChannels"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myCalendarChannels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"connectedAccountId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"syncStage"}},{"kind":"Field","name":{"kind":"Name","value":"syncStageStartedAt"}},{"kind":"Field","name":{"kind":"Name","value":"isContactAutoCreationEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"contactAutoCreationPolicy"}},{"kind":"Field","name":{"kind":"Name","value":"isSyncEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"connectedAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode; -export const MyConnectedAccountsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyConnectedAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myConnectedAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"authFailedAt"}},{"kind":"Field","name":{"kind":"Name","value":"archivedAt"}},{"kind":"Field","name":{"kind":"Name","value":"scopes"}},{"kind":"Field","name":{"kind":"Name","value":"handleAliases"}},{"kind":"Field","name":{"kind":"Name","value":"lastSignedInAt"}},{"kind":"Field","name":{"kind":"Name","value":"userWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"connectionProviderId"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"lastCredentialsRefreshedAt"}},{"kind":"Field","name":{"kind":"Name","value":"connectionParameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"IMAP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"SMTP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"CALDAV"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode; +export const MyConnectedAccountsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyConnectedAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myConnectedAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"authFailedAt"}},{"kind":"Field","name":{"kind":"Name","value":"archivedAt"}},{"kind":"Field","name":{"kind":"Name","value":"scopes"}},{"kind":"Field","name":{"kind":"Name","value":"handleAliases"}},{"kind":"Field","name":{"kind":"Name","value":"lastSignedInAt"}},{"kind":"Field","name":{"kind":"Name","value":"userWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"connectionProviderId"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"lastCredentialsRefreshedAt"}},{"kind":"Field","name":{"kind":"Name","value":"connectionParameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"IMAP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"connectionSecurity"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"SMTP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"connectionSecurity"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"CALDAV"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode; export const MyMessageChannelsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyMessageChannels"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myMessageChannels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"connectedAccountId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"isContactAutoCreationEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"contactAutoCreationPolicy"}},{"kind":"Field","name":{"kind":"Name","value":"messageFolderImportPolicy"}},{"kind":"Field","name":{"kind":"Name","value":"excludeNonProfessionalEmails"}},{"kind":"Field","name":{"kind":"Name","value":"excludeGroupEmails"}},{"kind":"Field","name":{"kind":"Name","value":"isSyncEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"syncStage"}},{"kind":"Field","name":{"kind":"Name","value":"syncStageStartedAt"}},{"kind":"Field","name":{"kind":"Name","value":"connectedAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"connectedAccount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode; export const MyMessageFoldersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyMessageFolders"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"messageChannelId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myMessageFolders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"messageChannelId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"messageChannelId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"isSynced"}},{"kind":"Field","name":{"kind":"Name","value":"isSentFolder"}},{"kind":"Field","name":{"kind":"Name","value":"parentFolderId"}},{"kind":"Field","name":{"kind":"Name","value":"externalId"}},{"kind":"Field","name":{"kind":"Name","value":"messageChannelId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode; export const DeleteApplicationRegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteApplicationRegistration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteApplicationRegistration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}]}}]} as unknown as DocumentNode; diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsConnectionForm.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsConnectionForm.tsx index d06e726cab..9829ffea98 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsConnectionForm.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsConnectionForm.tsx @@ -192,18 +192,19 @@ export const SettingsAccountsConnectionForm = ({ ( )} /> diff --git a/packages/twenty-front/src/modules/settings/accounts/graphql/queries/getConnectedImapSmtpCaldavAccount.ts b/packages/twenty-front/src/modules/settings/accounts/graphql/queries/getConnectedImapSmtpCaldavAccount.ts index 0042b08b2c..3771cf40cf 100644 --- a/packages/twenty-front/src/modules/settings/accounts/graphql/queries/getConnectedImapSmtpCaldavAccount.ts +++ b/packages/twenty-front/src/modules/settings/accounts/graphql/queries/getConnectedImapSmtpCaldavAccount.ts @@ -11,19 +11,19 @@ export const GET_CONNECTED_IMAP_SMTP_CALDAV_ACCOUNT = gql` IMAP { host port - secure + connectionSecurity username } SMTP { host username port - secure + connectionSecurity } CALDAV { host port - secure + connectionSecurity username } } diff --git a/packages/twenty-front/src/modules/settings/accounts/graphql/queries/getMyConnectedAccounts.ts b/packages/twenty-front/src/modules/settings/accounts/graphql/queries/getMyConnectedAccounts.ts index 8677192bc1..4632c5a889 100644 --- a/packages/twenty-front/src/modules/settings/accounts/graphql/queries/getMyConnectedAccounts.ts +++ b/packages/twenty-front/src/modules/settings/accounts/graphql/queries/getMyConnectedAccounts.ts @@ -20,13 +20,13 @@ export const GET_MY_CONNECTED_ACCOUNTS = gql` IMAP { host port - secure + connectionSecurity username } SMTP { host port - secure + connectionSecurity username } CALDAV { diff --git a/packages/twenty-front/src/modules/settings/accounts/hooks/useImapSmtpCaldavConnectionForm.ts b/packages/twenty-front/src/modules/settings/accounts/hooks/useImapSmtpCaldavConnectionForm.ts index 11c8e0abaf..29e3a456e0 100644 --- a/packages/twenty-front/src/modules/settings/accounts/hooks/useImapSmtpCaldavConnectionForm.ts +++ b/packages/twenty-front/src/modules/settings/accounts/hooks/useImapSmtpCaldavConnectionForm.ts @@ -9,6 +9,7 @@ import { t } from '@lingui/core/macro'; import { SettingsPath } from 'twenty-shared/types'; import { type ConnectionParametersInput, + EmailConnectionSecurity, SaveImapSmtpCaldavAccountDocument, } from '~/generated-metadata/graphql'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; @@ -38,9 +39,25 @@ export type ConnectionFormData = { } & ImapSmtpCaldavAccountInput; const DEFAULT_PROTOCOL_VALUES: Record = { - IMAP: { host: '', port: 993, password: '', secure: true }, - SMTP: { host: '', username: '', port: 587, password: '', secure: true }, - CALDAV: { host: '', port: 443, password: '', secure: true }, + IMAP: { + host: '', + port: 993, + password: '', + connectionSecurity: EmailConnectionSecurity.SSL_TLS, + }, + SMTP: { + host: '', + username: '', + port: 587, + password: '', + connectionSecurity: EmailConnectionSecurity.STARTTLS, + }, + CALDAV: { + host: '', + port: 443, + password: '', + connectionSecurity: EmailConnectionSecurity.SSL_TLS, + }, }; export const useImapSmtpCaldavConnectionForm = ({ diff --git a/packages/twenty-front/src/modules/settings/accounts/validation-schemas/connectionImapSmtpCalDav.ts b/packages/twenty-front/src/modules/settings/accounts/validation-schemas/connectionImapSmtpCalDav.ts index d2ba749d87..8e5667c943 100644 --- a/packages/twenty-front/src/modules/settings/accounts/validation-schemas/connectionImapSmtpCalDav.ts +++ b/packages/twenty-front/src/modules/settings/accounts/validation-schemas/connectionImapSmtpCalDav.ts @@ -13,7 +13,9 @@ const connectionParameters = z port: z.int().nullable().default(null), username: z.string().optional(), password: z.string().default(''), - secure: z.boolean().default(true), + connectionSecurity: z + .enum(['NONE', 'STARTTLS', 'SSL_TLS']) + .default('SSL_TLS'), }) .refine( (data) => { diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-15/2-15-instance-command-slow-1781461753981-backfill-connection-security.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-15/2-15-instance-command-slow-1781461753981-backfill-connection-security.ts new file mode 100644 index 0000000000..97fae6c4e4 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-15/2-15-instance-command-slow-1781461753981-backfill-connection-security.ts @@ -0,0 +1,65 @@ +import { DataSource, QueryRunner } from 'typeorm'; + +import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; +import { SlowInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/slow-instance-command.interface'; + +// Replaces the legacy `secure` boolean with the `connectionSecurity` enum, +// preserving the previously deployed on-wire behavior exactly. SMTP used +// implicit TLS on port 465 (-> SSL_TLS) and opportunistic STARTTLS elsewhere +// (-> STARTTLS); IMAP used implicit TLS when secure (-> SSL_TLS) and +// opportunistic STARTTLS otherwise (-> STARTTLS); CalDAV is TLS over its https +// host (-> SSL_TLS). STARTTLS stays opportunistic so no account is forced onto +// a stricter handshake than it already used. +@RegisteredInstanceCommand('2.15.0', 1781461753981, { type: 'slow' }) +export class BackfillConnectionSecuritySlowInstanceCommand + implements SlowInstanceCommand +{ + async runDataMigration(dataSource: DataSource): Promise { + await dataSource.query( + `UPDATE "core"."connectedAccount" + SET "connectionParameters" = jsonb_set( + "connectionParameters" #- '{SMTP,secure}', + '{SMTP,connectionSecurity}', + to_jsonb( + CASE WHEN "connectionParameters"->'SMTP'->>'port' = '465' + THEN 'SSL_TLS' ELSE 'STARTTLS' END + ) + ) + WHERE "connectionParameters" ? 'SMTP' + AND NOT "connectionParameters"->'SMTP' ? 'connectionSecurity'`, + ); + + await dataSource.query( + `UPDATE "core"."connectedAccount" + SET "connectionParameters" = jsonb_set( + "connectionParameters" #- '{IMAP,secure}', + '{IMAP,connectionSecurity}', + to_jsonb( + CASE WHEN "connectionParameters"->'IMAP'->>'secure' = 'false' + THEN 'STARTTLS' ELSE 'SSL_TLS' END + ) + ) + WHERE "connectionParameters" ? 'IMAP' + AND NOT "connectionParameters"->'IMAP' ? 'connectionSecurity'`, + ); + + await dataSource.query( + `UPDATE "core"."connectedAccount" + SET "connectionParameters" = jsonb_set( + "connectionParameters" #- '{CALDAV,secure}', + '{CALDAV,connectionSecurity}', + to_jsonb('SSL_TLS'::text) + ) + WHERE "connectionParameters" ? 'CALDAV' + AND NOT "connectionParameters"->'CALDAV' ? 'connectionSecurity'`, + ); + } + + public async up(_queryRunner: QueryRunner): Promise { + return; + } + + public async down(_queryRunner: QueryRunner): Promise { + return; + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts index 19ea4e264e..6a8999d359 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts @@ -70,6 +70,7 @@ import { RenameIsUiReadOnlyToIsUiEditableFastInstanceCommand } from 'src/databas import { BackfillNonUiCreatableStandardSystemObjectsSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-slow-1781277480000-backfill-non-ui-creatable-standard-system-objects'; import { CommandMenuItemOverridableEntityFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781253016028-command-menu-item-overridable-entity'; import { SetTableWidgetViewsVisibilityToWorkspaceSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-14/2-14-instance-command-slow-1781515653781-set-table-widget-views-visibility-to-workspace'; +import { BackfillConnectionSecuritySlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-15/2-15-instance-command-slow-1781461753981-backfill-connection-security'; export const INSTANCE_COMMANDS = [ AddViewFieldGroupIdIndexOnViewFieldFastInstanceCommand, @@ -142,4 +143,5 @@ export const INSTANCE_COMMANDS = [ BackfillNonUiCreatableStandardSystemObjectsSlowInstanceCommand, CommandMenuItemOverridableEntityFastInstanceCommand, SetTableWidgetViewsVisibilityToWorkspaceSlowInstanceCommand, + BackfillConnectionSecuritySlowInstanceCommand, ]; diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/dtos/imap-smtp-caldav-connected-account.dto.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/dtos/imap-smtp-caldav-connected-account.dto.ts index a29742a578..7bd7ed6b8a 100644 --- a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/dtos/imap-smtp-caldav-connected-account.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/dtos/imap-smtp-caldav-connected-account.dto.ts @@ -2,6 +2,8 @@ import { Field, ObjectType } from '@nestjs/graphql'; import { ConnectedAccountProvider } from 'twenty-shared/types'; +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; + import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; @ObjectType('ImapSmtpCaldavPublicConnectionParams') @@ -15,8 +17,8 @@ class PublicConnectionParamsDTO { @Field(() => String, { nullable: true }) username?: string; - @Field(() => Boolean, { nullable: true }) - secure?: boolean; + @Field(() => EmailConnectionSecurity, { nullable: true }) + connectionSecurity?: EmailConnectionSecurity; } @ObjectType('ImapSmtpCaldavPublicConnectionParameters') diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/dtos/imap-smtp-caldav-connection.input.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/dtos/imap-smtp-caldav-connection.input.ts index 2b6d1ec723..a7ebc7e351 100644 --- a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/dtos/imap-smtp-caldav-connection.input.ts +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/dtos/imap-smtp-caldav-connection.input.ts @@ -1,4 +1,10 @@ -import { Field, InputType } from '@nestjs/graphql'; +import { Field, InputType, registerEnumType } from '@nestjs/graphql'; + +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; + +registerEnumType(EmailConnectionSecurity, { + name: 'EmailConnectionSecurity', +}); @InputType() export class AccountType { @@ -20,8 +26,8 @@ export class ConnectionParametersInput { @Field(() => String, { nullable: true }) password?: string; - @Field(() => Boolean, { nullable: true }) - secure?: boolean; + @Field(() => EmailConnectionSecurity, { nullable: true }) + connectionSecurity?: EmailConnectionSecurity; } @InputType('EmailAccountConnectionParameters') diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum.ts new file mode 100644 index 0000000000..31aeda3b4d --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum.ts @@ -0,0 +1,5 @@ +export enum EmailConnectionSecurity { + NONE = 'NONE', + STARTTLS = 'STARTTLS', + SSL_TLS = 'SSL_TLS', +} diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/schemas/connection-parameters.schema.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/schemas/connection-parameters.schema.ts index f979e7ed6e..0bee7e33ee 100644 --- a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/schemas/connection-parameters.schema.ts +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/schemas/connection-parameters.schema.ts @@ -1,3 +1,4 @@ +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; import { plaintextStringSchema } from 'src/engine/core-modules/secret-encryption/branded-strings/plaintext-string.type'; import { z } from 'zod'; @@ -6,5 +7,7 @@ export const connectionParametersSchema = z.object({ port: z.int().positive('Port must be a positive number'), username: z.string().optional(), password: plaintextStringSchema.min(1, 'Password is required'), - secure: z.boolean().optional(), + connectionSecurity: z + .nativeEnum(EmailConnectionSecurity) + .default(EmailConnectionSecurity.SSL_TLS), }); diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/services/__tests__/imap-smtp-caldav-connection.service.spec.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/services/__tests__/imap-smtp-caldav-connection.service.spec.ts index cd3e20d1eb..25cf60ccad 100644 --- a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/services/__tests__/imap-smtp-caldav-connection.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/services/__tests__/imap-smtp-caldav-connection.service.spec.ts @@ -1,7 +1,9 @@ import { Test, type TestingModule } from '@nestjs/testing'; +import { createTransport } from 'nodemailer'; import { type DAVClient } from 'tsdav'; +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; import { ImapSmtpCaldavValidatorService } from 'src/engine/core-modules/imap-smtp-caldav-connection/services/imap-smtp-caldav-connection-validator.service'; import { ImapSmtpCaldavService } from 'src/engine/core-modules/imap-smtp-caldav-connection/services/imap-smtp-caldav-connection.service'; import { type ConnectionParameters } from 'src/engine/core-modules/imap-smtp-caldav-connection/types/imap-smtp-caldav-connection.type'; @@ -10,11 +12,20 @@ import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twent import { CalDavClientService } from 'src/modules/calendar/calendar-event-import-manager/drivers/caldav/services/caldav-client.service'; import { CalDavFetchEventsService } from 'src/modules/calendar/calendar-event-import-manager/drivers/caldav/services/caldav-fetch-events.service'; +jest.mock('nodemailer', () => ({ + createTransport: jest.fn(), +})); + describe('ImapSmtpCaldavService', () => { let service: ImapSmtpCaldavService; const mockClient = {} as DAVClient; + const mockVerify = jest.fn().mockResolvedValue(true); + const mockGetValidatedHost = jest + .fn() + .mockImplementation((host: string) => Promise.resolve(host)); + const mockCalDavClientService = { getClient: jest.fn(), }; @@ -25,6 +36,8 @@ describe('ImapSmtpCaldavService', () => { beforeEach(async () => { jest.clearAllMocks(); + (createTransport as jest.Mock).mockReturnValue({ verify: mockVerify }); + mockVerify.mockResolvedValue(true); mockCalDavClientService.getClient.mockResolvedValue(mockClient); mockCalDavFetchEventsService.listEventCalendars.mockResolvedValue([ { url: 'https://caldav.example.com/calendars/user/default/' }, @@ -33,7 +46,10 @@ describe('ImapSmtpCaldavService', () => { const module: TestingModule = await Test.createTestingModule({ providers: [ ImapSmtpCaldavService, - { provide: SecureHttpClientService, useValue: {} }, + { + provide: SecureHttpClientService, + useValue: { getValidatedHost: mockGetValidatedHost }, + }, { provide: ImapSmtpCaldavValidatorService, useValue: {} }, { provide: TwentyConfigService, @@ -59,6 +75,7 @@ describe('ImapSmtpCaldavService', () => { port: 443, username: 'user@example.com', password: 'password123', + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }; it('builds a CalDAV client and lists its event calendars', async () => { @@ -93,4 +110,48 @@ describe('ImapSmtpCaldavService', () => { ).rejects.toThrow('No calendar with event support found'); }); }); + + describe('testSmtpConnection', () => { + const params: ConnectionParameters = { + host: 'smtp.example.com', + port: 587, + username: 'user@example.com', + password: 'password123', + connectionSecurity: EmailConnectionSecurity.STARTTLS, + }; + + it('uses implicit TLS when connectionSecurity is SSL_TLS', async () => { + await service.testSmtpConnection('user@example.com', { + ...params, + port: 465, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, + }); + + expect(createTransport).toHaveBeenCalledWith( + expect.objectContaining({ secure: true }), + ); + }); + + it('upgrades opportunistically via STARTTLS', async () => { + await service.testSmtpConnection('user@example.com', { + ...params, + connectionSecurity: EmailConnectionSecurity.STARTTLS, + }); + + expect(createTransport).toHaveBeenCalledWith( + expect.objectContaining({ secure: false }), + ); + }); + + it('disables TLS when connectionSecurity is NONE', async () => { + await service.testSmtpConnection('user@example.com', { + ...params, + connectionSecurity: EmailConnectionSecurity.NONE, + }); + + expect(createTransport).toHaveBeenCalledWith( + expect.objectContaining({ secure: false, ignoreTLS: true }), + ); + }); + }); }); diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/services/imap-smtp-caldav-connection.service.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/services/imap-smtp-caldav-connection.service.ts index 03d762913b..8c9e279124 100644 --- a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/services/imap-smtp-caldav-connection.service.ts +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/services/imap-smtp-caldav-connection.service.ts @@ -14,6 +14,8 @@ import { type ConnectionParameters, type PlaintextImapSmtpCaldavParams, } from 'src/engine/core-modules/imap-smtp-caldav-connection/types/imap-smtp-caldav-connection.type'; +import { buildImapTlsOptions } from 'src/engine/core-modules/imap-smtp-caldav-connection/utils/build-imap-tls-options.util'; +import { buildSmtpTlsOptions } from 'src/engine/core-modules/imap-smtp-caldav-connection/utils/build-smtp-tls-options.util'; import { SecureHttpClientService } from 'src/engine/core-modules/secure-http-client/secure-http-client.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { CalDavClientService } from 'src/modules/calendar/calendar-event-import-manager/drivers/caldav/services/caldav-client.service'; @@ -41,7 +43,7 @@ export class ImapSmtpCaldavService { const client = new ImapFlow({ host: validatedHost, port: params.port, - secure: params.secure ?? true, + ...buildImapTlsOptions(params.connectionSecurity), auth: { user: params.username ?? handle, pass: params.password, @@ -114,6 +116,7 @@ export class ImapSmtpCaldavService { const transport = createTransport({ host: validatedHost, port: params.port, + ...buildSmtpTlsOptions(params.connectionSecurity), auth: { user: params.username ?? handle, pass: params.password, diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/types/imap-smtp-caldav-connection.type.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/types/imap-smtp-caldav-connection.type.ts index 7be1c1ce20..37923774b6 100644 --- a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/types/imap-smtp-caldav-connection.type.ts +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/types/imap-smtp-caldav-connection.type.ts @@ -24,6 +24,8 @@ export type ConnectionParametersUpdate = Omit< export type AccountType = (typeof ACCOUNT_TYPES)[number]; +export { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; + export type ImapSmtpCaldavParams = { IMAP?: ConnectionParameters; SMTP?: ConnectionParameters; diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/__tests__/build-imap-tls-options.util.spec.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/__tests__/build-imap-tls-options.util.spec.ts new file mode 100644 index 0000000000..9a3cf4d62f --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/__tests__/build-imap-tls-options.util.spec.ts @@ -0,0 +1,23 @@ +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; +import { buildImapTlsOptions } from 'src/engine/core-modules/imap-smtp-caldav-connection/utils/build-imap-tls-options.util'; + +describe('buildImapTlsOptions', () => { + it('negotiates TLS at connection time for SSL_TLS', () => { + expect(buildImapTlsOptions(EmailConnectionSecurity.SSL_TLS)).toEqual({ + secure: true, + }); + }); + + it('upgrades opportunistically via STARTTLS when the server offers it', () => { + expect(buildImapTlsOptions(EmailConnectionSecurity.STARTTLS)).toEqual({ + secure: false, + }); + }); + + it('forces plaintext for NONE by disabling the STARTTLS upgrade', () => { + expect(buildImapTlsOptions(EmailConnectionSecurity.NONE)).toEqual({ + secure: false, + doSTARTTLS: false, + }); + }); +}); diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/__tests__/build-smtp-tls-options.util.spec.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/__tests__/build-smtp-tls-options.util.spec.ts new file mode 100644 index 0000000000..23f6cda5ad --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/__tests__/build-smtp-tls-options.util.spec.ts @@ -0,0 +1,23 @@ +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; +import { buildSmtpTlsOptions } from 'src/engine/core-modules/imap-smtp-caldav-connection/utils/build-smtp-tls-options.util'; + +describe('buildSmtpTlsOptions', () => { + it('negotiates TLS at connection time for SSL_TLS', () => { + expect(buildSmtpTlsOptions(EmailConnectionSecurity.SSL_TLS)).toEqual({ + secure: true, + }); + }); + + it('upgrades opportunistically via STARTTLS when the server offers it', () => { + expect(buildSmtpTlsOptions(EmailConnectionSecurity.STARTTLS)).toEqual({ + secure: false, + }); + }); + + it('forces plaintext for NONE by skipping the STARTTLS upgrade entirely', () => { + expect(buildSmtpTlsOptions(EmailConnectionSecurity.NONE)).toEqual({ + secure: false, + ignoreTLS: true, + }); + }); +}); diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-imap-tls-options.util.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-imap-tls-options.util.ts new file mode 100644 index 0000000000..be58f93f8a --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-imap-tls-options.util.ts @@ -0,0 +1,19 @@ +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; + +type ImapTlsOptions = { + secure: boolean; + doSTARTTLS?: boolean; +}; + +export const buildImapTlsOptions = ( + connectionSecurity: EmailConnectionSecurity, +): ImapTlsOptions => { + switch (connectionSecurity) { + case EmailConnectionSecurity.SSL_TLS: + return { secure: true }; + case EmailConnectionSecurity.STARTTLS: + return { secure: false }; + case EmailConnectionSecurity.NONE: + return { secure: false, doSTARTTLS: false }; + } +}; diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-public-connection-parameters.util.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-public-connection-parameters.util.ts index 7bd8ce9e03..f0f566e27c 100644 --- a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-public-connection-parameters.util.ts +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-public-connection-parameters.util.ts @@ -1,13 +1,16 @@ import { ACCOUNT_TYPES } from 'twenty-shared/constants'; import { isDefined } from 'twenty-shared/utils'; -import { type ImapSmtpCaldavParams } from 'src/engine/core-modules/imap-smtp-caldav-connection/types/imap-smtp-caldav-connection.type'; +import { + type EmailConnectionSecurity, + type ImapSmtpCaldavParams, +} from 'src/engine/core-modules/imap-smtp-caldav-connection/types/imap-smtp-caldav-connection.type'; type PublicConnectionParams = { host: string; port: number; username?: string; - secure?: boolean; + connectionSecurity?: EmailConnectionSecurity; }; type PublicConnectionParameters = { diff --git a/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-smtp-tls-options.util.ts b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-smtp-tls-options.util.ts new file mode 100644 index 0000000000..fa6fd8af77 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/utils/build-smtp-tls-options.util.ts @@ -0,0 +1,19 @@ +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; + +type SmtpTlsOptions = { + secure: boolean; + ignoreTLS?: boolean; +}; + +export const buildSmtpTlsOptions = ( + connectionSecurity: EmailConnectionSecurity, +): SmtpTlsOptions => { + switch (connectionSecurity) { + case EmailConnectionSecurity.SSL_TLS: + return { secure: true }; + case EmailConnectionSecurity.STARTTLS: + return { secure: false }; + case EmailConnectionSecurity.NONE: + return { secure: false, ignoreTLS: true }; + } +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/connected-account/dtos/connected-account-public.dto.ts b/packages/twenty-server/src/engine/metadata-modules/connected-account/dtos/connected-account-public.dto.ts index 78a72c3ee4..a915d7a724 100644 --- a/packages/twenty-server/src/engine/metadata-modules/connected-account/dtos/connected-account-public.dto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/connected-account/dtos/connected-account-public.dto.ts @@ -2,6 +2,7 @@ import { Field, ObjectType, OmitType } from '@nestjs/graphql'; import { IsOptional } from 'class-validator'; +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; import { ConnectedAccountDTO } from 'src/engine/metadata-modules/connected-account/dtos/connected-account.dto'; @ObjectType('PublicConnectionParametersOutput') @@ -15,8 +16,8 @@ class PublicConnectionParametersDTO { @Field(() => String, { nullable: true }) username?: string; - @Field(() => Boolean, { nullable: true }) - secure?: boolean; + @Field(() => EmailConnectionSecurity, { nullable: true }) + connectionSecurity?: EmailConnectionSecurity; } @ObjectType('PublicImapSmtpCaldavConnectionParameters') diff --git a/packages/twenty-server/src/modules/connected-account/services/imap-smtp-caldav-apis.service.spec.ts b/packages/twenty-server/src/modules/connected-account/services/imap-smtp-caldav-apis.service.spec.ts index d61e333474..b9eb2b58f2 100644 --- a/packages/twenty-server/src/modules/connected-account/services/imap-smtp-caldav-apis.service.spec.ts +++ b/packages/twenty-server/src/modules/connected-account/services/imap-smtp-caldav-apis.service.spec.ts @@ -245,13 +245,13 @@ describe('ImapSmtpCalDavAPIService', () => { IMAP: { host: 'imap.example.com', port: 993, - secure: true, + connectionSecurity: 'SSL_TLS', password: 'password' as PlaintextString, }, SMTP: { host: 'smtp.example.com', port: 587, - secure: true, + connectionSecurity: 'SSL_TLS', username: 'test@example.com', password: 'password' as PlaintextString, }, @@ -342,7 +342,7 @@ describe('ImapSmtpCalDavAPIService', () => { CALDAV: { host: 'caldav.example.com', port: 443, - secure: true, + connectionSecurity: 'SSL_TLS', username: 'test@example.com', password: 'password' as PlaintextString, }, @@ -472,7 +472,7 @@ describe('ImapSmtpCalDavAPIService', () => { IMAP: { host: 'imap.example.com', port: 993, - secure: true, + connectionSecurity: 'SSL_TLS', password: 'password' as PlaintextString, }, } as PlaintextImapSmtpCaldavParams, @@ -507,7 +507,7 @@ describe('ImapSmtpCalDavAPIService', () => { CALDAV: { host: 'caldav.example.com', port: 443, - secure: true, + connectionSecurity: 'SSL_TLS', username: 'test@example.com', password: 'password' as PlaintextString, }, @@ -543,13 +543,13 @@ describe('ImapSmtpCalDavAPIService', () => { IMAP: { host: 'imap.example.com', port: 993, - secure: true, + connectionSecurity: 'SSL_TLS', password: 'password' as PlaintextString, }, SMTP: { host: 'smtp.example.com', port: 587, - secure: true, + connectionSecurity: 'SSL_TLS', username: 'test@example.com', password: 'password' as PlaintextString, }, @@ -585,20 +585,20 @@ describe('ImapSmtpCalDavAPIService', () => { IMAP: { host: 'imap.example.com', port: 993, - secure: true, + connectionSecurity: 'SSL_TLS', password: 'password' as PlaintextString, }, SMTP: { host: 'smtp.example.com', port: 587, - secure: true, + connectionSecurity: 'SSL_TLS', username: 'test@example.com', password: 'password' as PlaintextString, }, CALDAV: { host: 'caldav.example.com', port: 443, - secure: true, + connectionSecurity: 'SSL_TLS', username: 'test@example.com', password: 'password' as PlaintextString, }, @@ -680,7 +680,7 @@ describe('ImapSmtpCalDavAPIService', () => { SMTP: { host: 'smtp.example.com', port: 587, - secure: true, + connectionSecurity: 'SSL_TLS', username: 'test@example.com', password: 'password' as PlaintextString, }, diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/imap/providers/imap-client.provider.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/imap/providers/imap-client.provider.ts index cb62b7a7da..0f88066b11 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/imap/providers/imap-client.provider.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/imap/providers/imap-client.provider.ts @@ -6,6 +6,7 @@ import { ConnectedAccountProvider } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { Repository } from 'typeorm'; +import { buildImapTlsOptions } from 'src/engine/core-modules/imap-smtp-caldav-connection/utils/build-imap-tls-options.util'; import { SecureHttpClientService } from 'src/engine/core-modules/secure-http-client/secure-http-client.service'; import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity'; import { ConnectedAccountTokenEncryptionService } from 'src/engine/metadata-modules/connected-account/services/connected-account-token-encryption.service'; @@ -94,7 +95,7 @@ export class ImapClientProvider { const client = new ImapFlow({ host: validatedImapHost, port: imapParams.port || 993, - secure: imapParams.secure, + ...buildImapTlsOptions(imapParams.connectionSecurity), auth: { user: isDefined(imapParams.username) ? imapParams.username diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/smtp/providers/smtp-client.provider.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/smtp/providers/smtp-client.provider.ts index bf4f750fa3..a979ebe29f 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/smtp/providers/smtp-client.provider.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/smtp/providers/smtp-client.provider.ts @@ -9,6 +9,7 @@ import { ConnectedAccountProvider } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { Repository } from 'typeorm'; +import { buildSmtpTlsOptions } from 'src/engine/core-modules/imap-smtp-caldav-connection/utils/build-smtp-tls-options.util'; import { SecureHttpClientService } from 'src/engine/core-modules/secure-http-client/secure-http-client.service'; import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity'; import { ConnectedAccountTokenEncryptionService } from 'src/engine/metadata-modules/connected-account/services/connected-account-token-encryption.service'; @@ -52,6 +53,7 @@ export class SmtpClientProvider { const options: SMTPConnection.Options = { host: validatedSmtpHost, port: smtpParams.port, + ...buildSmtpTlsOptions(smtpParams.connectionSecurity), auth: { user: smtpParams.username ?? connectedAccount.handle ?? '', pass: smtpParams.password, diff --git a/packages/twenty-server/test/integration/metadata/suites/connected-account/failing-save-imap-smtp-caldav-account.integration-spec.ts b/packages/twenty-server/test/integration/metadata/suites/connected-account/failing-save-imap-smtp-caldav-account.integration-spec.ts index 4b8f0e2a36..c245b8bfa9 100644 --- a/packages/twenty-server/test/integration/metadata/suites/connected-account/failing-save-imap-smtp-caldav-account.integration-spec.ts +++ b/packages/twenty-server/test/integration/metadata/suites/connected-account/failing-save-imap-smtp-caldav-account.integration-spec.ts @@ -5,30 +5,22 @@ import { type EachTestingContext, } from 'twenty-shared/testing'; +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; + +type ProtocolConnectionContext = { + host: string; + port: number; + username?: string; + password?: string; + connectionSecurity?: EmailConnectionSecurity; +}; + type TestContext = { handle: string; connectionParameters: { - IMAP?: { - host: string; - port: number; - username?: string; - password?: string; - secure?: boolean; - }; - SMTP?: { - host: string; - port: number; - username?: string; - password?: string; - secure?: boolean; - }; - CALDAV?: { - host: string; - port: number; - username?: string; - password?: string; - secure?: boolean; - }; + IMAP?: ProtocolConnectionContext; + SMTP?: ProtocolConnectionContext; + CALDAV?: ProtocolConnectionContext; }; id?: string; }; @@ -48,7 +40,7 @@ describe('Connected account creation should fail', () => { host: 'imap.example.com', port: 993, username: 'user@example.com', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, }, }, @@ -62,7 +54,7 @@ describe('Connected account creation should fail', () => { host: 'smtp.example.com', port: 465, username: 'user@example.com', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, }, }, @@ -76,7 +68,7 @@ describe('Connected account creation should fail', () => { host: 'caldav.example.com', port: 443, username: 'user@example.com', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, }, }, @@ -90,7 +82,7 @@ describe('Connected account creation should fail', () => { host: '', port: 993, password: 'secret', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, }, }, @@ -104,7 +96,7 @@ describe('Connected account creation should fail', () => { host: 'imap.example.com', port: 0, password: 'secret', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, }, }, @@ -118,7 +110,7 @@ describe('Connected account creation should fail', () => { host: 'imap.example.com', port: 993, password: '', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, }, }, diff --git a/packages/twenty-server/test/integration/metadata/suites/connected-account/successful-save-imap-smtp-caldav-account.integration-spec.ts b/packages/twenty-server/test/integration/metadata/suites/connected-account/successful-save-imap-smtp-caldav-account.integration-spec.ts index 0743d678e8..a00b6ce236 100644 --- a/packages/twenty-server/test/integration/metadata/suites/connected-account/successful-save-imap-smtp-caldav-account.integration-spec.ts +++ b/packages/twenty-server/test/integration/metadata/suites/connected-account/successful-save-imap-smtp-caldav-account.integration-spec.ts @@ -2,6 +2,8 @@ import { deleteConnectedAccount } from 'test/integration/metadata/suites/connect import { getConnectedImapSmtpCaldavAccount } from 'test/integration/metadata/suites/connected-account/utils/get-connected-imap-smtp-caldav-account.util'; import { saveImapSmtpCaldavAccount } from 'test/integration/metadata/suites/connected-account/utils/save-imap-smtp-caldav-account.util'; +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; + const createAccount = async (handle: string): Promise => { const { data } = await saveImapSmtpCaldavAccount({ expectToFail: false, @@ -13,14 +15,14 @@ const createAccount = async (handle: string): Promise => { port: 993, username: 'user@example.com', password: 'test-password', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, SMTP: { host: 'smtp.fastmail.com', port: 465, username: 'user@example.com', password: 'test-password', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, }, }, @@ -49,14 +51,14 @@ describe('Successful save IMAP/SMTP/CALDAV account', () => { port: 993, username: 'user@example.com', password: 'test-password', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, SMTP: { host: 'smtp.fastmail.com', port: 465, username: 'user@example.com', password: 'test-password', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, }, }, @@ -78,13 +80,13 @@ describe('Successful save IMAP/SMTP/CALDAV account', () => { host: 'imap.fastmail.com', port: 993, username: 'user@example.com', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, SMTP: { host: 'smtp.fastmail.com', port: 465, username: 'user@example.com', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, CALDAV: null, }); @@ -104,13 +106,13 @@ describe('Successful save IMAP/SMTP/CALDAV account', () => { host: 'imap-updated.fastmail.com', port: 993, username: 'updated-user@example.com', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, SMTP: { host: 'smtp-updated.fastmail.com', port: 587, username: 'updated-user@example.com', - secure: false, + connectionSecurity: EmailConnectionSecurity.STARTTLS, }, }, id: accountId, @@ -129,13 +131,13 @@ describe('Successful save IMAP/SMTP/CALDAV account', () => { host: 'imap-updated.fastmail.com', port: 993, username: 'updated-user@example.com', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, SMTP: { host: 'smtp-updated.fastmail.com', port: 587, username: 'updated-user@example.com', - secure: false, + connectionSecurity: EmailConnectionSecurity.STARTTLS, }, CALDAV: null, }); @@ -156,7 +158,7 @@ describe('Successful save IMAP/SMTP/CALDAV account', () => { port: 993, username: 'user@example.com', password: 'test-password', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, }, id: accountId, @@ -175,7 +177,7 @@ describe('Successful save IMAP/SMTP/CALDAV account', () => { host: 'imap.fastmail.com', port: 993, username: 'user@example.com', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, SMTP: null, CALDAV: null, @@ -197,14 +199,14 @@ describe('Successful save IMAP/SMTP/CALDAV account', () => { port: 993, username: 'user@example.com', password: 'new-password', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, SMTP: { host: 'smtp.fastmail.com', port: 465, username: 'user@example.com', password: 'new-password', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, }, id: accountId, @@ -223,13 +225,13 @@ describe('Successful save IMAP/SMTP/CALDAV account', () => { host: 'imap.fastmail.com', port: 993, username: 'user@example.com', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, SMTP: { host: 'smtp.fastmail.com', port: 465, username: 'user@example.com', - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, CALDAV: null, }); diff --git a/packages/twenty-server/test/integration/metadata/suites/connected-account/utils/get-connected-imap-smtp-caldav-account.util.ts b/packages/twenty-server/test/integration/metadata/suites/connected-account/utils/get-connected-imap-smtp-caldav-account.util.ts index 3304d18206..4586cc45b6 100644 --- a/packages/twenty-server/test/integration/metadata/suites/connected-account/utils/get-connected-imap-smtp-caldav-account.util.ts +++ b/packages/twenty-server/test/integration/metadata/suites/connected-account/utils/get-connected-imap-smtp-caldav-account.util.ts @@ -19,19 +19,19 @@ export const getConnectedImapSmtpCaldavAccount = async ({ host port username - secure + connectionSecurity } SMTP { host port username - secure + connectionSecurity } CALDAV { host port username - secure + connectionSecurity } } } diff --git a/packages/twenty-server/test/integration/metadata/suites/connected-account/utils/save-imap-smtp-caldav-account.util.ts b/packages/twenty-server/test/integration/metadata/suites/connected-account/utils/save-imap-smtp-caldav-account.util.ts index d790f2a109..de5c88ba61 100644 --- a/packages/twenty-server/test/integration/metadata/suites/connected-account/utils/save-imap-smtp-caldav-account.util.ts +++ b/packages/twenty-server/test/integration/metadata/suites/connected-account/utils/save-imap-smtp-caldav-account.util.ts @@ -1,30 +1,22 @@ import { gql } from 'graphql-tag'; import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util'; +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; + +type ProtocolConnectionInput = { + host: string; + port: number; + username?: string; + password?: string; + connectionSecurity?: EmailConnectionSecurity; +}; + type SaveImapSmtpCaldavAccountInput = { handle: string; connectionParameters: { - IMAP?: { - host: string; - port: number; - username?: string; - password?: string; - secure?: boolean; - }; - SMTP?: { - host: string; - port: number; - username?: string; - password?: string; - secure?: boolean; - }; - CALDAV?: { - host: string; - port: number; - username?: string; - password?: string; - secure?: boolean; - }; + IMAP?: ProtocolConnectionInput; + SMTP?: ProtocolConnectionInput; + CALDAV?: ProtocolConnectionInput; }; id?: string; }; diff --git a/packages/twenty-server/test/integration/secret-encryption/connection-parameters-rotation.integration-spec.ts b/packages/twenty-server/test/integration/secret-encryption/connection-parameters-rotation.integration-spec.ts index 0dc7144a8b..e5525574f5 100644 --- a/packages/twenty-server/test/integration/secret-encryption/connection-parameters-rotation.integration-spec.ts +++ b/packages/twenty-server/test/integration/secret-encryption/connection-parameters-rotation.integration-spec.ts @@ -6,6 +6,7 @@ import { saveImapSmtpCaldavAccount } from 'test/integration/metadata/suites/conn import { runSecretEncryptionRotationCommand } from 'test/integration/secret-encryption/utils/run-secret-encryption-rotation-command.util'; import { buildSecretEncryptionServiceFromEnv } from 'test/integration/upgrade/utils/build-secret-encryption-service.util'; +import { EmailConnectionSecurity } from 'src/engine/core-modules/imap-smtp-caldav-connection/enums/email-connection-security.enum'; import { type EncryptedImapSmtpCaldavParams } from 'src/engine/core-modules/imap-smtp-caldav-connection/types/imap-smtp-caldav-connection.type'; import { type SecretEncryptionService } from 'src/engine/core-modules/secret-encryption/secret-encryption.service'; @@ -53,12 +54,9 @@ const expectAllPasswordsDecryptTo = ({ expect(params).toBeDefined(); expect(params?.password).toMatch(V2_ENVELOPE_REGEX); - const decrypted = secretEncryption.decryptVersioned( - params!.password, - { - workspaceId: row.workspaceId, - }, - ); + const decrypted = secretEncryption.decryptVersioned(params!.password, { + workspaceId: row.workspaceId, + }); expect(decrypted).toBe(expectedPlaintextByProtocol[protocol]); } @@ -83,21 +81,21 @@ describe('secret-encryption:rotate command — connection-parameters site (integ port: 993, username: 'rotation@example.com', password: IMAP_PASSWORD, - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, SMTP: { host: 'smtp.fastmail.com', port: 465, username: 'rotation@example.com', password: SMTP_PASSWORD, - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, CALDAV: { host: 'caldav.fastmail.com', port: 443, username: 'rotation@example.com', password: CALDAV_PASSWORD, - secure: true, + connectionSecurity: EmailConnectionSecurity.SSL_TLS, }, }, }, diff --git a/packages/twenty-server/test/integration/upgrade/suites/2-15-instance-command-slow-1781461753981-backfill-connection-security.integration-spec.ts b/packages/twenty-server/test/integration/upgrade/suites/2-15-instance-command-slow-1781461753981-backfill-connection-security.integration-spec.ts new file mode 100644 index 0000000000..2e748e7c46 --- /dev/null +++ b/packages/twenty-server/test/integration/upgrade/suites/2-15-instance-command-slow-1781461753981-backfill-connection-security.integration-spec.ts @@ -0,0 +1,189 @@ +import { config } from 'dotenv'; +import { isDefined } from 'twenty-shared/utils'; +import { DataSource } from 'typeorm'; + +import { BackfillConnectionSecuritySlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-15/2-15-instance-command-slow-1781461753981-backfill-connection-security'; + +jest.useRealTimers(); + +config({ + path: process.env.NODE_ENV === 'test' ? '.env.test' : '.env', + override: true, +}); + +const TEST_ROW_HANDLE_PREFIX = 'backfill-connection-security-test-'; + +describe('BackfillConnectionSecuritySlowInstanceCommand (integration)', () => { + let dataSource: DataSource; + let command: BackfillConnectionSecuritySlowInstanceCommand; + let workspaceId: string; + let userWorkspaceId: string; + const seededRowIds: string[] = []; + + const seedAccount = async ( + connectionParameters: Record, + ): Promise => { + const [row] = await dataSource.query( + `INSERT INTO "core"."connectedAccount" + ("handle", "provider", "userWorkspaceId", "workspaceId", "visibility", "connectionParameters") + VALUES ($1, 'imap_smtp_caldav', $2, $3, 'user', $4) + RETURNING id`, + [ + `${TEST_ROW_HANDLE_PREFIX}${seededRowIds.length}`, + userWorkspaceId, + workspaceId, + JSON.stringify(connectionParameters), + ], + ); + + seededRowIds.push(row.id as string); + + return row.id as string; + }; + + const getConnectionParameters = async ( + id: string, + ): Promise>> => { + const [row] = await dataSource.query( + `SELECT "connectionParameters" FROM "core"."connectedAccount" WHERE id = $1`, + [id], + ); + + return row.connectionParameters; + }; + + beforeAll(async () => { + dataSource = new DataSource({ + type: 'postgres', + url: process.env.PG_DATABASE_URL, + schema: 'core', + entities: [], + synchronize: false, + }); + await dataSource.initialize(); + + command = new BackfillConnectionSecuritySlowInstanceCommand(); + + const [seedWorkspaceRow] = await dataSource.query( + `SELECT uw.id AS "userWorkspaceId", uw."workspaceId" AS "workspaceId" + FROM "core"."userWorkspace" uw + LIMIT 1`, + ); + + if (!isDefined(seedWorkspaceRow)) { + throw new Error( + 'No seeded userWorkspace row found; run database:reset before the integration suite.', + ); + } + + userWorkspaceId = seedWorkspaceRow.userWorkspaceId; + workspaceId = seedWorkspaceRow.workspaceId; + }, 30000); + + afterEach(async () => { + if (seededRowIds.length > 0) { + await dataSource.query( + `DELETE FROM "core"."connectedAccount" WHERE id = ANY($1::uuid[])`, + [seededRowIds], + ); + seededRowIds.length = 0; + } + }); + + afterAll(async () => { + await dataSource?.destroy(); + }); + + it('maps every legacy protocol to the mode matching its prior on-wire behavior and drops the secure key', async () => { + const id = await seedAccount({ + IMAP: { + host: 'imap.example.com', + port: 993, + secure: true, + password: 'enc:v2:x', + }, + SMTP: { + host: 'smtp.example.com', + port: 587, + secure: true, + password: 'enc:v2:x', + }, + CALDAV: { + host: 'https://dav.example.com', + port: 443, + secure: true, + password: 'enc:v2:x', + }, + }); + + await command.runDataMigration(dataSource); + + const params = await getConnectionParameters(id); + + expect(params.IMAP.connectionSecurity).toBe('SSL_TLS'); + expect(params.SMTP.connectionSecurity).toBe('STARTTLS'); + expect(params.CALDAV.connectionSecurity).toBe('SSL_TLS'); + expect(params.IMAP.secure).toBeUndefined(); + expect(params.SMTP.secure).toBeUndefined(); + expect(params.CALDAV.secure).toBeUndefined(); + }); + + it('maps implicit-TLS SMTP (port 465) and opportunistic IMAP (secure:false) correctly', async () => { + const implicitSmtpId = await seedAccount({ + SMTP: { + host: 'smtp.example.com', + port: 465, + secure: true, + password: 'enc:v2:x', + }, + }); + const plaintextImapId = await seedAccount({ + IMAP: { + host: 'imap.example.com', + port: 143, + secure: false, + password: 'enc:v2:x', + }, + }); + + await command.runDataMigration(dataSource); + + expect( + (await getConnectionParameters(implicitSmtpId)).SMTP.connectionSecurity, + ).toBe('SSL_TLS'); + expect( + (await getConnectionParameters(plaintextImapId)).IMAP.connectionSecurity, + ).toBe('STARTTLS'); + }); + + it('is idempotent and leaves already-migrated accounts untouched', async () => { + const legacyId = await seedAccount({ + SMTP: { + host: 'smtp.example.com', + port: 587, + secure: true, + password: 'enc:v2:x', + }, + }); + const alreadyMigratedId = await seedAccount({ + SMTP: { + host: 'smtp.example.com', + port: 465, + connectionSecurity: 'STARTTLS', + password: 'enc:v2:x', + }, + }); + + await command.runDataMigration(dataSource); + await command.runDataMigration(dataSource); + + expect( + (await getConnectionParameters(legacyId)).SMTP.connectionSecurity, + ).toBe('STARTTLS'); + // A pre-set connectionSecurity is never overwritten, even when it disagrees with the port. + expect( + (await getConnectionParameters(alreadyMigratedId)).SMTP + .connectionSecurity, + ).toBe('STARTTLS'); + }); +});