@veilio-inc/cli 0.2.0 → 0.3.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/LICENSE +30 -5
- package/README.md +23 -16
- package/dist/args.d.ts +11 -1
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +32 -1
- package/dist/args.js.map +1 -1
- package/dist/cloud-commands.d.ts +30 -0
- package/dist/cloud-commands.d.ts.map +1 -1
- package/dist/cloud-commands.js +284 -6
- package/dist/cloud-commands.js.map +1 -1
- package/dist/cloud.d.ts +80 -8
- package/dist/cloud.d.ts.map +1 -1
- package/dist/cloud.js +38 -4
- package/dist/cloud.js.map +1 -1
- package/dist/commands.d.ts +14 -2
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +63 -10
- package/dist/commands.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -3
- package/dist/index.js.map +1 -1
- package/dist/rules.d.ts +35 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +103 -0
- package/dist/rules.js.map +1 -0
- package/dist/team-namespace.d.ts +38 -0
- package/dist/team-namespace.d.ts.map +1 -0
- package/dist/team-namespace.js +188 -0
- package/dist/team-namespace.js.map +1 -0
- package/dist/team-unlock.d.ts +49 -0
- package/dist/team-unlock.d.ts.map +1 -0
- package/dist/team-unlock.js +134 -0
- package/dist/team-unlock.js.map +1 -0
- package/package.json +7 -4
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAW,MAAM,eAAe,CAAA;AAChG,OAAO,EACL,QAAQ,EACR,SAAS,EACT,SAAS,EACT,WAAW,EACX,WAAW,EACX,WAAW,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/rules.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type CustomRule } from '@veilio-inc/engine';
|
|
2
|
+
export declare const RULES_FILE = "rules.json";
|
|
3
|
+
export interface CachedRules {
|
|
4
|
+
/** Which account these belong to - a different sign-in does not inherit them. */
|
|
5
|
+
instance: string;
|
|
6
|
+
account: string;
|
|
7
|
+
/** ISO time of the pull, so `scrub` can say how old they are. */
|
|
8
|
+
pulledAt: string;
|
|
9
|
+
/** Already merged into the order the engine applies them in. */
|
|
10
|
+
rules: CustomRule[];
|
|
11
|
+
}
|
|
12
|
+
export declare function rulesPath(home?: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Personal and team rules in the order the web app applies them:
|
|
15
|
+
* team whitelist, personal whitelist, team replace, personal replace.
|
|
16
|
+
*
|
|
17
|
+
* Whitelists first so a name either list keeps readable is never renamed by a
|
|
18
|
+
* replace rule; team before personal so the team's naming wins on a clash,
|
|
19
|
+
* which is what keeps two members' output interchangeable. Disabled rules are
|
|
20
|
+
* dropped and sort_order renumbered 0..n-1, so the engine sees one sequence.
|
|
21
|
+
* Must match `useMergedRules` in the Cloud frontend.
|
|
22
|
+
*/
|
|
23
|
+
export declare function mergeRules(personal: readonly CustomRule[], team: readonly CustomRule[]): CustomRule[];
|
|
24
|
+
/** The cached rules for this account, or null. Null for every kind of failure. */
|
|
25
|
+
export declare function readRules(owner: {
|
|
26
|
+
instance: string;
|
|
27
|
+
account: string;
|
|
28
|
+
}, home?: string): CachedRules | null;
|
|
29
|
+
/** 0600: the patterns name what a team considers sensitive. */
|
|
30
|
+
export declare function writeRules(cached: CachedRules, home?: string): void;
|
|
31
|
+
/** Remove the cache. Missing is not an error; failing to delete is. */
|
|
32
|
+
export declare function removeRules(home?: string): boolean;
|
|
33
|
+
/** "3 hours ago" - coarse on purpose; it answers "is this stale", no more. */
|
|
34
|
+
export declare function describeAge(pulledAt: string, now?: Date): string;
|
|
35
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAE/D,eAAO,MAAM,UAAU,eAAe,CAAA;AAEtC,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAA;IAChB,gEAAgE;IAChE,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAED,wBAAgB,SAAS,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,CAE1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,SAAS,UAAU,EAAE,EAC/B,IAAI,EAAE,SAAS,UAAU,EAAE,GAC1B,UAAU,EAAE,CAUd;AAUD,kFAAkF;AAClF,wBAAgB,SAAS,CACvB,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAC5C,IAAI,GAAE,MAAkB,GACvB,WAAW,GAAG,IAAI,CAcpB;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,GAAE,MAAkB,GAAG,IAAI,CAK9E;AAED,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,IAAI,GAAE,MAAkB,GAAG,OAAO,CAS7D;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CAQ5E"}
|
package/dist/rules.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// The account's custom rules, cached on this machine.
|
|
2
|
+
//
|
|
3
|
+
// Custom rules are defined in the web app and live in Cloud. Before this file
|
|
4
|
+
// the terminal and the MCP server never applied them: the same code masked
|
|
5
|
+
// differently in the browser than in `veilio scrub`, and a whitelisted name
|
|
6
|
+
// that the browser left readable came back as a placeholder here (found on
|
|
7
|
+
// staging, 2026-09-26).
|
|
8
|
+
//
|
|
9
|
+
// `veilio scrub` must stay offline (see offline.test.ts), so it cannot ask Cloud
|
|
10
|
+
// for them. `veilio rules pull` fetches them and writes this cache; `scrub`
|
|
11
|
+
// applies what the cache holds and says how old it is. Reads tolerate absence
|
|
12
|
+
// and damage the way credential.ts does: a broken cache reads as "no rules",
|
|
13
|
+
// never as a failed scrub.
|
|
14
|
+
import { chmodSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
15
|
+
import { dirname, join } from 'node:path';
|
|
16
|
+
import { homedir } from 'node:os';
|
|
17
|
+
import { STORE_DIR } from '@veilio-inc/engine';
|
|
18
|
+
export const RULES_FILE = 'rules.json';
|
|
19
|
+
export function rulesPath(home = homedir()) {
|
|
20
|
+
return join(home, STORE_DIR, RULES_FILE);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Personal and team rules in the order the web app applies them:
|
|
24
|
+
* team whitelist, personal whitelist, team replace, personal replace.
|
|
25
|
+
*
|
|
26
|
+
* Whitelists first so a name either list keeps readable is never renamed by a
|
|
27
|
+
* replace rule; team before personal so the team's naming wins on a clash,
|
|
28
|
+
* which is what keeps two members' output interchangeable. Disabled rules are
|
|
29
|
+
* dropped and sort_order renumbered 0..n-1, so the engine sees one sequence.
|
|
30
|
+
* Must match `useMergedRules` in the Cloud frontend.
|
|
31
|
+
*/
|
|
32
|
+
export function mergeRules(personal, team) {
|
|
33
|
+
const byOrder = (a, b) => a.sort_order - b.sort_order;
|
|
34
|
+
const on = (list, type) => list.filter((r) => r.enabled && r.type === type).sort(byOrder);
|
|
35
|
+
return [
|
|
36
|
+
...on(team, 'whitelist'),
|
|
37
|
+
...on(personal, 'whitelist'),
|
|
38
|
+
...on(team, 'replace'),
|
|
39
|
+
...on(personal, 'replace'),
|
|
40
|
+
].map((r, i) => ({ ...r, sort_order: i }));
|
|
41
|
+
}
|
|
42
|
+
function isRule(value) {
|
|
43
|
+
if (typeof value !== 'object' || value === null)
|
|
44
|
+
return false;
|
|
45
|
+
const r = value;
|
|
46
|
+
if (typeof r.pattern !== 'string' || typeof r.sort_order !== 'number')
|
|
47
|
+
return false;
|
|
48
|
+
if (r.type === 'whitelist')
|
|
49
|
+
return true;
|
|
50
|
+
return r.type === 'replace' && typeof r.placeholder === 'string';
|
|
51
|
+
}
|
|
52
|
+
/** The cached rules for this account, or null. Null for every kind of failure. */
|
|
53
|
+
export function readRules(owner, home = homedir()) {
|
|
54
|
+
let parsed;
|
|
55
|
+
try {
|
|
56
|
+
parsed = JSON.parse(readFileSync(rulesPath(home), 'utf8'));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
62
|
+
return null;
|
|
63
|
+
const c = parsed;
|
|
64
|
+
if (c.instance !== owner.instance || c.account !== owner.account)
|
|
65
|
+
return null;
|
|
66
|
+
if (typeof c.pulledAt !== 'string' || !Array.isArray(c.rules) || !c.rules.every(isRule)) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return parsed;
|
|
70
|
+
}
|
|
71
|
+
/** 0600: the patterns name what a team considers sensitive. */
|
|
72
|
+
export function writeRules(cached, home = homedir()) {
|
|
73
|
+
const path = rulesPath(home);
|
|
74
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
75
|
+
writeFileSync(path, `${JSON.stringify(cached, null, 2)}\n`, { mode: 0o600 });
|
|
76
|
+
chmodSync(path, 0o600);
|
|
77
|
+
}
|
|
78
|
+
/** Remove the cache. Missing is not an error; failing to delete is. */
|
|
79
|
+
export function removeRules(home = homedir()) {
|
|
80
|
+
const path = rulesPath(home);
|
|
81
|
+
try {
|
|
82
|
+
statSync(path);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
rmSync(path, { recursive: true, force: true });
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
/** "3 hours ago" - coarse on purpose; it answers "is this stale", no more. */
|
|
91
|
+
export function describeAge(pulledAt, now = new Date()) {
|
|
92
|
+
const ms = now.getTime() - new Date(pulledAt).getTime();
|
|
93
|
+
if (!Number.isFinite(ms))
|
|
94
|
+
return 'at an unknown time';
|
|
95
|
+
const minutes = Math.max(0, Math.floor(ms / 60_000));
|
|
96
|
+
if (minutes < 60)
|
|
97
|
+
return minutes <= 1 ? 'just now' : `${minutes} minutes ago`;
|
|
98
|
+
const hours = Math.floor(minutes / 60);
|
|
99
|
+
if (hours < 48)
|
|
100
|
+
return `${hours} hour${hours === 1 ? '' : 's'} ago`;
|
|
101
|
+
return `${Math.floor(hours / 24)} days ago`;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type TeamNamespaceAnalysis } from '@veilio-inc/engine';
|
|
2
|
+
export type TeamNamespaceResult =
|
|
3
|
+
/**
|
|
4
|
+
* The team's maps, read and analyzed (namespace, aliases, conflicts, highest).
|
|
5
|
+
* `conflictDetection: false`: an older instance merged them server-side, with
|
|
6
|
+
* no way to tell a disputed placeholder from a first-written one - fine for
|
|
7
|
+
* anonymizing, never used to restore (spec 028, review).
|
|
8
|
+
*/
|
|
9
|
+
{
|
|
10
|
+
status: 'team';
|
|
11
|
+
analysis: TeamNamespaceAnalysis;
|
|
12
|
+
conflictDetection: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** Nothing to read: signed out, or not in a team. The local namespace is right. */
|
|
15
|
+
| {
|
|
16
|
+
status: 'local';
|
|
17
|
+
}
|
|
18
|
+
/** In a team, but no team key on this machine: `veilio team unlock`. */
|
|
19
|
+
| {
|
|
20
|
+
status: 'locked';
|
|
21
|
+
}
|
|
22
|
+
/** In a team, and the maps could not be read. `reason` says why. */
|
|
23
|
+
| {
|
|
24
|
+
status: 'unavailable';
|
|
25
|
+
reason: string;
|
|
26
|
+
};
|
|
27
|
+
export declare function resolveTeamNamespace(home?: string, opts?: {
|
|
28
|
+
retryDelayMs?: number;
|
|
29
|
+
/** Give up after this long in total (the CLI's pipeline cap). */
|
|
30
|
+
deadlineMs?: number;
|
|
31
|
+
}): Promise<TeamNamespaceResult>;
|
|
32
|
+
/**
|
|
33
|
+
* What a restore says when it needed the team's maps and did not get them -
|
|
34
|
+
* the same words from `veilio restore` and the MCP's `restore_text`.
|
|
35
|
+
* `missing`: the placeholders the own map could not explain.
|
|
36
|
+
*/
|
|
37
|
+
export declare function teamLayerNote(result: TeamNamespaceResult, missing: readonly string[]): string | null;
|
|
38
|
+
//# sourceMappingURL=team-namespace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-namespace.d.ts","sourceRoot":"","sources":["../src/team-namespace.ts"],"names":[],"mappings":"AAaA,OAAO,EAOL,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAA;AAY3B,MAAM,MAAM,mBAAmB;AAC7B;;;;;GAKG;AACD;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,qBAAqB,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAAE;AACjF,mFAAmF;GACjF;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE;AACrB,wEAAwE;GACtE;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE;AACtB,oEAAoE;GAClE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAuB7C,wBAAsB,oBAAoB,CACxC,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,GAAE;IACJ,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAA;CACf,GACL,OAAO,CAAC,mBAAmB,CAAC,CAgC9B;AAwHD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,MAAM,GAAG,IAAI,CAcf"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// The team's shared placeholder namespace, read from Cloud and opened with the
|
|
2
|
+
// team keys `veilio team unlock` left on disk.
|
|
3
|
+
//
|
|
4
|
+
// Moved here from the MCP server (spec 028) so that `veilio restore` reads the
|
|
5
|
+
// team's maps exactly as the MCP does - until then only the web app restored a
|
|
6
|
+
// teammate's placeholders. The MCP imports it, as it already imports `cloud`
|
|
7
|
+
// and `team-unlock`.
|
|
8
|
+
//
|
|
9
|
+
// It never falls back quietly. What it found is one of four states, and the
|
|
10
|
+
// caller says which: a coding agent or a terminal that silently used the local
|
|
11
|
+
// namespace looked exactly like one that used the team's, until a teammate's
|
|
12
|
+
// placeholders came back unrestored (Constitution V).
|
|
13
|
+
import { analyzeTeamNamespace, decryptTeamMapWithAny, importTeamKey, } from '@veilio-inc/engine';
|
|
14
|
+
import { readCredential } from './credential.js';
|
|
15
|
+
import { CloudError, getMap, getTeamEnvelopes, listMaps, } from './cloud.js';
|
|
16
|
+
import { readTeamUnlock } from './team-unlock.js';
|
|
17
|
+
/**
|
|
18
|
+
* Worth one more try: the network, or the server. Not a 401/402/403 - a lapsed
|
|
19
|
+
* or revoked account does not come back in a second, and it is not a team
|
|
20
|
+
* failure either (review): there is no team to speak of.
|
|
21
|
+
*/
|
|
22
|
+
function transient(err) {
|
|
23
|
+
return err instanceof CloudError && (err.kind === 'unreachable' || err.kind === 'server');
|
|
24
|
+
}
|
|
25
|
+
function noTeamToSpeakOf(err) {
|
|
26
|
+
return (err instanceof CloudError &&
|
|
27
|
+
(err.kind === 'unauthenticated' ||
|
|
28
|
+
err.kind === 'unentitled' ||
|
|
29
|
+
err.kind === 'forbidden' ||
|
|
30
|
+
err.kind === 'suspended'));
|
|
31
|
+
}
|
|
32
|
+
const RETRY_DELAY_MS = 1500;
|
|
33
|
+
export async function resolveTeamNamespace(home, opts = {}) {
|
|
34
|
+
const credential = readCredential(home);
|
|
35
|
+
// Not signed in: no request - a signed-out terminal has nothing to ask Cloud.
|
|
36
|
+
if (!credential)
|
|
37
|
+
return { status: 'local' };
|
|
38
|
+
const giveUp = new AbortController();
|
|
39
|
+
const timer = opts.deadlineMs === undefined ? null : setTimeout(() => giveUp.abort(), opts.deadlineMs);
|
|
40
|
+
const gaveUp = () => ({
|
|
41
|
+
status: 'unavailable',
|
|
42
|
+
reason: `did not wait for Cloud longer than ${Math.round((opts.deadlineMs ?? 0) / 1000)} s`,
|
|
43
|
+
});
|
|
44
|
+
try {
|
|
45
|
+
try {
|
|
46
|
+
return await attempt(credential, home, giveUp.signal);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (giveUp.signal.aborted)
|
|
50
|
+
return gaveUp();
|
|
51
|
+
if (noTeamToSpeakOf(err))
|
|
52
|
+
return { status: 'local' };
|
|
53
|
+
if (!transient(err))
|
|
54
|
+
return { status: 'unavailable', reason: describe(err) };
|
|
55
|
+
}
|
|
56
|
+
await new Promise((resolve) => setTimeout(resolve, opts.retryDelayMs ?? RETRY_DELAY_MS));
|
|
57
|
+
if (giveUp.signal.aborted)
|
|
58
|
+
return gaveUp();
|
|
59
|
+
try {
|
|
60
|
+
return await attempt(credential, home, giveUp.signal);
|
|
61
|
+
}
|
|
62
|
+
catch (again) {
|
|
63
|
+
if (giveUp.signal.aborted)
|
|
64
|
+
return gaveUp();
|
|
65
|
+
if (noTeamToSpeakOf(again))
|
|
66
|
+
return { status: 'local' };
|
|
67
|
+
return { status: 'unavailable', reason: describe(again) };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
if (timer)
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function describe(err) {
|
|
76
|
+
if (err instanceof CloudError)
|
|
77
|
+
return `${err.message}${err.status ? ` (HTTP ${err.status})` : ''}`;
|
|
78
|
+
return err instanceof Error ? err.message : String(err);
|
|
79
|
+
}
|
|
80
|
+
async function attempt(credential, home, signal) {
|
|
81
|
+
const list = await listMaps(credential, signal);
|
|
82
|
+
// An older self-hosted Cloud may still merge server-side; that answer needs no
|
|
83
|
+
// key. It carries no aliases or conflicts - it predates both.
|
|
84
|
+
if (list.teamNamespace) {
|
|
85
|
+
return {
|
|
86
|
+
status: 'team',
|
|
87
|
+
analysis: { namespace: list.teamNamespace, aliases: {}, conflicts: {}, highest: {} },
|
|
88
|
+
conflictDetection: false,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const teamId = list.team?.id;
|
|
92
|
+
if (!teamId)
|
|
93
|
+
return { status: 'local' };
|
|
94
|
+
const keys = await heldTeamKeys(credential, home, teamId);
|
|
95
|
+
if (keys.length === 0)
|
|
96
|
+
return { status: 'locked' };
|
|
97
|
+
const entries = await readTeamEntries(credential, keys, teamScopedMaps(list), signal);
|
|
98
|
+
// Every map unreadable is not a team namespace, it is a failed one.
|
|
99
|
+
if (entries.every((e) => e.map === null) && entries.length > 0) {
|
|
100
|
+
return { status: 'unavailable', reason: 'none of the team maps opened with the unlocked key' };
|
|
101
|
+
}
|
|
102
|
+
return { status: 'team', analysis: analyzeTeamNamespace(entries), conflictDetection: true };
|
|
103
|
+
}
|
|
104
|
+
/** A member's OWN team maps arrive under personalMaps - the listing splits by
|
|
105
|
+
* ownership, not by scope - so both lists are read. */
|
|
106
|
+
function teamScopedMaps(list) {
|
|
107
|
+
return [...list.personalMaps, ...list.teamMaps].filter((m) => m.scope === 'team');
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The team keys this machine has unlocked. Absent, expired, for another
|
|
111
|
+
* account or another team all read the same way: none.
|
|
112
|
+
*/
|
|
113
|
+
async function heldTeamKeys(credential, home, teamId) {
|
|
114
|
+
const unlock = readTeamUnlock({ instance: credential.instance, account: credential.account }, home);
|
|
115
|
+
if (!unlock || unlock.teamId !== teamId)
|
|
116
|
+
return [];
|
|
117
|
+
const keys = [];
|
|
118
|
+
for (const stored of unlock.keys) {
|
|
119
|
+
try {
|
|
120
|
+
keys.push({ version: stored.version, key: await importTeamKey(stored.key) });
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// A damaged entry is skipped: the others may still open the team's maps.
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return keys;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Every team map, opened with the held keys. One request where Cloud offers it;
|
|
131
|
+
* one per map only for an instance that predates it (404). A failure of the
|
|
132
|
+
* single request throws - a namespace missing a teammate's newest map restores
|
|
133
|
+
* their placeholders wrong - and the caller reports it.
|
|
134
|
+
*/
|
|
135
|
+
async function readTeamEntries(credential, keys, teamScoped, signal) {
|
|
136
|
+
let bulk;
|
|
137
|
+
try {
|
|
138
|
+
bulk = await getTeamEnvelopes(credential, signal);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
if (err instanceof CloudError && err.status === 404) {
|
|
142
|
+
return Promise.all(teamScoped.map((m) => openTeamMap(credential, m, keys, signal)));
|
|
143
|
+
}
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
return Promise.all(bulk.maps.map(async (row) => {
|
|
147
|
+
try {
|
|
148
|
+
const envelope = JSON.parse(row.map_data);
|
|
149
|
+
return { createdAt: row.created_at, map: await decryptTeamMapWithAny(keys, envelope) };
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// A version this member was never granted: skipped, not fatal.
|
|
153
|
+
return { createdAt: row.created_at, map: null };
|
|
154
|
+
}
|
|
155
|
+
}));
|
|
156
|
+
}
|
|
157
|
+
async function openTeamMap(credential, summary, keys, signal) {
|
|
158
|
+
try {
|
|
159
|
+
const full = await getMap(credential, summary.id, signal);
|
|
160
|
+
if (typeof full.map_data !== 'string')
|
|
161
|
+
return { createdAt: summary.created_at, map: full.map_data };
|
|
162
|
+
const envelope = JSON.parse(full.map_data);
|
|
163
|
+
return { createdAt: summary.created_at, map: await decryptTeamMapWithAny(keys, envelope) };
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return { createdAt: summary.created_at, map: null };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* What a restore says when it needed the team's maps and did not get them -
|
|
171
|
+
* the same words from `veilio restore` and the MCP's `restore_text`.
|
|
172
|
+
* `missing`: the placeholders the own map could not explain.
|
|
173
|
+
*/
|
|
174
|
+
export function teamLayerNote(result, missing) {
|
|
175
|
+
if (missing.length === 0)
|
|
176
|
+
return null;
|
|
177
|
+
if (result.status === 'team' && !result.conflictDetection)
|
|
178
|
+
return (`${missing.join(', ')} ${missing.length === 1 ? 'is' : 'are'} not in this project's map, and this ` +
|
|
179
|
+
'Cloud instance predates conflict detection, so its team namespace is not used to restore. ' +
|
|
180
|
+
"Restored from this project's map only.");
|
|
181
|
+
const which = `${missing.join(', ')} ${missing.length === 1 ? 'is' : 'are'} not in this project's map`;
|
|
182
|
+
if (result.status === 'locked')
|
|
183
|
+
return `${which}, and the team key is locked on this machine. Run \`veilio team unlock\`, then restore again.`;
|
|
184
|
+
if (result.status === 'unavailable')
|
|
185
|
+
return `${which}, and could not read the team's maps: ${result.reason}. Restored from this project's map only.`;
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=team-namespace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-namespace.js","sourceRoot":"","sources":["../src/team-namespace.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+CAA+C;AAC/C,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,6EAA6E;AAC7E,qBAAqB;AACrB,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,6EAA6E;AAC7E,sDAAsD;AAEtD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,aAAa,GAKd,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,cAAc,EAAmB,MAAM,iBAAiB,CAAA;AACjE,OAAO,EACL,UAAU,EACV,MAAM,EACN,gBAAgB,EAChB,QAAQ,GAGT,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAiBjD;;;;GAIG;AACH,SAAS,SAAS,CAAC,GAAY;IAC7B,OAAO,GAAG,YAAY,UAAU,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,aAAa,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;AAC3F,CAAC;AAED,SAAS,eAAe,CAAC,GAAY;IACnC,OAAO,CACL,GAAG,YAAY,UAAU;QACzB,CAAC,GAAG,CAAC,IAAI,KAAK,iBAAiB;YAC7B,GAAG,CAAC,IAAI,KAAK,YAAY;YACzB,GAAG,CAAC,IAAI,KAAK,WAAW;YACxB,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,CAC5B,CAAA;AACH,CAAC;AAED,MAAM,cAAc,GAAG,IAAI,CAAA;AAE3B,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAa,EACb,OAII,EAAE;IAEN,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;IACvC,8EAA8E;IAC9E,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;IAE3C,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAA;IACpC,MAAM,KAAK,GACT,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,UAAU,CAAC,CAAA;IAC1F,MAAM,MAAM,GAAG,GAAwB,EAAE,CAAC,CAAC;QACzC,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,sCAAsC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI;KAC5F,CAAC,CAAA;IACF,IAAI,CAAC;QACH,IAAI,CAAC;YACH,OAAO,MAAM,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;QACvD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO,MAAM,EAAE,CAAA;YAC1C,IAAI,eAAe,CAAC,GAAG,CAAC;gBAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;YACpD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;gBAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAA;QAC9E,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,IAAI,cAAc,CAAC,CAAC,CAAA;QACxF,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,MAAM,EAAE,CAAA;QAC1C,IAAI,CAAC;YACH,OAAO,MAAM,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO,MAAM,EAAE,CAAA;YAC1C,IAAI,eAAe,CAAC,KAAK,CAAC;gBAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;YACtD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAA;QAC3D,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAA;IAChC,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,GAAY;IAC5B,IAAI,GAAG,YAAY,UAAU;QAAE,OAAO,GAAG,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;IAClG,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AACzD,CAAC;AAED,KAAK,UAAU,OAAO,CACpB,UAAsB,EACtB,IAAwB,EACxB,MAAmB;IAEnB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAE/C,+EAA+E;IAC/E,8DAA8D;IAC9D,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,OAAO;YACL,MAAM,EAAE,MAAM;YACd,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;YACpF,iBAAiB,EAAE,KAAK;SACzB,CAAA;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,CAAA;IAC5B,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;IACvC,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;IACzD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;IAElD,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,UAAU,EAAE,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;IACrF,oEAAoE;IACpE,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/D,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,oDAAoD,EAAE,CAAA;IAChG,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,CAAC,OAAO,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAA;AAC7F,CAAC;AAED;wDACwD;AACxD,SAAS,cAAc,CAAC,IAAkB;IACxC,OAAO,CAAC,GAAG,IAAI,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAA;AACnF,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,YAAY,CACzB,UAAsB,EACtB,IAAwB,EACxB,MAAc;IAEd,MAAM,MAAM,GAAG,cAAc,CAC3B,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,EAC9D,IAAI,CACL,CAAA;IACD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,EAAE,CAAA;IAClD,MAAM,IAAI,GAA8C,EAAE,CAAA;IAC1D,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC9E,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;YACzE,SAAQ;QACV,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,eAAe,CAC5B,UAAsB,EACtB,IAAwD,EACxD,UAAsC,EACtC,MAAmB;IAEnB,IAAI,IAAkD,CAAA;IACtD,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IACnD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,UAAU,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACpD,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;QACrF,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAChB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAyB,EAAE;QACjD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAoB,CAAA;YAC5D,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAA;QACxF,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;YAC/D,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,CAAA;QACjD,CAAC;IACH,CAAC,CAAC,CACH,CAAA;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,UAAsB,EACtB,OAAwB,EACxB,IAAwD,EACxD,MAAmB;IAEnB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;QACzD,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ;YACnC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAA;QAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAoB,CAAA;QAC7D,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,UAAU,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAA;IAC5F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,CAAA;IACrD,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,MAA2B,EAC3B,OAA0B;IAE1B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACrC,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,MAAM,CAAC,iBAAiB;QACvD,OAAO,CACL,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,uCAAuC;YACnG,4FAA4F;YAC5F,wCAAwC,CACzC,CAAA;IACH,MAAM,KAAK,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,4BAA4B,CAAA;IACtG,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ;QAC5B,OAAO,GAAG,KAAK,+FAA+F,CAAA;IAChH,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa;QACjC,OAAO,GAAG,KAAK,yCAAyC,MAAM,CAAC,MAAM,0CAA0C,CAAA;IACjH,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export declare const TEAM_UNLOCK_FILE = "team-keys.json";
|
|
2
|
+
/** How long an unlock lasts unless asked for something shorter. */
|
|
3
|
+
export declare const DEFAULT_UNLOCK_DAYS = 7;
|
|
4
|
+
export interface StoredTeamKey {
|
|
5
|
+
version: number;
|
|
6
|
+
/** Raw AES-256 key, base64. */
|
|
7
|
+
key: string;
|
|
8
|
+
}
|
|
9
|
+
export interface TeamUnlock {
|
|
10
|
+
v: 1;
|
|
11
|
+
/** Bound to the instance and account that unlocked it, so a file left behind
|
|
12
|
+
* by one sign-in is never used by another. The same reasoning as the wrap
|
|
13
|
+
* context: material that is valid somewhere must not be valid everywhere. */
|
|
14
|
+
instance: string;
|
|
15
|
+
account: string;
|
|
16
|
+
teamId: string;
|
|
17
|
+
/** ISO-8601. Past this, reads return null and the file is ignored. */
|
|
18
|
+
expiresAt: string;
|
|
19
|
+
keys: StoredTeamKey[];
|
|
20
|
+
}
|
|
21
|
+
/** Where the unlocked keys live: beside the credential, not in a project. */
|
|
22
|
+
export declare function teamUnlockPath(home?: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* The unlocked keys, or null.
|
|
25
|
+
*
|
|
26
|
+
* Null means "not unlocked", for every reason it can mean that. `now` is
|
|
27
|
+
* injectable so the expiry can be tested without waiting a week.
|
|
28
|
+
*/
|
|
29
|
+
export declare function readTeamUnlock(binding: {
|
|
30
|
+
instance: string;
|
|
31
|
+
account: string;
|
|
32
|
+
}, home?: string, now?: Date): TeamUnlock | null;
|
|
33
|
+
/** Write the unlocked keys, readable only by this user. */
|
|
34
|
+
export declare function writeTeamUnlock(unlock: TeamUnlock, home?: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Remove the unlocked keys. Returns whether there were any to remove.
|
|
37
|
+
*
|
|
38
|
+
* Called by `team lock` and by `logout` — signing out must not leave live team
|
|
39
|
+
* keys behind, which would be exactly the gap between what a person believes
|
|
40
|
+
* they revoked and what is still readable on disk.
|
|
41
|
+
*
|
|
42
|
+
* A failure to DELETE throws rather than returning false, for the reason
|
|
43
|
+
* `removeCredential` gives: reporting "nothing to remove" while key material
|
|
44
|
+
* sits there inverts the whole point of the call.
|
|
45
|
+
*/
|
|
46
|
+
export declare function removeTeamUnlock(home?: string): boolean;
|
|
47
|
+
/** When an unlock made now should expire. */
|
|
48
|
+
export declare function expiryFrom(now: Date, days?: number): string;
|
|
49
|
+
//# sourceMappingURL=team-unlock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-unlock.d.ts","sourceRoot":"","sources":["../src/team-unlock.ts"],"names":[],"mappings":"AAwCA,eAAO,MAAM,gBAAgB,mBAAmB,CAAA;AAEhD,mEAAmE;AACnE,eAAO,MAAM,mBAAmB,IAAI,CAAA;AAEpC,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,CAAC,CAAA;IACJ;;kFAE8E;IAC9E,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,aAAa,EAAE,CAAA;CACtB;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,CAE/D;AAiBD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAC9C,IAAI,GAAE,MAAkB,EACxB,GAAG,GAAE,IAAiB,GACrB,UAAU,GAAG,IAAI,CAyBnB;AAED,2DAA2D;AAC3D,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,GAAE,MAAkB,GAAG,IAAI,CAQlF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,MAAkB,GAAG,OAAO,CASlE;AAED,6CAA6C;AAC7C,wBAAgB,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,GAAE,MAA4B,GAAG,MAAM,CAEhF"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// The team keys, unlocked for processes that have nobody to ask.
|
|
2
|
+
//
|
|
3
|
+
// An MCP server starts inside a coding agent. There is no terminal attached and
|
|
4
|
+
// no one present to type a vault passphrase, so a key it needs must have been
|
|
5
|
+
// put here by an earlier run in a terminal where somebody was. `veilio team
|
|
6
|
+
// unlock` is that run.
|
|
7
|
+
//
|
|
8
|
+
// WHAT THIS FILE HOLDS, AND WHY IT IS THE NARROWER OF TWO BAD OPTIONS
|
|
9
|
+
//
|
|
10
|
+
// It holds unwrapped TEAM keys. The obvious alternative — storing the vault key
|
|
11
|
+
// and re-deriving everything per process — is worse in every direction that
|
|
12
|
+
// matters: the vault key also opens every personal map, and unwraps the private
|
|
13
|
+
// key, which in turn opens any wrap ever addressed to this account, including
|
|
14
|
+
// ones granted after the file was written. A team key opens team maps and
|
|
15
|
+
// nothing else, and a team already shares them by construction.
|
|
16
|
+
//
|
|
17
|
+
// It is still real key material at rest. Whoever holds this file can read the
|
|
18
|
+
// team's maps until the keys rotate. It is written 0600 beside the session
|
|
19
|
+
// token, which is the same posture the token itself gets, and it expires — so a
|
|
20
|
+
// machine compromised weeks after somebody ran `unlock` does not hand over a
|
|
21
|
+
// live key for a forgotten session.
|
|
22
|
+
//
|
|
23
|
+
// WHAT IT DOES NOT SURVIVE
|
|
24
|
+
//
|
|
25
|
+
// A rotation. Removing a member mints a new version, and the copy here is of
|
|
26
|
+
// the old one, so maps rewritten under the new key stop opening. That is
|
|
27
|
+
// deliberate: the stale file degrades into "some maps cannot be read", which
|
|
28
|
+
// `decryptTeamMapWithAny` already handles by skipping them, rather than into
|
|
29
|
+
// continued access a rotation was meant to end. Re-running `unlock` picks up
|
|
30
|
+
// the new version.
|
|
31
|
+
//
|
|
32
|
+
// Reads tolerate everything, exactly as `credential.ts` does: a missing file,
|
|
33
|
+
// a corrupt one, an expired one and one belonging to another account all mean
|
|
34
|
+
// the same thing to every caller — not unlocked, resolve locally.
|
|
35
|
+
import { chmodSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
36
|
+
import { dirname, join } from 'node:path';
|
|
37
|
+
import { homedir } from 'node:os';
|
|
38
|
+
import { STORE_DIR } from '@veilio-inc/engine';
|
|
39
|
+
export const TEAM_UNLOCK_FILE = 'team-keys.json';
|
|
40
|
+
/** How long an unlock lasts unless asked for something shorter. */
|
|
41
|
+
export const DEFAULT_UNLOCK_DAYS = 7;
|
|
42
|
+
/** Where the unlocked keys live: beside the credential, not in a project. */
|
|
43
|
+
export function teamUnlockPath(home = homedir()) {
|
|
44
|
+
return join(home, STORE_DIR, TEAM_UNLOCK_FILE);
|
|
45
|
+
}
|
|
46
|
+
function isTeamUnlock(value) {
|
|
47
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
48
|
+
return false;
|
|
49
|
+
const u = value;
|
|
50
|
+
if (u.v !== 1)
|
|
51
|
+
return false;
|
|
52
|
+
for (const field of ['instance', 'account', 'teamId', 'expiresAt']) {
|
|
53
|
+
if (typeof u[field] !== 'string' || u[field] === '')
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (!Array.isArray(u.keys) || u.keys.length === 0)
|
|
57
|
+
return false;
|
|
58
|
+
return u.keys.every((k) => {
|
|
59
|
+
if (typeof k !== 'object' || k === null)
|
|
60
|
+
return false;
|
|
61
|
+
const key = k;
|
|
62
|
+
return typeof key.version === 'number' && typeof key.key === 'string' && key.key !== '';
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The unlocked keys, or null.
|
|
67
|
+
*
|
|
68
|
+
* Null means "not unlocked", for every reason it can mean that. `now` is
|
|
69
|
+
* injectable so the expiry can be tested without waiting a week.
|
|
70
|
+
*/
|
|
71
|
+
export function readTeamUnlock(binding, home = homedir(), now = new Date()) {
|
|
72
|
+
let raw;
|
|
73
|
+
try {
|
|
74
|
+
raw = readFileSync(teamUnlockPath(home), 'utf8');
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
let parsed;
|
|
80
|
+
try {
|
|
81
|
+
parsed = JSON.parse(raw);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
if (!isTeamUnlock(parsed))
|
|
87
|
+
return null;
|
|
88
|
+
// Someone else's unlock, or one from another instance. Not an error — a
|
|
89
|
+
// machine can be signed in to a self-hosted instance today and to the hosted
|
|
90
|
+
// one tomorrow, and the leftover file is simply not ours.
|
|
91
|
+
if (parsed.instance !== binding.instance || parsed.account !== binding.account)
|
|
92
|
+
return null;
|
|
93
|
+
const expiresAt = Date.parse(parsed.expiresAt);
|
|
94
|
+
if (Number.isNaN(expiresAt) || expiresAt <= now.getTime())
|
|
95
|
+
return null;
|
|
96
|
+
return parsed;
|
|
97
|
+
}
|
|
98
|
+
/** Write the unlocked keys, readable only by this user. */
|
|
99
|
+
export function writeTeamUnlock(unlock, home = homedir()) {
|
|
100
|
+
const path = teamUnlockPath(home);
|
|
101
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
102
|
+
// `chmodSync` after the write for the same reason `writeCredential` does it:
|
|
103
|
+
// `mode` applies only when the file is created, so re-unlocking over a
|
|
104
|
+
// world-readable file left from an earlier mistake would keep it that way.
|
|
105
|
+
writeFileSync(path, `${JSON.stringify(unlock, null, 2)}\n`, { mode: 0o600 });
|
|
106
|
+
chmodSync(path, 0o600);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Remove the unlocked keys. Returns whether there were any to remove.
|
|
110
|
+
*
|
|
111
|
+
* Called by `team lock` and by `logout` — signing out must not leave live team
|
|
112
|
+
* keys behind, which would be exactly the gap between what a person believes
|
|
113
|
+
* they revoked and what is still readable on disk.
|
|
114
|
+
*
|
|
115
|
+
* A failure to DELETE throws rather than returning false, for the reason
|
|
116
|
+
* `removeCredential` gives: reporting "nothing to remove" while key material
|
|
117
|
+
* sits there inverts the whole point of the call.
|
|
118
|
+
*/
|
|
119
|
+
export function removeTeamUnlock(home = homedir()) {
|
|
120
|
+
const path = teamUnlockPath(home);
|
|
121
|
+
try {
|
|
122
|
+
statSync(path);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
rmSync(path, { recursive: true, force: true });
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
/** When an unlock made now should expire. */
|
|
131
|
+
export function expiryFrom(now, days = DEFAULT_UNLOCK_DAYS) {
|
|
132
|
+
return new Date(now.getTime() + days * 24 * 60 * 60 * 1000).toISOString();
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=team-unlock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-unlock.js","sourceRoot":"","sources":["../src/team-unlock.ts"],"names":[],"mappings":"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"}
|