jsftpd
Advanced tools
Comparing version 1.0.0 to 1.1.0
@@ -31,6 +31,3 @@ /* | ||
user: [], | ||
allowUserFileOverwrite: true, | ||
allowUserFileDelete: true, | ||
allowUserFolderDelete: true, | ||
allowUserFolderCreate: true, | ||
allowAnonymousFileCreate: false, | ||
allowAnonymousFileOverwrite: false, | ||
@@ -40,8 +37,17 @@ allowAnonymousFileDelete: false, | ||
allowAnonymousFolderCreate: false, | ||
allowLoginWithoutPassword: false, | ||
allowAnonymousLogin: false, | ||
minDataPort: 1024, | ||
uploadHandler: null | ||
uploadHandler: null, | ||
downloadHandler: null | ||
} | ||
const UserDefaults = { | ||
allowLoginWithoutPassword: false, | ||
allowUserFileCreate: true, | ||
allowUserFileOverwrite: true, | ||
allowUserFileDelete: true, | ||
allowUserFolderDelete: true, | ||
allowUserFolderCreate: true | ||
} | ||
const LoginType = Object.freeze({ | ||
@@ -64,3 +70,3 @@ None: 0, | ||
this._opt.tls = Object.assign({}, TLSserverDefaults, options && options.tls) | ||
this._opt.cnf = Object.assign({}, FTPdefaults, options && options.cnf) | ||
this._opt.cnf = Object.assign({}, FTPdefaults, UserDefaults, options && options.cnf) | ||
this._useTLS = options && options.tls | ||
@@ -126,3 +132,3 @@ | ||
let authenticated = false | ||
let isSecure = socket.encrypted | ||
let isSecure = socket.encrypted || false | ||
let protection = false | ||
@@ -143,2 +149,3 @@ let username | ||
let retrOffset = 0 | ||
let allowFileCreate = false | ||
let allowFileOverwrite = false | ||
@@ -314,3 +321,3 @@ let allowFileDelete = false | ||
if (newPath.charAt(0) === '/') { | ||
let folder = path.normalize(basefolder + newPath) | ||
let folder = path.join(basefolder, newPath) | ||
if (fs.existsSync(folder) === true && fs.statSync(folder).isDirectory() === true && main._beginsWith(basefolder, folder) === true) { | ||
@@ -328,3 +335,3 @@ if (folder.charAt(folder.length - 1) !== '/') { | ||
} else if (newPath !== '..') { | ||
let folder = path.normalize(basefolder + relativePath + newPath) | ||
let folder = path.join(basefolder, relativePath, newPath) | ||
if (fs.existsSync(folder) === true && fs.statSync(folder).isDirectory() === true && main._beginsWith(basefolder, folder) === true) { | ||
@@ -341,18 +348,17 @@ if (folder.charAt(folder.length - 1) !== '/') { | ||
} | ||
} else if (relativePath !== '/') { | ||
newPath = relativePath.split('/') | ||
newPath.pop() | ||
newPath.pop() | ||
newPath = newPath.join('/') + '/' | ||
let folder = path.normalize(basefolder + newPath) | ||
if (fs.existsSync(folder) === true && fs.statSync(folder).isDirectory() === true && main._beginsWith(basefolder, folder) === true) { | ||
if (folder.charAt(folder.length - 1) !== '/') { | ||
folder += '/' | ||
} else if (newPath === '..') { | ||
if (relativePath !== '/') { | ||
newPath = relativePath.split('/') | ||
newPath.pop() | ||
newPath.pop() | ||
newPath = newPath.join('/') + '/' | ||
const folder = path.join(basefolder, newPath) | ||
if (fs.existsSync(folder) === true && fs.statSync(folder).isDirectory() === true && main._beginsWith(basefolder, folder) === true) { | ||
absolutePath = folder | ||
relativePath = newPath | ||
return main._writeToSocket(socket, '250', ' ', `CWD successful. "${relativePath}" is current directory`, connectionInfo, SocketStateAfterWrite.Open) | ||
} | ||
absolutePath = folder | ||
relativePath = newPath | ||
} else { | ||
return main._writeToSocket(socket, '250', ' ', `CWD successful. "${relativePath}" is current directory`, connectionInfo, SocketStateAfterWrite.Open) | ||
} | ||
} else if (relativePath === '/' && newPath === '..') { | ||
return main._writeToSocket(socket, '250', ' ', `CWD successful. "${relativePath}" is current directory`, connectionInfo, SocketStateAfterWrite.Open) | ||
} | ||
@@ -408,5 +414,5 @@ return main._writeToSocket(socket, '530', ' ', 'CWD not successful', connectionInfo, SocketStateAfterWrite.Open) | ||
if (folder.charAt(0) === '/') { | ||
folder = path.normalize(basefolder + folder) | ||
folder = path.join(basefolder, folder) | ||
} else { | ||
folder = path.normalize(basefolder + relativePath + folder) | ||
folder = path.join(basefolder, relativePath, folder) | ||
} | ||
@@ -431,5 +437,5 @@ if (allowFolderDelete && main._beginsWith(basefolder, folder) === true) { | ||
if (folder.charAt(0) === '/') { | ||
folder = path.normalize(basefolder + folder) | ||
folder = path.join(basefolder, folder) | ||
} else { | ||
folder = path.normalize(basefolder + relativePath + folder) | ||
folder = path.join(basefolder, relativePath, folder) | ||
} | ||
@@ -575,33 +581,41 @@ if (allowFolderCreate && main._beginsWith(basefolder, folder) === true) { | ||
if (relativeFile.charAt(0) === '/') { | ||
file = path.normalize(basefolder + relativeFile) | ||
file = path.join(basefolder, relativeFile) | ||
} else { | ||
file = path.normalize(basefolder + relativePath + relativeFile) | ||
file = path.join(basefolder, relativePath, relativeFile) | ||
} | ||
if (fs.existsSync(file) === true && fs.statSync(file).isFile() === true && main._beginsWith(basefolder, file) === true) { | ||
dataObj.method = function (obj) { | ||
dataObj.method = async function (obj) { | ||
if (obj.dataSocket && obj.cmdSocket && obj.file && obj.relativeFile) { | ||
const streamOpts = { | ||
flags: 'r', | ||
start: retrOffset, | ||
encoding: asciiOn ? 'ascii' : null, | ||
autoClose: true, | ||
emitClose: true | ||
} | ||
retrOffset = 0 | ||
asciiOn && obj.dataSocket.setEncoding('ascii') | ||
const stream = fs.createReadStream(obj.file, streamOpts) | ||
stream.on('error', main.ErrorHandler) | ||
stream.on('open', () => { | ||
obj.dataSocket.on('close', () => { | ||
if (!obj.dataSocket.destroyed) { | ||
stream.destroy() | ||
main._writeToSocket(obj.cmdSocket, '426', ' ', `Connection closed. Aborted transfer of "${obj.relativeFile}"`, connectionInfo, SocketStateAfterWrite.Open) | ||
} | ||
}) | ||
stream.pipe(obj.dataSocket) | ||
}) | ||
stream.on('end', () => { | ||
if (obj.handler) { | ||
const data = await obj.handler(username, relativePath, obj.fileName, retrOffset) | ||
retrOffset = 0 | ||
obj.dataSocket.write(data) | ||
obj.dataSocket.end() | ||
main._writeToSocket(obj.cmdSocket, '226', ' ', `Successfully transferred "${obj.relativeFile}"`, connectionInfo, SocketStateAfterWrite.Open) | ||
}) | ||
} else { | ||
const streamOpts = { | ||
flags: 'r', | ||
start: retrOffset, | ||
encoding: asciiOn ? 'ascii' : null, | ||
autoClose: true, | ||
emitClose: true | ||
} | ||
retrOffset = 0 | ||
const stream = fs.createReadStream(obj.file, streamOpts) | ||
stream.on('error', main.ErrorHandler) | ||
stream.on('open', () => { | ||
obj.dataSocket.on('close', () => { | ||
if (!obj.dataSocket.destroyed) { | ||
stream.destroy() | ||
main._writeToSocket(obj.cmdSocket, '426', ' ', `Connection closed. Aborted transfer of "${obj.relativeFile}"`, connectionInfo, SocketStateAfterWrite.Open) | ||
} | ||
}) | ||
stream.pipe(obj.dataSocket) | ||
}) | ||
stream.on('end', () => { | ||
obj.dataSocket.end() | ||
main._writeToSocket(obj.cmdSocket, '226', ' ', `Successfully transferred "${obj.relativeFile}"`, connectionInfo, SocketStateAfterWrite.Open) | ||
}) | ||
} | ||
} | ||
@@ -611,3 +625,5 @@ } | ||
dataObj.file = file | ||
dataObj.fileName = path.basename(file) | ||
dataObj.relativeFile = relativeFile | ||
dataObj.handler = main._opt.cnf.downloadHandler | ||
openDataChannel(dataObj) | ||
@@ -640,5 +656,5 @@ } else { | ||
if (relativeFile.charAt(0) === '/') { | ||
file = path.normalize(basefolder + relativeFile) | ||
file = path.join(basefolder, relativeFile) | ||
} else { | ||
file = path.normalize(basefolder + relativePath + relativeFile) | ||
file = path.join(basefolder, relativePath, relativeFile) | ||
} | ||
@@ -648,2 +664,5 @@ if (fs.existsSync(file) === true && allowFileOverwrite === false) { | ||
} | ||
if (fs.existsSync(file) === false && allowFileCreate === false) { | ||
return main._writeToSocket(socket, '550', ' ', `Transfer failed "${relativeFile}"`, connectionInfo, SocketStateAfterWrite.Open) | ||
} | ||
if (main._beginsWith(basefolder, file) === true) { | ||
@@ -663,4 +682,4 @@ dataObj.cmdSocket = socket | ||
obj.dataSocket.on('data', (d) => data.push(d)) | ||
obj.dataSocket.on('close', () => { | ||
obj.handler(relativePath, obj.fileName, Buffer.concat(data)) | ||
obj.dataSocket.on('close', async () => { | ||
await obj.handler(username, relativePath, obj.fileName, Buffer.concat(data), obj.retrOffset) | ||
main._writeToSocket(obj.cmdSocket, '226', ' ', `Successfully transferred "${obj.relativeFile}"`, connectionInfo, SocketStateAfterWrite.Open) | ||
@@ -678,2 +697,4 @@ }) | ||
if (dataObj.handler) { | ||
dataObj.retrOffset = retrOffset | ||
retrOffset = 0 | ||
openDataChannel(dataObj) | ||
@@ -703,3 +724,3 @@ } else { | ||
} else { | ||
main._writeToSocket(socket, '550', ' ', `Transfer failed "${relativeFile}`, connectionInfo, SocketStateAfterWrite.Open) | ||
main._writeToSocket(socket, '550', ' ', `Transfer failed "${relativeFile}"`, connectionInfo, SocketStateAfterWrite.Open) | ||
} | ||
@@ -774,5 +795,5 @@ } | ||
if (file.charAt(0) === '/') { | ||
file = path.normalize(basefolder + file) | ||
file = path.join(basefolder, file) | ||
} else { | ||
file = path.normalize(basefolder + relativePath + file) | ||
file = path.join(basefolder, relativePath, file) | ||
} | ||
@@ -825,3 +846,3 @@ if (fs.existsSync(file) === true && fs.statSync(file).isFile() === true && main._beginsWith(basefolder, file) === true) { | ||
for (let i = 0; i < main._opt.cnf.user.length; i++) { | ||
const u = main._opt.cnf.user[i] | ||
const u = Object.assign({}, UserDefaults, main._opt.cnf.user[i]) | ||
if (typeof u === 'object' && username === u.username) { | ||
@@ -851,2 +872,3 @@ if (Object.prototype.hasOwnProperty.call(u, 'allowLoginWithoutPassword') && u.allowLoginWithoutPassword === true) { | ||
if (username === 'anonymous' && main._opt.cnf.allowAnonymousLogin) { | ||
allowFileCreate = main._opt.cnf.allowAnonymousFileCreate | ||
allowFileOverwrite = main._opt.cnf.allowAnonymousFileOverwrite | ||
@@ -859,3 +881,3 @@ allowFileDelete = main._opt.cnf.allowAnonymousFileDelete | ||
for (let i = 0; i < main._opt.cnf.user.length; i++) { | ||
const u = main._opt.cnf.user[i] | ||
const u = Object.assign({}, UserDefaults, main._opt.cnf.user[i]) | ||
if (typeof u === 'object' && username === u.username && (u.allowLoginWithoutPassword === true || password === u.password)) { | ||
@@ -880,2 +902,3 @@ setUserRights(u) | ||
} | ||
Object.prototype.hasOwnProperty.call(obj, 'allowUserFileCreate') && (allowFileCreate = obj.allowUserFileCreate) | ||
Object.prototype.hasOwnProperty.call(obj, 'allowUserFileOverwrite') && (allowFileOverwrite = obj.allowUserFileOverwrite) | ||
@@ -962,3 +985,3 @@ Object.prototype.hasOwnProperty.call(obj, 'allowUserFileDelete') && (allowFileDelete = obj.allowUserFileDelete) | ||
_beginsWith (needle, haystack) { | ||
return (haystack.substr(0, needle.length) === needle) | ||
return haystack.startsWith(needle) | ||
} | ||
@@ -965,0 +988,0 @@ |
{ | ||
"name": "jsftpd", | ||
"id": "jsftpd", | ||
"version": "1.0.0", | ||
"description": "FTP server in pure javascript", | ||
"version": "1.1.0", | ||
"description": "FTP server for node.js", | ||
"main": "index.js", | ||
@@ -12,6 +12,10 @@ "repository": { | ||
"keywords": [ | ||
"nodejs", | ||
"ftp", | ||
"ftpd", | ||
"files", | ||
"daemon" | ||
"ftpd-server", | ||
"file-transfer", | ||
"ftp-server", | ||
"file-transfer-protocol", | ||
"ftpserver" | ||
], | ||
@@ -18,0 +22,0 @@ "author": { |
const { ftpd } = require('../index') | ||
const util = require('util') | ||
const net = require('net') | ||
@@ -8,6 +9,14 @@ const tls = require('tls') | ||
const formatPort = (addr, port) => { | ||
const p1 = (port) / 256 | 0 | ||
const p2 = (port) % 256 | ||
return util.format('%s,%d,%d', addr.split('.').join(','), p1, p2) | ||
} | ||
afterEach(() => { | ||
server.stop() | ||
server.cleanup() | ||
server = null | ||
if (server) { | ||
server.stop() | ||
server.cleanup() | ||
server = null | ||
} | ||
}); | ||
@@ -43,2 +52,28 @@ | ||
test('ftp server fails when basefolder does not exist', () => { | ||
try { | ||
server = new ftpd({cnf: {basefolder: '/NOTEXISTING'}}) | ||
} catch(err) { | ||
expect(err.message).toMatch('Basefolder must exist') | ||
} | ||
}); | ||
test('error message when not logged in', async () => { | ||
server = new ftpd({cnf: {port: 50021}}) | ||
expect(server).toBeInstanceOf(ftpd); | ||
server.start() | ||
const promiseSocket = new PromiseSocket(new net.Socket()) | ||
const socket = promiseSocket.stream | ||
let content | ||
await socket.connect(50021, 'localhost') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('220 Welcome') | ||
await promiseSocket.write('REST 0') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('530 Not logged in') | ||
await promiseSocket.end() | ||
}); | ||
test('login as anonymous not allowed by default', async () => { | ||
@@ -677,2 +712,3 @@ server = new ftpd({cnf: {port: 50021}}) | ||
allowLoginWithoutPassword: true, | ||
allowUserFolderCreate: false, | ||
} | ||
@@ -732,2 +768,6 @@ ] | ||
await promiseSocket.write('RMD /pete') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('550 Folder not found') | ||
await promiseSocket.write('RMD john') | ||
@@ -745,3 +785,4 @@ content = await promiseSocket.read(); | ||
allowLoginWithoutPassword: true, | ||
allowUserFolderCreate: true | ||
allowUserFolderCreate: true, | ||
allowUserFolderDelete: false, | ||
} | ||
@@ -929,2 +970,42 @@ ] | ||
test('test STOR message without permission', async () => { | ||
const users = [ | ||
{ | ||
username: 'john', | ||
allowLoginWithoutPassword: true, | ||
allowUserFileCreate: false, | ||
} | ||
] | ||
server = new ftpd({cnf: {port: 50021, user: users}}) | ||
expect(server).toBeInstanceOf(ftpd); | ||
server.start() | ||
let content | ||
let promiseSocket = new PromiseSocket(new net.Socket()) | ||
let socket = promiseSocket.stream | ||
await socket.connect(50021, 'localhost') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('220 Welcome') | ||
await promiseSocket.write('USER john') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('232 User logged in') | ||
await promiseSocket.write('EPSV') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('229 Entering extended passive mode (|||1024|)') | ||
let promiseDataSocket = new PromiseSocket(new net.Socket()) | ||
let dataSocket = promiseDataSocket.stream | ||
await dataSocket.connect(1024, 'localhost') | ||
await promiseSocket.write('STOR mytestfile') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('550 Transfer failed "mytestfile"') | ||
await dataSocket.end() | ||
await promiseSocket.end() | ||
}); | ||
test('test STOR message', async () => { | ||
@@ -953,2 +1034,6 @@ const users = [ | ||
await promiseSocket.write('STOR ../../mytestfile') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('550 Transfer failed "../../mytestfile"') | ||
await promiseSocket.write('EPSV') | ||
@@ -1004,6 +1089,8 @@ content = await promiseSocket.read(); | ||
] | ||
const handler = (path, filename, data) => { | ||
const handler = async (username, path, filename, data, offset) => { | ||
expect(username).toMatch('john') | ||
expect(filename).toMatch('mytestfile') | ||
expect(path).toMatch('/') | ||
expect(data.toString()).toMatch('SOMETESTCONTENT') | ||
expect(offset).toBe(0) | ||
} | ||
@@ -1098,2 +1185,6 @@ server = new ftpd({cnf: {uploadHandler: handler, port: 50021, user: users}}) | ||
await promiseSocket.write('RETR /someotherfile') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('550 File not found') | ||
await promiseSocket.write('RETR mytestfile') | ||
@@ -1113,2 +1204,74 @@ content = await promiseSocket.read(); | ||
test('test RETR message with handler', async () => { | ||
const users = [ | ||
{ | ||
username: 'john', | ||
allowLoginWithoutPassword: true, | ||
} | ||
] | ||
const handler = async (username, path, filename, offset) => { | ||
expect(username).toMatch('john') | ||
expect(filename).toMatch('mytestfile') | ||
expect(path).toMatch('/') | ||
expect(offset).toBe(0) | ||
return 'SOMETESTCONTENT' | ||
} | ||
server = new ftpd({cnf: {downloadHandler: handler, port: 50021, user: users}}) | ||
expect(server).toBeInstanceOf(ftpd); | ||
server.start() | ||
let content | ||
let promiseSocket = new PromiseSocket(new net.Socket()) | ||
let socket = promiseSocket.stream | ||
await socket.connect(50021, 'localhost') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('220 Welcome') | ||
await promiseSocket.write('USER john') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('232 User logged in') | ||
await promiseSocket.write('EPSV') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('229 Entering extended passive mode (|||1024|)') | ||
let promiseDataSocket = new PromiseSocket(new net.Socket()) | ||
let dataSocket = promiseDataSocket.stream | ||
await dataSocket.connect(1024, 'localhost') | ||
await promiseSocket.write('STOR mytestfile') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('150 Opening data channel') | ||
await promiseDataSocket.write('SOMETESTCONTENT'); | ||
dataSocket.end() | ||
await promiseDataSocket.end() | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('226 Successfully transferred "mytestfile"') | ||
await promiseSocket.write('EPSV') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('229 Entering extended passive mode (|||1024|)') | ||
promiseDataSocket = new PromiseSocket(new net.Socket()) | ||
dataSocket = promiseDataSocket.stream | ||
await dataSocket.connect(1024, 'localhost') | ||
await promiseSocket.write('RETR /someotherfile') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('550 File not found') | ||
await promiseSocket.write('RETR mytestfile') | ||
// content = await promiseSocket.read(); | ||
// expect(content.toString().trim()).toBe('150 Opening data channel') | ||
content = await promiseDataSocket.read(); | ||
expect(content.toString().trim()).toMatch('SOMETESTCONTENT') | ||
await promiseDataSocket.end() | ||
await promiseSocket.end() | ||
}); | ||
test('test MFMT message', async () => { | ||
@@ -1264,2 +1427,3 @@ const users = [ | ||
allowLoginWithoutPassword: true, | ||
allowUserFileDelete: false, | ||
} | ||
@@ -1352,2 +1516,6 @@ ] | ||
await promiseSocket.write('DELE someotherfile') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('550 File not found') | ||
await promiseSocket.write('DELE mytestfile') | ||
@@ -1567,1 +1735,91 @@ content = await promiseSocket.read(); | ||
}); | ||
test('test PORT message', async () => { | ||
const users = [ | ||
{ | ||
username: 'john', | ||
allowLoginWithoutPassword: true, | ||
allowUserFolderCreate: true | ||
} | ||
] | ||
server = new ftpd({cnf: {port: 50021, user: users}}) | ||
expect(server).toBeInstanceOf(ftpd); | ||
server.start() | ||
let content | ||
let promiseSocket = new PromiseSocket(new net.Socket()) | ||
let socket = promiseSocket.stream | ||
await socket.connect(50021, 'localhost') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('220 Welcome') | ||
await promiseSocket.write('USER john') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('232 User logged in') | ||
await promiseSocket.write('MKD john') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('250 Folder created successfully') | ||
const dataServer = net.createServer() | ||
let promiseDataSocket = new PromiseSocket(dataServer) | ||
await promiseDataSocket.stream.listen(20, '127.0.0.1') | ||
const portData = formatPort('127.0.0.1', 20) | ||
await promiseSocket.write(`PORT ${portData}`) | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('200 Port command successful') | ||
await promiseSocket.write('MLSD') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('150 Opening data channel') | ||
await promiseDataSocket.stream.close() | ||
await promiseSocket.end() | ||
}); | ||
test('test EPRT message', async () => { | ||
const users = [ | ||
{ | ||
username: 'john', | ||
allowLoginWithoutPassword: true, | ||
allowUserFolderCreate: true | ||
} | ||
] | ||
server = new ftpd({cnf: {port: 50021, user: users}}) | ||
expect(server).toBeInstanceOf(ftpd); | ||
server.start() | ||
let content | ||
let promiseSocket = new PromiseSocket(new net.Socket()) | ||
let socket = promiseSocket.stream | ||
await socket.connect(50021, 'localhost') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('220 Welcome') | ||
await promiseSocket.write('USER john') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('232 User logged in') | ||
await promiseSocket.write('MKD john') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('250 Folder created successfully') | ||
const dataServer = net.createServer() | ||
let promiseDataSocket = new PromiseSocket(dataServer) | ||
await promiseDataSocket.stream.listen(20, '127.0.0.1') | ||
await promiseSocket.write(`EPRT ||127.0.0.1|20|`) | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('200 Extended Port command successful') | ||
await promiseSocket.write('MLSD') | ||
content = await promiseSocket.read(); | ||
expect(content.toString().trim()).toBe('150 Opening data channel') | ||
await promiseDataSocket.stream.close() | ||
await promiseSocket.end() | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
138333
18
2579
42