ftpd-lite 1.0.10 → 1.0.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/README.md CHANGED
@@ -1,39 +1,29 @@
1
1
  # ftpd-lite
2
2
  ![NPM Downloads](https://img.shields.io/npm/dw/ftpd-lite) ![Docker Pulls](https://img.shields.io/docker/pulls/asymmetricstar/docker-ftpd)
3
3
 
4
-
5
4
  Simple and lightweight FTP server written in Node.js + TypeScript.
6
5
  * multiple users
7
6
  * permission control
8
7
  * passive port support
9
-
8
+ * SQLite persistence (`ftpd.db`)
10
9
 
11
10
  ## Installation
11
+
12
12
  ```bash
13
13
  npm install ftpd-lite
14
14
  ```
15
15
 
16
16
  ## Quick Start
17
- It is imported as a library (`require`/`import`), and the port listening process starts when you call `start()`.
17
+
18
+ The package is imported as a library (`require` / `import`). The listening process starts when you call `start()`.
18
19
 
19
20
  ```js
20
21
  const { FtpServer } = require('ftpd-lite');
21
22
 
22
23
  const server = new FtpServer({
23
- ip: 0.0.0.0,
24
- port: 21,
25
- dataPort: 20,
26
- userFile: './users.json',
27
- maxConnections: 100,
28
- logLevel: 'info',
29
-
30
- // 220 welcome message (banner).
31
- // If left empty, it automatically writes "<port> FTP Server Ready".
24
+ dbPath: './ftpd.db', // SQLite database (users + settings tables)
32
25
  banner: '',
33
-
34
- // PASV (passive mode) data connection ports are selected from this range.
35
- // It must be the same as the range that needs to be opened in the firewall.
36
- passivePortRange: { min: 50000, max: 50050 },
26
+ logLevel: 'info',
37
27
  });
38
28
 
39
29
  server.start();
@@ -45,61 +35,53 @@ TypeScript:
45
35
  import { FtpServer, type ServerConfig } from 'ftpd-lite';
46
36
 
47
37
  const config: ServerConfig = {
48
- port: 21,
49
- dataPort: 20,
50
- userFile: './users.json',
51
- maxConnections: 100,
52
- logLevel: 'info',
38
+ dbPath: './ftpd.db',
53
39
  banner: 'My FTP Server',
54
- passivePortRange: { min: 50000, max: 50050 },
40
+ logLevel: 'info',
55
41
  };
56
42
 
57
43
  new FtpServer(config).start();
58
44
  ```
59
45
 
60
- ## Settings
46
+ ## Configuration
47
+
48
+ Only `dbPath`, `banner` and `logLevel` are part of the public `ServerConfig`.
49
+ All other settings are read from the SQLite `settings` table.
61
50
 
62
- | Field | Default | Description |
51
+ | Key | Default | Description |
63
52
  | --- | --- | --- |
64
- | `port` | `21` | Control (command) port |
65
- | `dataPort` | `20` | Classic data port |
66
- | `userFile` | `<package>/users.json` | Path to the user file (JSON) |
67
- | `maxConnections` | `100` | Maximum number of open connections at the same time |
68
- | `logLevel` | `'info'` | `debug` \| `info` \| `warn` \| `error` |
69
- | `banner` | `''` | 220 welcome message; if empty, `"<port> FTP Server Ready"` |
70
- | `passivePortRange` | `{ min: 50000, max: 50050 }` | Range from which PASV data ports will be selected (fallback) |
53
+ | `ftp.port` | `21` | Control (command) port |
54
+ | `ftp.dataPort` | `20` | Classic data port |
55
+ | `ftp.maxConnections` | `100` | Maximum number of open connections at the same time |
56
+ | `ftp.logLevel` | `'info'` | `debug` \| `info` \| `warn` \| `error` |
57
+ | `ftp.banner` | `''` | 220 welcome message; if empty, `"<port> FTP Server Ready"` |
58
+ | `ftp.passivePortRange` | `'50000:50050'` | PASV range as `min:max` |
71
59
 
72
60
  If an invalid `passivePortRange` is provided, a warning is logged and the default range is used.
73
61
 
74
- ## User file (`users.json`)
75
-
76
- ```json
77
- {
78
- "users": [
79
- {
80
- "username": "admin",
81
- "password": "admin123",
82
- "homeDir": "./files/admin",
83
- "permissions": {
84
- "read": true,
85
- "write": true,
86
- "list": true,
87
- "create": true,
88
- "delete": true,
89
- "mkd": true,
90
- "rmdir": true,
91
- "rename": true
92
- },
93
- "isActive": true
94
- }
95
- ],
96
- "lastUpdated": "2026-10-29T12:30:00.000Z"
97
- },
98
- {...}
99
- ```
62
+ ## Database
100
63
 
101
- `homeDir` is the user's virtual root: the client always sees it as `/` and
102
- the client cannot go outside this directory (CWD/RETR/STOR/DELE/MKD/RMD/RNFR/RNTO are checked).
64
+ The server stores all data in a SQLite database file (default: `./ftpd.db`).
65
+
66
+ - `users` table: user credentials, home directory and permissions (Linux style, e.g. `rwxr-xr-x`).
67
+ - `settings` table: server settings (`ftp.*` keys).
68
+
69
+ ## User
70
+
71
+ Users are persisted in the SQLite `users` table.
72
+
73
+ ```sql
74
+ CREATE TABLE users (
75
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
76
+ username TEXT UNIQUE NOT NULL,
77
+ password TEXT NOT NULL,
78
+ homeDir TEXT NOT NULL,
79
+ permissions TEXT NOT NULL DEFAULT '{}',
80
+ isActive INTEGER NOT NULL DEFAULT 1,
81
+ createdAt TEXT NOT NULL DEFAULT (datetime('now')),
82
+ updatedAt TEXT NOT NULL DEFAULT (datetime('now'))
83
+ );
84
+ ```
103
85
 
104
86
  ## Supported commands
105
87
 
@@ -109,28 +91,11 @@ the client cannot go outside this directory (CWD/RETR/STOR/DELE/MKD/RMD/RNFR/RNT
109
91
  > TLS/SSL (`AUTH TLS`), `MLSD`/`MLST`, `SIZE` and `MDTM` are not yet implemented and
110
92
  > are not advertised in the `FEAT` response.
111
93
 
112
- ## Development in this repository
94
+ ## CLI / Interactive terminal
113
95
 
114
- ```bash
115
- npm run type-check # tsc --noEmit
116
- npm run build # src -> npm_build (index.js + index.d.ts)
117
- npm start # runs the example server examples/basic.js
118
- npm test # test client test/ftp-client.js
119
- ```
120
-
121
- To see the package contents before publishing:
96
+ The `ftpd` binary starts an interactive FTP terminal:
122
97
 
123
98
  ```bash
124
- npm pack --dry-run
99
+ npx ftpd
100
+ $: ftpd
125
101
  ```
126
-
127
- ## docker-Installation
128
- ```bash
129
- docker pull asymmetricstar/docker-ftpd:latest
130
- ```
131
-
132
- ```bash
133
- docker run -d -p 21:21 -p 20:20 -p 50000-50050:50000-50050 \
134
- -e FTP_DEFAULT_USER=admin -e FTP_DEFAULT_PASS=admin123 \
135
- --name docker-ftpd asymmetricstar/docker-ftpd:latest
136
- ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ftpd-lite",
3
- "version": "1.0.10",
3
+ "version": "1.0.15",
4
4
  "description": "TCP-based FTP server with multi-user support and permission control",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -12,6 +12,9 @@
12
12
  },
13
13
  "./package.json": "./package.json"
14
14
  },
15
+ "bin": {
16
+ "ftpd": "src/ftpd.js"
17
+ },
15
18
  "files": [
16
19
  "src",
17
20
  "examples"
@@ -0,0 +1,6 @@
1
+ export interface FtpPromptInfo {
2
+ user: string | null;
3
+ currentDir: string;
4
+ }
5
+ export declare function renderFtpPrompt(info: FtpPromptInfo): string;
6
+ export declare function renderFtpBanner(port: number): string;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderFtpPrompt = renderFtpPrompt;
4
+ exports.renderFtpBanner = renderFtpBanner;
5
+ const SERVER_NAME = 'ftpd';
6
+ function renderFtpPrompt(info) {
7
+ const user = info.user || 'anonymous';
8
+ const dir = info.currentDir || '~';
9
+ return `${user}@${SERVER_NAME}:${dir} $`;
10
+ }
11
+ function renderFtpBanner(port) {
12
+ return [
13
+ `FTP server ${SERVER_NAME} ready`,
14
+ `Listening on port ${port}`,
15
+ ].join('\n');
16
+ }
17
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFubmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaS9iYW5uZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQVdBLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQztBQUszQix5QkFBZ0MsSUFBbUI7SUFDakQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksSUFBSSxXQUFXLENBQUM7SUFDdEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLFVBQVUsSUFBSSxHQUFHLENBQUM7SUFFbkMsT0FBTyxHQUFHLElBQUksSUFBSSxXQUFXLElBQUksR0FBRyxJQUFJLENBQUM7QUFDM0MsQ0FBQztBQUtELHlCQUFnQyxJQUFZO0lBQzFDLE9BQU87UUFDTCxjQUFjLFdBQVcsUUFBUTtRQUNqQyxxQkFBcUIsSUFBSSxFQUFFO0tBQzVCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ2YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRlRQIENMSSBwcm9tcHQgdmUgYmFubmVyIMO8cmV0aWNpbGVyaVxuICpcbiAqIMOWcm5layBwcm9tcHQ6XG4gKiAgIGFkbWluQGZ0cGQ6fi9hZG1pbiAkXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRnRwUHJvbXB0SW5mbyB7XG4gIHVzZXI6IHN0cmluZyB8IG51bGw7XG4gIGN1cnJlbnREaXI6IHN0cmluZztcbn1cblxuY29uc3QgU0VSVkVSX05BTUUgPSAnZnRwZCc7XG5cbi8qKlxuICogQWt0aWYga3VsbGFuxLFjxLF5YSBnw7ZyZSBwcm9tcHQgw7xyZXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbmRlckZ0cFByb21wdChpbmZvOiBGdHBQcm9tcHRJbmZvKTogc3RyaW5nIHtcbiAgY29uc3QgdXNlciA9IGluZm8udXNlciB8fCAnYW5vbnltb3VzJztcbiAgY29uc3QgZGlyID0gaW5mby5jdXJyZW50RGlyIHx8ICd+JztcbiAgLy8gS3VsbGFuxLFjxLFAcHJvZ3JhbTpkaXppbiAkXG4gIHJldHVybiBgJHt1c2VyfUAke1NFUlZFUl9OQU1FfToke2Rpcn0gJGA7XG59XG5cbi8qKlxuICogU3VudWN1IGJhbm5lcifEsVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVuZGVyRnRwQmFubmVyKHBvcnQ6IG51bWJlcik6IHN0cmluZyB7XG4gIHJldHVybiBbXG4gICAgYEZUUCBzZXJ2ZXIgJHtTRVJWRVJfTkFNRX0gcmVhZHlgLFxuICAgIGBMaXN0ZW5pbmcgb24gcG9ydCAke3BvcnR9YCxcbiAgXS5qb2luKCdcXG4nKTtcbn1cbiJdfQ==
@@ -0,0 +1,10 @@
1
+ import { FtpServer } from '../core/FtpServer';
2
+ import { FtpConnection } from '../types';
3
+ export interface FtpCliContext {
4
+ server: FtpServer;
5
+ user: string | null;
6
+ homeDir: string;
7
+ currentDir: string;
8
+ connection: FtpConnection | null;
9
+ }
10
+ export declare function createFtpContext(server: FtpServer): FtpCliContext;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createFtpContext = createFtpContext;
4
+ function createFtpContext(server) {
5
+ return {
6
+ server,
7
+ user: null,
8
+ homeDir: '',
9
+ currentDir: '',
10
+ connection: null,
11
+ };
12
+ }
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jbGkvY29udGV4dC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFvQkEsMEJBQWlDLE1BQWlCO0lBQ2hELE9BQU87UUFDTCxNQUFNO1FBQ04sSUFBSSxFQUFFLElBQUk7UUFDVixPQUFPLEVBQUUsRUFBRTtRQUNYLFVBQVUsRUFBRSxFQUFFO1FBQ2QsVUFBVSxFQUFFLElBQUk7S0FDakIsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBGdHBTZXJ2ZXIgfSBmcm9tICcuLi9jb3JlL0Z0cFNlcnZlcic7XG5pbXBvcnQgeyBGdHBDb25uZWN0aW9uIH0gZnJvbSAnLi4vdHlwZXMnO1xuXG4vKipcbiAqIEZUUCBDTEkgKGludGVyYWt0aWYgdGVybWluYWwpIGJhxJ9sYW3EsVxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZ0cENsaUNvbnRleHQge1xuICBzZXJ2ZXI6IEZ0cFNlcnZlcjtcbiAgLyoqIEFrdGlmIEZUUCBrdWxsYW7EsWPEsSBhZMSxIChudWxsIC0+IGtpbWxpayBkb8SfcnVsYW1hc8SxIGJla2xlbml5b3IpICovXG4gIHVzZXI6IHN0cmluZyB8IG51bGw7XG4gIC8qKiBBa3RpZiBrdWxsYW7EsWPEsW7EsW4gaG9tZSBkaXppbmkgKi9cbiAgaG9tZURpcjogc3RyaW5nO1xuICAvKiogQWt0aWYga3VsbGFuxLFjxLFuxLFuIMWfdSBhbmtpIGRpemluaSAqL1xuICBjdXJyZW50RGlyOiBzdHJpbmc7XG4gIGNvbm5lY3Rpb246IEZ0cENvbm5lY3Rpb24gfCBudWxsO1xufVxuXG4vKipcbiAqIFllbmkgQ0xJIGJhxJ9sYW3EsSBvbHXFn3R1clxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRnRwQ29udGV4dChzZXJ2ZXI6IEZ0cFNlcnZlcik6IEZ0cENsaUNvbnRleHQge1xuICByZXR1cm4ge1xuICAgIHNlcnZlcixcbiAgICB1c2VyOiBudWxsLFxuICAgIGhvbWVEaXI6ICcnLFxuICAgIGN1cnJlbnREaXI6ICcnLFxuICAgIGNvbm5lY3Rpb246IG51bGwsXG4gIH07XG59XG4iXX0=
@@ -0,0 +1,7 @@
1
+ import { FtpCliContext } from './context';
2
+ export interface FtpCommandResult {
3
+ lines: string[];
4
+ clear?: boolean;
5
+ exit?: boolean;
6
+ }
7
+ export declare function handleFtpCommand(rawLine: string, ctx: FtpCliContext): FtpCommandResult;
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.handleFtpCommand = handleFtpCommand;
37
+ const path = __importStar(require("path"));
38
+ const fs = __importStar(require("fs"));
39
+ function handleFtpCommand(rawLine, ctx) {
40
+ const line = (rawLine || '').trim();
41
+ if (line === '') {
42
+ return { lines: [] };
43
+ }
44
+ const separatorIndex = line.search(/\s/);
45
+ const command = (separatorIndex === -1 ? line : line.slice(0, separatorIndex)).toLowerCase();
46
+ const args = separatorIndex === -1 ? '' : line.slice(separatorIndex).trim();
47
+ switch (command) {
48
+ case 'help':
49
+ return {
50
+ lines: [
51
+ 'Available commands:',
52
+ ' help - Show this help',
53
+ ' clear - Clear screen',
54
+ ' exit - Exit the FTP shell (Ctrl+D / quit / q / :q)',
55
+ ' quit - Exit the FTP shell',
56
+ ' q - Exit the FTP shell',
57
+ ' version - Show version',
58
+ ' status - Show session status',
59
+ ' whoami - Show current user',
60
+ ' ls [path] - List directory',
61
+ ' pwd - Print working directory',
62
+ ' cd <path> - Change directory',
63
+ ],
64
+ };
65
+ case 'clear':
66
+ return { lines: [], clear: true };
67
+ case 'version':
68
+ return { lines: ['ftpd version 0.0.2'] };
69
+ case 'exit':
70
+ case 'quit':
71
+ case 'q':
72
+ case ':q':
73
+ return { lines: [], exit: true };
74
+ case 'status':
75
+ case 'whoami':
76
+ case 'who': {
77
+ const user = ctx.user;
78
+ const lines = [];
79
+ lines.push(`Session: ${user ? user : 'anonymous'}`);
80
+ lines.push(`Home: ${ctx.homeDir || '-'}`);
81
+ lines.push(`CurrentDir: ${ctx.currentDir || '-'}`);
82
+ return { lines };
83
+ }
84
+ case 'pwd':
85
+ return { lines: [`Pwd: ${ctx.currentDir || ctx.homeDir || '~'}`] };
86
+ case 'ls': {
87
+ if (!ctx.user) {
88
+ return { lines: ['Not logged in'] };
89
+ }
90
+ const userManager = ctx.server.getUserManager();
91
+ if (!userManager) {
92
+ return { lines: ['UserManager not initialized'] };
93
+ }
94
+ const hasList = userManager.checkPermission(ctx.user, 'list');
95
+ if (!hasList) {
96
+ return { lines: ['Permission denied: ls'] };
97
+ }
98
+ const targetDir = path.resolve(ctx.currentDir || ctx.homeDir || '.');
99
+ const dirents = fs.readdirSync(targetDir).map((name) => {
100
+ const full = path.join(targetDir, name);
101
+ const st = fs.statSync(full);
102
+ const type = st.isDirectory() ? 'd' : '-';
103
+ const size = st.size;
104
+ return `${type} ${size.toString().padStart(8)} ${name}`;
105
+ });
106
+ if (dirents.length === 0) {
107
+ return { lines: [`${targetDir} :: (empty)`] };
108
+ }
109
+ return { lines: dirents.map((l) => l) };
110
+ }
111
+ case 'cd': {
112
+ if (!ctx.user) {
113
+ return { lines: ['Not logged in'] };
114
+ }
115
+ const userManager = ctx.server.getUserManager();
116
+ if (!userManager) {
117
+ return { lines: ['UserManager not initialized'] };
118
+ }
119
+ const hasList = userManager.checkPermission(ctx.user, 'list');
120
+ if (!hasList) {
121
+ return { lines: ['Permission denied: cd'] };
122
+ }
123
+ const targetDir = args.trim() ? path.resolve(args.trim()) : ctx.homeDir || '.';
124
+ ctx.currentDir = targetDir;
125
+ return { lines: [`Cd ok: ${targetDir}`] };
126
+ }
127
+ default:
128
+ return { lines: [`Command not implemented: ${command}`] };
129
+ }
130
+ }
131
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaXN0cnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xpL3JlZ2lzdHJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVBLE1BQVksSUFBSSxpQ0FBYTtBQUM3QixNQUFZLEVBQUUsK0JBQVc7QUFXekIsMEJBQWlDLE9BQWUsRUFBRSxHQUFrQjtJQUNsRSxNQUFNLElBQUksR0FBRyxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNwQyxJQUFJLElBQUksS0FBSyxFQUFFLEVBQUUsQ0FBQztRQUNoQixPQUFPLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3pDLE1BQU0sT0FBTyxHQUFHLENBQUMsY0FBYyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDN0YsTUFBTSxJQUFJLEdBQUcsY0FBYyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7SUFFNUUsUUFBUSxPQUFPLEVBQUUsQ0FBQztRQUNoQixLQUFLLE1BQU07WUFDVCxPQUFPO2dCQUNMLEtBQUssRUFBRTtvQkFDTCxxQkFBcUI7b0JBQ3JCLG9DQUFvQztvQkFDcEMsa0NBQWtDO29CQUNsQyxpRUFBaUU7b0JBQ2pFLHdDQUF3QztvQkFDeEMsd0NBQXdDO29CQUN4QyxrQ0FBa0M7b0JBQ2xDLHlDQUF5QztvQkFDekMsdUNBQXVDO29CQUN2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QUFDO1lBQzNCLE9BQU8sRUFBRSxLQUFLLEVBQUUsQ0FBQyxVQUFVLFNBQVMsRUFBRSxDQUFDLEVBQUUsQ0FBQztRQUM1QyxDQUFDO1FBRUQ7WUFDRSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUMsNEJBQTRCLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUM5RCxDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEZ0cENsaUNvbnRleHQgfSBmcm9tICcuL2NvbnRleHQnO1xuaW1wb3J0IHsgRnRwU2VydmVyIH0gZnJvbSAnLi4vY29yZS9GdHBTZXJ2ZXInO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcblxuZXhwb3J0IGludGVyZmFjZSBGdHBDb21tYW5kUmVzdWx0IHtcbiAgbGluZXM6IHN0cmluZ1tdO1xuICBjbGVhcj86IGJvb2xlYW47XG4gIGV4aXQ/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEZUUCBDTEkga29tdXRsYXLEsW7EsSBpxZ9sZVxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFuZGxlRnRwQ29tbWFuZChyYXdMaW5lOiBzdHJpbmcsIGN0eDogRnRwQ2xpQ29udGV4dCk6IEZ0cENvbW1hbmRSZXN1bHQge1xuICBjb25zdCBsaW5lID0gKHJhd0xpbmUgfHwgJycpLnRyaW0oKTtcbiAgaWYgKGxpbmUgPT09ICcnKSB7XG4gICAgcmV0dXJuIHsgbGluZXM6IFtdIH07XG4gIH1cblxuICBjb25zdCBzZXBhcmF0b3JJbmRleCA9IGxpbmUuc2VhcmNoKC9cXHMvKTtcbiAgY29uc3QgY29tbWFuZCA9IChzZXBhcmF0b3JJbmRleCA9PT0gLTEgPyBsaW5lIDogbGluZS5zbGljZSgwLCBzZXBhcmF0b3JJbmRleCkpLnRvTG93ZXJDYXNlKCk7XG4gIGNvbnN0IGFyZ3MgPSBzZXBhcmF0b3JJbmRleCA9PT0gLTEgPyAnJyA6IGxpbmUuc2xpY2Uoc2VwYXJhdG9ySW5kZXgpLnRyaW0oKTtcblxuICBzd2l0Y2ggKGNvbW1hbmQpIHtcbiAgICBjYXNlICdoZWxwJzpcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGxpbmVzOiBbXG4gICAgICAgICAgJ0F2YWlsYWJsZSBjb21tYW5kczonLFxuICAgICAgICAgICcgIGhlbHAgICAgICAgICAgICAtIFNob3cgdGhpcyBoZWxwJyxcbiAgICAgICAgICAnICBjbGVhciAgICAgICAgICAgLSBDbGVhciBzY3JlZW4nLFxuICAgICAgICAgICcgIGV4aXQgICAgICAgICAgICAtIEV4aXQgdGhlIEZUUCBzaGVsbCAoQ3RybCtEIC8gcXVpdCAvIHEgLyA6cSknLFxuICAgICAgICAgICcgIHF1aXQgICAgICAgICAgICAtIEV4aXQgdGhlIEZUUCBzaGVsbCcsXG4gICAgICAgICAgJyAgcSAgICAgICAgICAgICAgIC0gRXhpdCB0aGUgRlRQIHNoZWxsJyxcbiAgICAgICAgICAnICB2ZXJzaW9uICAgICAgICAgLSBTaG93IHZlcnNpb24nLFxuICAgICAgICAgICcgIHN0YXR1cyAgICAgICAgICAtIFNob3cgc2Vzc2lvbiBzdGF0dXMnLFxuICAgICAgICAgICcgIHdob2FtaSAgICAgICAgICAtIFNob3cgY3VycmVudCB1c2VyJyxcbiAgICAgICAgICAnICBscyBbcGF0aF0gICAgICAgLSBMaXN0IGRpcmVjdG9yeScsXG4gICAgICAgICAgJyAgcHdkICAgICAgICAgICAgIC0gUHJpbnQgd29ya2luZyBkaXJlY3RvcnknLFxuICAgICAgICAgICcgIGNkIDxwYXRoPiAgICAgICAtIENoYW5nZSBkaXJlY3RvcnknLFxuICAgICAgICBdLFxuICAgICAgfTtcblxuICAgIGNhc2UgJ2NsZWFyJzpcbiAgICAgIHJldHVybiB7IGxpbmVzOiBbXSwgY2xlYXI6IHRydWUgfTtcblxuICAgIGNhc2UgJ3ZlcnNpb24nOlxuICAgICAgcmV0dXJuIHsgbGluZXM6IFsnZnRwZCB2ZXJzaW9uIDAuMC4yJ10gfTtcblxuICAgIGNhc2UgJ2V4aXQnOlxuICAgIGNhc2UgJ3F1aXQnOlxuICAgIGNhc2UgJ3EnOlxuICAgIGNhc2UgJzpxJzpcbiAgICAgIHJldHVybiB7IGxpbmVzOiBbXSwgZXhpdDogdHJ1ZSB9O1xuXG4gICAgY2FzZSAnc3RhdHVzJzpcbiAgICBjYXNlICd3aG9hbWknOlxuICAgIGNhc2UgJ3dobyc6IHtcbiAgICAgIGNvbnN0IHVzZXIgPSBjdHgudXNlcjtcbiAgICAgIGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgbGluZXMucHVzaChgU2Vzc2lvbjogJHt1c2VyID8gdXNlciA6ICdhbm9ueW1vdXMnfWApO1xuICAgICAgbGluZXMucHVzaChgSG9tZTogJHtjdHguaG9tZURpciB8fCAnLSd9YCk7XG4gICAgICBsaW5lcy5wdXNoKGBDdXJyZW50RGlyOiAke2N0eC5jdXJyZW50RGlyIHx8ICctJ31gKTtcbiAgICAgIHJldHVybiB7IGxpbmVzIH07XG4gICAgfVxuXG4gICAgY2FzZSAncHdkJzpcbiAgICAgIHJldHVybiB7IGxpbmVzOiBbYFB3ZDogJHtjdHguY3VycmVudERpciB8fCBjdHguaG9tZURpciB8fCAnfid9YF0gfTtcblxuICAgIGNhc2UgJ2xzJzoge1xuICAgICAgaWYgKCFjdHgudXNlcikge1xuICAgICAgICByZXR1cm4geyBsaW5lczogWydOb3QgbG9nZ2VkIGluJ10gfTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHVzZXJNYW5hZ2VyID0gY3R4LnNlcnZlci5nZXRVc2VyTWFuYWdlcigpO1xuICAgICAgaWYgKCF1c2VyTWFuYWdlcikge1xuICAgICAgICByZXR1cm4geyBsaW5lczogWydVc2VyTWFuYWdlciBub3QgaW5pdGlhbGl6ZWQnXSB9O1xuICAgICAgfVxuICAgICAgY29uc3QgaGFzTGlzdCA9IHVzZXJNYW5hZ2VyLmNoZWNrUGVybWlzc2lvbihjdHgudXNlciwgJ2xpc3QnKTtcbiAgICAgIGlmICghaGFzTGlzdCkge1xuICAgICAgICByZXR1cm4geyBsaW5lczogWydQZXJtaXNzaW9uIGRlbmllZDogbHMnXSB9O1xuICAgICAgfVxuICAgICAgY29uc3QgdGFyZ2V0RGlyID0gcGF0aC5yZXNvbHZlKGN0eC5jdXJyZW50RGlyIHx8IGN0eC5ob21lRGlyIHx8ICcuJyk7XG4gICAgICBjb25zdCBkaXJlbnRzID0gZnMucmVhZGRpclN5bmModGFyZ2V0RGlyKS5tYXAoKG5hbWUpID0+IHtcbiAgICAgICAgY29uc3QgZnVsbCA9IHBhdGguam9pbih0YXJnZXREaXIsIG5hbWUpO1xuICAgICAgICBjb25zdCBzdCA9IGZzLnN0YXRTeW5jKGZ1bGwpO1xuICAgICAgICBjb25zdCB0eXBlID0gc3QuaXNEaXJlY3RvcnkoKSA/ICdkJyA6ICctJztcbiAgICAgICAgY29uc3Qgc2l6ZSA9IHN0LnNpemU7XG4gICAgICAgIHJldHVybiBgJHt0eXBlfSAke3NpemUudG9TdHJpbmcoKS5wYWRTdGFydCg4KX0gJHtuYW1lfWA7XG4gICAgICB9KTtcbiAgICAgIGlmIChkaXJlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4geyBsaW5lczogW2Ake3RhcmdldERpcn0gOjogKGVtcHR5KWBdIH07XG4gICAgICB9XG4gICAgICByZXR1cm4geyBsaW5lczogZGlyZW50cy5tYXAoKGwpID0+IGwpIH07XG4gICAgfVxuXG4gICAgY2FzZSAnY2QnOiB7XG4gICAgICBpZiAoIWN0eC51c2VyKSB7XG4gICAgICAgIHJldHVybiB7IGxpbmVzOiBbJ05vdCBsb2dnZWQgaW4nXSB9O1xuICAgICAgfVxuICAgICAgY29uc3QgdXNlck1hbmFnZXIgPSBjdHguc2VydmVyLmdldFVzZXJNYW5hZ2VyKCk7XG4gICAgICBpZiAoIXVzZXJNYW5hZ2VyKSB7XG4gICAgICAgIHJldHVybiB7IGxpbmVzOiBbJ1VzZXJNYW5hZ2VyIG5vdCBpbml0aWFsaXplZCddIH07XG4gICAgICB9XG4gICAgICBjb25zdCBoYXNMaXN0ID0gdXNlck1hbmFnZXIuY2hlY2tQZXJtaXNzaW9uKGN0eC51c2VyLCAnbGlzdCcpO1xuICAgICAgaWYgKCFoYXNMaXN0KSB7XG4gICAgICAgIHJldHVybiB7IGxpbmVzOiBbJ1Blcm1pc3Npb24gZGVuaWVkOiBjZCddIH07XG4gICAgICB9XG4gICAgICBjb25zdCB0YXJnZXREaXIgPSBhcmdzLnRyaW0oKSA/IHBhdGgucmVzb2x2ZShhcmdzLnRyaW0oKSkgOiBjdHguaG9tZURpciB8fCAnLic7XG4gICAgICBjdHguY3VycmVudERpciA9IHRhcmdldERpcjtcbiAgICAgIHJldHVybiB7IGxpbmVzOiBbYENkIG9rOiAke3RhcmdldERpcn1gXSB9O1xuICAgIH1cblxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4geyBsaW5lczogW2BDb21tYW5kIG5vdCBpbXBsZW1lbnRlZDogJHtjb21tYW5kfWBdIH07XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,2 @@
1
+ import { FtpServer } from '../core/FtpServer';
2
+ export declare function startFtpRepl(server: FtpServer, port: number): Promise<void>;
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.startFtpRepl = startFtpRepl;
37
+ const readline = __importStar(require("readline"));
38
+ const registry_1 = require("./registry");
39
+ const banner_1 = require("./banner");
40
+ async function startFtpRepl(server, port) {
41
+ const ctx = {
42
+ server,
43
+ user: null,
44
+ homeDir: '',
45
+ currentDir: '',
46
+ connection: null,
47
+ };
48
+ const rl = readline.createInterface({
49
+ input: process.stdin,
50
+ output: process.stdout,
51
+ terminal: true,
52
+ });
53
+ let prompt = (0, banner_1.renderFtpPrompt)(ctx);
54
+ const writeLines = (lines) => {
55
+ for (const line of lines) {
56
+ process.stdout.write(`${line}\r\n`);
57
+ }
58
+ };
59
+ const showPrompt = () => {
60
+ prompt = (0, banner_1.renderFtpPrompt)(ctx);
61
+ rl.setPrompt(prompt);
62
+ rl.prompt();
63
+ };
64
+ rl.setPrompt(prompt);
65
+ rl.prompt();
66
+ rl.on('line', (line) => {
67
+ const result = (0, registry_1.handleFtpCommand)(line, ctx);
68
+ if (result.clear) {
69
+ process.stdout.write('\u001b[2J\u001b[H');
70
+ return;
71
+ }
72
+ if (result.exit) {
73
+ process.stdout.write('\r\n');
74
+ rl.close();
75
+ process.exit(0);
76
+ }
77
+ if (result.lines.length > 0) {
78
+ writeLines(result.lines);
79
+ }
80
+ showPrompt();
81
+ });
82
+ rl.on('close', () => {
83
+ process.stdout.write('\r\n');
84
+ process.exit(0);
85
+ });
86
+ process.on('SIGINT', () => {
87
+ process.stdout.write('\r\n');
88
+ rl.close();
89
+ process.exit(0);
90
+ });
91
+ }
92
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jbGkvcmVwbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxNQUFZLFFBQVEscUNBQWlCO0FBR3JDLHlDQUE4QztBQUM5QyxxQ0FBMkM7QUFLcEMsS0FBSyx1QkFBdUIsTUFBaUIsRUFBRSxJQUFZO0lBQ2hFLE1BQU0sR0FBRyxHQUFrQjtRQUN6QixNQUFNO1FBQ04sSUFBSSxFQUFFLElBQUk7UUFDVixPQUFPLEVBQUUsRUFBRTtRQUNYLFVBQVUsRUFBRSxFQUFFO1FBQ2QsVUFBVSxFQUFFLElBQUk7S0FDakIsQ0FBQztJQUVGLE1BQU0sRUFBRSxHQUFHLFFBQVEsQ0FBQyxlQUFlLENBQUM7UUFDbEMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLO1FBQ3BCLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTTtRQUN0QixRQUFRLEVBQUUsSUFBSTtLQUNmLENBQUMsQ0FBQztJQUVILElBQUksTUFBTSxHQUFHLElBQUEsd0JBQWUsRUFBQyxHQUFHLENBQUMsQ0FBQztJQUVsQyxNQUFNLFVBQVUsR0FBRyxDQUFDLEtBQWUsRUFBUSxFQUFFO1FBQzNDLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7WUFDekIsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLE1BQU0sQ0FBQyxDQUFDO1FBQ3RDLENBQUM7SUFDSCxDQUFDLENBQUM7SUFFRixNQUFNLFVBQVUsR0FBRyxHQUFTLEVBQUU7UUFDNUIsTUFBTSxHQUFHLElBQUEsd0JBQWUsRUFBQyxHQUFHLENBQUMsQ0FBQztRQUM5QixFQUFFLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3JCLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUNkLENBQUMsQ0FBQztJQUVGLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDckIsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBRVosRUFBRSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFZLEVBQUUsRUFBRTtRQUM3QixNQUFNLE1BQU0sR0FBRyxJQUFBLDJCQUFnQixFQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztRQUMzQyxJQUFJLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNqQixPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lBQzFDLE9BQU87UUFDVCxDQUFDO1FBQ0QsSUFBSSxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDaEIsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDN0IsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ1gsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNsQixDQUFDO1FBQ0QsSUFBSSxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUM1QixVQUFVLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzNCLENBQUM7UUFDRCxVQUFVLEVBQUUsQ0FBQztJQUNmLENBQUMsQ0FBQyxDQUFDO0lBRUgsRUFBRSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFO1FBQ2xCLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzdCLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEIsQ0FBQyxDQUFDLENBQUM7SUFHSCxPQUFPLENBQUMsRUFBRSxDQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUU7UUFDeEIsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDN0IsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsQixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyByZWFkbGluZSBmcm9tICdyZWFkbGluZSc7XG5pbXBvcnQgeyBGdHBTZXJ2ZXIgfSBmcm9tICcuLi9jb3JlL0Z0cFNlcnZlcic7XG5pbXBvcnQgeyBGdHBDbGlDb250ZXh0IH0gZnJvbSAnLi9jb250ZXh0JztcbmltcG9ydCB7IGhhbmRsZUZ0cENvbW1hbmQgfSBmcm9tICcuL3JlZ2lzdHJ5JztcbmltcG9ydCB7IHJlbmRlckZ0cFByb21wdCB9IGZyb20gJy4vYmFubmVyJztcblxuLyoqXG4gKiBGVFAgaW50ZXJha3RpZiB0ZXJtaW5hbCAoQ0xJIFJFUEwpIGJhxZ9sYXRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0RnRwUmVwbChzZXJ2ZXI6IEZ0cFNlcnZlciwgcG9ydDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGN0eDogRnRwQ2xpQ29udGV4dCA9IHtcbiAgICBzZXJ2ZXIsXG4gICAgdXNlcjogbnVsbCxcbiAgICBob21lRGlyOiAnJyxcbiAgICBjdXJyZW50RGlyOiAnJyxcbiAgICBjb25uZWN0aW9uOiBudWxsLFxuICB9O1xuXG4gIGNvbnN0IHJsID0gcmVhZGxpbmUuY3JlYXRlSW50ZXJmYWNlKHtcbiAgICBpbnB1dDogcHJvY2Vzcy5zdGRpbixcbiAgICBvdXRwdXQ6IHByb2Nlc3Muc3Rkb3V0LFxuICAgIHRlcm1pbmFsOiB0cnVlLFxuICB9KTtcblxuICBsZXQgcHJvbXB0ID0gcmVuZGVyRnRwUHJvbXB0KGN0eCk7XG5cbiAgY29uc3Qgd3JpdGVMaW5lcyA9IChsaW5lczogc3RyaW5nW10pOiB2b2lkID0+IHtcbiAgICBmb3IgKGNvbnN0IGxpbmUgb2YgbGluZXMpIHtcbiAgICAgIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke2xpbmV9XFxyXFxuYCk7XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IHNob3dQcm9tcHQgPSAoKTogdm9pZCA9PiB7XG4gICAgcHJvbXB0ID0gcmVuZGVyRnRwUHJvbXB0KGN0eCk7XG4gICAgcmwuc2V0UHJvbXB0KHByb21wdCk7XG4gICAgcmwucHJvbXB0KCk7XG4gIH07XG5cbiAgcmwuc2V0UHJvbXB0KHByb21wdCk7XG4gIHJsLnByb21wdCgpO1xuXG4gIHJsLm9uKCdsaW5lJywgKGxpbmU6IHN0cmluZykgPT4ge1xuICAgIGNvbnN0IHJlc3VsdCA9IGhhbmRsZUZ0cENvbW1hbmQobGluZSwgY3R4KTtcbiAgICBpZiAocmVzdWx0LmNsZWFyKSB7XG4gICAgICBwcm9jZXNzLnN0ZG91dC53cml0ZSgnXFx1MDAxYlsySlxcdTAwMWJbSCcpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAocmVzdWx0LmV4aXQpIHtcbiAgICAgIHByb2Nlc3Muc3Rkb3V0LndyaXRlKCdcXHJcXG4nKTtcbiAgICAgIHJsLmNsb3NlKCk7XG4gICAgICBwcm9jZXNzLmV4aXQoMCk7XG4gICAgfVxuICAgIGlmIChyZXN1bHQubGluZXMubGVuZ3RoID4gMCkge1xuICAgICAgd3JpdGVMaW5lcyhyZXN1bHQubGluZXMpO1xuICAgIH1cbiAgICBzaG93UHJvbXB0KCk7XG4gIH0pO1xuXG4gIHJsLm9uKCdjbG9zZScsICgpID0+IHtcbiAgICBwcm9jZXNzLnN0ZG91dC53cml0ZSgnXFxyXFxuJyk7XG4gICAgcHJvY2Vzcy5leGl0KDApO1xuICB9KTtcblxuICAvLyBHcmFjZWZ1bCBzaHV0ZG93blxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCAoKSA9PiB7XG4gICAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoJ1xcclxcbicpO1xuICAgIHJsLmNsb3NlKCk7XG4gICAgcHJvY2Vzcy5leGl0KDApO1xuICB9KTtcbn1cbiJdfQ==
@@ -1,11 +1,13 @@
1
1
  import { ServerConfig } from '../types';
2
- declare const DEFAULT_CONFIG: ServerConfig;
2
+ import { UserManager } from '../userManager';
3
+ import { DatabaseManager } from '../db/database';
3
4
  export declare class FtpServer {
4
5
  private server;
5
6
  private dataServer;
6
7
  private connections;
7
8
  private dataConnections;
8
- private config;
9
+ private runtime;
10
+ private db;
9
11
  private userManager;
10
12
  private connectionCount;
11
13
  private maxConnections;
@@ -28,7 +30,12 @@ export declare class FtpServer {
28
30
  private passiveConnId;
29
31
  private dataWaitTimer;
30
32
  private static readonly DATA_WAIT_TIMEOUT_MS;
31
- constructor(config?: Partial<typeof DEFAULT_CONFIG>);
33
+ constructor(config?: Partial<ServerConfig>);
34
+ private loadConfigFromSettings;
35
+ private saveSettingToDb;
36
+ updateSetting(key: keyof ServerConfig, value: any): void;
37
+ getDb(): DatabaseManager;
38
+ getUserManager(): UserManager | null;
32
39
  private normalizePortRange;
33
40
  private normalizeIp;
34
41
  private resolvePassiveIp;
@@ -50,4 +57,3 @@ export declare class FtpServer {
50
57
  private writeControl;
51
58
  closeConnection(connId: string, reason?: string): void;
52
59
  }
53
- export {};