@rndmjoker/proton-mcp 0.4.4

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.
Files changed (141) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +405 -0
  3. package/dist/activity.d.ts +49 -0
  4. package/dist/activity.js +72 -0
  5. package/dist/activity.js.map +1 -0
  6. package/dist/bridge/certificate.d.ts +75 -0
  7. package/dist/bridge/certificate.js +176 -0
  8. package/dist/bridge/certificate.js.map +1 -0
  9. package/dist/bridge/connection.d.ts +99 -0
  10. package/dist/bridge/connection.js +244 -0
  11. package/dist/bridge/connection.js.map +1 -0
  12. package/dist/bridge/errors.d.ts +35 -0
  13. package/dist/bridge/errors.js +56 -0
  14. package/dist/bridge/errors.js.map +1 -0
  15. package/dist/config.d.ts +92 -0
  16. package/dist/config.js +142 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/credentials/availability.d.ts +62 -0
  19. package/dist/credentials/availability.js +107 -0
  20. package/dist/credentials/availability.js.map +1 -0
  21. package/dist/credentials/encrypted-file.d.ts +50 -0
  22. package/dist/credentials/encrypted-file.js +156 -0
  23. package/dist/credentials/encrypted-file.js.map +1 -0
  24. package/dist/credentials/keyring.d.ts +48 -0
  25. package/dist/credentials/keyring.js +97 -0
  26. package/dist/credentials/keyring.js.map +1 -0
  27. package/dist/credentials/plain-file.d.ts +24 -0
  28. package/dist/credentials/plain-file.js +78 -0
  29. package/dist/credentials/plain-file.js.map +1 -0
  30. package/dist/credentials/probe-keyring.d.ts +11 -0
  31. package/dist/credentials/probe-keyring.js +57 -0
  32. package/dist/credentials/probe-keyring.js.map +1 -0
  33. package/dist/credentials/session.d.ts +15 -0
  34. package/dist/credentials/session.js +21 -0
  35. package/dist/credentials/session.js.map +1 -0
  36. package/dist/credentials/store.d.ts +80 -0
  37. package/dist/credentials/store.js +94 -0
  38. package/dist/credentials/store.js.map +1 -0
  39. package/dist/in-flight.d.ts +33 -0
  40. package/dist/in-flight.js +78 -0
  41. package/dist/in-flight.js.map +1 -0
  42. package/dist/mail/actions.d.ts +116 -0
  43. package/dist/mail/actions.js +265 -0
  44. package/dist/mail/actions.js.map +1 -0
  45. package/dist/mail/attachments.d.ts +39 -0
  46. package/dist/mail/attachments.js +86 -0
  47. package/dist/mail/attachments.js.map +1 -0
  48. package/dist/mail/compose.d.ts +264 -0
  49. package/dist/mail/compose.js +395 -0
  50. package/dist/mail/compose.js.map +1 -0
  51. package/dist/mail/drafts.d.ts +138 -0
  52. package/dist/mail/drafts.js +449 -0
  53. package/dist/mail/drafts.js.map +1 -0
  54. package/dist/mail/ids.d.ts +78 -0
  55. package/dist/mail/ids.js +135 -0
  56. package/dist/mail/ids.js.map +1 -0
  57. package/dist/mail/labels.d.ts +61 -0
  58. package/dist/mail/labels.js +139 -0
  59. package/dist/mail/labels.js.map +1 -0
  60. package/dist/mail/markup.d.ts +91 -0
  61. package/dist/mail/markup.js +265 -0
  62. package/dist/mail/markup.js.map +1 -0
  63. package/dist/mail/messages.d.ts +147 -0
  64. package/dist/mail/messages.js +219 -0
  65. package/dist/mail/messages.js.map +1 -0
  66. package/dist/mail/quote.d.ts +65 -0
  67. package/dist/mail/quote.js +157 -0
  68. package/dist/mail/quote.js.map +1 -0
  69. package/dist/mail/search.d.ts +66 -0
  70. package/dist/mail/search.js +107 -0
  71. package/dist/mail/search.js.map +1 -0
  72. package/dist/mail/send.d.ts +61 -0
  73. package/dist/mail/send.js +132 -0
  74. package/dist/mail/send.js.map +1 -0
  75. package/dist/mime/parse.d.ts +110 -0
  76. package/dist/mime/parse.js +194 -0
  77. package/dist/mime/parse.js.map +1 -0
  78. package/dist/server.d.ts +13 -0
  79. package/dist/server.js +387 -0
  80. package/dist/server.js.map +1 -0
  81. package/dist/session.d.ts +86 -0
  82. package/dist/session.js +220 -0
  83. package/dist/session.js.map +1 -0
  84. package/dist/settings.d.ts +52 -0
  85. package/dist/settings.js +80 -0
  86. package/dist/settings.js.map +1 -0
  87. package/dist/tools/actions.d.ts +21 -0
  88. package/dist/tools/actions.js +133 -0
  89. package/dist/tools/actions.js.map +1 -0
  90. package/dist/tools/capabilities.d.ts +52 -0
  91. package/dist/tools/capabilities.js +96 -0
  92. package/dist/tools/capabilities.js.map +1 -0
  93. package/dist/tools/confirm.d.ts +84 -0
  94. package/dist/tools/confirm.js +212 -0
  95. package/dist/tools/confirm.js.map +1 -0
  96. package/dist/tools/drafts.d.ts +21 -0
  97. package/dist/tools/drafts.js +199 -0
  98. package/dist/tools/drafts.js.map +1 -0
  99. package/dist/tools/failures.d.ts +46 -0
  100. package/dist/tools/failures.js +157 -0
  101. package/dist/tools/failures.js.map +1 -0
  102. package/dist/tools/format.d.ts +55 -0
  103. package/dist/tools/format.js +220 -0
  104. package/dist/tools/format.js.map +1 -0
  105. package/dist/tools/guidance.d.ts +38 -0
  106. package/dist/tools/guidance.js +226 -0
  107. package/dist/tools/guidance.js.map +1 -0
  108. package/dist/tools/interface.d.ts +28 -0
  109. package/dist/tools/interface.js +63 -0
  110. package/dist/tools/interface.js.map +1 -0
  111. package/dist/tools/labels.d.ts +21 -0
  112. package/dist/tools/labels.js +92 -0
  113. package/dist/tools/labels.js.map +1 -0
  114. package/dist/tools/list-folders.d.ts +14 -0
  115. package/dist/tools/list-folders.js +70 -0
  116. package/dist/tools/list-folders.js.map +1 -0
  117. package/dist/tools/messages.d.ts +9 -0
  118. package/dist/tools/messages.js +221 -0
  119. package/dist/tools/messages.js.map +1 -0
  120. package/dist/tools/send.d.ts +29 -0
  121. package/dist/tools/send.js +236 -0
  122. package/dist/tools/send.js.map +1 -0
  123. package/dist/tools/sign-in-required.d.ts +94 -0
  124. package/dist/tools/sign-in-required.js +168 -0
  125. package/dist/tools/sign-in-required.js.map +1 -0
  126. package/dist/web/layout.d.ts +75 -0
  127. package/dist/web/layout.js +590 -0
  128. package/dist/web/layout.js.map +1 -0
  129. package/dist/web/pages.d.ts +79 -0
  130. package/dist/web/pages.js +284 -0
  131. package/dist/web/pages.js.map +1 -0
  132. package/dist/web/sections.d.ts +105 -0
  133. package/dist/web/sections.js +207 -0
  134. package/dist/web/sections.js.map +1 -0
  135. package/dist/web/security.d.ts +122 -0
  136. package/dist/web/security.js +180 -0
  137. package/dist/web/security.js.map +1 -0
  138. package/dist/web/server.d.ts +153 -0
  139. package/dist/web/server.js +622 -0
  140. package/dist/web/server.js.map +1 -0
  141. package/package.json +70 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Configuration from environment variables and from a credentials file.
3
+ *
4
+ * The Bridge's ports are configurable in the Bridge itself, so they are never
5
+ * hard-coded anywhere.
6
+ *
7
+ * Why a file at all: an AI client stores the environment it passes to a server
8
+ * in its own configuration, in plain text, and reads it on every start. Keeping
9
+ * the Bridge password out of there is worth a little machinery. A file outside
10
+ * the repository with mode 600 keeps it out of there, and it works the same on
11
+ * every platform, unlike a wrapper script.
12
+ *
13
+ * This is a stopgap. The real answer is signing in through the local web
14
+ * interface, tracked in #16 and #17, after which this path goes away (#18).
15
+ */
16
+ export interface Config {
17
+ /** Address of the Bridge, in practice always 127.0.0.1. */
18
+ host: string;
19
+ /**
20
+ * The Bridge's IMAP port.
21
+ *
22
+ * Changeable while the server runs, through the web interface. The one
23
+ * configuration object is shared with the Connection, which reads it on every
24
+ * reconnect, so writing here and closing the connection is all it takes. See
25
+ * settings.ts for why this one setting is worth that.
26
+ */
27
+ imapPort: number;
28
+ smtpPort: number;
29
+ /** When true, every modifying operation is blocked. */
30
+ readOnly: boolean;
31
+ /** Port for the local web interface. Fixed for the life of the process. */
32
+ webPort: number;
33
+ }
34
+ /** Credentials, whether they come from the environment or from a store. */
35
+ export interface BridgeCredentials {
36
+ user: string;
37
+ pass: string;
38
+ }
39
+ /** Thrown when the configuration is unusable. */
40
+ export declare class ConfigError extends Error {
41
+ name: string;
42
+ }
43
+ /** Where the credentials file is looked for. */
44
+ export declare function credentialsPath(env?: NodeJS.ProcessEnv): string;
45
+ /**
46
+ * Parses a file of `KEY=value` lines.
47
+ *
48
+ * Comments and blank lines are ignored. Values are taken literally apart from
49
+ * one layer of surrounding quotes, because a Bridge password can contain
50
+ * characters that would otherwise invite guessing games.
51
+ */
52
+ export declare function parseEnvFile(content: string): Record<string, string>;
53
+ /**
54
+ * Warns when a credentials file is readable by others.
55
+ *
56
+ * A warning rather than a refusal: on Windows the POSIX bits carry no meaning,
57
+ * and refusing to start over a file mode would be a poor trade for someone who
58
+ * knows what their setup looks like.
59
+ */
60
+ export declare function permissionWarning(mode: number): string | undefined;
61
+ export interface LoadOptions {
62
+ /** Where warnings go. Defaults to stderr, never stdout, which carries the protocol. */
63
+ onWarning?: (message: string) => void;
64
+ /** Skips the credentials file. Used by tests. */
65
+ skipFile?: boolean;
66
+ }
67
+ /**
68
+ * Reads the configuration.
69
+ *
70
+ * Credentials are no longer part of this: they can arrive through the web
71
+ * interface at any time, so a missing password is not a configuration error and
72
+ * must not stop the server from starting. See session.ts.
73
+ */
74
+ export declare function loadConfig(env?: NodeJS.ProcessEnv): Config;
75
+ /**
76
+ * Which ports the user set themselves.
77
+ *
78
+ * Stored settings must not override an explicit environment variable: someone
79
+ * who set BRIDGE_IMAP_PORT meant it, and having a saved value quietly win would
80
+ * make their setting a lie that is very hard to spot.
81
+ */
82
+ export declare function portsSetExplicitly(env?: NodeJS.ProcessEnv): {
83
+ imapPort: boolean;
84
+ smtpPort: boolean;
85
+ };
86
+ /**
87
+ * Credentials from the environment, if they are there.
88
+ *
89
+ * Only the environment: the file is read by the plain-file store, which is one
90
+ * of the four the user can choose from.
91
+ */
92
+ export declare function credentialsFromEnvironment(env?: NodeJS.ProcessEnv): BridgeCredentials | undefined;
package/dist/config.js ADDED
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Configuration from environment variables and from a credentials file.
3
+ *
4
+ * The Bridge's ports are configurable in the Bridge itself, so they are never
5
+ * hard-coded anywhere.
6
+ *
7
+ * Why a file at all: an AI client stores the environment it passes to a server
8
+ * in its own configuration, in plain text, and reads it on every start. Keeping
9
+ * the Bridge password out of there is worth a little machinery. A file outside
10
+ * the repository with mode 600 keeps it out of there, and it works the same on
11
+ * every platform, unlike a wrapper script.
12
+ *
13
+ * This is a stopgap. The real answer is signing in through the local web
14
+ * interface, tracked in #16 and #17, after which this path goes away (#18).
15
+ */
16
+ import { readFileSync, statSync } from 'node:fs';
17
+ import { homedir, platform } from 'node:os';
18
+ import { join } from 'node:path';
19
+ /** Thrown when the configuration is unusable. */
20
+ export class ConfigError extends Error {
21
+ name = 'ConfigError';
22
+ }
23
+ /** Where the credentials file is looked for. */
24
+ export function credentialsPath(env = process.env) {
25
+ if (env.PROTON_MCP_ENV_FILE)
26
+ return env.PROTON_MCP_ENV_FILE;
27
+ return join(homedir(), '.config', 'proton-mcp', 'env');
28
+ }
29
+ /**
30
+ * Parses a file of `KEY=value` lines.
31
+ *
32
+ * Comments and blank lines are ignored. Values are taken literally apart from
33
+ * one layer of surrounding quotes, because a Bridge password can contain
34
+ * characters that would otherwise invite guessing games.
35
+ */
36
+ export function parseEnvFile(content) {
37
+ const out = {};
38
+ for (const line of content.split(/\r?\n/)) {
39
+ const trimmed = line.trim();
40
+ if (!trimmed || trimmed.startsWith('#'))
41
+ continue;
42
+ const eq = trimmed.indexOf('=');
43
+ if (eq <= 0)
44
+ continue;
45
+ const key = trimmed.slice(0, eq).trim();
46
+ let value = trimmed.slice(eq + 1).trim();
47
+ if ((value.startsWith('"') && value.endsWith('"') && value.length > 1) ||
48
+ (value.startsWith("'") && value.endsWith("'") && value.length > 1)) {
49
+ value = value.slice(1, -1);
50
+ }
51
+ out[key] = value;
52
+ }
53
+ return out;
54
+ }
55
+ /**
56
+ * Warns when a credentials file is readable by others.
57
+ *
58
+ * A warning rather than a refusal: on Windows the POSIX bits carry no meaning,
59
+ * and refusing to start over a file mode would be a poor trade for someone who
60
+ * knows what their setup looks like.
61
+ */
62
+ export function permissionWarning(mode) {
63
+ // Anything set in the group or other bits.
64
+ if ((mode & 0o077) === 0)
65
+ return undefined;
66
+ return (`the file is readable by other users (mode ${(mode & 0o777).toString(8)}). ` +
67
+ 'Restrict it with: chmod 600 <file>');
68
+ }
69
+ /** Reads the credentials file if there is one. Absence is not an error. */
70
+ function readCredentialsFile(path, onWarning) {
71
+ let content;
72
+ try {
73
+ content = readFileSync(path, 'utf8');
74
+ }
75
+ catch {
76
+ // No file, unreadable, whatever: fall back to the environment.
77
+ return {};
78
+ }
79
+ if (platform() !== 'win32') {
80
+ try {
81
+ const warning = permissionWarning(statSync(path).mode);
82
+ if (warning)
83
+ onWarning(`${path}: ${warning}`);
84
+ }
85
+ catch {
86
+ // Not being able to stat a file we just read is not worth failing over.
87
+ }
88
+ }
89
+ return parseEnvFile(content);
90
+ }
91
+ function port(value, fallback, field) {
92
+ if (value === undefined || value === '')
93
+ return fallback;
94
+ const n = Number(value);
95
+ if (!Number.isInteger(n) || n < 1 || n > 65535) {
96
+ throw new ConfigError(`${field} is "${value}", which is not a valid port number. Expected a whole number between 1 and 65535.`);
97
+ }
98
+ return n;
99
+ }
100
+ /**
101
+ * Reads the configuration.
102
+ *
103
+ * Credentials are no longer part of this: they can arrive through the web
104
+ * interface at any time, so a missing password is not a configuration error and
105
+ * must not stop the server from starting. See session.ts.
106
+ */
107
+ export function loadConfig(env = process.env) {
108
+ return {
109
+ host: env.BRIDGE_HOST?.trim() || '127.0.0.1',
110
+ imapPort: port(env.BRIDGE_IMAP_PORT, 1143, 'BRIDGE_IMAP_PORT'),
111
+ smtpPort: port(env.BRIDGE_SMTP_PORT, 1025, 'BRIDGE_SMTP_PORT'),
112
+ readOnly: env.PROTON_MCP_READ_ONLY === 'true',
113
+ webPort: port(env.PROTON_MCP_WEB_PORT, 7345, 'PROTON_MCP_WEB_PORT'),
114
+ };
115
+ }
116
+ /**
117
+ * Which ports the user set themselves.
118
+ *
119
+ * Stored settings must not override an explicit environment variable: someone
120
+ * who set BRIDGE_IMAP_PORT meant it, and having a saved value quietly win would
121
+ * make their setting a lie that is very hard to spot.
122
+ */
123
+ export function portsSetExplicitly(env = process.env) {
124
+ return {
125
+ imapPort: Boolean(env.BRIDGE_IMAP_PORT?.trim()),
126
+ smtpPort: Boolean(env.BRIDGE_SMTP_PORT?.trim()),
127
+ };
128
+ }
129
+ /**
130
+ * Credentials from the environment, if they are there.
131
+ *
132
+ * Only the environment: the file is read by the plain-file store, which is one
133
+ * of the four the user can choose from.
134
+ */
135
+ export function credentialsFromEnvironment(env = process.env) {
136
+ const user = env.BRIDGE_USER?.trim();
137
+ const pass = env.BRIDGE_PASS;
138
+ if (!user || !pass)
139
+ return undefined;
140
+ return { user, pass };
141
+ }
142
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Which storage options actually work on this machine.
3
+ *
4
+ * A table saying "Linux can do this" would be wrong: the same Linux with and
5
+ * without a graphical session is a different machine as far as a keyring is
6
+ * concerned. So the keyring is probed for real, by writing a value and reading
7
+ * it back.
8
+ *
9
+ * The probe runs in a **child process**, and that is the whole point of this
10
+ * module. A locked keyring opens a dialog, the underlying calls are synchronous,
11
+ * and a synchronous call cannot be abandoned from the same thread. In-process
12
+ * the probe could therefore hang forever, taking the server with it. A child
13
+ * process can be killed.
14
+ */
15
+ import { type StoreKind, type StoreDescription } from './store.js';
16
+ export interface StoreAvailability extends StoreDescription {
17
+ available: boolean;
18
+ /** Why it cannot be used. Only set when available is false. */
19
+ reason?: string;
20
+ /** How long the probe took, for diagnostics. Only for the keyring. */
21
+ probeMs?: number;
22
+ }
23
+ /** How long the keyring probe may take before it counts as unusable. */
24
+ export declare const PROBE_TIMEOUT_MS = 5000;
25
+ export type ProbeResult = {
26
+ ok: true;
27
+ writeMs: number;
28
+ readMs: number;
29
+ } | {
30
+ ok: false;
31
+ reason: string;
32
+ };
33
+ /**
34
+ * Probes the keyring in a child process.
35
+ *
36
+ * Timing out is a normal result, not an error: it is what a locked keyring looks
37
+ * like from the outside, and the answer in both cases is the same, namely that
38
+ * this option cannot be relied on right now.
39
+ */
40
+ export declare function probeKeyring(timeoutMs?: number): Promise<ProbeResult>;
41
+ /**
42
+ * Lists every option with whether it works here.
43
+ *
44
+ * All four are always listed. An unavailable one keeps its description and gains
45
+ * a reason, rather than disappearing: a user who wonders why the keyring is not
46
+ * offered deserves an answer instead of a shorter list.
47
+ */
48
+ export declare function listStores(options?: {
49
+ probe?: (timeoutMs?: number) => Promise<ProbeResult>;
50
+ os?: string;
51
+ }): Promise<StoreAvailability[]>;
52
+ /**
53
+ * The option to preselect.
54
+ *
55
+ * The keyring when it works, because it is the only one that is both convenient
56
+ * and not a file. Otherwise the encrypted file, which works everywhere. Never
57
+ * the plain file: that one should be a deliberate choice, not a default someone
58
+ * ends up with.
59
+ */
60
+ export declare function recommend(stores: StoreAvailability[]): StoreKind;
61
+ /** Why the recommendation is what it is, for display next to it. */
62
+ export declare function recommendationReason(stores: StoreAvailability[]): string;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Which storage options actually work on this machine.
3
+ *
4
+ * A table saying "Linux can do this" would be wrong: the same Linux with and
5
+ * without a graphical session is a different machine as far as a keyring is
6
+ * concerned. So the keyring is probed for real, by writing a value and reading
7
+ * it back.
8
+ *
9
+ * The probe runs in a **child process**, and that is the whole point of this
10
+ * module. A locked keyring opens a dialog, the underlying calls are synchronous,
11
+ * and a synchronous call cannot be abandoned from the same thread. In-process
12
+ * the probe could therefore hang forever, taking the server with it. A child
13
+ * process can be killed.
14
+ */
15
+ import { fork } from 'node:child_process';
16
+ import { fileURLToPath } from 'node:url';
17
+ import { dirname, join } from 'node:path';
18
+ import { platform } from 'node:os';
19
+ import { STORE_DESCRIPTIONS, PRESENTATION_ORDER, } from './store.js';
20
+ /** How long the keyring probe may take before it counts as unusable. */
21
+ export const PROBE_TIMEOUT_MS = 5000;
22
+ /**
23
+ * Probes the keyring in a child process.
24
+ *
25
+ * Timing out is a normal result, not an error: it is what a locked keyring looks
26
+ * like from the outside, and the answer in both cases is the same, namely that
27
+ * this option cannot be relied on right now.
28
+ */
29
+ export function probeKeyring(timeoutMs = PROBE_TIMEOUT_MS) {
30
+ return new Promise((resolve) => {
31
+ const here = dirname(fileURLToPath(import.meta.url));
32
+ const child = fork(join(here, 'probe-keyring.js'), [], {
33
+ // The child must not inherit stdio: this process speaks the MCP protocol
34
+ // over stdout, and a stray line from a child would corrupt it.
35
+ stdio: ['ignore', 'ignore', 'ignore', 'ipc'],
36
+ });
37
+ let settled = false;
38
+ const finish = (result) => {
39
+ if (settled)
40
+ return;
41
+ settled = true;
42
+ clearTimeout(timer);
43
+ child.kill('SIGKILL');
44
+ resolve(result);
45
+ };
46
+ const timer = setTimeout(() => {
47
+ finish({
48
+ ok: false,
49
+ reason: `the keyring did not answer within ${timeoutMs} ms. It is probably locked and waiting ` +
50
+ 'for input. Unlock it and try again, or choose a different place to keep the credentials.',
51
+ });
52
+ }, timeoutMs);
53
+ child.on('message', (message) => finish(message));
54
+ child.on('error', (error) => finish({ ok: false, reason: error.message }));
55
+ child.on('exit', (code) => {
56
+ if (settled)
57
+ return;
58
+ finish({ ok: false, reason: `the probe exited unexpectedly with code ${code}.` });
59
+ });
60
+ });
61
+ }
62
+ /**
63
+ * Lists every option with whether it works here.
64
+ *
65
+ * All four are always listed. An unavailable one keeps its description and gains
66
+ * a reason, rather than disappearing: a user who wonders why the keyring is not
67
+ * offered deserves an answer instead of a shorter list.
68
+ */
69
+ export async function listStores(options = {}) {
70
+ const probe = options.probe ?? probeKeyring;
71
+ const started = Date.now();
72
+ const keyring = await probe();
73
+ const probeMs = Date.now() - started;
74
+ return PRESENTATION_ORDER.map((kind) => {
75
+ const entry = { ...STORE_DESCRIPTIONS[kind], available: true };
76
+ if (kind === 'keyring') {
77
+ entry.available = keyring.ok;
78
+ entry.probeMs = probeMs;
79
+ if (!keyring.ok)
80
+ entry.reason = keyring.reason;
81
+ }
82
+ return entry;
83
+ });
84
+ }
85
+ /**
86
+ * The option to preselect.
87
+ *
88
+ * The keyring when it works, because it is the only one that is both convenient
89
+ * and not a file. Otherwise the encrypted file, which works everywhere. Never
90
+ * the plain file: that one should be a deliberate choice, not a default someone
91
+ * ends up with.
92
+ */
93
+ export function recommend(stores) {
94
+ return stores.find((s) => s.kind === 'keyring')?.available ? 'keyring' : 'encrypted-file';
95
+ }
96
+ /** Why the recommendation is what it is, for display next to it. */
97
+ export function recommendationReason(stores) {
98
+ const keyring = stores.find((s) => s.kind === 'keyring');
99
+ if (keyring?.available) {
100
+ return ('Suggested because this machine has a working keyring, and it is the only option that is both ' +
101
+ 'convenient and keeps the password out of a file. You can pick any of the others.');
102
+ }
103
+ return ('The system keyring is not usable on this machine, so the encrypted file is suggested instead: ' +
104
+ 'it works everywhere and keeps the password unreadable without your master password. ' +
105
+ `Reason the keyring is out: ${keyring?.reason ?? 'unknown'}`);
106
+ }
107
+ //# sourceMappingURL=availability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability.js","sourceRoot":"","sources":["../../src/credentials/availability.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Credentials in a file, encrypted with a master password.
3
+ *
4
+ * The option that needs no system service, which makes it the one for
5
+ * containers, headless machines and anywhere a keyring is out of reach. The
6
+ * price is honest and unavoidable: the master password has to be entered every
7
+ * time the server starts, because storing it somewhere would only move the
8
+ * problem.
9
+ *
10
+ * AES-256-GCM with a key derived by scrypt. GCM rather than CBC so a modified
11
+ * file is detected instead of decrypting into garbage, and scrypt rather than a
12
+ * plain hash so guessing the master password stays expensive.
13
+ */
14
+ import type { CredentialStore, Credentials } from './store.js';
15
+ /** What ends up in the file. Everything except the master password. */
16
+ interface Envelope {
17
+ version: 1;
18
+ algorithm: 'aes-256-gcm';
19
+ kdf: 'scrypt';
20
+ salt: string;
21
+ iv: string;
22
+ authTag: string;
23
+ ciphertext: string;
24
+ }
25
+ export declare function encryptedFilePath(env?: NodeJS.ProcessEnv): string;
26
+ /** Encrypts credentials into the envelope that gets written to disk. */
27
+ export declare function seal(credentials: Credentials, masterPassword: string): Promise<Envelope>;
28
+ /** Decrypts an envelope. A wrong master password and a tampered file look alike. */
29
+ export declare function unseal(envelope: Envelope, masterPassword: string): Promise<Credentials>;
30
+ export declare class EncryptedFileStore implements CredentialStore {
31
+ /** Supplies the master password. Asked for as late as possible. */
32
+ private readonly masterPassword;
33
+ private readonly path;
34
+ readonly kind: 'encrypted-file';
35
+ constructor(
36
+ /** Supplies the master password. Asked for as late as possible. */
37
+ masterPassword: () => Promise<string>, path?: string);
38
+ /**
39
+ * Whether a credentials file is there, without trying to decrypt it.
40
+ *
41
+ * Answers the question the sign-in page needs before it can decide what to
42
+ * ask for: an existing file means the user only has to supply the master
43
+ * password, not their Bridge password all over again.
44
+ */
45
+ exists(): Promise<boolean>;
46
+ load(): Promise<Credentials | undefined>;
47
+ save(credentials: Credentials): Promise<void>;
48
+ clear(): Promise<void>;
49
+ }
50
+ export {};
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Credentials in a file, encrypted with a master password.
3
+ *
4
+ * The option that needs no system service, which makes it the one for
5
+ * containers, headless machines and anywhere a keyring is out of reach. The
6
+ * price is honest and unavoidable: the master password has to be entered every
7
+ * time the server starts, because storing it somewhere would only move the
8
+ * problem.
9
+ *
10
+ * AES-256-GCM with a key derived by scrypt. GCM rather than CBC so a modified
11
+ * file is detected instead of decrypting into garbage, and scrypt rather than a
12
+ * plain hash so guessing the master password stays expensive.
13
+ */
14
+ import { randomBytes, scrypt as scryptCallback, createCipheriv, createDecipheriv } from 'node:crypto';
15
+ import { readFile, writeFile, unlink, mkdir, access, constants } from 'node:fs/promises';
16
+ import { dirname, join } from 'node:path';
17
+ import { homedir } from 'node:os';
18
+ import { BridgeError } from '../bridge/errors.js';
19
+ /**
20
+ * Own wrapper instead of promisify: scrypt is overloaded, and promisify picks
21
+ * the signature without the options object, which is exactly the one we need
22
+ * because the cost parameters live in there.
23
+ */
24
+ function scrypt(password, salt, keyLength, options) {
25
+ return new Promise((resolve, reject) => {
26
+ scryptCallback(password, salt, keyLength, options, (error, derived) => {
27
+ if (error)
28
+ reject(error);
29
+ else
30
+ resolve(derived);
31
+ });
32
+ });
33
+ }
34
+ /** Deliberately costly. These are the defaults Node documents as reasonable. */
35
+ const SCRYPT = { N: 16_384, r: 8, p: 1, keyLength: 32 };
36
+ const SALT_BYTES = 16;
37
+ const IV_BYTES = 12;
38
+ export function encryptedFilePath(env = process.env) {
39
+ if (env.PROTON_MCP_VAULT_FILE)
40
+ return env.PROTON_MCP_VAULT_FILE;
41
+ return join(homedir(), '.config', 'proton-mcp', 'credentials.enc');
42
+ }
43
+ async function deriveKey(masterPassword, salt) {
44
+ return scrypt(masterPassword, salt, SCRYPT.keyLength, {
45
+ N: SCRYPT.N,
46
+ r: SCRYPT.r,
47
+ p: SCRYPT.p,
48
+ });
49
+ }
50
+ /** Encrypts credentials into the envelope that gets written to disk. */
51
+ export async function seal(credentials, masterPassword) {
52
+ if (!masterPassword) {
53
+ throw new BridgeError('A master password is required to encrypt the credentials.');
54
+ }
55
+ const salt = randomBytes(SALT_BYTES);
56
+ const iv = randomBytes(IV_BYTES);
57
+ const key = await deriveKey(masterPassword, salt);
58
+ const cipher = createCipheriv('aes-256-gcm', key, iv);
59
+ const plaintext = JSON.stringify({ user: credentials.user, pass: credentials.pass });
60
+ const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
61
+ return {
62
+ version: 1,
63
+ algorithm: 'aes-256-gcm',
64
+ kdf: 'scrypt',
65
+ salt: salt.toString('base64'),
66
+ iv: iv.toString('base64'),
67
+ authTag: cipher.getAuthTag().toString('base64'),
68
+ ciphertext: ciphertext.toString('base64'),
69
+ };
70
+ }
71
+ /** Decrypts an envelope. A wrong master password and a tampered file look alike. */
72
+ export async function unseal(envelope, masterPassword) {
73
+ if (envelope.version !== 1 || envelope.algorithm !== 'aes-256-gcm') {
74
+ throw new BridgeError(`The credentials file uses an unknown format (version ${envelope.version}, ${envelope.algorithm}). ` +
75
+ 'It was probably written by a newer version of proton-mcp.');
76
+ }
77
+ const key = await deriveKey(masterPassword, Buffer.from(envelope.salt, 'base64'));
78
+ const decipher = createDecipheriv('aes-256-gcm', key, Buffer.from(envelope.iv, 'base64'));
79
+ decipher.setAuthTag(Buffer.from(envelope.authTag, 'base64'));
80
+ let plaintext;
81
+ try {
82
+ plaintext = Buffer.concat([
83
+ decipher.update(Buffer.from(envelope.ciphertext, 'base64')),
84
+ decipher.final(),
85
+ ]).toString('utf8');
86
+ }
87
+ catch {
88
+ // GCM cannot tell a wrong key from a modified file, and neither can we.
89
+ // Saying so is better than guessing which one it was.
90
+ throw new BridgeError('The credentials could not be decrypted. Either the master password is wrong, or the file ' +
91
+ 'was modified. Nothing was changed on disk.');
92
+ }
93
+ const parsed = JSON.parse(plaintext);
94
+ if (!parsed.user || !parsed.pass) {
95
+ throw new BridgeError('The credentials file decrypted but does not contain a user and password.');
96
+ }
97
+ return { user: parsed.user, pass: parsed.pass };
98
+ }
99
+ export class EncryptedFileStore {
100
+ masterPassword;
101
+ path;
102
+ kind = 'encrypted-file';
103
+ constructor(
104
+ /** Supplies the master password. Asked for as late as possible. */
105
+ masterPassword, path = encryptedFilePath()) {
106
+ this.masterPassword = masterPassword;
107
+ this.path = path;
108
+ }
109
+ /**
110
+ * Whether a credentials file is there, without trying to decrypt it.
111
+ *
112
+ * Answers the question the sign-in page needs before it can decide what to
113
+ * ask for: an existing file means the user only has to supply the master
114
+ * password, not their Bridge password all over again.
115
+ */
116
+ async exists() {
117
+ try {
118
+ await access(this.path, constants.R_OK);
119
+ return true;
120
+ }
121
+ catch {
122
+ return false;
123
+ }
124
+ }
125
+ async load() {
126
+ let raw;
127
+ try {
128
+ raw = await readFile(this.path, 'utf8');
129
+ }
130
+ catch {
131
+ return undefined;
132
+ }
133
+ let envelope;
134
+ try {
135
+ envelope = JSON.parse(raw);
136
+ }
137
+ catch {
138
+ throw new BridgeError(`${this.path} is not readable as a credentials file. Delete it and sign in again.`);
139
+ }
140
+ return unseal(envelope, await this.masterPassword());
141
+ }
142
+ async save(credentials) {
143
+ const envelope = await seal(credentials, await this.masterPassword());
144
+ await mkdir(dirname(this.path), { recursive: true, mode: 0o700 });
145
+ await writeFile(this.path, `${JSON.stringify(envelope, null, 2)}\n`, { mode: 0o600 });
146
+ }
147
+ async clear() {
148
+ try {
149
+ await unlink(this.path);
150
+ }
151
+ catch {
152
+ // Already gone is the outcome we wanted.
153
+ }
154
+ }
155
+ }
156
+ //# sourceMappingURL=encrypted-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encrypted-file.js","sourceRoot":"","sources":["../../src/credentials/encrypted-file.ts"],"names":[],"mappings":"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"}