emailengine-app 2.67.3 → 2.68.1
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/.github/codeql/codeql-config.yml +16 -0
- package/.github/workflows/codeql.yml +102 -0
- package/.github/workflows/deploy.yml +6 -0
- package/.github/workflows/test.yml +6 -0
- package/CHANGELOG.md +36 -0
- package/SECURITY.md +80 -0
- package/SECURITY.txt +27 -0
- package/data/google-crawlers.json +7 -1
- package/lib/account.js +24 -1
- package/lib/api-routes/account-routes.js +12 -2
- package/lib/email-client/base-client.js +26 -20
- package/lib/email-client/gmail-client.js +14 -12
- package/lib/imapproxy/imap-core/lib/imap-command.js +1 -1
- package/lib/imapproxy/imap-core/lib/imap-connection.js +7 -0
- package/lib/imapproxy/imap-core/lib/imap-server.js +1 -1
- package/lib/imapproxy/imap-server.js +92 -29
- package/lib/oauth/external-account-config.js +132 -0
- package/lib/oauth/external-account-signer.js +256 -0
- package/lib/oauth/gmail.js +113 -14
- package/lib/oauth/verify-app.js +397 -0
- package/lib/oauth2-apps.js +51 -6
- package/lib/routes-ui.js +153 -1
- package/lib/schemas.js +80 -2
- package/lib/settings.js +1 -0
- package/lib/tools.js +15 -10
- package/package.json +28 -28
- package/sbom.json +1 -1
- package/server.js +3 -3
- package/static/js/ace/ace.js +1 -1
- package/static/js/ace/ext-searchbox.js +1 -1
- package/static/js/ace/mode-handlebars.js +1 -1
- package/static/js/ace/mode-html.js +1 -1
- package/static/js/ace/mode-javascript.js +1 -1
- package/static/js/ace/mode-markdown.js +1 -1
- package/static/js/ace/worker-html.js +1 -1
- package/static/js/ace/worker-javascript.js +1 -1
- package/static/js/ace/worker-json.js +1 -1
- package/static/licenses.html +145 -115
- package/translations/messages.pot +49 -49
- package/views/config/oauth/app.hbs +224 -0
- package/views/config/oauth/edit.hbs +69 -0
- package/views/config/oauth/new.hbs +69 -0
- package/views/partials/oauth_form.hbs +99 -32
- package/workers/api.js +91 -2
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: "EmailEngine CodeQL config"
|
|
2
|
+
|
|
3
|
+
# Exclude code that is not part of the production runtime from analysis.
|
|
4
|
+
# These paths generate only false-positive noise:
|
|
5
|
+
# - test fixtures intentionally disable TLS verification, build shell
|
|
6
|
+
# commands from fixed paths, etc.
|
|
7
|
+
# - vendored third-party browser assets (Bootstrap and other bundles) ship
|
|
8
|
+
# with their own known patterns and are not maintained here
|
|
9
|
+
# - developer helper scripts (e.g. test-token refresh) deliberately print
|
|
10
|
+
# tokens to the console for local debugging
|
|
11
|
+
paths-ignore:
|
|
12
|
+
- test
|
|
13
|
+
- '**/test/**'
|
|
14
|
+
- scripts
|
|
15
|
+
- static/bootstrap-4.6.2-dist
|
|
16
|
+
- static/vendor
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# For most projects, this workflow file will not need changing; you simply need
|
|
2
|
+
# to commit it to your repository.
|
|
3
|
+
#
|
|
4
|
+
# You may wish to alter this file to override the set of languages analyzed,
|
|
5
|
+
# or to provide custom queries or build logic.
|
|
6
|
+
#
|
|
7
|
+
# ******** NOTE ********
|
|
8
|
+
# We have attempted to detect the languages in your repository. Please check
|
|
9
|
+
# the `language` matrix defined below to confirm you have the correct set of
|
|
10
|
+
# supported CodeQL languages.
|
|
11
|
+
#
|
|
12
|
+
name: "CodeQL Advanced"
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: [ "master" ]
|
|
17
|
+
pull_request:
|
|
18
|
+
branches: [ "master" ]
|
|
19
|
+
schedule:
|
|
20
|
+
- cron: '40 17 * * 6'
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
analyze:
|
|
24
|
+
name: Analyze (${{ matrix.language }})
|
|
25
|
+
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
|
26
|
+
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
|
27
|
+
# - https://gh.io/supported-runners-and-hardware-resources
|
|
28
|
+
# - https://gh.io/using-larger-runners (GitHub.com only)
|
|
29
|
+
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
|
|
30
|
+
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
|
31
|
+
permissions:
|
|
32
|
+
# required for all workflows
|
|
33
|
+
security-events: write
|
|
34
|
+
|
|
35
|
+
# required to fetch internal or private CodeQL packs
|
|
36
|
+
packages: read
|
|
37
|
+
|
|
38
|
+
# only required for workflows in private repositories
|
|
39
|
+
actions: read
|
|
40
|
+
contents: read
|
|
41
|
+
|
|
42
|
+
strategy:
|
|
43
|
+
fail-fast: false
|
|
44
|
+
matrix:
|
|
45
|
+
include:
|
|
46
|
+
- language: actions
|
|
47
|
+
build-mode: none
|
|
48
|
+
- language: javascript-typescript
|
|
49
|
+
build-mode: none
|
|
50
|
+
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
|
|
51
|
+
# Use `c-cpp` to analyze code written in C, C++ or both
|
|
52
|
+
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
|
|
53
|
+
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
|
54
|
+
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
|
|
55
|
+
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
|
|
56
|
+
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
|
|
57
|
+
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
|
58
|
+
steps:
|
|
59
|
+
- name: Checkout repository
|
|
60
|
+
uses: actions/checkout@v4
|
|
61
|
+
|
|
62
|
+
# Add any setup steps before running the `github/codeql-action/init` action.
|
|
63
|
+
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
|
64
|
+
# or others). This is typically only required for manual builds.
|
|
65
|
+
# - name: Setup runtime (example)
|
|
66
|
+
# uses: actions/setup-example@v1
|
|
67
|
+
|
|
68
|
+
# Initializes the CodeQL tools for scanning.
|
|
69
|
+
- name: Initialize CodeQL
|
|
70
|
+
uses: github/codeql-action/init@v4
|
|
71
|
+
with:
|
|
72
|
+
languages: ${{ matrix.language }}
|
|
73
|
+
build-mode: ${{ matrix.build-mode }}
|
|
74
|
+
config-file: ./.github/codeql/codeql-config.yml
|
|
75
|
+
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
76
|
+
# By default, queries listed here will override any specified in a config file.
|
|
77
|
+
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
78
|
+
|
|
79
|
+
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
|
80
|
+
# queries: security-extended,security-and-quality
|
|
81
|
+
|
|
82
|
+
# If the analyze step fails for one of the languages you are analyzing with
|
|
83
|
+
# "We were unable to automatically build your code", modify the matrix above
|
|
84
|
+
# to set the build mode to "manual" for that language. Then modify this step
|
|
85
|
+
# to build your code.
|
|
86
|
+
# ℹ️ Command-line programs to run using the OS shell.
|
|
87
|
+
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
|
88
|
+
- name: Run manual build steps
|
|
89
|
+
if: matrix.build-mode == 'manual'
|
|
90
|
+
shell: bash
|
|
91
|
+
run: |
|
|
92
|
+
echo 'If you are using a "manual" build mode for one or more of the' \
|
|
93
|
+
'languages you are analyzing, replace this with the commands to build' \
|
|
94
|
+
'your code, for example:'
|
|
95
|
+
echo ' make bootstrap'
|
|
96
|
+
echo ' make release'
|
|
97
|
+
exit 1
|
|
98
|
+
|
|
99
|
+
- name: Perform CodeQL Analysis
|
|
100
|
+
uses: github/codeql-action/analyze@v4
|
|
101
|
+
with:
|
|
102
|
+
category: "/language:${{matrix.language}}"
|
|
@@ -5,6 +5,9 @@ on:
|
|
|
5
5
|
|
|
6
6
|
name: Deploy test instance and Docker image
|
|
7
7
|
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
8
11
|
concurrency:
|
|
9
12
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
13
|
cancel-in-progress: true
|
|
@@ -60,6 +63,9 @@ jobs:
|
|
|
60
63
|
docker:
|
|
61
64
|
name: Build Docker Image
|
|
62
65
|
runs-on: ubuntu-24.04
|
|
66
|
+
permissions:
|
|
67
|
+
contents: read
|
|
68
|
+
packages: write
|
|
63
69
|
|
|
64
70
|
steps:
|
|
65
71
|
- name: Checkout
|
|
@@ -4,6 +4,9 @@ on:
|
|
|
4
4
|
push:
|
|
5
5
|
pull_request:
|
|
6
6
|
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
7
10
|
concurrency:
|
|
8
11
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
9
12
|
cancel-in-progress: true
|
|
@@ -88,3 +91,6 @@ jobs:
|
|
|
88
91
|
GMAIL_SERVICE_POSTALSYS_SERVICE_EMAIL: ${{ secrets.GMAIL_SERVICE_POSTALSYS_SERVICE_EMAIL }}
|
|
89
92
|
GMAIL_SERVICE_POSTALSYS_KEY: ${{ secrets.GMAIL_SERVICE_POSTALSYS_KEY }}
|
|
90
93
|
GMAIL_SERVICE_POSTALSYS_ACCOUNT_EMAIL: ${{ secrets.GMAIL_SERVICE_POSTALSYS_ACCOUNT_EMAIL }}
|
|
94
|
+
GMAIL_WIF_SA_KEY: ${{ secrets.GMAIL_WIF_SA_KEY }}
|
|
95
|
+
GMAIL_WIF_AUDIENCE: ${{ secrets.GMAIL_WIF_AUDIENCE }}
|
|
96
|
+
GMAIL_WIF_ACCOUNT_EMAIL: ${{ secrets.GMAIL_WIF_ACCOUNT_EMAIL }}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.68.1](https://github.com/postalsys/emailengine/compare/v2.68.0...v2.68.1) (2026-06-01)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* harden mergeObjects and tighten CodeQL scanning ([d35025d](https://github.com/postalsys/emailengine/commit/d35025daabf8fe7b3f5200b0000f52c3a012f4eb))
|
|
9
|
+
* prevent IMAP proxy worker crashes and connection leaks ([#596](https://github.com/postalsys/emailengine/issues/596)) ([4453330](https://github.com/postalsys/emailengine/commit/4453330ad38fb3e64692add1357d48227e1956e0))
|
|
10
|
+
* stop referencing prepared password string in error log ([50cdb89](https://github.com/postalsys/emailengine/commit/50cdb8998e27f33f700f267cb39ddba39e7d32d0))
|
|
11
|
+
|
|
12
|
+
## [2.68.0](https://github.com/postalsys/emailengine/compare/v2.67.3...v2.68.0) (2026-05-26)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* accept threadId on the submit reference object ([b1b3dc7](https://github.com/postalsys/emailengine/commit/b1b3dc73ec5870a7a8ab9f0844055822ad046d2a))
|
|
18
|
+
* add direct account registration for email service account apps ([6602b2e](https://github.com/postalsys/emailengine/commit/6602b2ee3f851bcfec00b34e70756007763f5490))
|
|
19
|
+
* add OAuth2 app "Verify setup" diagnostic ([cba9f58](https://github.com/postalsys/emailengine/commit/cba9f58bc58a434c6156cd2e55fee655336a4cf4))
|
|
20
|
+
* add Workload Identity Federation for Gmail service accounts ([1879c5a](https://github.com/postalsys/emailengine/commit/1879c5aaf30ccff1879e74d28b0c76e25b3d77ae))
|
|
21
|
+
* lock Gmail auth method display after app creation ([6ba16c2](https://github.com/postalsys/emailengine/commit/6ba16c2fbca571d500b21be776dbf5eb76fcf8a1))
|
|
22
|
+
* revoke upstream OAuth2 grant on account delete via ?revoke=true ([2a8c8fa](https://github.com/postalsys/emailengine/commit/2a8c8faf7f63acfab31998fb067289d4c6bd2f09))
|
|
23
|
+
* revoke upstream OAuth2 grant on account delete via ?revoke=true ([15bc43a](https://github.com/postalsys/emailengine/commit/15bc43ae0f8dbf70021a1e13de55c80ec7271a15))
|
|
24
|
+
* use tabs for Gmail auth method and lock it after creation ([6c74521](https://github.com/postalsys/emailengine/commit/6c7452138c257ecf0667aa9b44d1fa91186e2302))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Bug Fixes
|
|
28
|
+
|
|
29
|
+
* clearer error when loading wrong file into WIF config field ([40686d4](https://github.com/postalsys/emailengine/commit/40686d409229347193c1e153e9e47f98b5de86dc))
|
|
30
|
+
* flag WIF support in the gmailService form intro ([61fab27](https://github.com/postalsys/emailengine/commit/61fab2720aa2f289a944ae99629bc47ada8e9e09))
|
|
31
|
+
* force-exit external-account-signer test to unblock CI ([f4a1e4e](https://github.com/postalsys/emailengine/commit/f4a1e4e50ac890d7771e38181a9488837c67757a))
|
|
32
|
+
* let npm run gettext parse object spread and drop non-ASCII from template ([195ce60](https://github.com/postalsys/emailengine/commit/195ce601db50f394164ca05e2efb6de4b784a77a))
|
|
33
|
+
* mask externalAccount in OAuth2 app API responses ([fac18bf](https://github.com/postalsys/emailengine/commit/fac18bfdc11d5d252e0d93980aad7c90d92b246f))
|
|
34
|
+
* pkg config options must be a string array ([6c4702d](https://github.com/postalsys/emailengine/commit/6c4702dbc85171a2987b8cfb6e5a3dc3d656a99d))
|
|
35
|
+
* prefer refresh token and skip gmailService when revoking on delete ([e0dbea8](https://github.com/postalsys/emailengine/commit/e0dbea8a4cd4804bf64d50523c8a1152c2119e26))
|
|
36
|
+
* relax cross-folder assertion in Graph API parentFolderId test ([770279d](https://github.com/postalsys/emailengine/commit/770279ded669efdc5d6a2c33d05290daf91251ea))
|
|
37
|
+
* right-align the service account Add account button ([c6f77b9](https://github.com/postalsys/emailengine/commit/c6f77b9777fb1cb9b1449662d05d4887e36a6ad8))
|
|
38
|
+
|
|
3
39
|
## [2.67.3](https://github.com/postalsys/emailengine/compare/v2.67.2...v2.67.3) (2026-04-21)
|
|
4
40
|
|
|
5
41
|
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
EmailEngine is a self-hosted email integration platform that stores email
|
|
4
|
+
account credentials and proxies access to IMAP/SMTP, the Gmail API, and the
|
|
5
|
+
Microsoft Graph API. Because it handles sensitive credentials and message
|
|
6
|
+
content, we take security reports seriously and aim to respond quickly.
|
|
7
|
+
|
|
8
|
+
## Supported Versions
|
|
9
|
+
|
|
10
|
+
Security fixes are released only against the latest version. We do not backport
|
|
11
|
+
patches to older releases - upgrading to the current release line is the
|
|
12
|
+
supported way to receive security updates.
|
|
13
|
+
|
|
14
|
+
| Version | Supported |
|
|
15
|
+
| ------- | ------------------ |
|
|
16
|
+
| 2.x | :white_check_mark: |
|
|
17
|
+
| < 2.0 | :x: |
|
|
18
|
+
|
|
19
|
+
If you are on an older version, please upgrade. See the release notes at
|
|
20
|
+
<https://github.com/postalsys/emailengine/releases> before updating.
|
|
21
|
+
|
|
22
|
+
## Reporting a Vulnerability
|
|
23
|
+
|
|
24
|
+
**Please do not report security vulnerabilities through public GitHub issues,
|
|
25
|
+
pull requests, or discussions.**
|
|
26
|
+
|
|
27
|
+
Report privately through one of the following channels:
|
|
28
|
+
|
|
29
|
+
1. **GitHub Security Advisories (preferred).** Open a private report at
|
|
30
|
+
<https://github.com/postalsys/emailengine/security/advisories/new>. This keeps
|
|
31
|
+
the discussion private until a fix is published and lets us credit you.
|
|
32
|
+
2. **Email.** Send details to **andris@postalsys.com** (the contact listed in
|
|
33
|
+
[`SECURITY.txt`](SECURITY.txt)). Encrypt sensitive details if possible.
|
|
34
|
+
|
|
35
|
+
When reporting, please include as much of the following as you can:
|
|
36
|
+
|
|
37
|
+
- The affected version(s) and environment (EmailEngine version, Node.js version,
|
|
38
|
+
OS, deployment method - npm, Docker, or prebuilt binary).
|
|
39
|
+
- The component involved (e.g. REST API, admin web UI, OAuth2 flows, IMAP/SMTP
|
|
40
|
+
proxy server, webhook delivery, credential encryption, the export pipeline).
|
|
41
|
+
- A clear description of the issue and its impact (e.g. authentication bypass,
|
|
42
|
+
privilege escalation, credential disclosure, SSRF, injection, information
|
|
43
|
+
disclosure, denial of service).
|
|
44
|
+
- A minimal proof of concept or reproduction steps.
|
|
45
|
+
- Any suggested remediation, if you have one.
|
|
46
|
+
|
|
47
|
+
We are a small team, so there is no guaranteed response time - sometimes reports
|
|
48
|
+
are handled within hours, sometimes they take longer. Accepted issues are fixed
|
|
49
|
+
in a new release and coordinated through a GitHub Security Advisory, and
|
|
50
|
+
reporters who wish to be named are credited.
|
|
51
|
+
|
|
52
|
+
## CVEs
|
|
53
|
+
|
|
54
|
+
We track and disclose vulnerabilities through GitHub Security Advisories. We do
|
|
55
|
+
not request or manage CVE identifiers ourselves. If you need a CVE assigned for a
|
|
56
|
+
reported issue, please request one yourself - for example, through GitHub's own
|
|
57
|
+
CVE request flow on the published advisory, or another CNA.
|
|
58
|
+
|
|
59
|
+
## Scope
|
|
60
|
+
|
|
61
|
+
In scope: the EmailEngine application source in this repository - the REST API
|
|
62
|
+
and admin web UI (authentication, session and token handling, CSRF protection),
|
|
63
|
+
OAuth2 application handling, credential encryption at rest, the IMAP/SMTP and
|
|
64
|
+
IMAP proxy servers, webhook delivery (including custom filter/transform
|
|
65
|
+
functions), the export pipeline, and inter-worker communication.
|
|
66
|
+
|
|
67
|
+
Out of scope:
|
|
68
|
+
|
|
69
|
+
- Vulnerabilities in your own application code that integrates with EmailEngine.
|
|
70
|
+
- Misconfiguration of your deployment - for example, exposing the admin
|
|
71
|
+
interface or REST API to untrusted networks, weak service secrets, an
|
|
72
|
+
unauthenticated or publicly reachable Redis instance, or missing TLS.
|
|
73
|
+
- Issues that require an already-compromised host or pre-existing administrator
|
|
74
|
+
access.
|
|
75
|
+
- Vulnerabilities in third-party email providers and services that EmailEngine
|
|
76
|
+
connects to (Gmail, Microsoft 365, arbitrary IMAP/SMTP servers).
|
|
77
|
+
- Social-engineering reports and missing security headers without a
|
|
78
|
+
demonstrated, concrete impact.
|
|
79
|
+
|
|
80
|
+
Thank you for helping keep EmailEngine and its users safe.
|
package/SECURITY.txt
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
-----BEGIN PGP SIGNED MESSAGE-----
|
|
2
|
+
Hash: SHA256
|
|
3
|
+
|
|
4
|
+
Contact: https://github.com/postalsys/emailengine/security/advisories/new
|
|
5
|
+
Contact: mailto:andris@postalsys.com
|
|
6
|
+
Expires: 2027-06-01T00:00:00.000Z
|
|
7
|
+
Encryption: https://keys.openpgp.org/vks/v1/by-fingerprint/5D952A46E1D8C931F6364E01DC6C83F4D584D364
|
|
8
|
+
Preferred-Languages: en, et
|
|
9
|
+
Canonical: https://github.com/postalsys/emailengine/blob/master/SECURITY.txt
|
|
10
|
+
Policy: https://github.com/postalsys/emailengine/blob/master/SECURITY.md
|
|
11
|
+
-----BEGIN PGP SIGNATURE-----
|
|
12
|
+
|
|
13
|
+
iQJPBAEBCAA5FiEEXZUqRuHYyTH2Nk4B3GyD9NWE02QFAmodKpsbFIAAAAAABAAO
|
|
14
|
+
bWFudTIsMi41KzEuMTIsMCwzAAoJENxsg/TVhNNkbcEP/j1v3M9ebklJgaCxkVEl
|
|
15
|
+
xij24q4p+28s1ywf4y/aquBtcVkWd+y6vjG/f4RUUUtaSVChvnI5en14X8QuuSnk
|
|
16
|
+
egsRARvCY9E2dbodMSyDUMWS8slRcFTDczQJhtXBD8Fu+/tWPj1UfQ8xR87ZUZ5b
|
|
17
|
+
nOgCfCFnvSuDh9KBauUKZcSyuLCJ5saBuZ3RACzmz57wpzFE3vi4/q4tQAaBM5Za
|
|
18
|
+
m4293Yx8ioX01S3nR5VRL8dlpdMEFy0dj66v/OFu4p3MjGf+0cpmZ7YKC8U5PhNQ
|
|
19
|
+
FcQMTNkfBtkgc5lj42cKV8BBhCtN2og3u+Bhih0h0XItv4b/o9rWBtivXIQcHdtl
|
|
20
|
+
WyGrrbgfGl503aVj8N0cIQ1eaWAbuRRJVHwF/G11sX6ZvhiLHdHf5YSjOrmyhSmx
|
|
21
|
+
6t2gsKMrrvoODRUOqpu8ll8Rosu6m/EaNWgh9KXJyYqgQqGS+NeQHcC51fWMLjxd
|
|
22
|
+
7zvYrNKqhMEU8e6siyLdJJgqAJCCtl9vS/kLItPz9hBk3KE2/kXfvQc6OF4I4ziU
|
|
23
|
+
3/Edf1v37koEnT07P5HdiGgUo+u4Vo8OUEm5Ih88EWaWijHGLPeJ0NyMfkwsveTw
|
|
24
|
+
n1z7pmCdZ+B9pglRGx3Mae7P8L1s1LeL8cQWo4QZ2nUcA5vtOiWfDAywlrN0mSNv
|
|
25
|
+
lfeE0/subU9kC04LRJ6NUhZp
|
|
26
|
+
=8lqK
|
|
27
|
+
-----END PGP SIGNATURE-----
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"creationTime": "2026-
|
|
2
|
+
"creationTime": "2026-05-29T14:45:42.000000",
|
|
3
3
|
"prefixes": [
|
|
4
4
|
{
|
|
5
5
|
"ipv6Prefix": "2001:4860:4801:2008::/64"
|
|
@@ -307,6 +307,9 @@
|
|
|
307
307
|
{
|
|
308
308
|
"ipv6Prefix": "2001:4860:4801:207d::/64"
|
|
309
309
|
},
|
|
310
|
+
{
|
|
311
|
+
"ipv6Prefix": "2001:4860:4801:207e::/64"
|
|
312
|
+
},
|
|
310
313
|
{
|
|
311
314
|
"ipv6Prefix": "2001:4860:4801:2080::/64"
|
|
312
315
|
},
|
|
@@ -790,6 +793,9 @@
|
|
|
790
793
|
{
|
|
791
794
|
"ipv4Prefix": "74.125.219.160/27"
|
|
792
795
|
},
|
|
796
|
+
{
|
|
797
|
+
"ipv4Prefix": "74.125.219.192/27"
|
|
798
|
+
},
|
|
793
799
|
{
|
|
794
800
|
"ipv4Prefix": "74.125.219.32/27"
|
|
795
801
|
},
|
package/lib/account.js
CHANGED
|
@@ -977,9 +977,32 @@ class Account {
|
|
|
977
977
|
return { account: this.account, state };
|
|
978
978
|
}
|
|
979
979
|
|
|
980
|
-
async delete() {
|
|
980
|
+
async delete(opts) {
|
|
981
|
+
opts = opts || {};
|
|
982
|
+
|
|
981
983
|
let accountData = await this.loadAccountData(this.account);
|
|
982
984
|
|
|
985
|
+
if (opts.revoke && accountData.oauth2?.provider) {
|
|
986
|
+
// Prefer refresh token over access token: revoking either invalidates the grant per Google's docs,
|
|
987
|
+
// but the stored access token may be expired (a 400 from the provider would leave the grant intact),
|
|
988
|
+
// while the refresh token is long-lived. Skip gmailService - Workspace service accounts have no
|
|
989
|
+
// per-user grant to revoke.
|
|
990
|
+
let token = accountData.oauth2.refreshToken || accountData.oauth2.accessToken;
|
|
991
|
+
if (token) {
|
|
992
|
+
try {
|
|
993
|
+
let oauth2App = await oauth2Apps.get(accountData.oauth2.provider);
|
|
994
|
+
if (oauth2App && oauth2App.provider !== 'gmailService') {
|
|
995
|
+
let oauthClient = await oauth2Apps.getClient(accountData.oauth2.provider, { logger: this.logger });
|
|
996
|
+
if (oauthClient && typeof oauthClient.revokeToken === 'function') {
|
|
997
|
+
await oauthClient.revokeToken(token);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
} catch (err) {
|
|
1001
|
+
this.logger.warn({ msg: 'Failed to revoke OAuth2 grant before account delete', account: this.account, err });
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
983
1006
|
const dateKeyTdy = new Date().toISOString().substring(0, 10).replace(/-/g, '');
|
|
984
1007
|
const dateKeyYdy = new Date(Date.now() - 24 * 3600 * 1000).toISOString().substring(0, 10).replace(/-/g, '');
|
|
985
1008
|
|
|
@@ -530,7 +530,7 @@ async function init(args) {
|
|
|
530
530
|
});
|
|
531
531
|
|
|
532
532
|
try {
|
|
533
|
-
return await accountObject.delete();
|
|
533
|
+
return await accountObject.delete({ revoke: request.query.revoke });
|
|
534
534
|
} catch (err) {
|
|
535
535
|
request.logger.error({ msg: 'API request failed', err });
|
|
536
536
|
if (Boom.isBoom(err)) {
|
|
@@ -545,7 +545,7 @@ async function init(args) {
|
|
|
545
545
|
},
|
|
546
546
|
options: {
|
|
547
547
|
description: 'Remove account',
|
|
548
|
-
notes: "Stop processing and clear the account's cache",
|
|
548
|
+
notes: "Stop processing and clear the account's cache. Pass revoke=true to also attempt revocation of the upstream OAuth2 grant at the provider before the account is removed.",
|
|
549
549
|
|
|
550
550
|
tags: ['api', 'Account'],
|
|
551
551
|
|
|
@@ -567,6 +567,16 @@ async function init(args) {
|
|
|
567
567
|
|
|
568
568
|
params: Joi.object({
|
|
569
569
|
account: accountIdSchema.required()
|
|
570
|
+
}),
|
|
571
|
+
|
|
572
|
+
query: Joi.object({
|
|
573
|
+
revoke: Joi.boolean()
|
|
574
|
+
.truthy('Y', 'true', '1')
|
|
575
|
+
.falsy('N', 'false', 0)
|
|
576
|
+
.default(false)
|
|
577
|
+
.description(
|
|
578
|
+
'If true, EmailEngine attempts to revoke the upstream OAuth2 grant at the provider before deleting the account. Currently supported for individual Gmail OAuth grants. For Gmail Workspace service-account integrations (gmailService), Outlook, and non-OAuth2 accounts the flag is a no-op. Revoke failures are logged and do not block deletion.'
|
|
579
|
+
)
|
|
570
580
|
})
|
|
571
581
|
},
|
|
572
582
|
|
|
@@ -1687,8 +1687,8 @@ class BaseClient {
|
|
|
1687
1687
|
data.reference.update = true;
|
|
1688
1688
|
}
|
|
1689
1689
|
|
|
1690
|
-
// Preserve thread ID
|
|
1691
|
-
if (referencedMessage.threadId) {
|
|
1690
|
+
// Preserve thread ID, but let a caller-supplied threadId win
|
|
1691
|
+
if (!data.reference.threadId && referencedMessage.threadId) {
|
|
1692
1692
|
data.reference.threadId = referencedMessage.threadId;
|
|
1693
1693
|
}
|
|
1694
1694
|
|
|
@@ -1906,15 +1906,18 @@ class BaseClient {
|
|
|
1906
1906
|
messageId
|
|
1907
1907
|
};
|
|
1908
1908
|
|
|
1909
|
-
if (data.reference && data.reference.message) {
|
|
1910
|
-
response.reference = {
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1909
|
+
if (data.reference && (data.reference.message || data.reference.threadId)) {
|
|
1910
|
+
response.reference = {};
|
|
1911
|
+
if (data.reference.message) {
|
|
1912
|
+
response.reference.message = data.reference.message;
|
|
1913
|
+
response.reference.documentStore = documentStoreUsed;
|
|
1914
|
+
response.reference.success = referencedMessage ? true : false;
|
|
1915
|
+
if (!referencedMessage) {
|
|
1916
|
+
response.reference.error = 'Referenced message was not found';
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
if (data.reference.threadId) {
|
|
1920
|
+
response.reference.threadId = data.reference.threadId;
|
|
1918
1921
|
}
|
|
1919
1922
|
}
|
|
1920
1923
|
|
|
@@ -2069,15 +2072,18 @@ class BaseClient {
|
|
|
2069
2072
|
queueId
|
|
2070
2073
|
};
|
|
2071
2074
|
|
|
2072
|
-
if (data.reference && data.reference.message) {
|
|
2073
|
-
response.reference = {
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2075
|
+
if (data.reference && (data.reference.message || data.reference.threadId)) {
|
|
2076
|
+
response.reference = {};
|
|
2077
|
+
if (data.reference.message) {
|
|
2078
|
+
response.reference.message = data.reference.message;
|
|
2079
|
+
response.reference.documentStore = documentStoreUsed;
|
|
2080
|
+
response.reference.success = referencedMessage ? true : false;
|
|
2081
|
+
if (!referencedMessage) {
|
|
2082
|
+
response.reference.error = 'Referenced message was not found';
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
if (data.reference.threadId) {
|
|
2086
|
+
response.reference.threadId = data.reference.threadId;
|
|
2081
2087
|
}
|
|
2082
2088
|
}
|
|
2083
2089
|
|
|
@@ -1502,9 +1502,8 @@ class GmailClient extends BaseClient {
|
|
|
1502
1502
|
raw: raw.toString('base64url')
|
|
1503
1503
|
};
|
|
1504
1504
|
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
payload.threadId = referencedMessage.threadId;
|
|
1505
|
+
if (data.reference?.threadId) {
|
|
1506
|
+
payload.threadId = data.reference.threadId;
|
|
1508
1507
|
}
|
|
1509
1508
|
|
|
1510
1509
|
let uploadInfo;
|
|
@@ -1533,15 +1532,18 @@ class GmailClient extends BaseClient {
|
|
|
1533
1532
|
messageId
|
|
1534
1533
|
};
|
|
1535
1534
|
|
|
1536
|
-
if (data.reference && data.reference.message) {
|
|
1537
|
-
response.reference = {
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1535
|
+
if (data.reference && (data.reference.message || data.reference.threadId)) {
|
|
1536
|
+
response.reference = {};
|
|
1537
|
+
if (data.reference.message) {
|
|
1538
|
+
response.reference.message = data.reference.message;
|
|
1539
|
+
response.reference.documentStore = documentStoreUsed;
|
|
1540
|
+
response.reference.success = referencedMessage ? true : false;
|
|
1541
|
+
if (!referencedMessage) {
|
|
1542
|
+
response.reference.error = 'Referenced message was not found';
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
if (data.reference.threadId) {
|
|
1546
|
+
response.reference.threadId = data.reference.threadId;
|
|
1545
1547
|
}
|
|
1546
1548
|
}
|
|
1547
1549
|
|
|
@@ -369,7 +369,7 @@ class IMAPCommand {
|
|
|
369
369
|
countBadResponses() {
|
|
370
370
|
this.connection._badCount++;
|
|
371
371
|
if (this.connection._badCount > MAX_BAD_COMMANDS) {
|
|
372
|
-
this.clearNotificationListener();
|
|
372
|
+
this.connection.clearNotificationListener();
|
|
373
373
|
this.connection.send('* BYE Too many protocol errors');
|
|
374
374
|
setImmediate(() => this.connection.close(true));
|
|
375
375
|
return false;
|
|
@@ -210,6 +210,13 @@ class IMAPConnection extends EventEmitter {
|
|
|
210
210
|
this._socket.setTimeout(0, this._onTimeoutHandler);
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
// After handoff to proxy mode the connection's own close/end handlers are gone,
|
|
214
|
+
// so _onClose can never run to remove this connection from the server set.
|
|
215
|
+
// Drop it from the set when the handed-off socket finally closes to avoid a leak.
|
|
216
|
+
this._socket.once('close', () => {
|
|
217
|
+
this._server.connections.delete(this);
|
|
218
|
+
});
|
|
219
|
+
|
|
213
220
|
return { socket: this._socket };
|
|
214
221
|
}
|
|
215
222
|
|