Skip to main content
Deno 2 is finally here 🎉️
Learn more

DFtpS - Deno Ftp Server

alt text deno doc

DFtpS is an FTP server based on ftp-srv with Deno.

Usage

Install

curl -fsSL https://deno.land/x/dftps/install.sh | sh

Install Specific Version

curl -fsSL https://deno.land/x/dftps/install.sh | sh -s v1.0.0

Make your own

Simple

import { Server } from "https://deno.land/x/dftps/server/mod.ts";
import type { UsernameResolvable, LoginResolvable } from "https://deno.land/x/dftps/server/connection.ts";

const serve = new Server({
  port: 21,
  hostname: "127.0.0.1" // (optional)
}, {
  /** Url for passive connection. */
  pasvUrl?: string; // (optional)
  /** Minimum port for passive connection. */
  pasvMin?: number; // (optional)
  /** Maximum port for passive connection. */
  pasvMax?: number; // (optional)
  /** Handle anonymous connexion. */
  anonymous?: boolean; // (optional)
  /** Sets the format to use for file stat queries such as "LIST". */
  fileFormat?: string; // (optional)
  /** Array of commands that are not allowed */
  blacklist?: string[];
});

for await (const connection of serve) {
  const { awaitUsername, awaitLogin } = connection;
  /** waiting to receiving username from connection */
  awaitUsername.then(({ username, resolveUsername }: UsernameResolvable) => {
    if (!username !== "my-username") return resolveUsername.reject("Incorrect username!");
    resolveUsername.resolve();
  });
  /** waiting to receiving password from connection and finalize the user authenticate */
  awaitLogin.then(async ({ password, resolvePassword }: LoginResolvable) => {
    if (password !== "my-password") return resolvePassword.reject("Wrong password!");
    resolvePassword.resolve({ root: "my-folder", uid: 1000, gid: 1000 });
  });
}

With database

import { Server } from "https://deno.land/x/dftps/server/mod.ts";
import type { UsernameResolvable, LoginResolvable } from "https://deno.land/x/dftps/server/connection.ts";

import createDb from "../db/mod.ts";
import Users from "../db/Users.ts";

await createDb({
  connector: "MariaDB" | "MongoDB" | "MySQL" | "PostgreSQL" | "SQLite",

  /* Maria, MySQL, PostgreSQL Example
  database: 'my-database',
  host: 'url-to-db.com',
  username: 'username',
  password: 'password',
  port: 3306 // (optional)
  */

  /* MongoDB Example
  uri: 'mongodb://127.0.0.1:27017',
  database: 'test'
  */

  /* SQLite Example
  filepath: './database.sqlite'
  */
});

const serve = new Server({
  port: 21,
  hostname: "127.0.0.1" // (optional)
}, {
  /** Url for passive connection. */
  pasvUrl: string, // (optional)
  /** Minimum port for passive connection. */
  pasvMin: number, // (optional)
  /** Maximum port for passive connection. */
  pasvMax: number, // (optional)
  /** Handle anonymous connexion. */
  anonymous: boolean, // (optional)
  /** Sets the format to use for file stat queries such as "LIST". */
  fileFormat: string, // (optional)
  /** Array of commands that are not allowed */
  blacklist: string[] // (optional)
});

for await (const connection of serve) {
  const { awaitUsername, awaitLogin } = connection;
  /** Get all users in database */
  const users = await Users.select("username", "password", "root", "uid", "gid").all();
  let user: Model;
  /** Waiting to receiving username from connection */
  awaitUsername.then(({ username, resolveUsername }: UsernameResolvable) => {
      const found = users.find(u => u.username === username);
      if (!found) return resolveUsername.reject("Incorrect username!");
      user = found;
      resolveUsername.resolve();
  });
  /** Waiting to receiving password from connection and finalize the user authenticate */
  awaitLogin.then(async ({ password, resolvePassword }: LoginResolvable) => {
      if (!user) return resolvePassword.reject("User not found!");
      if (! await verify(password, (user.password as string))) return resolvePassword.reject("Wrong password!");

      const { root, uid, gid } = user;
      resolvePassword.resolve({ root: (root as string), uid: (uid as number), gid: (gid as number) });
  });
}

Deno Dependencies

List of FTP commands

See COMMANDS.md

Contributing

See CONTRIBUTING.md

References