@rndmjoker/proton-mcp 0.4.13 → 0.5.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/README.md +138 -21
- package/dist/browser/channel.d.ts +76 -0
- package/dist/browser/channel.js +162 -0
- package/dist/browser/channel.js.map +1 -0
- package/dist/browser/client.d.ts +50 -0
- package/dist/browser/client.js +284 -0
- package/dist/browser/client.js.map +1 -0
- package/dist/browser/connector.d.ts +15 -0
- package/dist/browser/connector.js +26 -0
- package/dist/browser/connector.js.map +1 -0
- package/dist/browser/host.d.ts +50 -0
- package/dist/browser/host.js +258 -0
- package/dist/browser/host.js.map +1 -0
- package/dist/browser/messages.d.ts +163 -0
- package/dist/browser/messages.js +338 -0
- package/dist/browser/messages.js.map +1 -0
- package/dist/browser/paths.d.ts +51 -0
- package/dist/browser/paths.js +92 -0
- package/dist/browser/paths.js.map +1 -0
- package/dist/browser/setup.d.ts +42 -0
- package/dist/browser/setup.js +170 -0
- package/dist/browser/setup.js.map +1 -0
- package/dist/filters/order.d.ts +66 -0
- package/dist/filters/order.js +108 -0
- package/dist/filters/order.js.map +1 -0
- package/dist/filters/sieve.d.ts +184 -0
- package/dist/filters/sieve.js +1312 -0
- package/dist/filters/sieve.js.map +1 -0
- package/dist/instances.d.ts +58 -0
- package/dist/instances.js +145 -0
- package/dist/instances.js.map +1 -0
- package/dist/mail/compose.d.ts +10 -0
- package/dist/mail/compose.js.map +1 -1
- package/dist/mail/record.d.ts +36 -0
- package/dist/mail/record.js +74 -0
- package/dist/mail/record.js.map +1 -0
- package/dist/permissions.d.ts +139 -0
- package/dist/permissions.js +355 -0
- package/dist/permissions.js.map +1 -0
- package/dist/server.js +330 -16
- package/dist/server.js.map +1 -1
- package/dist/session.d.ts +12 -0
- package/dist/session.js +23 -0
- package/dist/session.js.map +1 -1
- package/dist/settings.d.ts +81 -11
- package/dist/settings.js +160 -25
- package/dist/settings.js.map +1 -1
- package/dist/tools/confirm.d.ts +4 -2
- package/dist/tools/confirm.js +12 -3
- package/dist/tools/confirm.js.map +1 -1
- package/dist/tools/failures.d.ts +6 -8
- package/dist/tools/failures.js +36 -17
- package/dist/tools/failures.js.map +1 -1
- package/dist/tools/filter-tools.d.ts +82 -0
- package/dist/tools/filter-tools.js +729 -0
- package/dist/tools/filter-tools.js.map +1 -0
- package/dist/tools/filters.d.ts +8 -1
- package/dist/tools/filters.js +24 -12
- package/dist/tools/filters.js.map +1 -1
- package/dist/tools/format.d.ts +15 -0
- package/dist/tools/format.js +4 -3
- package/dist/tools/format.js.map +1 -1
- package/dist/tools/guidance.js +12 -7
- package/dist/tools/guidance.js.map +1 -1
- package/dist/tools/interface.d.ts +20 -6
- package/dist/tools/interface.js +40 -16
- package/dist/tools/interface.js.map +1 -1
- package/dist/tools/send.d.ts +9 -0
- package/dist/tools/send.js +51 -9
- package/dist/tools/send.js.map +1 -1
- package/dist/tools/sign-in-required.d.ts +15 -2
- package/dist/tools/sign-in-required.js +30 -2
- package/dist/tools/sign-in-required.js.map +1 -1
- package/dist/web/layout.d.ts +12 -5
- package/dist/web/layout.js +32 -9
- package/dist/web/layout.js.map +1 -1
- package/dist/web/pages.d.ts +4 -2
- package/dist/web/pages.js +10 -9
- package/dist/web/pages.js.map +1 -1
- package/dist/web/pending.d.ts +9 -6
- package/dist/web/pending.js +9 -7
- package/dist/web/pending.js.map +1 -1
- package/dist/web/preview-server.d.ts +33 -0
- package/dist/web/preview-server.js +102 -0
- package/dist/web/preview-server.js.map +1 -0
- package/dist/web/sections.d.ts +86 -1
- package/dist/web/sections.js +290 -7
- package/dist/web/sections.js.map +1 -1
- package/dist/web/security.d.ts +48 -13
- package/dist/web/security.js +68 -16
- package/dist/web/security.js.map +1 -1
- package/dist/web/server.d.ts +81 -24
- package/dist/web/server.js +478 -117
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the assistant may do, tool by tool.
|
|
3
|
+
*
|
|
4
|
+
* Three levels, decided per tool by the user:
|
|
5
|
+
*
|
|
6
|
+
* - `off`: the tool does not exist as far as the assistant is concerned. It is
|
|
7
|
+
* taken out of the list the client sees, and a call that arrives anyway is
|
|
8
|
+
* refused with the name of the setting that refused it.
|
|
9
|
+
* - `ask`: the tool runs only after the person agrees through the client. Every
|
|
10
|
+
* sending tool works this way by default, and so does proposing a filter.
|
|
11
|
+
* - `act`: the tool runs without asking. Every other tool works this way by
|
|
12
|
+
* default.
|
|
13
|
+
*
|
|
14
|
+
* The defaults are exactly the behaviour before this file existed, so nothing
|
|
15
|
+
* changes on an upgrade. Only the tools that can ask at all offer `ask`: for a
|
|
16
|
+
* tool that reads, a question before every call would be noise nobody reads.
|
|
17
|
+
*
|
|
18
|
+
* ## Who decides
|
|
19
|
+
*
|
|
20
|
+
* The environment first, then the interface, then the default. An environment
|
|
21
|
+
* variable is set where the server is registered with the client, which takes
|
|
22
|
+
* a person editing that configuration; the interface takes a PIN once the user
|
|
23
|
+
* sets one, and without a PIN anything on the machine can change it, the
|
|
24
|
+
* assistant included. Both are said where they are set.
|
|
25
|
+
*
|
|
26
|
+
* ## Sending without asking
|
|
27
|
+
*
|
|
28
|
+
* When a sending tool acts on its own, three optional bounds apply, and a send
|
|
29
|
+
* outside any of them asks instead of failing: permitted recipients or domains,
|
|
30
|
+
* a maximum per rolling hour, and a last day. A bound turns a mistake or a
|
|
31
|
+
* crafted message into a question rather than into mail that has left.
|
|
32
|
+
*/
|
|
33
|
+
import type { Level, SendLimits, StoredSettings } from './settings.js';
|
|
34
|
+
import { type Unlockable } from './filters/sieve.js';
|
|
35
|
+
/** The tools in each group, as they are named to the client. */
|
|
36
|
+
export declare const GROUPS: {
|
|
37
|
+
readonly reading: readonly ['list_folders', 'list_messages', 'search_messages', 'get_message', 'get_attachment', 'list_drafts', 'manage_filters', 'list_filters', 'get_filters'];
|
|
38
|
+
readonly filing: readonly ['add_label', 'remove_label', 'move_messages', 'set_flags', 'trash_messages'];
|
|
39
|
+
readonly writing: readonly ['create_draft', 'update_draft', 'reply_draft', 'forward_draft', 'save_attachment', 'delete_saved_attachments'];
|
|
40
|
+
readonly sending: readonly ['send_message', 'send_reply', 'send_forward', 'send_draft'];
|
|
41
|
+
readonly filters: readonly ['propose_filter', 'apply_filter', 'reorder_filters', 'delete_filter', 'set_filter_status'];
|
|
42
|
+
};
|
|
43
|
+
export type Group = keyof typeof GROUPS;
|
|
44
|
+
/** Tools that are always there: the way to the interface, and the update check. */
|
|
45
|
+
export declare const ALWAYS: Set<string>;
|
|
46
|
+
/** Every tool a level can be set for, in a stable order. */
|
|
47
|
+
export declare const CONTROLLED: readonly string[];
|
|
48
|
+
/** The tools that can ask first: the ones whose effect leaves this machine or outlives the session. */
|
|
49
|
+
export declare function canAsk(tool: string): boolean;
|
|
50
|
+
export declare function defaultLevel(tool: string): Level;
|
|
51
|
+
/** Which levels a tool offers. */
|
|
52
|
+
export declare function levelsFor(tool: string): Level[];
|
|
53
|
+
/** Where a tool's level comes from, so the interface and the answers can say. */
|
|
54
|
+
export type LevelSource = 'environment' | 'read-only' | 'interface' | 'default';
|
|
55
|
+
/** A configuration that cannot be honoured. The server refuses to start rather than guess. */
|
|
56
|
+
export declare class PermissionsError extends Error {
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Reads the three lists from the environment.
|
|
60
|
+
*
|
|
61
|
+
* A tool named on its own wins over a group it belongs to, so that "every
|
|
62
|
+
* sending tool acts on its own, but send_forward asks" can be written as
|
|
63
|
+
* exactly that. Every real contradiction is fatal: an unknown name, the same
|
|
64
|
+
* tool or the same group in two lists, or `ask` for a tool that cannot ask. A
|
|
65
|
+
* server that guessed would run with permissions nobody chose, and the place to
|
|
66
|
+
* find out is the start, not the first send.
|
|
67
|
+
*/
|
|
68
|
+
export declare function levelsFromEnvironment(env?: NodeJS.ProcessEnv): Map<string, Level>;
|
|
69
|
+
/** The bounds from the environment, each one only when set. */
|
|
70
|
+
export declare function limitsFromEnvironment(env?: NodeJS.ProcessEnv): SendLimits;
|
|
71
|
+
/**
|
|
72
|
+
* What a filter may do beyond filing and flags, from PROTON_MCP_FILTER_ACTIONS,
|
|
73
|
+
* or nothing when it is not set. An unknown name stops the start, like an
|
|
74
|
+
* unknown tool: a typo must not quietly allow less, or more, than was meant.
|
|
75
|
+
*/
|
|
76
|
+
export declare function unlocksFromEnvironment(env?: NodeJS.ProcessEnv): Unlockable[] | undefined;
|
|
77
|
+
/** Whether a recipient address matches an entry of the permitted list. */
|
|
78
|
+
export declare function permitted(address: string, allowed: readonly string[]): boolean;
|
|
79
|
+
export interface PermissionsOptions {
|
|
80
|
+
env?: NodeJS.ProcessEnv;
|
|
81
|
+
/** The shared settings as they are now. Read on every question, never cached. */
|
|
82
|
+
settings: () => StoredSettings;
|
|
83
|
+
/** PROTON_MCP_READ_ONLY. */
|
|
84
|
+
readOnly: boolean;
|
|
85
|
+
clock?: () => number;
|
|
86
|
+
}
|
|
87
|
+
/** Why a send that may act on its own still asks. Nothing means it may go. */
|
|
88
|
+
export type HoldBack = {
|
|
89
|
+
reason: string;
|
|
90
|
+
} | undefined;
|
|
91
|
+
export declare class Permissions {
|
|
92
|
+
#private;
|
|
93
|
+
constructor(options: PermissionsOptions);
|
|
94
|
+
/**
|
|
95
|
+
* Where the level of a tool comes from.
|
|
96
|
+
*
|
|
97
|
+
* Read-only mode first: it is the strongest thing a user can say, and the
|
|
98
|
+
* mail layer refuses every change under it anyway, so a level claiming
|
|
99
|
+
* otherwise would only mislead.
|
|
100
|
+
*/
|
|
101
|
+
source(tool: string): LevelSource;
|
|
102
|
+
/** The level in force for a tool right now. */
|
|
103
|
+
level(tool: string): Level;
|
|
104
|
+
/** The bounds in force: each one from the environment when set there, else from the interface. */
|
|
105
|
+
limits(): SendLimits;
|
|
106
|
+
/** Which bounds the environment fixed, so the interface shows them as fixed. */
|
|
107
|
+
limitsFixed(): {
|
|
108
|
+
allowed: boolean;
|
|
109
|
+
maxPerHour: boolean;
|
|
110
|
+
until: boolean;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* What a filter may do beyond filing and flags: from the environment when
|
|
114
|
+
* set there, else from the interface. Nothing by default. The extension has
|
|
115
|
+
* the same switches in its popup, and an action needs both.
|
|
116
|
+
*/
|
|
117
|
+
unlocks(): ReadonlySet<Unlockable>;
|
|
118
|
+
/** Whether the environment fixed what filters may do, so the interface shows it as fixed. */
|
|
119
|
+
unlocksFixed(): boolean;
|
|
120
|
+
/** Where to change what filters may do, for answers that refuse. */
|
|
121
|
+
unlocksWhere(): string;
|
|
122
|
+
/** Every tool whose level departs from the default, for the status line and the overview. */
|
|
123
|
+
departures(): Array<{
|
|
124
|
+
tool: string;
|
|
125
|
+
level: Level;
|
|
126
|
+
source: LevelSource;
|
|
127
|
+
}>;
|
|
128
|
+
/**
|
|
129
|
+
* Whether a send at level `act` may go without asking, given its recipients.
|
|
130
|
+
*
|
|
131
|
+
* Returns the bound that holds it back, or nothing. Checked in the order a
|
|
132
|
+
* person would care about: the last day, the recipients, then the count.
|
|
133
|
+
*/
|
|
134
|
+
holdBack(recipients: readonly string[]): HoldBack;
|
|
135
|
+
/** Records a send that went out without asking, for the hourly bound. */
|
|
136
|
+
recordSent(): void;
|
|
137
|
+
/** Where to change a tool's level, for answers that refuse or act on their own. */
|
|
138
|
+
where(tool: string): string;
|
|
139
|
+
}
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the assistant may do, tool by tool.
|
|
3
|
+
*
|
|
4
|
+
* Three levels, decided per tool by the user:
|
|
5
|
+
*
|
|
6
|
+
* - `off`: the tool does not exist as far as the assistant is concerned. It is
|
|
7
|
+
* taken out of the list the client sees, and a call that arrives anyway is
|
|
8
|
+
* refused with the name of the setting that refused it.
|
|
9
|
+
* - `ask`: the tool runs only after the person agrees through the client. Every
|
|
10
|
+
* sending tool works this way by default, and so does proposing a filter.
|
|
11
|
+
* - `act`: the tool runs without asking. Every other tool works this way by
|
|
12
|
+
* default.
|
|
13
|
+
*
|
|
14
|
+
* The defaults are exactly the behaviour before this file existed, so nothing
|
|
15
|
+
* changes on an upgrade. Only the tools that can ask at all offer `ask`: for a
|
|
16
|
+
* tool that reads, a question before every call would be noise nobody reads.
|
|
17
|
+
*
|
|
18
|
+
* ## Who decides
|
|
19
|
+
*
|
|
20
|
+
* The environment first, then the interface, then the default. An environment
|
|
21
|
+
* variable is set where the server is registered with the client, which takes
|
|
22
|
+
* a person editing that configuration; the interface takes a PIN once the user
|
|
23
|
+
* sets one, and without a PIN anything on the machine can change it, the
|
|
24
|
+
* assistant included. Both are said where they are set.
|
|
25
|
+
*
|
|
26
|
+
* ## Sending without asking
|
|
27
|
+
*
|
|
28
|
+
* When a sending tool acts on its own, three optional bounds apply, and a send
|
|
29
|
+
* outside any of them asks instead of failing: permitted recipients or domains,
|
|
30
|
+
* a maximum per rolling hour, and a last day. A bound turns a mistake or a
|
|
31
|
+
* crafted message into a question rather than into mail that has left.
|
|
32
|
+
*/
|
|
33
|
+
import { UNLOCKABLE, NO_UNLOCKS } from './filters/sieve.js';
|
|
34
|
+
/** The tools in each group, as they are named to the client. */
|
|
35
|
+
export const GROUPS = {
|
|
36
|
+
reading: [
|
|
37
|
+
'list_folders',
|
|
38
|
+
'list_messages',
|
|
39
|
+
'search_messages',
|
|
40
|
+
'get_message',
|
|
41
|
+
'get_attachment',
|
|
42
|
+
'list_drafts',
|
|
43
|
+
'manage_filters',
|
|
44
|
+
'list_filters',
|
|
45
|
+
'get_filters',
|
|
46
|
+
],
|
|
47
|
+
filing: ['add_label', 'remove_label', 'move_messages', 'set_flags', 'trash_messages'],
|
|
48
|
+
writing: [
|
|
49
|
+
'create_draft',
|
|
50
|
+
'update_draft',
|
|
51
|
+
'reply_draft',
|
|
52
|
+
'forward_draft',
|
|
53
|
+
'save_attachment',
|
|
54
|
+
'delete_saved_attachments',
|
|
55
|
+
],
|
|
56
|
+
sending: ['send_message', 'send_reply', 'send_forward', 'send_draft'],
|
|
57
|
+
filters: ['propose_filter', 'apply_filter', 'reorder_filters', 'delete_filter', 'set_filter_status'],
|
|
58
|
+
};
|
|
59
|
+
/** Tools that are always there: the way to the interface, and the update check. */
|
|
60
|
+
export const ALWAYS = new Set(['open_configuration', 'check_for_updates']);
|
|
61
|
+
/** Every tool a level can be set for, in a stable order. */
|
|
62
|
+
export const CONTROLLED = Object.values(GROUPS).flat();
|
|
63
|
+
const GROUP_OF = new Map(Object.entries(GROUPS).flatMap(([group, tools]) => tools.map((tool) => [tool, group])));
|
|
64
|
+
/** The tools that can ask first: the ones whose effect leaves this machine or outlives the session. */
|
|
65
|
+
export function canAsk(tool) {
|
|
66
|
+
const group = GROUP_OF.get(tool);
|
|
67
|
+
return group === 'sending' || group === 'filters';
|
|
68
|
+
}
|
|
69
|
+
/** Groups whose tools change something. Read-only mode switches all of them off. */
|
|
70
|
+
const CHANGING = new Set(['filing', 'writing', 'sending', 'filters']);
|
|
71
|
+
/**
|
|
72
|
+
* Tools that are off until the user switches them on: deleting a filter and
|
|
73
|
+
* switching one on or off. Both were left out of #59 at first, and came in on
|
|
74
|
+
* Tobi's word of 06.11.2026 that the user decides, with today's behaviour as
|
|
75
|
+
* the default.
|
|
76
|
+
*/
|
|
77
|
+
const OFF_BY_DEFAULT = new Set(['delete_filter', 'set_filter_status']);
|
|
78
|
+
export function defaultLevel(tool) {
|
|
79
|
+
if (OFF_BY_DEFAULT.has(tool))
|
|
80
|
+
return 'off';
|
|
81
|
+
return canAsk(tool) ? 'ask' : 'act';
|
|
82
|
+
}
|
|
83
|
+
/** Which levels a tool offers. */
|
|
84
|
+
export function levelsFor(tool) {
|
|
85
|
+
return canAsk(tool) ? ['off', 'ask', 'act'] : ['off', 'act'];
|
|
86
|
+
}
|
|
87
|
+
/** A configuration that cannot be honoured. The server refuses to start rather than guess. */
|
|
88
|
+
export class PermissionsError extends Error {
|
|
89
|
+
}
|
|
90
|
+
const ENV_LISTS = [
|
|
91
|
+
['PROTON_MCP_OFF', 'off'],
|
|
92
|
+
['PROTON_MCP_ASK_FIRST', 'ask'],
|
|
93
|
+
['PROTON_MCP_ACT_ON_ITS_OWN', 'act'],
|
|
94
|
+
];
|
|
95
|
+
/** Splits a list written with commas, spaces or both. */
|
|
96
|
+
function entries(raw) {
|
|
97
|
+
return (raw ?? '')
|
|
98
|
+
.split(/[\s,]+/)
|
|
99
|
+
.map((entry) => entry.trim())
|
|
100
|
+
.filter(Boolean);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Reads the three lists from the environment.
|
|
104
|
+
*
|
|
105
|
+
* A tool named on its own wins over a group it belongs to, so that "every
|
|
106
|
+
* sending tool acts on its own, but send_forward asks" can be written as
|
|
107
|
+
* exactly that. Every real contradiction is fatal: an unknown name, the same
|
|
108
|
+
* tool or the same group in two lists, or `ask` for a tool that cannot ask. A
|
|
109
|
+
* server that guessed would run with permissions nobody chose, and the place to
|
|
110
|
+
* find out is the start, not the first send.
|
|
111
|
+
*/
|
|
112
|
+
export function levelsFromEnvironment(env = process.env) {
|
|
113
|
+
const fromGroups = new Map();
|
|
114
|
+
const fromTools = new Map();
|
|
115
|
+
const groupNamedIn = new Map();
|
|
116
|
+
const toolNamedIn = new Map();
|
|
117
|
+
const check = (variable, level, tool, how) => {
|
|
118
|
+
if (level === 'ask' && !canAsk(tool)) {
|
|
119
|
+
throw new PermissionsError(`${variable} names ${how}, and ${tool} cannot ask first: only the sending tools and the filter ` +
|
|
120
|
+
'tools that change something can. Use PROTON_MCP_OFF or PROTON_MCP_ACT_ON_ITS_OWN for it.');
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
for (const [variable, level] of ENV_LISTS) {
|
|
124
|
+
for (const entry of entries(env[variable])) {
|
|
125
|
+
if (entry in GROUPS) {
|
|
126
|
+
const earlier = groupNamedIn.get(entry);
|
|
127
|
+
if (earlier && earlier !== variable) {
|
|
128
|
+
throw new PermissionsError(`The group ${entry} is named in both ${earlier} and ${variable}.`);
|
|
129
|
+
}
|
|
130
|
+
groupNamedIn.set(entry, variable);
|
|
131
|
+
for (const tool of GROUPS[entry]) {
|
|
132
|
+
check(variable, level, tool, `the group ${entry}`);
|
|
133
|
+
fromGroups.set(tool, level);
|
|
134
|
+
}
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (!GROUP_OF.has(entry)) {
|
|
138
|
+
const always = ALWAYS.has(entry) ? ' It is always available and has no level.' : '';
|
|
139
|
+
throw new PermissionsError(`${variable} names "${entry}", which is neither a tool nor a group.${always} Groups are ` +
|
|
140
|
+
`${Object.keys(GROUPS).join(', ')}.`);
|
|
141
|
+
}
|
|
142
|
+
const earlier = toolNamedIn.get(entry);
|
|
143
|
+
if (earlier && earlier !== variable) {
|
|
144
|
+
throw new PermissionsError(`${entry} is named in both ${earlier} and ${variable}. Each tool may appear in one of them only.`);
|
|
145
|
+
}
|
|
146
|
+
check(variable, level, entry, entry);
|
|
147
|
+
toolNamedIn.set(entry, variable);
|
|
148
|
+
fromTools.set(entry, level);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return new Map([...fromGroups, ...fromTools]);
|
|
152
|
+
}
|
|
153
|
+
/** The bounds from the environment, each one only when set. */
|
|
154
|
+
export function limitsFromEnvironment(env = process.env) {
|
|
155
|
+
const limits = {};
|
|
156
|
+
const allowed = entries(env.PROTON_MCP_SEND_ALLOWED);
|
|
157
|
+
if (allowed.length > 0)
|
|
158
|
+
limits.allowed = allowed;
|
|
159
|
+
const max = env.PROTON_MCP_SEND_MAX_PER_HOUR?.trim();
|
|
160
|
+
if (max) {
|
|
161
|
+
const value = Number(max);
|
|
162
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
163
|
+
throw new PermissionsError(`PROTON_MCP_SEND_MAX_PER_HOUR is "${max}", which is not a whole number of at least 1.`);
|
|
164
|
+
}
|
|
165
|
+
limits.maxPerHour = value;
|
|
166
|
+
}
|
|
167
|
+
const until = env.PROTON_MCP_ACT_UNTIL?.trim();
|
|
168
|
+
if (until) {
|
|
169
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(until) || Number.isNaN(Date.parse(`${until}T00:00:00Z`))) {
|
|
170
|
+
throw new PermissionsError(`PROTON_MCP_ACT_UNTIL is "${until}", which is not a day written YYYY-MM-DD.`);
|
|
171
|
+
}
|
|
172
|
+
limits.until = until;
|
|
173
|
+
}
|
|
174
|
+
return limits;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* What a filter may do beyond filing and flags, from PROTON_MCP_FILTER_ACTIONS,
|
|
178
|
+
* or nothing when it is not set. An unknown name stops the start, like an
|
|
179
|
+
* unknown tool: a typo must not quietly allow less, or more, than was meant.
|
|
180
|
+
*/
|
|
181
|
+
export function unlocksFromEnvironment(env = process.env) {
|
|
182
|
+
const raw = env.PROTON_MCP_FILTER_ACTIONS;
|
|
183
|
+
if (raw === undefined || raw.trim() === '')
|
|
184
|
+
return undefined;
|
|
185
|
+
const named = entries(raw);
|
|
186
|
+
if (named.length === 1 && named[0] === 'none')
|
|
187
|
+
return [];
|
|
188
|
+
const unknown = named.find((entry) => !UNLOCKABLE.includes(entry));
|
|
189
|
+
if (unknown) {
|
|
190
|
+
throw new PermissionsError(`PROTON_MCP_FILTER_ACTIONS names "${unknown}", which is not an action a filter can be allowed. ` +
|
|
191
|
+
`They are ${UNLOCKABLE.join(', ')}, or none.`);
|
|
192
|
+
}
|
|
193
|
+
return [...new Set(named)];
|
|
194
|
+
}
|
|
195
|
+
/** Whether a recipient address matches an entry of the permitted list. */
|
|
196
|
+
export function permitted(address, allowed) {
|
|
197
|
+
const candidate = address.trim().toLowerCase();
|
|
198
|
+
const domain = candidate.slice(candidate.lastIndexOf('@'));
|
|
199
|
+
return allowed.some((entry) => {
|
|
200
|
+
const rule = entry.trim().toLowerCase();
|
|
201
|
+
return rule.startsWith('@') ? domain === rule : candidate === rule;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
/** The local calendar day of a moment, YYYY-MM-DD, which is how the last day is written. */
|
|
205
|
+
function day(at) {
|
|
206
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
207
|
+
return `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())}`;
|
|
208
|
+
}
|
|
209
|
+
export class Permissions {
|
|
210
|
+
#fromEnv;
|
|
211
|
+
#limitsFromEnv;
|
|
212
|
+
#unlocksFromEnv;
|
|
213
|
+
#settings;
|
|
214
|
+
#readOnly;
|
|
215
|
+
#clock;
|
|
216
|
+
/** When each send without asking went out, for the hourly bound. This server only. */
|
|
217
|
+
#sent = [];
|
|
218
|
+
constructor(options) {
|
|
219
|
+
const env = options.env ?? process.env;
|
|
220
|
+
this.#fromEnv = levelsFromEnvironment(env);
|
|
221
|
+
this.#limitsFromEnv = limitsFromEnvironment(env);
|
|
222
|
+
this.#unlocksFromEnv = unlocksFromEnvironment(env);
|
|
223
|
+
this.#settings = options.settings;
|
|
224
|
+
this.#readOnly = options.readOnly;
|
|
225
|
+
this.#clock = options.clock ?? Date.now;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Where the level of a tool comes from.
|
|
229
|
+
*
|
|
230
|
+
* Read-only mode first: it is the strongest thing a user can say, and the
|
|
231
|
+
* mail layer refuses every change under it anyway, so a level claiming
|
|
232
|
+
* otherwise would only mislead.
|
|
233
|
+
*/
|
|
234
|
+
source(tool) {
|
|
235
|
+
const group = GROUP_OF.get(tool);
|
|
236
|
+
if (this.#readOnly && group && CHANGING.has(group))
|
|
237
|
+
return 'read-only';
|
|
238
|
+
if (this.#fromEnv.has(tool))
|
|
239
|
+
return 'environment';
|
|
240
|
+
if (this.#settings().levels?.[tool] !== undefined)
|
|
241
|
+
return 'interface';
|
|
242
|
+
return 'default';
|
|
243
|
+
}
|
|
244
|
+
/** The level in force for a tool right now. */
|
|
245
|
+
level(tool) {
|
|
246
|
+
if (ALWAYS.has(tool) || !GROUP_OF.has(tool))
|
|
247
|
+
return 'act';
|
|
248
|
+
const group = GROUP_OF.get(tool);
|
|
249
|
+
if (this.#readOnly && CHANGING.has(group))
|
|
250
|
+
return 'off';
|
|
251
|
+
const fromEnv = this.#fromEnv.get(tool);
|
|
252
|
+
if (fromEnv)
|
|
253
|
+
return fromEnv;
|
|
254
|
+
const chosen = this.#settings().levels?.[tool];
|
|
255
|
+
if (chosen && levelsFor(tool).includes(chosen))
|
|
256
|
+
return chosen;
|
|
257
|
+
return defaultLevel(tool);
|
|
258
|
+
}
|
|
259
|
+
/** The bounds in force: each one from the environment when set there, else from the interface. */
|
|
260
|
+
limits() {
|
|
261
|
+
const stored = this.#settings().limits ?? {};
|
|
262
|
+
const limits = {};
|
|
263
|
+
const allowed = this.#limitsFromEnv.allowed ?? stored.allowed;
|
|
264
|
+
const maxPerHour = this.#limitsFromEnv.maxPerHour ?? stored.maxPerHour;
|
|
265
|
+
const until = this.#limitsFromEnv.until ?? stored.until;
|
|
266
|
+
if (allowed)
|
|
267
|
+
limits.allowed = allowed;
|
|
268
|
+
if (maxPerHour !== undefined)
|
|
269
|
+
limits.maxPerHour = maxPerHour;
|
|
270
|
+
if (until)
|
|
271
|
+
limits.until = until;
|
|
272
|
+
return limits;
|
|
273
|
+
}
|
|
274
|
+
/** Which bounds the environment fixed, so the interface shows them as fixed. */
|
|
275
|
+
limitsFixed() {
|
|
276
|
+
return {
|
|
277
|
+
allowed: this.#limitsFromEnv.allowed !== undefined,
|
|
278
|
+
maxPerHour: this.#limitsFromEnv.maxPerHour !== undefined,
|
|
279
|
+
until: this.#limitsFromEnv.until !== undefined,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* What a filter may do beyond filing and flags: from the environment when
|
|
284
|
+
* set there, else from the interface. Nothing by default. The extension has
|
|
285
|
+
* the same switches in its popup, and an action needs both.
|
|
286
|
+
*/
|
|
287
|
+
unlocks() {
|
|
288
|
+
if (this.#readOnly)
|
|
289
|
+
return NO_UNLOCKS;
|
|
290
|
+
const chosen = this.#unlocksFromEnv ?? this.#settings().filterActions ?? [];
|
|
291
|
+
return new Set(UNLOCKABLE.filter((action) => chosen.includes(action)));
|
|
292
|
+
}
|
|
293
|
+
/** Whether the environment fixed what filters may do, so the interface shows it as fixed. */
|
|
294
|
+
unlocksFixed() {
|
|
295
|
+
return this.#unlocksFromEnv !== undefined;
|
|
296
|
+
}
|
|
297
|
+
/** Where to change what filters may do, for answers that refuse. */
|
|
298
|
+
unlocksWhere() {
|
|
299
|
+
return this.#unlocksFromEnv !== undefined
|
|
300
|
+
? 'set in the environment of this server (PROTON_MCP_FILTER_ACTIONS)'
|
|
301
|
+
: 'on the Permissions page of the local interface';
|
|
302
|
+
}
|
|
303
|
+
/** Every tool whose level departs from the default, for the status line and the overview. */
|
|
304
|
+
departures() {
|
|
305
|
+
return CONTROLLED.filter((tool) => this.level(tool) !== defaultLevel(tool)).map((tool) => ({
|
|
306
|
+
tool,
|
|
307
|
+
level: this.level(tool),
|
|
308
|
+
source: this.source(tool),
|
|
309
|
+
}));
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Whether a send at level `act` may go without asking, given its recipients.
|
|
313
|
+
*
|
|
314
|
+
* Returns the bound that holds it back, or nothing. Checked in the order a
|
|
315
|
+
* person would care about: the last day, the recipients, then the count.
|
|
316
|
+
*/
|
|
317
|
+
holdBack(recipients) {
|
|
318
|
+
const limits = this.limits();
|
|
319
|
+
const now = this.#clock();
|
|
320
|
+
if (limits.until && day(new Date(now)) > limits.until) {
|
|
321
|
+
return { reason: `sending without asking ended after ${limits.until}` };
|
|
322
|
+
}
|
|
323
|
+
if (limits.allowed) {
|
|
324
|
+
const outside = recipients.filter((address) => !permitted(address, limits.allowed));
|
|
325
|
+
if (outside.length > 0) {
|
|
326
|
+
return { reason: `not every recipient is on the permitted list (${outside.join(', ')})` };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (limits.maxPerHour !== undefined) {
|
|
330
|
+
this.#sent = this.#sent.filter((at) => now - at < 3_600_000);
|
|
331
|
+
if (this.#sent.length >= limits.maxPerHour) {
|
|
332
|
+
return { reason: `${limits.maxPerHour} messages already went out without asking within the hour` };
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return undefined;
|
|
336
|
+
}
|
|
337
|
+
/** Records a send that went out without asking, for the hourly bound. */
|
|
338
|
+
recordSent() {
|
|
339
|
+
this.#sent.push(this.#clock());
|
|
340
|
+
}
|
|
341
|
+
/** Where to change a tool's level, for answers that refuse or act on their own. */
|
|
342
|
+
where(tool) {
|
|
343
|
+
switch (this.source(tool)) {
|
|
344
|
+
case 'environment':
|
|
345
|
+
return 'set in the environment of this server (PROTON_MCP_OFF, PROTON_MCP_ASK_FIRST or PROTON_MCP_ACT_ON_ITS_OWN)';
|
|
346
|
+
case 'read-only':
|
|
347
|
+
return 'set by PROTON_MCP_READ_ONLY';
|
|
348
|
+
case 'interface':
|
|
349
|
+
return 'set on the Permissions page of the local interface';
|
|
350
|
+
default:
|
|
351
|
+
return 'the default';
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"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"}
|