feat: convert commonjs to esm modules

This commit is contained in:
T. R. Bernstein
2025-05-29 15:38:05 +02:00
parent cf7c678136
commit 7a51ed9d07
58 changed files with 248 additions and 219 deletions

View File

@@ -1,8 +1,6 @@
const FtpSrv = require('./src')
const FileSystem = require('./src/fs')
const errors = require('./src/errors')
import FtpSrv from './src/index.js'
import FileSystem from './src/fs.js'
import ftpErrors from './src/errors.js'
module.exports = FtpSrv
module.exports.FtpSrv = FtpSrv
module.exports.FileSystem = FileSystem
module.exports.ftpErrors = errors
export default FtpSrv
export { FtpSrv, FileSystem, ftpErrors }

View File

@@ -17,6 +17,7 @@
"bin",
"ftp-srv.d.ts"
],
"type": "module",
"main": "ftp-srv.js",
"bin": "./bin/index.js",
"types": "./ftp-srv.d.ts",

View File

@@ -1,11 +1,10 @@
const _ = require('lodash')
const Promise = require('bluebird')
const REGISTRY = require('./registry')
import _ from 'lodash'
import Promise from 'bluebird'
import REGISTRY from './registry.js'
const CMD_FLAG_REGEX = new RegExp(/^-(\w{1})$/)
class FtpCommands {
export default class FtpCommands {
constructor(connection) {
this.connection = connection
this.previousCommand = {}
@@ -75,4 +74,3 @@ class FtpCommands {
})
}
}
module.exports = FtpCommands

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
directive: 'ABOR',
handler: function () {
return this.connector

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
directive: 'ALLO',
handler: function () {
return this.reply(202)

View File

@@ -1,9 +1,9 @@
const stor = require('./stor').handler
import stor from './stor.js'
module.exports = {
export default {
directive: 'APPE',
handler: function (args) {
return stor.call(this, args)
return stor.handler.call(this, args)
},
syntax: '{{cmd}} <path>',
description: 'Append to a file'

View File

@@ -1,7 +1,7 @@
const _ = require('lodash')
const tls = require('tls')
import _ from 'lodash'
import tls from 'node:tls'
module.exports = {
export default {
directive: 'AUTH',
handler: function ({ command } = {}) {
const method = _.upperCase(command.arg)

View File

@@ -1,10 +1,10 @@
const cwd = require('./cwd').handler
import cwd from './cwd.js'
module.exports = {
export default {
directive: ['CDUP', 'XCUP'],
handler: function (args) {
args.command.arg = '..'
return cwd.call(this, args)
return cwd.handler.call(this, args)
},
syntax: '{{cmd}}',
description: 'Change to Parent Directory'

View File

@@ -1,7 +1,7 @@
const Promise = require('bluebird')
const escapePath = require('../../helpers/escape-path')
import Promise from 'bluebird'
import escapePath from '../../helpers/escape-path.js'
module.exports = {
export default {
directive: ['CWD', 'XCWD'],
handler: function ({ log, command } = {}) {
if (!this.fs) return this.reply(550, 'File system not instantiated')

View File

@@ -1,6 +1,6 @@
const Promise = require('bluebird')
import Promise from 'bluebird'
module.exports = {
export default {
directive: 'DELE',
handler: function ({ log, command } = {}) {
if (!this.fs) return this.reply(550, 'File system not instantiated')

View File

@@ -1,12 +1,12 @@
const _ = require('lodash')
const ActiveConnector = require('../../connector/active')
import _ from 'lodash'
import ActiveConnector from '../../connector/active.js'
const FAMILY = {
1: 4,
2: 6
}
module.exports = {
export default {
directive: 'EPRT',
handler: function ({ log, command } = {}) {
const [, protocol, ip, port] = _.chain(command).get('arg', '').split('|').value()

View File

@@ -1,6 +1,6 @@
const PassiveConnector = require('../../connector/passive')
import PassiveConnector from '../../connector/passive.js'
module.exports = {
export default {
directive: 'EPSV',
handler: function ({ log }) {
this.connector = new PassiveConnector(this)

View File

@@ -1,9 +1,9 @@
const _ = require('lodash')
import _ from 'lodash'
module.exports = {
export default {
directive: 'FEAT',
handler: function () {
const registry = require('../registry')
const registry = import('../registry')
const features = Object.keys(registry)
.reduce(
(feats, cmd) => {

View File

@@ -1,9 +1,9 @@
const _ = require('lodash')
import _ from 'lodash'
module.exports = {
export default {
directive: 'HELP',
handler: function ({ command } = {}) {
const registry = require('../registry')
const registry = import('../registry')
const directive = _.upperCase(command.arg)
if (directive) {
if (!registry.hasOwnProperty(directive)) return this.reply(502, `Unknown command ${directive}.`)

View File

@@ -1,10 +1,10 @@
const _ = require('lodash')
const Promise = require('bluebird')
const getFileStat = require('../../helpers/file-stat')
import _ from 'lodash'
import Promise from 'bluebird'
import getFileStat from '../../helpers/file-stat.js'
// http://cr.yp.to/ftp/list.html
// http://cr.yp.to/ftp/list/eplf.html
module.exports = {
export default {
directive: 'LIST',
handler: function ({ log, command } = {}) {
if (!this.fs) return this.reply(550, 'File system not instantiated')

View File

@@ -1,7 +1,7 @@
const Promise = require('bluebird')
const moment = require('moment')
import Promise from 'bluebird'
import moment from 'moment'
module.exports = {
export default {
directive: 'MDTM',
handler: function ({ log, command } = {}) {
if (!this.fs) return this.reply(550, 'File system not instantiated')

View File

@@ -1,7 +1,7 @@
const Promise = require('bluebird')
const escapePath = require('../../helpers/escape-path')
import Promise from 'bluebird'
import escapePath from '../../helpers/escape-path.js'
module.exports = {
export default {
directive: ['MKD', 'XMKD'],
handler: function ({ log, command } = {}) {
if (!this.fs) return this.reply(550, 'File system not instantiated')

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
directive: 'MODE',
handler: function ({ command } = {}) {
return this.reply(/^S$/i.test(command.arg) ? 200 : 504)

View File

@@ -1,9 +1,9 @@
const list = require('./list').handler
import list from './list.js'
module.exports = {
export default {
directive: 'NLST',
handler: function (args) {
return list.call(this, args)
return list.handler.call(this, args)
},
syntax: '{{cmd}} [<path>]',
description: 'Returns a list of file names in a specified directory'

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
directive: 'NOOP',
handler: function () {
return this.reply(200)

View File

@@ -1,11 +1,11 @@
const _ = require('lodash')
import _ from 'lodash'
const OPTIONS = {
UTF8: utf8,
'UTF-8': utf8
}
module.exports = {
export default {
directive: 'OPTS',
handler: function ({ command } = {}) {
if (!_.has(command, 'arg')) return this.reply(501)

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
directive: 'PASS',
handler: function ({ log, command } = {}) {
if (!this.username) return this.reply(503)

View File

@@ -1,8 +1,8 @@
const Promise = require('bluebird')
const PassiveConnector = require('../../connector/passive')
const { isLocalIP } = require('../../helpers/is-local')
import Promise from 'bluebird'
import PassiveConnector from '../../connector/passive.js'
import { isLocalIP } from '../../helpers/is-local.js'
module.exports = {
export default {
directive: 'PASV',
handler: function ({ log } = {}) {
if (!this.server.options.pasv_url) {

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
directive: 'PBSZ',
handler: function ({ command } = {}) {
if (!this.secure) return this.reply(202, 'Not supported')

View File

@@ -1,7 +1,7 @@
const _ = require('lodash')
const ActiveConnector = require('../../connector/active')
import _ from 'lodash'
import ActiveConnector from '../../connector/active.js'
module.exports = {
export default {
directive: 'PORT',
handler: function ({ log, command } = {}) {
this.connector = new ActiveConnector(this)

View File

@@ -1,6 +1,6 @@
const _ = require('lodash')
import _ from 'lodash'
module.exports = {
export default {
directive: 'PROT',
handler: function ({ command } = {}) {
if (!this.secure) return this.reply(202, 'Not supported')

View File

@@ -1,7 +1,7 @@
const Promise = require('bluebird')
const escapePath = require('../../helpers/escape-path')
import Promise from 'bluebird'
import escapePath from '../../helpers/escape-path.js'
module.exports = {
export default {
directive: ['PWD', 'XPWD'],
handler: function ({ log } = {}) {
if (!this.fs) return this.reply(550, 'File system not instantiated')

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
directive: 'QUIT',
handler: function () {
return this.close(221, 'Client called QUIT')

View File

@@ -1,6 +1,6 @@
const _ = require('lodash')
import _ from 'lodash'
module.exports = {
export default {
directive: 'REST',
handler: function ({ command } = {}) {
const arg = _.get(command, 'arg')

View File

@@ -1,6 +1,6 @@
const Promise = require('bluebird')
import Promise from 'bluebird'
module.exports = {
export default {
directive: 'RETR',
handler: function ({ log, command } = {}) {
if (!this.fs) return this.reply(550, 'File system not instantiated')

View File

@@ -1,9 +1,9 @@
const { handler: dele } = require('./dele')
import dele from './dele.js'
module.exports = {
export default {
directive: ['RMD', 'XRMD'],
handler: function (args) {
return dele.call(this, args)
return dele.handler.call(this, args)
},
syntax: '{{cmd}} <path>',
description: 'Remove a directory'

View File

@@ -1,6 +1,6 @@
const Promise = require('bluebird')
import Promise from 'bluebird'
module.exports = {
export default {
directive: 'RNFR',
handler: function ({ log, command } = {}) {
if (!this.fs) return this.reply(550, 'File system not instantiated')

View File

@@ -1,6 +1,6 @@
const Promise = require('bluebird')
import Promise from 'bluebird'
module.exports = {
export default {
directive: 'RNTO',
handler: function ({ log, command } = {}) {
if (!this.renameFrom) return this.reply(503)

View File

@@ -1,6 +1,6 @@
const Promise = require('bluebird')
import Promise from 'bluebird'
module.exports = function ({ log, command } = {}) {
export default function ({ log, command } = {}) {
if (!this.fs) return this.reply(550, 'File system not instantiated')
if (!this.fs.chmod) return this.reply(402, 'Not supported by file system')

View File

@@ -1,9 +1,9 @@
const Promise = require('bluebird')
const _ = require('lodash')
import Promise from 'bluebird'
import _ from 'lodash'
const registry = require('./registry')
import registry from './registry.js'
module.exports = {
export default {
directive: 'SITE',
handler: function ({ log, command } = {}) {
const rawSubCommand = _.get(command, 'arg', '')

View File

@@ -1,5 +1,6 @@
module.exports = {
import chmod from './chmod.js'
export default {
CHMOD: {
handler: require('./chmod')
handler: chmod
}
}

View File

@@ -1,6 +1,6 @@
const Promise = require('bluebird')
import Promise from 'bluebird'
module.exports = {
export default {
directive: 'SIZE',
handler: function ({ log, command } = {}) {
if (!this.fs) return this.reply(550, 'File system not instantiated')

View File

@@ -1,8 +1,8 @@
const _ = require('lodash')
const Promise = require('bluebird')
const getFileStat = require('../../helpers/file-stat')
import _ from 'lodash'
import Promise from 'bluebird'
import getFileStat from '../../helpers/file-stat.js'
module.exports = {
export default {
directive: 'STAT',
handler: function (args = {}) {
const { log, command } = args

View File

@@ -1,6 +1,6 @@
const Promise = require('bluebird')
import Promise from 'bluebird'
module.exports = {
export default {
directive: 'STOR',
handler: function ({ log, command } = {}) {
if (!this.fs) return this.reply(550, 'File system not instantiated')

View File

@@ -1,7 +1,7 @@
const Promise = require('bluebird')
const { handler: stor } = require('./stor')
import Promise from 'bluebird'
import stor from './stor.js'
module.exports = {
export default {
directive: 'STOU',
handler: function (args) {
if (!this.fs) return this.reply(550, 'File system not instantiated')
@@ -13,7 +13,7 @@ module.exports = {
.catch(() => fileName)
.then((name) => {
args.command.arg = name
return stor.call(this, args)
return stor.handler.call(this, args)
})
},
syntax: '{{cmd}}',

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
directive: 'STRU',
handler: function ({ command } = {}) {
return this.reply(/^F$/i.test(command.arg) ? 200 : 504)

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
directive: 'SYST',
handler: function () {
return this.reply(215)

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
directive: 'TYPE',
handler: function ({ command } = {}) {
if (/^A[0-9]?$/i.test(command.arg)) {

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
directive: 'USER',
handler: function ({ log, command } = {}) {
if (this.username) return this.reply(530, 'Username already set')

View File

@@ -1,44 +1,84 @@
import abor from './registration/abor.js'
import allo from './registration/allo.js'
import appe from './registration/appe.js'
import auth from './registration/auth.js'
import cdup from './registration/cdup.js'
import cwd from './registration/cwd.js'
import dele from './registration/dele.js'
import feat from './registration/feat.js'
import help from './registration/help.js'
import list from './registration/list.js'
import mdtm from './registration/mdtm.js'
import mkd from './registration/mkd.js'
import mode from './registration/mode.js'
import nlst from './registration/nlst.js'
import noop from './registration/noop.js'
import opts from './registration/opts.js'
import pass from './registration/pass.js'
import pasv from './registration/pasv.js'
import port from './registration/port.js'
import pwd from './registration/pwd.js'
import quit from './registration/quit.js'
import rest from './registration/rest.js'
import retr from './registration/retr.js'
import rmd from './registration/rmd.js'
import rnfr from './registration/rnfr.js'
import rnto from './registration/rnto.js'
import site from './registration/site/index.js'
import size from './registration/size.js'
import stat from './registration/stat.js'
import stor from './registration/stor.js'
import stou from './registration/stou.js'
import stru from './registration/stru.js'
import syst from './registration/syst.js'
import type from './registration/type.js'
import user from './registration/user.js'
import pbsz from './registration/pbsz.js'
import prot from './registration/prot.js'
import eprt from './registration/eprt.js'
import epsv from './registration/epsv.js'
/* eslint no-return-assign: 0 */
const commands = [
require('./registration/abor'),
require('./registration/allo'),
require('./registration/appe'),
require('./registration/auth'),
require('./registration/cdup'),
require('./registration/cwd'),
require('./registration/dele'),
require('./registration/feat'),
require('./registration/help'),
require('./registration/list'),
require('./registration/mdtm'),
require('./registration/mkd'),
require('./registration/mode'),
require('./registration/nlst'),
require('./registration/noop'),
require('./registration/opts'),
require('./registration/pass'),
require('./registration/pasv'),
require('./registration/port'),
require('./registration/pwd'),
require('./registration/quit'),
require('./registration/rest'),
require('./registration/retr'),
require('./registration/rmd'),
require('./registration/rnfr'),
require('./registration/rnto'),
require('./registration/site'),
require('./registration/size'),
require('./registration/stat'),
require('./registration/stor'),
require('./registration/stou'),
require('./registration/stru'),
require('./registration/syst'),
require('./registration/type'),
require('./registration/user'),
require('./registration/pbsz'),
require('./registration/prot'),
require('./registration/eprt'),
require('./registration/epsv')
abor,
allo,
appe,
auth,
cdup,
cwd,
dele,
feat,
help,
list,
mdtm,
mkd,
mode,
nlst,
noop,
opts,
pass,
pasv,
port,
pwd,
quit,
rest,
retr,
rmd,
rnfr,
rnto,
site,
size,
stat,
stor,
stou,
stru,
syst,
type,
user,
pbsz,
prot,
eprt,
epsv
]
const registry = commands.reduce((result, cmd) => {
@@ -47,4 +87,4 @@ const registry = commands.reduce((result, cmd) => {
return result
}, {})
module.exports = registry
export default registry

View File

@@ -1,15 +1,14 @@
const _ = require('lodash')
const uuid = require('uuid')
const Promise = require('bluebird')
const EventEmitter = require('events')
import _ from 'lodash'
import uuid from 'uuid'
import Promise from 'bluebird'
import { EventEmitter } from 'node:events'
import BaseConnector from './connector/base.js'
import { FileSystem } from './fs.js'
import Commands from './commands/index.js'
import errors from './errors.js'
import DEFAULT_MESSAGE from './messages.js'
const BaseConnector = require('./connector/base')
const FileSystem = require('./fs')
const Commands = require('./commands')
const errors = require('./errors')
const DEFAULT_MESSAGE = require('./messages')
class FtpConnection extends EventEmitter {
export default class FtpConnection extends EventEmitter {
constructor(server, options) {
super()
this.server = server
@@ -161,4 +160,3 @@ class FtpConnection extends EventEmitter {
})
}
}
module.exports = FtpConnection

View File

@@ -1,11 +1,11 @@
const { Socket } = require('net')
const tls = require('tls')
const ip = require('ip')
const Promise = require('bluebird')
const Connector = require('./base')
const { SocketError } = require('../errors')
import { Socket } from 'node:net'
import tls from 'node:tls'
import ip from 'ip'
import Promise from 'bluebird'
import Connector from './base.js'
import errors from '../errors.js'
class Active extends Connector {
export default class Active extends Connector {
constructor(connection) {
super(connection)
this.type = 'active'
@@ -29,7 +29,7 @@ class Active extends Connector {
return closeExistingServer().then(() => {
if (!ip.isEqual(this.connection.commandSocket.remoteAddress, host)) {
throw new SocketError('The given address is not yours', 500)
throw new errors.SocketError('The given address is not yours', 500)
}
this.dataSocket = new Socket()
@@ -55,4 +55,3 @@ class Active extends Connector {
})
}
}
module.exports = Active

View File

@@ -1,7 +1,7 @@
const Promise = require('bluebird')
const errors = require('../errors')
import Promise from 'bluebird'
import errors from '../errors.js'
class Connector {
export default class Connector {
constructor(connection) {
this.connection = connection
@@ -49,4 +49,3 @@ class Connector {
this.connection.connector = new Connector(this)
}
}
module.exports = Connector

View File

@@ -1,14 +1,14 @@
const net = require('net')
const tls = require('tls')
const ip = require('ip')
const Promise = require('bluebird')
import net from 'node:net'
import tls from 'node:tls'
import ip from 'ip'
import Promise from 'bluebird'
const Connector = require('./base')
const errors = require('../errors')
import Connector from './base.js'
import errors from '../errors.js'
const CONNECT_TIMEOUT = 30 * 1000
class Passive extends Connector {
export default class Passive extends Connector {
constructor(connection) {
super(connection)
this.type = 'passive'
@@ -119,4 +119,3 @@ class Passive extends Connector {
})
}
}
module.exports = Passive

View File

@@ -30,7 +30,7 @@ class ConnectorError extends Error {
}
}
module.exports = {
export default {
SocketError,
FileSystemError,
ConnectorError,

View File

@@ -1,15 +1,15 @@
const _ = require('lodash')
const nodePath = require('path')
const uuid = require('uuid')
const Promise = require('bluebird')
const { createReadStream, createWriteStream, constants } = require('fs')
const fsAsync = require('./helpers/fs-async')
const errors = require('./errors')
import _ from 'lodash'
import nodePath from 'node:path'
import uuid from 'uuid'
import Promise from 'bluebird'
import { createReadStream, createWriteStream, constants } from 'node:fs'
import fsAsync from './helpers/fs-async.js'
import errors from './errors.js'
const UNIX_SEP_REGEX = /\//g
const WIN_SEP_REGEX = /\\/g
class FileSystem {
export default class FileSystem {
constructor(connection, { root, cwd } = {}) {
this.connection = connection
this.cwd = nodePath.normalize((cwd || '/').replace(WIN_SEP_REGEX, '/'))
@@ -141,4 +141,5 @@ class FileSystem {
return uuid.v4().replace(/\W/g, '')
}
}
module.exports = FileSystem
export { FileSystem }

View File

@@ -1,3 +1,3 @@
module.exports = function (path) {
export default function (path) {
return path.replace(/"/g, '""')
}

View File

@@ -1,13 +1,13 @@
const _ = require('lodash')
const moment = require('moment')
const errors = require('../errors')
import _ from 'lodash'
import moment from 'moment'
import errors from '../errors.js'
const FORMATS = {
ls,
ep
}
module.exports = function (fileStat, format = 'ls') {
export default function (fileStat, format = 'ls') {
if (typeof format === 'function') return format(fileStat)
if (!FORMATS.hasOwnProperty(format)) {
throw new errors.FileSystemError('Bad file stat formatter')

View File

@@ -1,5 +1,5 @@
const net = require('net')
const errors = require('../errors')
import net from 'node:net'
import errors from '../errors.js'
const MAX_PORT = 65535
const MAX_PORT_CHECK_ATTEMPT = 5
@@ -56,7 +56,4 @@ function getNextPortFactory(host, portMin, portMax, maxAttempts = MAX_PORT_CHECK
})
}
module.exports = {
getNextPortFactory,
portNumberGenerator
}
export { getNextPortFactory, portNumberGenerator }

View File

@@ -1,9 +1,9 @@
const fs = require('fs')
const { promisify } = require('bluebird')
import fs from 'node:fs'
import Promise from 'bluebird'
const methods = ['stat', 'readdir', 'access', 'unlink', 'rmdir', 'mkdir', 'rename', 'chmod']
module.exports = methods.reduce((obj, method) => {
obj[method] = promisify(fs[method])
export default methods.reduce((obj, method) => {
obj[method] = Promise.promisify(fs[method])
return obj
}, {})

View File

@@ -1,3 +1,3 @@
module.exports.isLocalIP = function (ip) {
export const isLocalIP = function (ip) {
return ip === '127.0.0.1' || ip == '::1'
}

View File

@@ -1,15 +1,14 @@
const _ = require('lodash')
const Promise = require('bluebird')
const nodeUrl = require('url')
const buyan = require('bunyan')
const net = require('net')
const tls = require('tls')
const EventEmitter = require('events')
import _ from 'lodash'
import Promise from 'bluebird'
import nodeUrl from 'node:url'
import buyan from 'bunyan'
import net from 'node:net'
import tls from 'node:tls'
import { EventEmitter } from 'node:events'
import Connection from './connection.js'
import { getNextPortFactory } from './helpers/find-port.js'
const Connection = require('./connection')
const { getNextPortFactory } = require('./helpers/find-port')
class FtpServer extends EventEmitter {
export default class FtpServer extends EventEmitter {
constructor(options = {}) {
super()
this.options = Object.assign(
@@ -193,4 +192,3 @@ class FtpServer extends EventEmitter {
})
}
}
module.exports = FtpServer

View File

@@ -1,4 +1,4 @@
module.exports = {
export default {
// 100 - 199 :: Remarks
100: 'The requested action is being initiated',
110: 'Restart marker reply',