or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

http-tunneling.mdindex.mdkey-management.mdport-forwarding.mdsftp-operations.mdssh-agents.mdssh-client.mdssh-server.md

ssh-server.mddocs/

0

# SSH Server

1

2

Complete SSH server implementation for hosting SSH services with comprehensive authentication handling, session management, and client connection support.

3

4

## Capabilities

5

6

### Server Class

7

8

Creates and manages SSH server instances with full protocol support.

9

10

```javascript { .api }

11

/**

12

* SSH server for hosting SSH services

13

* Extends net.Server for network connection handling

14

*/

15

class Server extends net.Server {

16

constructor(config: ServerConfig, connectionListener?: ConnectionListener);

17

maxConnections: number;

18

}

19

20

interface ServerConfig {

21

// Required: Host keys for server identity

22

hostKeys: Array<Buffer | string | ParsedKey>;

23

24

// Protocol settings

25

algorithms?: AlgorithmList;

26

ident?: string;

27

banner?: string;

28

greeting?: string;

29

keepaliveInterval?: number;

30

keepaliveCountMax?: number;

31

32

// Debugging

33

debug?: DebugFunction;

34

}

35

36

type ConnectionListener = (client: IncomingClient, info: ClientInfo) => void;

37

38

interface ClientInfo {

39

ip: string;

40

header: {

41

identRaw: string;

42

versions: {

43

protocol: string;

44

software: string;

45

};

46

comments?: string;

47

};

48

}

49

```

50

51

**Usage Examples:**

52

53

```javascript

54

const { Server } = require('ssh2');

55

const fs = require('fs');

56

57

// Basic server setup

58

const hostKey = fs.readFileSync('host.key');

59

60

const server = new Server({

61

hostKeys: [hostKey]

62

}, (client) => {

63

console.log('Client connected!');

64

65

client.on('authentication', (ctx) => {

66

console.log(`Auth attempt: ${ctx.method} for ${ctx.username}`);

67

68

if (ctx.method === 'password') {

69

if (ctx.username === 'admin' && ctx.password === 'secret') {

70

ctx.accept();

71

} else {

72

ctx.reject();

73

}

74

} else {

75

ctx.reject(['password']);

76

}

77

});

78

});

79

80

server.listen(2222, '0.0.0.0', () => {

81

console.log('SSH server listening on port 2222');

82

});

83

```

84

85

### IncomingClient Class

86

87

Represents a connected SSH client with authentication and session management.

88

89

```javascript { .api }

90

/**

91

* Server-side representation of connected SSH client

92

* Extends EventEmitter for client lifecycle events

93

*/

94

class IncomingClient extends EventEmitter {

95

// Connection properties

96

authenticated: boolean;

97

noMoreSessions: boolean;

98

99

// Connection management

100

end(): boolean;

101

setNoDelay(noDelay?: boolean): boolean;

102

rekey(callback?: StatusCallback): boolean;

103

104

// Port forwarding

105

forwardOut(

106

boundAddr: string,

107

boundPort: number,

108

remoteAddr: string,

109

remotePort: number,

110

callback: ForwardOutCallback

111

): boolean;

112

113

// X11 forwarding

114

x11(

115

originAddr: string,

116

originPort: number,

117

callback: X11ForwardCallback

118

): boolean;

119

120

// OpenSSH extensions

121

openssh_forwardOutStreamLocal(

122

socketPath: string,

123

callback: ForwardOutCallback

124

): boolean;

125

}

126

127

type ForwardOutCallback = (err: Error | null, stream?: ServerChannel) => void;

128

type X11ForwardCallback = (err: Error | null, stream?: ServerChannel) => void;

129

type StatusCallback = (err?: Error | null) => void;

130

```

131

132

### Authentication Context Classes

133

134

Comprehensive authentication handling for different authentication methods.

135

136

```javascript { .api }

137

/**

138

* Base authentication context for all authentication methods

139

*/

140

class AuthContext {

141

username: string;

142

user: string; // Alias for username

143

service: string;

144

method: string;

145

146

/**

147

* Accept the authentication attempt

148

*/

149

accept(): void;

150

151

/**

152

* Reject the authentication attempt

153

* @param methodsLeft - Optional array of allowed methods for continuation

154

* @param isPartial - Whether this is partial authentication success

155

*/

156

reject(methodsLeft?: string[], isPartial?: boolean): void;

157

}

158

159

/**

160

* Password authentication context

161

*/

162

class PwdAuthContext extends AuthContext {

163

password: string;

164

165

/**

166

* Request password change from client

167

* @param prompt - Password change prompt message

168

* @param callback - Callback receiving new password

169

*/

170

requestChange(prompt: string, callback: PasswordChangeCallback): void;

171

}

172

173

/**

174

* Public key authentication context

175

*/

176

class PKAuthContext extends AuthContext {

177

key: ParsedKey;

178

signature?: Buffer;

179

blob: Buffer;

180

hashAlgo?: string;

181

}

182

183

/**

184

* Host-based authentication context

185

*/

186

class HostbasedAuthContext extends PKAuthContext {

187

localHostname: string;

188

localUsername: string;

189

}

190

191

/**

192

* Keyboard-interactive authentication context

193

*/

194

class KeyboardAuthContext extends AuthContext {

195

submethods: string[];

196

197

/**

198

* Send prompts to client for keyboard-interactive authentication

199

* @param prompts - Array of prompts to send

200

* @param title - Optional title for prompt dialog

201

* @param instructions - Optional instructions

202

* @param callback - Callback receiving user responses

203

*/

204

prompt(

205

prompts: KeyboardPrompt[],

206

title?: string,

207

instructions?: string,

208

callback: KeyboardResponseCallback

209

): void;

210

}

211

212

type PasswordChangeCallback = (newPassword: string) => void;

213

type KeyboardResponseCallback = (responses: string[]) => void;

214

```

215

216

**Authentication Examples:**

217

218

```javascript

219

client.on('authentication', (ctx) => {

220

console.log(`Authentication attempt: ${ctx.method} for user ${ctx.username}`);

221

222

switch (ctx.method) {

223

case 'password':

224

if (ctx.username === 'admin' && ctx.password === 'secret') {

225

ctx.accept();

226

} else {

227

ctx.reject();

228

}

229

break;

230

231

case 'publickey':

232

// Verify public key against authorized keys

233

const authorizedKey = getAuthorizedKey(ctx.username);

234

if (ctx.key.type === authorizedKey.type &&

235

ctx.key.public.equals(authorizedKey.public)) {

236

if (ctx.signature) {

237

// Verify signature if provided

238

const sigOK = ctx.key.verify(getAuthData(ctx), ctx.signature, ctx.hashAlgo);

239

if (sigOK) {

240

ctx.accept();

241

} else {

242

ctx.reject();

243

}

244

} else {

245

ctx.accept(); // Key is acceptable, signature will be checked on next attempt

246

}

247

} else {

248

ctx.reject();

249

}

250

break;

251

252

case 'keyboard-interactive':

253

ctx.prompt([

254

{ prompt: 'Password: ', echo: false },

255

{ prompt: 'Token: ', echo: false }

256

], 'Two-Factor Authentication', 'Please provide password and token', (responses) => {

257

if (responses[0] === 'secret' && responses[1] === '123456') {

258

ctx.accept();

259

} else {

260

ctx.reject();

261

}

262

});

263

break;

264

265

default:

266

ctx.reject(['password', 'publickey']);

267

}

268

});

269

```

270

271

### Session Management

272

273

Handle client session requests for shells, commands, and subsystems.

274

275

```javascript { .api }

276

/**

277

* Session represents a client session request

278

*/

279

interface Session extends EventEmitter {

280

// Session type events

281

on(event: 'shell', listener: (accept: AcceptSession, reject: RejectSession) => void): this;

282

on(event: 'exec', listener: (accept: AcceptSession, reject: RejectSession, info: ExecInfo) => void): this;

283

on(event: 'subsystem', listener: (accept: AcceptSession, reject: RejectSession, info: SubsystemInfo) => void): this;

284

on(event: 'sftp', listener: (accept: AcceptSession, reject: RejectSession) => void): this;

285

286

// Session control events

287

on(event: 'pty', listener: (accept: AcceptPty, reject: RejectPty, info: PtyInfo) => void): this;

288

on(event: 'window-change', listener: (accept: AcceptWindowChange, reject: RejectWindowChange, info: WindowChangeInfo) => void): this;

289

on(event: 'x11', listener: (accept: AcceptX11, reject: RejectX11, info: X11RequestInfo) => void): this;

290

on(event: 'env', listener: (accept: AcceptEnv, reject: RejectEnv, info: EnvInfo) => void): this;

291

on(event: 'signal', listener: (accept: AcceptSignal, reject: RejectSignal, info: SignalInfo) => void): this;

292

on(event: 'auth-agent', listener: (accept: AcceptAgent, reject: RejectAgent) => void): this;

293

294

// Session lifecycle

295

on(event: 'end', listener: () => void): this;

296

on(event: 'close', listener: () => void): this;

297

}

298

299

interface ExecInfo {

300

command: string;

301

}

302

303

interface SubsystemInfo {

304

name: string;

305

}

306

307

interface PtyInfo {

308

cols: number;

309

rows: number;

310

width: number;

311

height: number;

312

term: string;

313

modes: { [mode: string]: number };

314

}

315

316

interface WindowChangeInfo {

317

cols: number;

318

rows: number;

319

width: number;

320

height: number;

321

}

322

323

interface X11RequestInfo {

324

single: boolean;

325

protocol: string;

326

cookie: string;

327

screen: number;

328

}

329

330

interface EnvInfo {

331

key: string;

332

val: string;

333

}

334

335

interface SignalInfo {

336

name: string;

337

}

338

339

type AcceptSession = () => ServerChannel;

340

type RejectSession = () => boolean;

341

type AcceptPty = () => void;

342

type RejectPty = () => boolean;

343

type AcceptWindowChange = () => void;

344

type RejectWindowChange = () => boolean;

345

type AcceptX11 = () => void;

346

type RejectX11 = () => boolean;

347

type AcceptEnv = () => void;

348

type RejectEnv = () => boolean;

349

type AcceptSignal = () => void;

350

type RejectSignal = () => boolean;

351

type AcceptAgent = () => void;

352

type RejectAgent = () => boolean;

353

```

354

355

**Session Handling Examples:**

356

357

```javascript

358

client.on('ready', () => {

359

console.log('Client authenticated!');

360

361

client.on('session', (accept, reject) => {

362

const session = accept();

363

364

session.on('shell', (accept, reject) => {

365

const stream = accept();

366

console.log('Client requested shell');

367

368

// Set up shell interaction

369

stream.write('Welcome to SSH server!\n$ ');

370

371

stream.on('data', (data) => {

372

const command = data.toString().trim();

373

console.log('Command received:', command);

374

375

if (command === 'exit') {

376

stream.exit(0);

377

stream.end();

378

} else {

379

stream.write(`Command output for: ${command}\n$ `);

380

}

381

});

382

});

383

384

session.on('exec', (accept, reject, info) => {

385

const stream = accept();

386

console.log('Client wants to execute:', info.command);

387

388

// Execute command and send output

389

stream.write(`Output of ${info.command}\n`);

390

stream.exit(0);

391

stream.end();

392

});

393

394

session.on('sftp', (accept, reject) => {

395

console.log('Client requested SFTP subsystem');

396

const sftpStream = accept();

397

// Set up SFTP handling...

398

});

399

});

400

});

401

```

402

403

## Events

404

405

### Server Events

406

407

```javascript { .api }

408

interface ServerEvents {

409

/**

410

* Emitted when a new client connects

411

*/

412

'connection': (client: IncomingClient, info: ClientInfo) => void;

413

414

/**

415

* Emitted when server error occurs

416

*/

417

'error': (err: Error) => void;

418

419

/**

420

* Emitted when server starts listening

421

*/

422

'listening': () => void;

423

424

/**

425

* Emitted when server is closed

426

*/

427

'close': () => void;

428

}

429

```

430

431

### Client Events

432

433

```javascript { .api }

434

interface IncomingClientEvents {

435

/**

436

* Emitted for each authentication attempt

437

*/

438

'authentication': (ctx: AuthContext) => void;

439

440

/**

441

* Emitted when client is successfully authenticated

442

*/

443

'ready': () => void;

444

445

/**

446

* Emitted when client requests a new session

447

*/

448

'session': (accept: AcceptSession, reject: RejectSession) => void;

449

450

/**

451

* Emitted for direct TCP/IP connection requests (from local forwarding)

452

*/

453

'tcpip': (

454

accept: AcceptTcpip,

455

reject: RejectTcpip,

456

info: TcpipInfo

457

) => void;

458

459

/**

460

* Emitted for OpenSSH streamlocal connection requests

461

*/

462

'openssh.streamlocal': (

463

accept: AcceptStreamLocal,

464

reject: RejectStreamLocal,

465

info: StreamLocalInfo

466

) => void;

467

468

/**

469

* Emitted for global requests

470

*/

471

'request': (

472

accept: AcceptRequest,

473

reject: RejectRequest,

474

name: string,

475

info: RequestInfo

476

) => void;

477

478

/**

479

* Emitted when key re-exchange is initiated

480

*/

481

'rekey': () => void;

482

483

/**

484

* Emitted when client connection ends

485

*/

486

'end': () => void;

487

488

/**

489

* Emitted when client connection is closed

490

*/

491

'close': () => void;

492

493

/**

494

* Emitted when client connection error occurs

495

*/

496

'error': (err: Error) => void;

497

}

498

```

499

500

## Type Definitions

501

502

### Server Channel Types

503

504

```javascript { .api }

505

interface ServerChannel extends Duplex {

506

stderr: Writable;

507

508

/**

509

* Send exit status to client

510

*/

511

exit(status: number): boolean;

512

513

/**

514

* Send signal to client

515

*/

516

signal(signal: string): boolean;

517

518

/**

519

* Close the channel

520

*/

521

close(): boolean;

522

523

/**

524

* Set window size

525

*/

526

setWindow(rows: number, cols: number, height?: number, width?: number): boolean;

527

}

528

```

529

530

### Connection Request Types

531

532

```javascript { .api }

533

interface TcpipInfo {

534

srcIP: string;

535

srcPort: number;

536

destIP: string;

537

destPort: number;

538

}

539

540

interface StreamLocalInfo {

541

socketPath: string;

542

}

543

544

interface RequestInfo {

545

bindAddr?: string;

546

bindPort?: number;

547

socketPath?: string;

548

[key: string]: any;

549

}

550

551

type AcceptTcpip = () => ServerChannel;

552

type RejectTcpip = () => boolean;

553

type AcceptStreamLocal = () => ServerChannel;

554

type RejectStreamLocal = () => boolean;

555

type AcceptRequest = () => void;

556

type RejectRequest = () => boolean;

557

```

558

559

### Keyboard Interactive Types

560

561

```javascript { .api }

562

interface KeyboardPrompt {

563

prompt: string;

564

echo: boolean;

565

}

566

```