emailengine-app 2.64.0 → 2.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/routes-ui.js CHANGED
@@ -37,7 +37,7 @@ const { Account } = require('./account');
37
37
  const { Gateway } = require('./gateway');
38
38
  const { redis, submitQueue, notifyQueue, documentsQueue } = require('./db');
39
39
  const psl = require('psl');
40
- const { oauth2Apps, LEGACY_KEYS, OAUTH_PROVIDERS, oauth2ProviderData } = require('./oauth2-apps');
40
+ const { oauth2Apps, OAUTH_PROVIDERS, oauth2ProviderData, SERVICE_ACCOUNT_PROVIDERS } = require('./oauth2-apps');
41
41
  const { autodetectImapSettings } = require('./autodetect-imap-settings');
42
42
  const getSecret = require('./get-secret');
43
43
  const os = require('os');
@@ -45,10 +45,9 @@ const {
45
45
  ADDRESS_STRATEGIES,
46
46
  settingsSchema,
47
47
  oauthCreateSchema,
48
+ oauthUpdateSchema,
48
49
  accountIdSchema,
49
50
  defaultAccountTypeSchema,
50
- googleProjectIdSchema,
51
- googleWorkspaceAccountsSchema,
52
51
  exportIdSchema
53
52
  } = require('./schemas');
54
53
  const fs = require('fs');
@@ -357,150 +356,6 @@ const OKTA_OAUTH2_CLIENT_ID = readEnvValue('OKTA_OAUTH2_CLIENT_ID');
357
356
  const OKTA_OAUTH2_CLIENT_SECRET = readEnvValue('OKTA_OAUTH2_CLIENT_SECRET');
358
357
  const USE_OKTA_AUTH = !!(OKTA_OAUTH2_ISSUER && OKTA_OAUTH2_CLIENT_ID && OKTA_OAUTH2_CLIENT_SECRET);
359
358
 
360
- const oauthUpdateSchema = {
361
- app: Joi.string().empty('').max(255).example('gmail').label('Provider').required(),
362
-
363
- provider: Joi.string()
364
- .trim()
365
- .empty('')
366
- .max(256)
367
- .valid(...Object.keys(OAUTH_PROVIDERS))
368
- .example('gmail')
369
- .required()
370
- .description('OAuth2 provider'),
371
-
372
- name: Joi.string()
373
- .trim()
374
- .empty('')
375
- .max(256)
376
- .example('My Gmail App')
377
- .description('Application name')
378
- .when('app', {
379
- not: Joi.string().valid(...LEGACY_KEYS),
380
- then: Joi.required(),
381
- otherwise: Joi.optional().valid(false, null)
382
- }),
383
- description: Joi.string().trim().allow('').max(1024).example('My cool app').description('Application description'),
384
-
385
- title: Joi.string().allow('').trim().max(256).example('App title').description('Title for the application button'),
386
-
387
- enabled: Joi.boolean().truthy('Y', 'true', '1', 'on').falsy('N', 'false', 0, '').default(false).description('Enable this app'),
388
-
389
- clientId: Joi.string()
390
- .trim()
391
- .allow('')
392
- .max(256)
393
- .when('provider', {
394
- not: 'gmailService',
395
- then: Joi.required(),
396
- otherwise: Joi.optional().valid(false, null)
397
- })
398
- .description('OAuth2 Client ID'),
399
-
400
- clientSecret: Joi.string()
401
- .trim()
402
- .empty('', false, null)
403
- .max(256)
404
- .when('provider', {
405
- not: 'gmailService',
406
- then: Joi.optional(),
407
- otherwise: Joi.forbidden()
408
- })
409
- .description('OAuth2 Client Secret'),
410
-
411
- pubSubApp: Joi.string()
412
- .empty('')
413
- .base64({ paddingRequired: false, urlSafe: true })
414
- .max(512)
415
- .example('AAAAAQAACnA')
416
- .description('Cloud Pub/Sub app for Gmail API webhooks'),
417
-
418
- extraScopes: Joi.string()
419
- .allow('')
420
- .trim()
421
- .max(10 * 1024)
422
- .description('OAuth2 Extra Scopes'),
423
-
424
- skipScopes: Joi.string()
425
- .allow('')
426
- .trim()
427
- .max(10 * 1024)
428
- .description('OAuth2 scopes to skip from the base set'),
429
-
430
- serviceClient: Joi.string()
431
- .trim()
432
- .allow('')
433
- .max(256)
434
- .when('provider', {
435
- is: 'gmailService',
436
- then: Joi.required(),
437
- otherwise: Joi.optional().valid(false, null)
438
- })
439
- .description('OAuth2 Service Client ID'),
440
-
441
- googleProjectId: googleProjectIdSchema,
442
-
443
- googleWorkspaceAccounts: googleWorkspaceAccountsSchema.when('provider', {
444
- is: 'gmail',
445
- then: Joi.optional().default(false)
446
- }),
447
-
448
- serviceClientEmail: Joi.string()
449
- .trim()
450
- .allow('')
451
- .email()
452
- .when('provider', {
453
- is: 'gmailService',
454
- then: Joi.required(),
455
- otherwise: Joi.optional().valid(false, null)
456
- })
457
- .example('name@project-123.iam.gserviceaccount.com')
458
- .description('Service Client Email for 2-legged OAuth2 applications'),
459
-
460
- serviceKey: Joi.string()
461
- .trim()
462
- .empty('', false, null)
463
- .max(100 * 1024)
464
- .when('provider', {
465
- is: 'gmailService',
466
- then: Joi.optional(),
467
- otherwise: Joi.forbidden()
468
- })
469
- .description('OAuth2 Secret Service Key'),
470
-
471
- authority: Joi.string()
472
- .trim()
473
- .empty('')
474
- .max(1024)
475
- .when('provider', {
476
- is: 'outlook',
477
- then: Joi.required(),
478
- otherwise: Joi.optional().valid(false, null)
479
- })
480
- .example(false)
481
- .label('SupportedAccountTypes'),
482
-
483
- cloud: Joi.string()
484
- .trim()
485
- .empty('')
486
- .valid('global', 'gcc-high', 'dod', 'china')
487
- .example('global')
488
- .description('Azure cloud type for Outlook OAuth2 applications')
489
- .label('AzureCloud'),
490
-
491
- tenant: Joi.string().trim().empty('').max(1024).example('f8cdef31-a31e-4b4a-93e4-5f571e91255a').label('Directorytenant'),
492
-
493
- redirectUrl: Joi.string()
494
- .allow('')
495
- .uri({ scheme: ['http', 'https'], allowRelative: false })
496
- .when('provider', {
497
- not: 'gmailService',
498
- then: Joi.required(),
499
- otherwise: Joi.optional().valid(false, null)
500
- })
501
- .description('OAuth2 Callback URL')
502
- };
503
-
504
359
  function formatAccountData(account, gt) {
505
360
  account.type = {};
506
361
 
@@ -4761,6 +4616,11 @@ ${Buffer.from(data.content, 'base64url').toString('base64')}
4761
4616
  requestPayload.email = accountData.email;
4762
4617
  }
4763
4618
 
4619
+ // Service providers use client_credentials - no interactive authorization
4620
+ if (SERVICE_ACCOUNT_PROVIDERS.has(oAuth2Client.provider)) {
4621
+ throw Boom.badRequest('Application-only OAuth providers do not support interactive authorization');
4622
+ }
4623
+
4764
4624
  let authorizeUrl = oAuth2Client.generateAuthUrl(requestPayload);
4765
4625
 
4766
4626
  return h.redirect(authorizeUrl);
package/lib/schemas.js CHANGED
@@ -4,6 +4,7 @@ const Joi = require('joi');
4
4
  const config = require('@zone-eu/wild-config');
5
5
  const { getByteSize } = require('./tools');
6
6
  const { locales } = require('./translations');
7
+ const { LEGACY_KEYS, OAUTH_PROVIDERS } = require('./oauth2-apps');
7
8
 
8
9
  const RESYNC_DELAY = 15 * 60;
9
10
 
@@ -22,13 +23,6 @@ const ADDRESS_STRATEGIES = [
22
23
  { key: 'random', title: 'Random' }
23
24
  ];
24
25
 
25
- const OAUTH_PROVIDERS = {
26
- gmail: 'Gmail',
27
- gmailService: 'Gmail Service Accounts',
28
- outlook: 'Outlook',
29
- mailRu: 'Mail.ru'
30
- };
31
-
32
26
  const accountIdSchema = Joi.string().empty('').trim().max(256).example('user123').description('Unique identifier for the email account');
33
27
 
34
28
  // Allowed configuration keys
@@ -1529,8 +1523,18 @@ const oauthCreateSchema = {
1529
1523
  .empty('')
1530
1524
  .max(1024)
1531
1525
  .when('provider', {
1532
- is: 'outlook',
1533
- then: Joi.required(),
1526
+ switch: [
1527
+ {
1528
+ is: 'outlookService',
1529
+ then: Joi.string().required().invalid('common', 'organizations', 'consumers').messages({
1530
+ 'any.invalid': 'Client credentials flow requires a specific tenant ID; "{{#value}}" is not allowed'
1531
+ })
1532
+ },
1533
+ {
1534
+ is: 'outlook',
1535
+ then: Joi.required()
1536
+ }
1537
+ ],
1534
1538
  otherwise: Joi.optional().valid(false, null)
1535
1539
  })
1536
1540
  .example('common')
@@ -1541,7 +1545,7 @@ const oauthCreateSchema = {
1541
1545
  .trim()
1542
1546
  .empty('')
1543
1547
  .when('provider', {
1544
- is: 'outlook',
1548
+ is: Joi.valid('outlook', 'outlookService'),
1545
1549
  then: Joi.valid('global', 'gcc-high', 'dod', 'china').default('global'),
1546
1550
  otherwise: Joi.optional().valid(false, null)
1547
1551
  })
@@ -1565,7 +1569,7 @@ const oauthCreateSchema = {
1565
1569
  .allow('')
1566
1570
  .uri({ scheme: ['http', 'https'], allowRelative: false })
1567
1571
  .when('provider', {
1568
- not: 'gmailService',
1572
+ not: Joi.valid('gmailService', 'outlookService'),
1569
1573
  then: Joi.required(),
1570
1574
  otherwise: Joi.optional().valid(false, null)
1571
1575
  })
@@ -1574,6 +1578,160 @@ const oauthCreateSchema = {
1574
1578
  .label('OAuth2AppRedirectUrl')
1575
1579
  };
1576
1580
 
1581
+ const oauthUpdateSchema = {
1582
+ app: Joi.string().empty('').max(255).example('gmail').label('Provider').required(),
1583
+
1584
+ provider: Joi.string()
1585
+ .trim()
1586
+ .empty('')
1587
+ .max(256)
1588
+ .valid(...Object.keys(OAUTH_PROVIDERS))
1589
+ .example('gmail')
1590
+ .required()
1591
+ .description('OAuth2 provider'),
1592
+
1593
+ name: Joi.string()
1594
+ .trim()
1595
+ .empty('')
1596
+ .max(256)
1597
+ .example('My Gmail App')
1598
+ .description('Application name')
1599
+ .when('app', {
1600
+ not: Joi.string().valid(...LEGACY_KEYS),
1601
+ then: Joi.required(),
1602
+ otherwise: Joi.optional().valid(false, null)
1603
+ }),
1604
+ description: Joi.string().trim().allow('').max(1024).example('My cool app').description('Application description'),
1605
+
1606
+ title: Joi.string().allow('').trim().max(256).example('App title').description('Title for the application button'),
1607
+
1608
+ enabled: Joi.boolean().truthy('Y', 'true', '1', 'on').falsy('N', 'false', 0, '').default(false).description('Enable this app'),
1609
+
1610
+ clientId: Joi.string()
1611
+ .trim()
1612
+ .allow('')
1613
+ .max(256)
1614
+ .when('provider', {
1615
+ not: 'gmailService',
1616
+ then: Joi.required(),
1617
+ otherwise: Joi.optional().valid(false, null)
1618
+ })
1619
+ .description('OAuth2 Client ID'),
1620
+
1621
+ clientSecret: Joi.string()
1622
+ .trim()
1623
+ .empty('', false, null)
1624
+ .max(256)
1625
+ .when('provider', {
1626
+ not: 'gmailService',
1627
+ then: Joi.optional(),
1628
+ otherwise: Joi.forbidden()
1629
+ })
1630
+ .description('OAuth2 Client Secret'),
1631
+
1632
+ pubSubApp: Joi.string()
1633
+ .empty('')
1634
+ .base64({ paddingRequired: false, urlSafe: true })
1635
+ .max(512)
1636
+ .example('AAAAAQAACnA')
1637
+ .description('Cloud Pub/Sub app for Gmail API webhooks'),
1638
+
1639
+ extraScopes: Joi.string()
1640
+ .allow('')
1641
+ .trim()
1642
+ .max(10 * 1024)
1643
+ .description('OAuth2 Extra Scopes'),
1644
+
1645
+ skipScopes: Joi.string()
1646
+ .allow('')
1647
+ .trim()
1648
+ .max(10 * 1024)
1649
+ .description('OAuth2 scopes to skip from the base set'),
1650
+
1651
+ serviceClient: Joi.string()
1652
+ .trim()
1653
+ .allow('')
1654
+ .max(256)
1655
+ .when('provider', {
1656
+ is: 'gmailService',
1657
+ then: Joi.required(),
1658
+ otherwise: Joi.optional().valid(false, null)
1659
+ })
1660
+ .description('OAuth2 Service Client ID'),
1661
+
1662
+ googleProjectId: googleProjectIdSchema,
1663
+
1664
+ googleWorkspaceAccounts: googleWorkspaceAccountsSchema.when('provider', {
1665
+ is: 'gmail',
1666
+ then: Joi.optional().default(false)
1667
+ }),
1668
+
1669
+ serviceClientEmail: Joi.string()
1670
+ .trim()
1671
+ .allow('')
1672
+ .email()
1673
+ .when('provider', {
1674
+ is: 'gmailService',
1675
+ then: Joi.required(),
1676
+ otherwise: Joi.optional().valid(false, null)
1677
+ })
1678
+ .example('name@project-123.iam.gserviceaccount.com')
1679
+ .description('Service Client Email for 2-legged OAuth2 applications'),
1680
+
1681
+ serviceKey: Joi.string()
1682
+ .trim()
1683
+ .empty('', false, null)
1684
+ .max(100 * 1024)
1685
+ .when('provider', {
1686
+ is: 'gmailService',
1687
+ then: Joi.optional(),
1688
+ otherwise: Joi.forbidden()
1689
+ })
1690
+ .description('OAuth2 Secret Service Key'),
1691
+
1692
+ authority: Joi.string()
1693
+ .trim()
1694
+ .empty('')
1695
+ .max(1024)
1696
+ .when('provider', {
1697
+ switch: [
1698
+ {
1699
+ is: 'outlookService',
1700
+ then: Joi.string().required().invalid('common', 'organizations', 'consumers').messages({
1701
+ 'any.invalid': 'Client credentials flow requires a specific tenant ID; "{{#value}}" is not allowed'
1702
+ })
1703
+ },
1704
+ {
1705
+ is: 'outlook',
1706
+ then: Joi.required()
1707
+ }
1708
+ ],
1709
+ otherwise: Joi.optional().valid(false, null)
1710
+ })
1711
+ .example(false)
1712
+ .label('SupportedAccountTypes'),
1713
+
1714
+ cloud: Joi.string()
1715
+ .trim()
1716
+ .empty('')
1717
+ .valid('global', 'gcc-high', 'dod', 'china')
1718
+ .example('global')
1719
+ .description('Azure cloud type for Outlook OAuth2 applications')
1720
+ .label('AzureCloud'),
1721
+
1722
+ tenant: Joi.string().trim().empty('').max(1024).example('f8cdef31-a31e-4b4a-93e4-5f571e91255a').label('Directorytenant'),
1723
+
1724
+ redirectUrl: Joi.string()
1725
+ .allow('')
1726
+ .uri({ scheme: ['http', 'https'], allowRelative: false })
1727
+ .when('provider', {
1728
+ not: Joi.valid('gmailService', 'outlookService'),
1729
+ then: Joi.required(),
1730
+ otherwise: Joi.optional().valid(false, null)
1731
+ })
1732
+ .description('OAuth2 Callback URL')
1733
+ };
1734
+
1577
1735
  const tokenRestrictionsSchema = Joi.object({
1578
1736
  referrers: Joi.array()
1579
1737
  .items(Joi.string())
@@ -1822,6 +1980,7 @@ const exportStatusSchema = Joi.object({
1822
1980
  progress: exportProgressSchema,
1823
1981
  created: Joi.date().iso().example('2024-01-15T10:30:00Z').description('When export was created'),
1824
1982
  expiresAt: Joi.date().iso().example('2024-01-16T10:30:00Z').description('When export file expires'),
1983
+ truncated: Joi.boolean().example(true).description('Whether the export was truncated due to message count or size limits'),
1825
1984
  error: Joi.string().allow(null).description('Error message if export failed')
1826
1985
  }).label('ExportStatus');
1827
1986
 
@@ -1876,6 +2035,7 @@ module.exports = {
1876
2035
  searchSchema,
1877
2036
  messageUpdateSchema,
1878
2037
  oauthCreateSchema,
2038
+ oauthUpdateSchema,
1879
2039
  tokenRestrictionsSchema,
1880
2040
  accountIdSchema,
1881
2041
  ipSchema,
@@ -22,7 +22,7 @@ const {
22
22
  } = require('../tools');
23
23
  const { Account } = require('../account');
24
24
  const { Gateway } = require('../gateway');
25
- const { oauth2Apps, oauth2ProviderData } = require('../oauth2-apps');
25
+ const { oauth2Apps, oauth2ProviderData, SERVICE_ACCOUNT_PROVIDERS } = require('../oauth2-apps');
26
26
  const { autodetectImapSettings } = require('../autodetect-imap-settings');
27
27
  const getSecret = require('../get-secret');
28
28
  const capa = require('../capa');
@@ -538,6 +538,11 @@ function init(args) {
538
538
  requestPayload.email = accountData.email;
539
539
  }
540
540
 
541
+ // Service providers use client_credentials - no interactive authorization
542
+ if (SERVICE_ACCOUNT_PROVIDERS.has(oAuth2Client.provider)) {
543
+ throw Boom.badRequest('Application-only OAuth providers do not support interactive authorization');
544
+ }
545
+
541
546
  let authorizeUrl = oAuth2Client.generateAuthUrl(requestPayload);
542
547
 
543
548
  return h.redirect(authorizeUrl);
@@ -5,14 +5,22 @@ const Joi = require('joi');
5
5
 
6
6
  const settings = require('../settings');
7
7
  const { redis } = require('../db');
8
- const { oauth2Apps, LEGACY_KEYS, OAUTH_PROVIDERS, oauth2ProviderData } = require('../oauth2-apps');
8
+ const { oauth2Apps, OAUTH_PROVIDERS, oauth2ProviderData } = require('../oauth2-apps');
9
9
  const getSecret = require('../get-secret');
10
10
  const { Account } = require('../account');
11
- const { oauthCreateSchema, googleProjectIdSchema, googleWorkspaceAccountsSchema } = require('../schemas');
11
+ const { oauthCreateSchema, oauthUpdateSchema } = require('../schemas');
12
12
  const consts = require('../consts');
13
13
 
14
14
  const { DEFAULT_PAGE_SIZE } = consts;
15
15
 
16
+ // Microsoft Entra requires 'localhost' rather than '127.0.0.1' in redirect URIs
17
+ function normalizeOutlookRedirectUrl(redirectUrl, provider) {
18
+ if (provider === 'outlook') {
19
+ return redirectUrl.replace(/^http:\/\/127\.0\.0\.1\b/i, 'http://localhost');
20
+ }
21
+ return redirectUrl;
22
+ }
23
+
16
24
  const AZURE_CLOUDS = [
17
25
  {
18
26
  id: 'global',
@@ -39,150 +47,6 @@ const AZURE_CLOUDS = [
39
47
  }
40
48
  ];
41
49
 
42
- const oauthUpdateSchema = {
43
- app: Joi.string().empty('').max(255).example('gmail').label('Provider').required(),
44
-
45
- provider: Joi.string()
46
- .trim()
47
- .empty('')
48
- .max(256)
49
- .valid(...Object.keys(OAUTH_PROVIDERS))
50
- .example('gmail')
51
- .required()
52
- .description('OAuth2 provider'),
53
-
54
- name: Joi.string()
55
- .trim()
56
- .empty('')
57
- .max(256)
58
- .example('My Gmail App')
59
- .description('Application name')
60
- .when('app', {
61
- not: Joi.string().valid(...LEGACY_KEYS),
62
- then: Joi.required(),
63
- otherwise: Joi.optional().valid(false, null)
64
- }),
65
- description: Joi.string().trim().allow('').max(1024).example('My cool app').description('Application description'),
66
-
67
- title: Joi.string().allow('').trim().max(256).example('App title').description('Title for the application button'),
68
-
69
- enabled: Joi.boolean().truthy('Y', 'true', '1', 'on').falsy('N', 'false', 0, '').default(false).description('Enable this app'),
70
-
71
- clientId: Joi.string()
72
- .trim()
73
- .allow('')
74
- .max(256)
75
- .when('provider', {
76
- not: 'gmailService',
77
- then: Joi.required(),
78
- otherwise: Joi.optional().valid(false, null)
79
- })
80
- .description('OAuth2 Client ID'),
81
-
82
- clientSecret: Joi.string()
83
- .trim()
84
- .empty('', false, null)
85
- .max(256)
86
- .when('provider', {
87
- not: 'gmailService',
88
- then: Joi.optional(),
89
- otherwise: Joi.forbidden()
90
- })
91
- .description('OAuth2 Client Secret'),
92
-
93
- pubSubApp: Joi.string()
94
- .empty('')
95
- .base64({ paddingRequired: false, urlSafe: true })
96
- .max(512)
97
- .example('AAAAAQAACnA')
98
- .description('Cloud Pub/Sub app for Gmail API webhooks'),
99
-
100
- extraScopes: Joi.string()
101
- .allow('')
102
- .trim()
103
- .max(10 * 1024)
104
- .description('OAuth2 Extra Scopes'),
105
-
106
- skipScopes: Joi.string()
107
- .allow('')
108
- .trim()
109
- .max(10 * 1024)
110
- .description('OAuth2 scopes to skip from the base set'),
111
-
112
- serviceClient: Joi.string()
113
- .trim()
114
- .allow('')
115
- .max(256)
116
- .when('provider', {
117
- is: 'gmailService',
118
- then: Joi.required(),
119
- otherwise: Joi.optional().valid(false, null)
120
- })
121
- .description('OAuth2 Service Client ID'),
122
-
123
- googleProjectId: googleProjectIdSchema,
124
-
125
- googleWorkspaceAccounts: googleWorkspaceAccountsSchema.when('provider', {
126
- is: 'gmail',
127
- then: Joi.optional().default(false)
128
- }),
129
-
130
- serviceClientEmail: Joi.string()
131
- .trim()
132
- .allow('')
133
- .email()
134
- .when('provider', {
135
- is: 'gmailService',
136
- then: Joi.required(),
137
- otherwise: Joi.optional().valid(false, null)
138
- })
139
- .example('name@project-123.iam.gserviceaccount.com')
140
- .description('Service Client Email for 2-legged OAuth2 applications'),
141
-
142
- serviceKey: Joi.string()
143
- .trim()
144
- .empty('', false, null)
145
- .max(100 * 1024)
146
- .when('provider', {
147
- is: 'gmailService',
148
- then: Joi.optional(),
149
- otherwise: Joi.forbidden()
150
- })
151
- .description('OAuth2 Secret Service Key'),
152
-
153
- authority: Joi.string()
154
- .trim()
155
- .empty('')
156
- .max(1024)
157
- .when('provider', {
158
- is: 'outlook',
159
- then: Joi.required(),
160
- otherwise: Joi.optional().valid(false, null)
161
- })
162
- .example(false)
163
- .label('SupportedAccountTypes'),
164
-
165
- cloud: Joi.string()
166
- .trim()
167
- .empty('')
168
- .valid('global', 'gcc-high', 'dod', 'china')
169
- .example('global')
170
- .description('Azure cloud type for Outlook OAuth2 applications')
171
- .label('AzureCloud'),
172
-
173
- tenant: Joi.string().trim().empty('').max(1024).example('f8cdef31-a31e-4b4a-93e4-5f571e91255a').label('Directorytenant'),
174
-
175
- redirectUrl: Joi.string()
176
- .allow('')
177
- .uri({ scheme: ['http', 'https'], allowRelative: false })
178
- .when('provider', {
179
- not: 'gmailService',
180
- then: Joi.required(),
181
- otherwise: Joi.optional().valid(false, null)
182
- })
183
- .description('OAuth2 Callback URL')
184
- };
185
-
186
50
  function init({ server, call }) {
187
51
  // GET /admin/config/oauth - OAuth applications list
188
52
  server.route({
@@ -448,10 +312,7 @@ function init({ server, call }) {
448
312
  let providerData = oauth2ProviderData(provider);
449
313
 
450
314
  let serviceUrl = await settings.get('serviceUrl');
451
- let defaultRedirectUrl = `${serviceUrl}/oauth`;
452
- if (provider === 'outlook') {
453
- defaultRedirectUrl = defaultRedirectUrl.replace(/^http:\/\/127\.0\.0\.1\b/i, 'http://localhost');
454
- }
315
+ let defaultRedirectUrl = normalizeOutlookRedirectUrl(`${serviceUrl}/oauth`, provider);
455
316
 
456
317
  let pubSubApps = await oauth2Apps.list(0, 1000, { pubsub: true });
457
318
 
@@ -483,10 +344,10 @@ function init({ server, call }) {
483
344
 
484
345
  values: {
485
346
  provider,
486
- redirectUrl: defaultRedirectUrl
347
+ ...(provider !== 'outlookService' ? { redirectUrl: defaultRedirectUrl } : {})
487
348
  },
488
349
 
489
- authorityCommon: true
350
+ authorityCommon: provider !== 'outlookService'
490
351
  },
491
352
  {
492
353
  layout: 'app'
@@ -562,10 +423,7 @@ function init({ server, call }) {
562
423
  let providerData = oauth2ProviderData(provider);
563
424
 
564
425
  let serviceUrl = await settings.get('serviceUrl');
565
- let defaultRedirectUrl = `${serviceUrl}/oauth`;
566
- if (provider === 'outlook') {
567
- defaultRedirectUrl = defaultRedirectUrl.replace(/^http:\/\/127\.0\.0\.1\b/i, 'http://localhost');
568
- }
426
+ let defaultRedirectUrl = normalizeOutlookRedirectUrl(`${serviceUrl}/oauth`, provider);
569
427
 
570
428
  let pubSubApps = await oauth2Apps.list(0, 1000, { pubsub: true });
571
429
 
@@ -642,10 +500,7 @@ function init({ server, call }) {
642
500
  let providerData = oauth2ProviderData(provider);
643
501
 
644
502
  let serviceUrl = await settings.get('serviceUrl');
645
- let defaultRedirectUrl = `${serviceUrl}/oauth`;
646
- if (provider === 'outlook') {
647
- defaultRedirectUrl = defaultRedirectUrl.replace(/^http:\/\/127\.0\.0\.1\b/i, 'http://localhost');
648
- }
503
+ let defaultRedirectUrl = normalizeOutlookRedirectUrl(`${serviceUrl}/oauth`, provider);
649
504
 
650
505
  let pubSubApps = await oauth2Apps.list(0, 1000, { pubsub: true });
651
506
 
@@ -714,10 +569,7 @@ function init({ server, call }) {
714
569
 
715
570
  let providerData = oauth2ProviderData(appData.provider, appData.cloud);
716
571
  let serviceUrl = await settings.get('serviceUrl');
717
- let defaultRedirectUrl = `${serviceUrl}/oauth`;
718
- if (providerData.provider === 'outlook') {
719
- defaultRedirectUrl = defaultRedirectUrl.replace(/^http:\/\/127\.0\.0\.1\b/i, 'http://localhost');
720
- }
572
+ let defaultRedirectUrl = normalizeOutlookRedirectUrl(`${serviceUrl}/oauth`, providerData.provider);
721
573
 
722
574
  let values = Object.assign({}, appData, {
723
575
  clientSecret: '',
@@ -843,10 +695,7 @@ function init({ server, call }) {
843
695
  let providerData = oauth2ProviderData(appData.provider, appData.cloud);
844
696
 
845
697
  let serviceUrl = await settings.get('serviceUrl');
846
- let defaultRedirectUrl = `${serviceUrl}/oauth`;
847
- if (appData.provider === 'outlook') {
848
- defaultRedirectUrl = defaultRedirectUrl.replace(/^http:\/\/127\.0\.0\.1\b/i, 'http://localhost');
849
- }
698
+ let defaultRedirectUrl = normalizeOutlookRedirectUrl(`${serviceUrl}/oauth`, appData.provider);
850
699
 
851
700
  let pubSubApps = await oauth2Apps.list(0, 1000, { pubsub: true });
852
701
 
@@ -932,10 +781,7 @@ function init({ server, call }) {
932
781
  let providerData = oauth2ProviderData(provider);
933
782
 
934
783
  let serviceUrl = await settings.get('serviceUrl');
935
- let defaultRedirectUrl = `${serviceUrl}/oauth`;
936
- if (provider === 'outlook') {
937
- defaultRedirectUrl = defaultRedirectUrl.replace(/^http:\/\/127\.0\.0\.1\b/i, 'http://localhost');
938
- }
784
+ let defaultRedirectUrl = normalizeOutlookRedirectUrl(`${serviceUrl}/oauth`, provider);
939
785
 
940
786
  let pubSubApps = await oauth2Apps.list(0, 1000, { pubsub: true });
941
787