1
>
/*---------------------------------------------------------------------------------------------
localAgentHostMetadata.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import { execFile } from 'child_process';
7
>
import { createHash, randomBytes } from 'crypto';
8
>
import * as fs from 'fs';
9
>
import * as os from 'os';
10
>
import { join } from '../../../base/common/path.js';
11
>
import { vArray, vLiteral, vNumber, vObj, vString } from '../../../base/common/validation.js';
12
>
import { PROTOCOL_VERSION } from '../common/state/protocol/version/registry.js';
13
>
14
>
const metadataSchemaVersion = 1;
15
>
const metadataDirectoryName = 'agent-host';
16
>
const endpointDirectoryName = 'local-endpoint';
17
>
const metadataFileName = 'metadata.json';
18
>
19
>
export interface ILocalAgentHostEndpointMetadata {
20
>
readonly type: 'editor';
21
>
readonly schemaVersion: typeof metadataSchemaVersion;
22
>
readonly pid: number;
23
>
readonly instanceId: string;
24
>
readonly endpointPath: string;
25
>
readonly connectionToken: string;
26
>
readonly protocolVersion: string;
27
>
}
28
>
29
>
const metadataValidator = vArray(vObj({
30
>
type: vLiteral('editor'),
31
>
schemaVersion: vNumber(),
32
>
pid: vNumber(),
33
>
instanceId: vString(),
34
>
endpointPath: vString(),
35
>
connectionToken: vString(),
36
>
protocolVersion: vString(),
37
>
}));
38
>
39
>
export function createLocalAgentHostEndpointMetadata(userDataPath: string): ILocalAgentHostEndpointMetadata {
40
>
const instanceId = randomBytes(16).toString('base64url');
41
>
return {
42
>
type: 'editor',
43
>
schemaVersion: metadataSchemaVersion,
44
>
pid: process.pid,
45
>
instanceId,
46
>
endpointPath: getEndpointPath(userDataPath, instanceId),
47
>
connectionToken: randomBytes(32).toString('base64url'),
48
>
protocolVersion: PROTOCOL_VERSION,
49
>
};
50
>
}
51
>
52
>
export async function prepareLocalAgentHostEndpointMetadataDirectory(userDataPath: string): Promise<void> {
53
>
const directory = getMetadataDirectory(userDataPath);
54
>
await fs.promises.mkdir(directory, { recursive: true, mode: 0o700 });
55
>
const stat = await fs.promises.lstat(directory);
56
>
if (!stat.isDirectory() || stat.isSymbolicLink()) {
57
throw new Error(`Local agent host endpoint metadata directory is not a directory: ${directory}`);
58
}
60
>
if (process.platform === 'win32') {
61
await applyWindowsOwnerOnlyAcl(directory);
63
>
if (process.getuid && stat.uid !== process.getuid()) {
64
throw new Error(`Local agent host endpoint metadata directory is not owned by the current user: ${directory}`);
65
}
67
>
}
68
>
}
69
>
70
>
export async function prepareLocalAgentHostEndpointSocketDirectory(userDataPath: string): Promise<void> {
71
>
if (process.platform !== 'win32') {
72
>
const directory = getSocketDirectory(userDataPath);
73
>
await fs.promises.mkdir(directory, { recursive: true, mode: 0o700 });
74
>
const stat = await fs.promises.lstat(directory);
75
>
if (!stat.isDirectory() || stat.isSymbolicLink()) {
76
throw new Error(`Local agent host endpoint socket directory is not a directory: ${directory}`);
77
}
79
throw new Error(`Local agent host endpoint socket directory is not owned by the current user: ${directory}`);
80
}
82
>
}
83
>
}
84
>
85
export async function publishLocalAgentHostEndpointMetadata(userDataPath: string, metadata: ILocalAgentHostEndpointMetadata): Promise<void> {
86
const metadataPath = getMetadataPath(userDataPath);