{"id":41755337,"url":"https://github.com/kamicane/simple-ftpd","last_synced_at":"2026-01-25T01:35:44.509Z","repository":{"id":57095996,"uuid":"80381699","full_name":"kamicane/simple-ftpd","owner":"kamicane","description":"a simple ftp server","archived":false,"fork":false,"pushed_at":"2018-07-21T10:15:37.000Z","size":21,"stargazers_count":34,"open_issues_count":7,"forks_count":10,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-09-28T22:36:35.378Z","etag":null,"topics":["ftp-server"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kamicane.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-29T23:59:27.000Z","updated_at":"2024-10-17T11:25:05.000Z","dependencies_parsed_at":"2022-08-22T23:10:34.293Z","dependency_job_id":null,"html_url":"https://github.com/kamicane/simple-ftpd","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/kamicane/simple-ftpd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamicane%2Fsimple-ftpd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamicane%2Fsimple-ftpd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamicane%2Fsimple-ftpd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamicane%2Fsimple-ftpd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kamicane","download_url":"https://codeload.github.com/kamicane/simple-ftpd/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamicane%2Fsimple-ftpd/sbom","scorecard":{"id":548760,"data":{"date":"2025-08-11","repo":{"name":"github.com/kamicane/simple-ftpd","commit":"8aff1b48483c236d7a1a6aa864e786832cf6eff7"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/14 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-20T10:13:30.121Z","repository_id":57095996,"created_at":"2025-08-20T10:13:30.121Z","updated_at":"2025-08-20T10:13:30.121Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28740961,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-25T01:25:41.653Z","status":"ssl_error","status_checked_at":"2026-01-25T01:25:34.364Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ftp-server"],"created_at":"2026-01-25T01:35:44.447Z","updated_at":"2026-01-25T01:35:44.504Z","avatar_url":"https://github.com/kamicane.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# simple-ftpd\n\n`simple-ftpd` is a event based ftp-server for node.js.\n\n## Features\n\n- Supports multiple modern ftp clients such as FileZilla, WinSCP, Transmission.\n- A real File System is not required.\n- For now it only supports basic authentication.\n- It supports passive mode only.\n- It only supports streams for writing and reading files.\n- It currently only supports a subset of FTP commands, but it should be enough for any modern FTP client.\n- It is intended to be used mainly to create local network ftp servers.\n\nUsed [pyftpdlib](https://github.com/giampaolo/pyftpdlib) extensively as a reference for the FTP protocol specification, as reading RFC documents is super boring :=)\n\n## Install\n\n```sh\nyarn add simple-ftpd\n# or\nnpm install simple-ftpd --save\n```\n\n```js\nconst ftpd = require('simple-ftpd')\n```\n\n## API\n\nSyntax: `ftpd(opts, sessionCallback)` or `ftpd(host:port, sessionCallback)`\n\nShould you need more control, the `ftpd` function will return a [`net.Server`](https://nodejs.org/api/net.html#net_class_net_server) instance.\n\n## Example\n\nSimple, fs-based ftp server implementation example:\n\n```js\n'use strict'\n\nconst ftpd = require('simple-ftpd')\n\nftpd({ host: '127.0.0.1', port: 1337, root: '/public/files' }, (session) =\u003e {\n\n  session.on('pass', (username, password, cb) =\u003e {\n    if (username === 'superadmin' \u0026\u0026 password === '53cr3t') {\n      session.readOnly = false\n      session.root = '/private/secret/files'\n      cb(null, 'Welcome admin')\n    } else {\n      cb(null, 'Welcome guest')\n    }\n  })\n\n  session.on('stat', fs.stat)\n  // AKA\n  // session.on('stat', (pathName, cb) =\u003e {\n  //  fs.stat(pathName, cb)\n  // })\n\n  session.on('readdir', fs.readdir)\n  // AKA\n  // session.on('readdir', (pathName, cb) =\u003e {\n  //   fs.readdir(pathName, cb)\n  // })\n\n  session.on('read', (pathName, offset, cb) =\u003e {\n    cb(null, fs.createReadStream(pathName, { start: offset }))\n  })\n\n  session.on('write', (pathName, offset, cb) =\u003e {\n    cb(null, fs.createWriteStream(pathName, { start: offset }))\n  })\n\n  // I'd do some checking if I were you, but hey.\n\n  session.on('mkdir', fs.mkdir)\n  session.on('unlink', fs.unlink)\n  session.on('rename', fs.rename)\n  session.on('remove', require('rimraf'))\n})\n```\n\n## Options\n\n| option | | description |\n| --- | --- | --- |\n| `host` | required | Must be a valid ipv4 address (for now). Defaults to `127.0.0.1` |\n| `port` | required | Server port. Defaults to `1337`. |\n| `readOnly` | optional | Disables client write requests. Defaults to `true`. Can be overridden on a connection-basis by setting the readOnly property on the session object before logging in. |\n| `root` | optional | The path passed to events will always be joined to `root`. Can be overridden on a connection-basis by setting the root property on the session object before logging in. The ftp client will not see `root`, and will think he's at `/`. This is simply a convenience to avoid manually joining the path you get in every event. |\n| `maxConnections` | optional | Maximum number of server connections. Defaults to 10. |\n\nPassive connections will be initialized on an unused port assigned by the os.\n\nInstead of options, you can pass `${host}:${port}` (`\"192.168.1.10:1337\"`).\n\n## Events\n\nEvery event gets some arguments and a node-style callback you must call with an Error object (if any) and results.\n\nIf you do not listen to a specific event, then that feature will become unavailable to the client.\nFor example, if you do not listen to `write` events, the client will get a 502 error when trying to write files.\n\n### `pass [username, password, cb]`\n\nThe client wants to login with `username` and `password`.\nWill consider the user logged in if no error is passed to `cb()`\n\nUser names are always accepted, because (from pyftpdlib):\n\n\u003e In order to prevent a\n\u003e malicious client from determining valid usernames on a server,\n\u003e it is suggested by RFC-2577 that a server always return 331 to\n\u003e the USER command and then reject the combination of username\n\u003e and password for an invalid username when PASS is provided later.\n\n### `read [pathName, offset, cb]`:\n\nThe client wants to read the file at `pathName`, starting at `offset`.\nRequires a readable stream to be passed as `cb(null, readStream)`.\n\n### `write [pathName, offset, cb]`:\n\nThe client wants to write a file at `pathName`, starting at `offset`.\nRequires a writable stream to be passed as `cb(null, writeStream)`.\n\n### `stat [pathName, cb]`:\n\nthe client wants the stats to a file or directory at `pathName`.\nRequires a `fs.stat`-like object to be passed as `cb(null, stat)`.\n\nProperties are:\n\n```js\n{\n  // fs.stat mode\n  mode: 16822,\n  //  size in bytes\n  size: 12345,\n  // lastModifiedTime as Date or number (or whatever gets parsed by moment)\n  mtime: Date.now(),\n  // optional, will use it for display if available, otherwise \"owner\"\n  uname: 'kamicane',\n  // optional, will use it for display if available, otherwise \"group\"\n  gname: 'admins',\n}\n```\n\n### `readdir [pathName, cb]`:\n\nThe client wants a list of files in the directory `pathName`. requires an array of file names, relative to pathName, to be passed as `cb(null, list)`.\n\n### `mkdir [pathName, cb]`:\n\nThe client wants to create a directory at `pathName`.\nWill consider the directory written if no error is passed to `cb()`\n\n### `unlink [pathName, cb]`:\n\nThe client wants to delete the file at `pathName`.\nWill consider the file deleted if no error is passed to `cb()`\n\n### `remove [pathName, cb]`:\n\nThe client wants to remove a directory, and all of its contents, at `pathName`.\nWill consider the directory and its contents removed if no error is passed to `cb()`\n\n### `rename [fromName, toName, cb]`:\n\nThe client wants to rename a file or directory, from `fromName` to `toName`.\nWill consider the file renamed if no error is passed to `cb()`\n\n## CLI\n\nWhen installed globally, ftpd will provide a small cli, which will quickly create a fs-based ftp server.\n\nYou can use it like this:\n\n```sh\nftp-server /public/files --host 192.168.0.1 --port 1234 --max-connections 10\n```\n\n* `--host` will default to `127.0.0.1`\n* `--port` will default to `1337`\n* `--max-connections` will default to `10`\n* `--read-only` will default to `true`\n* Unless specified, the ftp root will default to `process.cwd()`\n\nThe cli will accept any login, so be careful when setting `--read-only` to `false`.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkamicane%2Fsimple-ftpd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkamicane%2Fsimple-ftpd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkamicane%2Fsimple-ftpd/lists"}