#!/usr/bin/env python3

import hashlib
import os
import pyftpdlib.authorizers
import pyftpdlib.handlers
import pyftpdlib.servers


class SHA256Authorizer(pyftpdlib.authorizers.DummyAuthorizer):

    def validate_authentication(self, username, password, handler):
        # pyftpdlib/authorizers.py", line 110, in add_user
        #   dic = {'pwd': str(password),
        # so we can not compare against .digest()
        password_hash = hashlib.sha256(password.encode()).hexdigest()
        if self.user_table[username]['pwd'] != password_hash.lower():
            raise pyftpdlib.authorizers.AuthenticationFailed()


def serve(root_dir_path, username, password_sha256_hexdigest, control_port, passive_port):
    assert os.path.isdir(root_dir_path), root_dir_path
    authorizer = SHA256Authorizer()
    authorizer.add_user(
        username,
        password_sha256_hexdigest.lower(),
        homedir=root_dir_path,
        # https://pyftpdlib.readthedocs.io/en/latest/api.html#pyftpdlib.authorizers.DummyAuthorizer.add_user
        # e: change dir
        # m: mkdir
        # w: write
        perm='emw',
        msg_login='renshi ni hen gaoxing',
        msg_quit='zaijian',
    )
    handler = pyftpdlib.handlers.FTPHandler
    handler.authorizer = authorizer
    handler.banner = 'ni hao'
    # handler.masquerade_address = '192.168.1.1'
    handler.passive_ports = (passive_port,)
    server = pyftpdlib.servers.FTPServer((None, control_port), handler)
    # apparently requires +1 for unknown reasons
    server.max_cons = 1 + 1
    server.serve_forever()


def _init_argparser():
    import argparse
    argparser = argparse.ArgumentParser()
    argparser.add_argument(
        '--root', '--root-dir',
        metavar='path',
        dest='root_dir_path',
        default=os.getcwd(),
        help='default: current working directory',
    )
    argparser.add_argument(
        '--user', '--username',
        metavar='username',
        dest='username',
        required=not os.environ.get('FTP_USERNAME'),
        default=os.environ.get('FTP_USERNAME'),
        help='default: env var $FTP_USERNAME',
    )
    argparser.add_argument(
        '--pwd-hash', '--password-hash',
        metavar='sha256_hexdigest',
        dest='password_sha256_hexdigest',
        required=not os.environ.get('FTP_PASSWORD_SHA256'),
        default=os.environ.get('FTP_PASSWORD_SHA256'),
        help='default: env var $FTP_PASSWORD_SHA256',
    )
    argparser.add_argument(
        '--ctrl-port', '--control-port',
        metavar='port',
        dest='control_port',
        default=2121,
    )
    argparser.add_argument(
        '--pasv-port', '--passive-port',
        metavar='port',
        dest='passive_port',
        default=62121,
    )
    return argparser


def main(argv):
    argparser = _init_argparser()
    args = argparser.parse_args(argv[1:])
    serve(**vars(args))
    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main(sys.argv))
