@lemoncat7/dsh-ssh 0.1.0-alpha.15
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 +21 -0
- package/README.md +105 -0
- package/cordis.patch.yml +10 -0
- package/lib/api.d.ts +23 -0
- package/lib/api.d.ts.map +1 -0
- package/lib/api.js +571 -0
- package/lib/api.js.map +1 -0
- package/lib/client-api.d.ts +174 -0
- package/lib/client-api.d.ts.map +1 -0
- package/lib/client-api.js +88 -0
- package/lib/client-api.js.map +1 -0
- package/lib/client.d.ts +4 -0
- package/lib/client.d.ts.map +1 -0
- package/lib/client.js +8067 -0
- package/lib/client.js.map +7 -0
- package/lib/config.d.ts +14 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +31 -0
- package/lib/config.js.map +1 -0
- package/lib/connector.d.ts +30 -0
- package/lib/connector.d.ts.map +1 -0
- package/lib/connector.js +216 -0
- package/lib/connector.js.map +1 -0
- package/lib/credentials.d.ts +25 -0
- package/lib/credentials.d.ts.map +1 -0
- package/lib/credentials.js +84 -0
- package/lib/credentials.js.map +1 -0
- package/lib/directory.d.ts +8 -0
- package/lib/directory.d.ts.map +1 -0
- package/lib/directory.js +45 -0
- package/lib/directory.js.map +1 -0
- package/lib/domain.d.ts +121 -0
- package/lib/domain.d.ts.map +1 -0
- package/lib/domain.js +136 -0
- package/lib/domain.js.map +1 -0
- package/lib/exec.d.ts +15 -0
- package/lib/exec.d.ts.map +1 -0
- package/lib/exec.js +82 -0
- package/lib/exec.js.map +1 -0
- package/lib/forwards.d.ts +26 -0
- package/lib/forwards.d.ts.map +1 -0
- package/lib/forwards.js +213 -0
- package/lib/forwards.js.map +1 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +53 -0
- package/lib/index.js.map +1 -0
- package/lib/proxy.d.ts +9 -0
- package/lib/proxy.d.ts.map +1 -0
- package/lib/proxy.js +116 -0
- package/lib/proxy.js.map +1 -0
- package/lib/sftp-client.d.ts +12 -0
- package/lib/sftp-client.d.ts.map +1 -0
- package/lib/sftp-client.js +123 -0
- package/lib/sftp-client.js.map +1 -0
- package/lib/sftp.d.ts +43 -0
- package/lib/sftp.d.ts.map +1 -0
- package/lib/sftp.js +251 -0
- package/lib/sftp.js.map +1 -0
- package/lib/sidebar-anchor.d.ts +8 -0
- package/lib/sidebar-anchor.d.ts.map +1 -0
- package/lib/sidebar-anchor.js +50 -0
- package/lib/sidebar-anchor.js.map +1 -0
- package/lib/store.d.ts +20 -0
- package/lib/store.d.ts.map +1 -0
- package/lib/store.js +154 -0
- package/lib/store.js.map +1 -0
- package/lib/terminal.d.ts +108 -0
- package/lib/terminal.d.ts.map +1 -0
- package/lib/terminal.js +384 -0
- package/lib/terminal.js.map +1 -0
- package/lib/tools.d.ts +7 -0
- package/lib/tools.d.ts.map +1 -0
- package/lib/tools.js +237 -0
- package/lib/tools.js.map +1 -0
- package/package.json +107 -0
package/lib/config.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Schema from '@deepseek-ai/schemastery';
|
|
2
|
+
export interface Config {
|
|
3
|
+
statePath: string;
|
|
4
|
+
exposeWeb: boolean;
|
|
5
|
+
apiPrefix: string;
|
|
6
|
+
defaultCommandTimeoutMs: number;
|
|
7
|
+
maxOutputChars: number;
|
|
8
|
+
allowPublicBind: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const Config: Schema<Config>;
|
|
11
|
+
export interface ResolvedConfig extends Config {
|
|
12
|
+
}
|
|
13
|
+
export declare function resolveConfig(config: Config): ResolvedConfig;
|
|
14
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAE7C,MAAM,WAAW,MAAM;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,uBAAuB,EAAE,MAAM,CAAA;IAC/B,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,OAAO,CAAA;CACzB;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,CAOhC,CAAA;AAEF,MAAM,WAAW,cAAe,SAAQ,MAAM;CAAG;AAEjD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAW5D"}
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import Schema from '@deepseek-ai/schemastery';
|
|
2
|
+
export const Config = Schema.object({
|
|
3
|
+
statePath: Schema.string().required(),
|
|
4
|
+
exposeWeb: Schema.boolean().default(true),
|
|
5
|
+
apiPrefix: Schema.string().default('/ssh-local/v1'),
|
|
6
|
+
defaultCommandTimeoutMs: Schema.number().min(1000).max(300_000).default(30_000),
|
|
7
|
+
maxOutputChars: Schema.number().min(1000).max(1_000_000).default(32_000),
|
|
8
|
+
allowPublicBind: Schema.boolean().default(false),
|
|
9
|
+
});
|
|
10
|
+
export function resolveConfig(config) {
|
|
11
|
+
const apiPrefix = normalizePrefix(config.apiPrefix ?? '/ssh-local/v1');
|
|
12
|
+
if (!config.statePath?.trim())
|
|
13
|
+
throw new Error('dsh-ssh requires statePath');
|
|
14
|
+
return {
|
|
15
|
+
statePath: config.statePath,
|
|
16
|
+
exposeWeb: config.exposeWeb ?? true,
|
|
17
|
+
apiPrefix,
|
|
18
|
+
defaultCommandTimeoutMs: config.defaultCommandTimeoutMs ?? 30_000,
|
|
19
|
+
maxOutputChars: config.maxOutputChars ?? 32_000,
|
|
20
|
+
allowPublicBind: config.allowPublicBind ?? false,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function normalizePrefix(value) {
|
|
24
|
+
const trimmed = value.trim();
|
|
25
|
+
const withSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
26
|
+
const normalized = withSlash.endsWith('/') ? withSlash.slice(0, -1) : withSlash;
|
|
27
|
+
if (!/^\/[a-zA-Z0-9/_-]+$/.test(normalized))
|
|
28
|
+
throw new Error('apiPrefix must be an absolute URL path');
|
|
29
|
+
return normalized;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAW7C,MAAM,CAAC,MAAM,MAAM,GAAmB,MAAM,CAAC,MAAM,CAAC;IAClD,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACrC,SAAS,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC;IACnD,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAC/E,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACxE,eAAe,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CACjD,CAAC,CAAA;AAIF,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,SAAS,IAAI,eAAe,CAAC,CAAA;IACtE,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;IAC5E,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;QACnC,SAAS;QACT,uBAAuB,EAAE,MAAM,CAAC,uBAAuB,IAAI,MAAM;QACjE,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,MAAM;QAC/C,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,KAAK;KACjD,CAAA;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5B,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAA;IACnE,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC/E,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IACtG,OAAO,UAAU,CAAA;AACnB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Client as SshClient } from 'ssh2';
|
|
2
|
+
import { SshCredentialVault } from './credentials.js';
|
|
3
|
+
import type { SshCredentialPayload, SshProfile } from './domain.js';
|
|
4
|
+
import { SshStore } from './store.js';
|
|
5
|
+
export declare class HostKeyRequiredError extends Error {
|
|
6
|
+
readonly profileId: string;
|
|
7
|
+
readonly fingerprint: string;
|
|
8
|
+
readonly code = "HOST_KEY_REQUIRED";
|
|
9
|
+
constructor(profileId: string, fingerprint: string);
|
|
10
|
+
}
|
|
11
|
+
export declare class SshConnector {
|
|
12
|
+
private readonly store;
|
|
13
|
+
private readonly credentials;
|
|
14
|
+
constructor(store: SshStore, credentials: SshCredentialVault);
|
|
15
|
+
connect(profileId: string, signal?: AbortSignal): Promise<ManagedSshConnection>;
|
|
16
|
+
connectDraft(profile: SshProfile, secrets: SshCredentialPayload, signal?: AbortSignal): Promise<ManagedSshConnection>;
|
|
17
|
+
private connectRecursive;
|
|
18
|
+
private connectResolved;
|
|
19
|
+
private connectJumpChain;
|
|
20
|
+
private resolveIdentity;
|
|
21
|
+
}
|
|
22
|
+
export declare class ManagedSshConnection {
|
|
23
|
+
readonly client: SshClient;
|
|
24
|
+
readonly profile: SshProfile;
|
|
25
|
+
private readonly parent?;
|
|
26
|
+
private closed;
|
|
27
|
+
constructor(client: SshClient, profile: SshProfile, parent?: ManagedSshConnection | undefined);
|
|
28
|
+
close(): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=connector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../src/connector.ts"],"names":[],"mappings":"AAAA,OAAa,EAAE,KAAK,MAAM,IAAI,SAAS,EAA0C,MAAM,MAAM,CAAA;AAG7F,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAErC,qBAAa,oBAAqB,SAAQ,KAAK;IAEjC,QAAQ,CAAC,SAAS,EAAE,MAAM;IAAE,QAAQ,CAAC,WAAW,EAAE,MAAM;IADpE,QAAQ,CAAC,IAAI,uBAAsB;gBACd,SAAS,EAAE,MAAM,EAAW,WAAW,EAAE,MAAM;CAIrE;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,KAAK;IAAY,OAAO,CAAC,QAAQ,CAAC,WAAW;gBAA7C,KAAK,EAAE,QAAQ,EAAmB,WAAW,EAAE,kBAAkB;IAExF,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAI/E,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC;YAK7G,gBAAgB;YAUhB,eAAe;YA4Bf,gBAAgB;YAgChB,eAAe;CAS9B;AAED,qBAAa,oBAAoB;IAEnB,QAAQ,CAAC,MAAM,EAAE,SAAS;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU;IAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAD9F,OAAO,CAAC,MAAM,CAAQ;gBACD,MAAM,EAAE,SAAS,EAAW,OAAO,EAAE,UAAU,EAAmB,MAAM,CAAC,EAAE,oBAAoB,YAAA;IACpH,KAAK,IAAI,IAAI;CAMd"}
|
package/lib/connector.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import ssh2 from 'ssh2';
|
|
2
|
+
import { connectHttpProxy, connectSocks5Proxy } from './proxy.js';
|
|
3
|
+
export class HostKeyRequiredError extends Error {
|
|
4
|
+
profileId;
|
|
5
|
+
fingerprint;
|
|
6
|
+
code = 'HOST_KEY_REQUIRED';
|
|
7
|
+
constructor(profileId, fingerprint) {
|
|
8
|
+
super(`Host key confirmation required for ${profileId}: ${fingerprint}`);
|
|
9
|
+
this.profileId = profileId;
|
|
10
|
+
this.fingerprint = fingerprint;
|
|
11
|
+
this.name = 'HostKeyRequiredError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class SshConnector {
|
|
15
|
+
store;
|
|
16
|
+
credentials;
|
|
17
|
+
constructor(store, credentials) {
|
|
18
|
+
this.store = store;
|
|
19
|
+
this.credentials = credentials;
|
|
20
|
+
}
|
|
21
|
+
async connect(profileId, signal) {
|
|
22
|
+
return this.connectRecursive(profileId, new Set(), signal);
|
|
23
|
+
}
|
|
24
|
+
async connectDraft(profile, secrets, signal) {
|
|
25
|
+
const identity = profile.credentialId === undefined ? { profile, secrets } : await this.resolveIdentity(profile);
|
|
26
|
+
return this.connectResolved(identity.profile, identity.secrets, new Set([profile.id]), signal);
|
|
27
|
+
}
|
|
28
|
+
async connectRecursive(profileId, chain, signal) {
|
|
29
|
+
signal?.throwIfAborted();
|
|
30
|
+
if (chain.has(profileId))
|
|
31
|
+
throw new Error(`SSH jump proxy cycle detected at ${profileId}`);
|
|
32
|
+
const storedProfile = this.store.profile(profileId);
|
|
33
|
+
if (storedProfile === undefined)
|
|
34
|
+
throw Object.assign(new Error(`SSH profile ${profileId} was not found`), { status: 404 });
|
|
35
|
+
const { profile, secrets } = await this.resolveIdentity(storedProfile);
|
|
36
|
+
const nextChain = new Set(chain).add(profileId);
|
|
37
|
+
return this.connectResolved(profile, secrets, nextChain, signal);
|
|
38
|
+
}
|
|
39
|
+
async connectResolved(profile, secrets, chain, signal) {
|
|
40
|
+
signal?.throwIfAborted();
|
|
41
|
+
let socket;
|
|
42
|
+
let parent;
|
|
43
|
+
try {
|
|
44
|
+
if (profile.proxy.type === 'http') {
|
|
45
|
+
socket = await connectHttpProxy(profile.proxy.host, profile.proxy.port, profile.host, profile.port, {
|
|
46
|
+
...profile.proxy.username === undefined ? {} : { username: profile.proxy.username },
|
|
47
|
+
...secrets.proxyPassword === undefined ? {} : { password: secrets.proxyPassword },
|
|
48
|
+
}, profile.connectTimeoutMs);
|
|
49
|
+
}
|
|
50
|
+
else if (profile.proxy.type === 'socks5') {
|
|
51
|
+
socket = await connectSocks5Proxy(profile.proxy.host, profile.proxy.port, profile.host, profile.port, {
|
|
52
|
+
...profile.proxy.username === undefined ? {} : { username: profile.proxy.username },
|
|
53
|
+
...secrets.proxyPassword === undefined ? {} : { password: secrets.proxyPassword },
|
|
54
|
+
}, profile.connectTimeoutMs);
|
|
55
|
+
}
|
|
56
|
+
else if (profile.proxy.type === 'jump') {
|
|
57
|
+
parent = await this.connectJumpChain(profile.proxy.profileIds, chain, signal);
|
|
58
|
+
socket = await forwardOut(parent.client, profile.host, profile.port);
|
|
59
|
+
}
|
|
60
|
+
const client = await connectClient(profile, secrets, socket, signal);
|
|
61
|
+
return new ManagedSshConnection(client, profile, parent);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
socket?.destroy();
|
|
65
|
+
parent?.close();
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async connectJumpChain(profileIds, chain, signal) {
|
|
70
|
+
let parent;
|
|
71
|
+
let visited = new Set(chain);
|
|
72
|
+
try {
|
|
73
|
+
for (const profileId of profileIds) {
|
|
74
|
+
signal?.throwIfAborted();
|
|
75
|
+
if (visited.has(profileId))
|
|
76
|
+
throw new Error(`SSH jump proxy cycle detected at ${profileId}`);
|
|
77
|
+
if (parent === undefined) {
|
|
78
|
+
parent = await this.connectRecursive(profileId, visited, signal);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const storedProfile = this.store.profile(profileId);
|
|
82
|
+
if (storedProfile === undefined)
|
|
83
|
+
throw Object.assign(new Error(`SSH profile ${profileId} was not found`), { status: 404 });
|
|
84
|
+
const { profile, secrets } = await this.resolveIdentity(storedProfile);
|
|
85
|
+
const socket = await forwardOut(parent.client, profile.host, profile.port);
|
|
86
|
+
try {
|
|
87
|
+
const client = await connectClient(profile, secrets, socket, signal);
|
|
88
|
+
parent = new ManagedSshConnection(client, profile, parent);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
socket.destroy();
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
visited = new Set(visited).add(profileId);
|
|
96
|
+
}
|
|
97
|
+
if (parent === undefined)
|
|
98
|
+
throw new Error('SSH jump proxy chain is empty');
|
|
99
|
+
return parent;
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
parent?.close();
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async resolveIdentity(profile) {
|
|
107
|
+
if (profile.credentialId === undefined)
|
|
108
|
+
return { profile, secrets: await this.credentials.read(profile.id) };
|
|
109
|
+
const entry = this.store.credentialEntry(profile.credentialId);
|
|
110
|
+
if (entry === undefined)
|
|
111
|
+
throw new Error(`SSH credential entry ${profile.credentialId} was not found`);
|
|
112
|
+
return {
|
|
113
|
+
profile: { ...profile, username: entry.username, authType: entry.authType },
|
|
114
|
+
secrets: await this.credentials.readEntry(entry.id),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export class ManagedSshConnection {
|
|
119
|
+
client;
|
|
120
|
+
profile;
|
|
121
|
+
parent;
|
|
122
|
+
closed = false;
|
|
123
|
+
constructor(client, profile, parent) {
|
|
124
|
+
this.client = client;
|
|
125
|
+
this.profile = profile;
|
|
126
|
+
this.parent = parent;
|
|
127
|
+
}
|
|
128
|
+
close() {
|
|
129
|
+
if (this.closed)
|
|
130
|
+
return;
|
|
131
|
+
this.closed = true;
|
|
132
|
+
this.client.end();
|
|
133
|
+
this.parent?.close();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function connectClient(profile, secrets, socket, signal) {
|
|
137
|
+
const config = {
|
|
138
|
+
host: profile.host,
|
|
139
|
+
port: profile.port,
|
|
140
|
+
username: profile.username,
|
|
141
|
+
readyTimeout: profile.connectTimeoutMs,
|
|
142
|
+
keepaliveInterval: profile.keepAliveIntervalMs,
|
|
143
|
+
keepaliveCountMax: 3,
|
|
144
|
+
hostHash: 'sha256',
|
|
145
|
+
...socket === undefined ? {} : { sock: socket },
|
|
146
|
+
};
|
|
147
|
+
if (profile.authType === 'password') {
|
|
148
|
+
if (!secrets.password)
|
|
149
|
+
throw Object.assign(new Error('SSH password is not configured'), { code: 'CREDENTIAL_MISSING' });
|
|
150
|
+
config.password = secrets.password;
|
|
151
|
+
}
|
|
152
|
+
else if (profile.authType === 'private-key') {
|
|
153
|
+
if (!secrets.privateKey)
|
|
154
|
+
throw Object.assign(new Error('SSH private key is not configured'), { code: 'CREDENTIAL_MISSING' });
|
|
155
|
+
config.privateKey = secrets.privateKey;
|
|
156
|
+
if (secrets.passphrase)
|
|
157
|
+
config.passphrase = secrets.passphrase;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
const agent = process.env.SSH_AUTH_SOCK;
|
|
161
|
+
if (!agent)
|
|
162
|
+
throw Object.assign(new Error('SSH_AUTH_SOCK is not available in this DSH process'), { code: 'CREDENTIAL_MISSING' });
|
|
163
|
+
config.agent = agent;
|
|
164
|
+
}
|
|
165
|
+
let observedFingerprint;
|
|
166
|
+
config.hostVerifier = (fingerprint) => {
|
|
167
|
+
observedFingerprint = `SHA256:${fingerprint}`;
|
|
168
|
+
return profile.hostFingerprint !== undefined && timingSafeEqualText(profile.hostFingerprint, observedFingerprint);
|
|
169
|
+
};
|
|
170
|
+
const client = new ssh2.Client();
|
|
171
|
+
return new Promise((resolve, reject) => {
|
|
172
|
+
let settled = false;
|
|
173
|
+
const abort = () => { client.end(); finishReject(signal?.reason instanceof Error ? signal.reason : new Error('SSH connection was aborted')); };
|
|
174
|
+
const cleanup = () => {
|
|
175
|
+
signal?.removeEventListener('abort', abort);
|
|
176
|
+
client.off('ready', ready);
|
|
177
|
+
client.off('error', failed);
|
|
178
|
+
};
|
|
179
|
+
const finishReject = (error) => {
|
|
180
|
+
if (settled)
|
|
181
|
+
return;
|
|
182
|
+
settled = true;
|
|
183
|
+
cleanup();
|
|
184
|
+
if (profile.hostFingerprint === undefined && observedFingerprint !== undefined)
|
|
185
|
+
reject(new HostKeyRequiredError(profile.id, observedFingerprint));
|
|
186
|
+
else
|
|
187
|
+
reject(error);
|
|
188
|
+
};
|
|
189
|
+
const ready = () => { if (settled)
|
|
190
|
+
return; settled = true; cleanup(); resolve(client); };
|
|
191
|
+
const failed = (error) => finishReject(error);
|
|
192
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
193
|
+
client.once('ready', ready);
|
|
194
|
+
client.once('error', failed);
|
|
195
|
+
try {
|
|
196
|
+
client.connect(config);
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
finishReject(error instanceof Error ? error : new Error(String(error)));
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
function forwardOut(client, host, port) {
|
|
204
|
+
return new Promise((resolve, reject) => {
|
|
205
|
+
client.forwardOut('127.0.0.1', 0, host, port, (error, channel) => error ? reject(error) : resolve(channel));
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
function timingSafeEqualText(left, right) {
|
|
209
|
+
if (left.length !== right.length)
|
|
210
|
+
return false;
|
|
211
|
+
let mismatch = 0;
|
|
212
|
+
for (let index = 0; index < left.length; index += 1)
|
|
213
|
+
mismatch |= left.charCodeAt(index) ^ right.charCodeAt(index);
|
|
214
|
+
return mismatch === 0;
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=connector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector.js","sourceRoot":"","sources":["../src/connector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type CredentialProvider } from '@deepseek-ai/dsh-credentials';
|
|
2
|
+
import { type SshCredentialPayload } from './domain.js';
|
|
3
|
+
export declare class SshCredentialVault {
|
|
4
|
+
private readonly provider;
|
|
5
|
+
constructor(provider: CredentialProvider);
|
|
6
|
+
describe(profileId: string): Promise<{
|
|
7
|
+
configured: boolean;
|
|
8
|
+
writable: boolean;
|
|
9
|
+
fields: string[];
|
|
10
|
+
}>;
|
|
11
|
+
read(profileId: string): Promise<SshCredentialPayload>;
|
|
12
|
+
write(profileId: string, patch: SshCredentialPayload): Promise<void>;
|
|
13
|
+
replace(profileId: string, value: SshCredentialPayload): Promise<void>;
|
|
14
|
+
delete(profileId: string): Promise<void>;
|
|
15
|
+
describeEntry(entryId: string): Promise<{
|
|
16
|
+
configured: boolean;
|
|
17
|
+
writable: boolean;
|
|
18
|
+
fields: string[];
|
|
19
|
+
}>;
|
|
20
|
+
readEntry(entryId: string): Promise<SshCredentialPayload>;
|
|
21
|
+
writeEntry(entryId: string, patch: SshCredentialPayload): Promise<void>;
|
|
22
|
+
replaceEntry(entryId: string, value: SshCredentialPayload): Promise<void>;
|
|
23
|
+
deleteEntry(entryId: string): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,kBAAkB,EAAoB,MAAM,8BAA8B,CAAA;AACvG,OAAO,EAAkB,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAKvE,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,kBAAkB;IAEnD,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAMlG,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAOtD,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUpE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtE,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAMrG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAOzD,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IASvE,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzE,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGlD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { credentialKey } from '@deepseek-ai/dsh-credentials';
|
|
2
|
+
import { compactSecrets } from './domain.js';
|
|
3
|
+
const SCOPE = 'dsh-ssh';
|
|
4
|
+
const VAULT_SCOPE = 'dsh-ssh-vault';
|
|
5
|
+
export class SshCredentialVault {
|
|
6
|
+
provider;
|
|
7
|
+
constructor(provider) {
|
|
8
|
+
this.provider = provider;
|
|
9
|
+
}
|
|
10
|
+
async describe(profileId) {
|
|
11
|
+
const info = await this.provider.describeRecord(credentialKey(SCOPE, profileId));
|
|
12
|
+
const payload = await this.read(profileId);
|
|
13
|
+
return { configured: info.configured, writable: info.writable, fields: Object.keys(payload) };
|
|
14
|
+
}
|
|
15
|
+
async read(profileId) {
|
|
16
|
+
const record = await this.provider.readRecord(credentialKey(SCOPE, profileId));
|
|
17
|
+
if (record === undefined)
|
|
18
|
+
return {};
|
|
19
|
+
if (record.kind !== 'grant')
|
|
20
|
+
throw new Error(`SSH credential ${profileId} has an incompatible record type`);
|
|
21
|
+
return parsePayload(record.payload);
|
|
22
|
+
}
|
|
23
|
+
async write(profileId, patch) {
|
|
24
|
+
const key = credentialKey(SCOPE, profileId);
|
|
25
|
+
await this.provider.modifyRecord(key, async (current) => {
|
|
26
|
+
if (current !== undefined && current.kind !== 'grant')
|
|
27
|
+
throw new Error(`SSH credential ${profileId} has an incompatible record type`);
|
|
28
|
+
const previous = current === undefined ? {} : parsePayload(current.payload);
|
|
29
|
+
const payload = compactSecrets({ ...previous, ...patch });
|
|
30
|
+
return { kind: 'grant', payload };
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async replace(profileId, value) {
|
|
34
|
+
const payload = compactSecrets(value);
|
|
35
|
+
await this.provider.modifyRecord(credentialKey(SCOPE, profileId), async () => ({ kind: 'grant', payload }));
|
|
36
|
+
}
|
|
37
|
+
async delete(profileId) {
|
|
38
|
+
await this.provider.deleteRecord(credentialKey(SCOPE, profileId));
|
|
39
|
+
}
|
|
40
|
+
async describeEntry(entryId) {
|
|
41
|
+
const info = await this.provider.describeRecord(credentialKey(VAULT_SCOPE, entryId));
|
|
42
|
+
const payload = await this.readEntry(entryId);
|
|
43
|
+
return { configured: info.configured, writable: info.writable, fields: Object.keys(payload) };
|
|
44
|
+
}
|
|
45
|
+
async readEntry(entryId) {
|
|
46
|
+
const record = await this.provider.readRecord(credentialKey(VAULT_SCOPE, entryId));
|
|
47
|
+
if (record === undefined)
|
|
48
|
+
return {};
|
|
49
|
+
if (record.kind !== 'grant')
|
|
50
|
+
throw new Error(`SSH vault entry ${entryId} has an incompatible record type`);
|
|
51
|
+
return parsePayload(record.payload);
|
|
52
|
+
}
|
|
53
|
+
async writeEntry(entryId, patch) {
|
|
54
|
+
const key = credentialKey(VAULT_SCOPE, entryId);
|
|
55
|
+
await this.provider.modifyRecord(key, async (current) => {
|
|
56
|
+
if (current !== undefined && current.kind !== 'grant')
|
|
57
|
+
throw new Error(`SSH vault entry ${entryId} has an incompatible record type`);
|
|
58
|
+
const previous = current === undefined ? {} : parsePayload(current.payload);
|
|
59
|
+
return { kind: 'grant', payload: compactSecrets({ ...previous, ...patch }) };
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async replaceEntry(entryId, value) {
|
|
63
|
+
await this.provider.modifyRecord(credentialKey(VAULT_SCOPE, entryId), async () => ({ kind: 'grant', payload: compactSecrets(value) }));
|
|
64
|
+
}
|
|
65
|
+
async deleteEntry(entryId) {
|
|
66
|
+
await this.provider.deleteRecord(credentialKey(VAULT_SCOPE, entryId));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function parsePayload(value) {
|
|
70
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
71
|
+
throw new Error('stored SSH credential payload is invalid');
|
|
72
|
+
const input = value;
|
|
73
|
+
const result = {};
|
|
74
|
+
for (const field of ['password', 'privateKey', 'passphrase', 'proxyPassword']) {
|
|
75
|
+
const candidate = input[field];
|
|
76
|
+
if (candidate !== undefined) {
|
|
77
|
+
if (typeof candidate !== 'string' || candidate.length === 0)
|
|
78
|
+
throw new Error(`stored SSH credential field ${field} is invalid`);
|
|
79
|
+
result[field] = candidate;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SshConnector } from './connector.js';
|
|
2
|
+
import type { SessionInjection } from './domain.js';
|
|
3
|
+
import { SshStore } from './store.js';
|
|
4
|
+
export declare function sessionDirectory(injection: SessionInjection, profileId: string): string;
|
|
5
|
+
export declare function resolveRemoteDirectory(connector: SshConnector, profileId: string, requested: string, signal?: AbortSignal): Promise<string>;
|
|
6
|
+
export declare function setSessionDirectory(store: SshStore, connector: SshConnector, sessionId: string, profileId: string, requested: string, signal?: AbortSignal): Promise<string>;
|
|
7
|
+
export declare function normalizeRemoteDirectory(value: unknown): string;
|
|
8
|
+
//# sourceMappingURL=directory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../src/directory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAKrC,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvF;AAED,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,YAAY,EACvB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,CAejB;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,QAAQ,EACf,SAAS,EAAE,YAAY,EACvB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,CAajB;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAO/D"}
|
package/lib/directory.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { executeSshCommand } from './exec.js';
|
|
2
|
+
const DIRECTORY_PROBE_TIMEOUT_MS = 10_000;
|
|
3
|
+
const DIRECTORY_PROBE_OUTPUT_CHARS = 8_192;
|
|
4
|
+
export function sessionDirectory(injection, profileId) {
|
|
5
|
+
return injection.workingDirectories[profileId] ?? '~';
|
|
6
|
+
}
|
|
7
|
+
export async function resolveRemoteDirectory(connector, profileId, requested, signal) {
|
|
8
|
+
const cwd = normalizeRemoteDirectory(requested);
|
|
9
|
+
const result = await executeSshCommand(connector, profileId, 'pwd -P', DIRECTORY_PROBE_TIMEOUT_MS, DIRECTORY_PROBE_OUTPUT_CHARS, signal, cwd);
|
|
10
|
+
if (result.exitCode !== 0)
|
|
11
|
+
throw directoryProbeError(result);
|
|
12
|
+
const resolved = result.stdout.trim().split(/\r?\n/).at(-1)?.trim();
|
|
13
|
+
if (!resolved?.startsWith('/'))
|
|
14
|
+
throw new Error('SSH directory did not resolve to an absolute path');
|
|
15
|
+
return normalizeRemoteDirectory(resolved);
|
|
16
|
+
}
|
|
17
|
+
export async function setSessionDirectory(store, connector, sessionId, profileId, requested, signal) {
|
|
18
|
+
const injection = store.injection(sessionId);
|
|
19
|
+
if (injection === undefined || !injection.profileIds.includes(profileId)) {
|
|
20
|
+
throw Object.assign(new Error('SSH profile is not injected into this DSH session'), { status: 403 });
|
|
21
|
+
}
|
|
22
|
+
const cwd = await resolveRemoteDirectory(connector, profileId, requested, signal);
|
|
23
|
+
await store.update(state => {
|
|
24
|
+
const current = state.injections.find(item => item.sessionId === sessionId);
|
|
25
|
+
if (current === undefined || !current.profileIds.includes(profileId))
|
|
26
|
+
throw new Error('SSH session injection changed while resolving the directory');
|
|
27
|
+
current.workingDirectories[profileId] = cwd;
|
|
28
|
+
current.updatedAt = Date.now();
|
|
29
|
+
});
|
|
30
|
+
return cwd;
|
|
31
|
+
}
|
|
32
|
+
export function normalizeRemoteDirectory(value) {
|
|
33
|
+
if (typeof value !== 'string')
|
|
34
|
+
throw Object.assign(new Error('cwd must be a string'), { status: 400 });
|
|
35
|
+
const cwd = value.trim();
|
|
36
|
+
if (cwd.length === 0 || cwd.length > 4096 || /[\0\r\n]/.test(cwd)) {
|
|
37
|
+
throw Object.assign(new Error('cwd must contain 1-4096 characters without line breaks'), { status: 400 });
|
|
38
|
+
}
|
|
39
|
+
return cwd;
|
|
40
|
+
}
|
|
41
|
+
function directoryProbeError(result) {
|
|
42
|
+
const detail = result.stderr.trim() || result.stdout.trim() || `exit ${String(result.exitCode)}`;
|
|
43
|
+
return Object.assign(new Error(`Cannot use SSH directory: ${detail}`), { status: 400 });
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=directory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory.js","sourceRoot":"","sources":["../src/directory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAmB,MAAM,WAAW,CAAA;AAK9D,MAAM,0BAA0B,GAAG,MAAM,CAAA;AACzC,MAAM,4BAA4B,GAAG,KAAK,CAAA;AAE1C,MAAM,UAAU,gBAAgB,CAAC,SAA2B,EAAE,SAAiB;IAC7E,OAAO,SAAS,CAAC,kBAAkB,CAAC,SAAS,CAAC,IAAI,GAAG,CAAA;AACvD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,SAAuB,EACvB,SAAiB,EACjB,SAAiB,EACjB,MAAoB;IAEpB,MAAM,GAAG,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAA;IAC/C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CACpC,SAAS,EACT,SAAS,EACT,QAAQ,EACR,0BAA0B,EAC1B,4BAA4B,EAC5B,MAAM,EACN,GAAG,CACJ,CAAA;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC;QAAE,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAA;IAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;IACnE,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACpG,OAAO,wBAAwB,CAAC,QAAQ,CAAC,CAAA;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,KAAe,EACf,SAAuB,EACvB,SAAiB,EACjB,SAAiB,EACjB,SAAiB,EACjB,MAAoB;IAEpB,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;IAC5C,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACzE,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,mDAAmD,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IACtG,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAAA;IACjF,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QACzB,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAA;QAC3E,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAA;QACpJ,OAAO,CAAC,kBAAkB,CAAC,SAAS,CAAC,GAAG,GAAG,CAAA;QAC3C,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAChC,CAAC,CAAC,CAAA;IACF,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,KAAc;IACrD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IACtG,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IACxB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,IAAI,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,wDAAwD,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IAC3G,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,mBAAmB,CAAC,MAAkB;IAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,QAAQ,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAA;IAChG,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;AACzF,CAAC"}
|
package/lib/domain.d.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export type SshAuthType = 'password' | 'private-key' | 'agent';
|
|
2
|
+
export type ProxyConfig = {
|
|
3
|
+
type: 'none';
|
|
4
|
+
} | {
|
|
5
|
+
type: 'http';
|
|
6
|
+
host: string;
|
|
7
|
+
port: number;
|
|
8
|
+
username?: string;
|
|
9
|
+
} | {
|
|
10
|
+
type: 'socks5';
|
|
11
|
+
host: string;
|
|
12
|
+
port: number;
|
|
13
|
+
username?: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: 'jump';
|
|
16
|
+
profileIds: string[];
|
|
17
|
+
};
|
|
18
|
+
export interface SshProfile {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
group?: string;
|
|
22
|
+
host: string;
|
|
23
|
+
port: number;
|
|
24
|
+
username: string;
|
|
25
|
+
authType: SshAuthType;
|
|
26
|
+
credentialId?: string;
|
|
27
|
+
hostFingerprint?: string;
|
|
28
|
+
proxy: ProxyConfig;
|
|
29
|
+
keepAliveIntervalMs: number;
|
|
30
|
+
connectTimeoutMs: number;
|
|
31
|
+
terminalType: string;
|
|
32
|
+
tags: string[];
|
|
33
|
+
createdAt: number;
|
|
34
|
+
updatedAt: number;
|
|
35
|
+
}
|
|
36
|
+
export interface CredentialEntry {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
username: string;
|
|
40
|
+
authType: Exclude<SshAuthType, 'agent'>;
|
|
41
|
+
createdAt: number;
|
|
42
|
+
updatedAt: number;
|
|
43
|
+
}
|
|
44
|
+
export interface SshCredentialPayload {
|
|
45
|
+
password?: string;
|
|
46
|
+
privateKey?: string;
|
|
47
|
+
passphrase?: string;
|
|
48
|
+
proxyPassword?: string;
|
|
49
|
+
}
|
|
50
|
+
export type ForwardKind = 'local' | 'remote' | 'dynamic';
|
|
51
|
+
export interface ForwardRule {
|
|
52
|
+
id: string;
|
|
53
|
+
profileId: string;
|
|
54
|
+
name: string;
|
|
55
|
+
kind: ForwardKind;
|
|
56
|
+
bindHost: string;
|
|
57
|
+
bindPort: number;
|
|
58
|
+
targetHost?: string;
|
|
59
|
+
targetPort?: number;
|
|
60
|
+
autoStart: boolean;
|
|
61
|
+
createdAt: number;
|
|
62
|
+
updatedAt: number;
|
|
63
|
+
}
|
|
64
|
+
export interface SessionInjection {
|
|
65
|
+
sessionId: string;
|
|
66
|
+
profileIds: string[];
|
|
67
|
+
permission: 'exec' | 'terminal';
|
|
68
|
+
requireCommandApproval: boolean;
|
|
69
|
+
workingDirectories: Record<string, string>;
|
|
70
|
+
updatedAt: number;
|
|
71
|
+
}
|
|
72
|
+
export interface SshSettings {
|
|
73
|
+
allowPublicBind: boolean;
|
|
74
|
+
defaultCommandTimeoutMs: number;
|
|
75
|
+
maxOutputChars: number;
|
|
76
|
+
}
|
|
77
|
+
export interface SshState {
|
|
78
|
+
schemaVersion: 1;
|
|
79
|
+
profiles: SshProfile[];
|
|
80
|
+
credentialEntries: CredentialEntry[];
|
|
81
|
+
forwardRules: ForwardRule[];
|
|
82
|
+
injections: SessionInjection[];
|
|
83
|
+
settings: SshSettings;
|
|
84
|
+
}
|
|
85
|
+
export interface ProfileDraft {
|
|
86
|
+
name: string;
|
|
87
|
+
group?: string;
|
|
88
|
+
host: string;
|
|
89
|
+
port?: number;
|
|
90
|
+
username: string;
|
|
91
|
+
authType: SshAuthType;
|
|
92
|
+
credentialId?: string;
|
|
93
|
+
hostFingerprint?: string;
|
|
94
|
+
proxy?: ProxyConfig;
|
|
95
|
+
keepAliveIntervalMs?: number;
|
|
96
|
+
connectTimeoutMs?: number;
|
|
97
|
+
terminalType?: string;
|
|
98
|
+
tags?: string[];
|
|
99
|
+
}
|
|
100
|
+
export interface CredentialEntryDraft {
|
|
101
|
+
name: string;
|
|
102
|
+
username: string;
|
|
103
|
+
authType: Exclude<SshAuthType, 'agent'>;
|
|
104
|
+
}
|
|
105
|
+
export interface ForwardDraft {
|
|
106
|
+
profileId: string;
|
|
107
|
+
name: string;
|
|
108
|
+
kind: ForwardKind;
|
|
109
|
+
bindHost?: string;
|
|
110
|
+
bindPort: number;
|
|
111
|
+
targetHost?: string;
|
|
112
|
+
targetPort?: number;
|
|
113
|
+
autoStart?: boolean;
|
|
114
|
+
}
|
|
115
|
+
export declare function normalizeProfileDraft(value: unknown): ProfileDraft;
|
|
116
|
+
export declare function normalizeCredentialEntryDraft(value: unknown): CredentialEntryDraft;
|
|
117
|
+
export declare function normalizeForwardDraft(value: unknown): ForwardDraft;
|
|
118
|
+
export declare function normalizeSecrets(value: unknown): SshCredentialPayload;
|
|
119
|
+
export declare function compactSecrets(value: SshCredentialPayload): SshCredentialPayload;
|
|
120
|
+
export declare function isLoopbackHost(host: string): boolean;
|
|
121
|
+
//# sourceMappingURL=domain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../src/domain.ts"],"names":[],"mappings":"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"}
|