pyftpd-sink 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #!/usr/bin/env python3
  2. import hashlib
  3. import os
  4. import pyftpdlib.authorizers
  5. import pyftpdlib.handlers
  6. import pyftpdlib.servers
  7. class SHA256Authorizer(pyftpdlib.authorizers.DummyAuthorizer):
  8. def validate_authentication(self, username, password, handler):
  9. # pyftpdlib/authorizers.py", line 110, in add_user
  10. # dic = {'pwd': str(password),
  11. # so we can not compare against .digest()
  12. password_hash = hashlib.sha256(password.encode()).hexdigest()
  13. if self.user_table[username]['pwd'] != password_hash.lower():
  14. raise pyftpdlib.authorizers.AuthenticationFailed()
  15. def serve(root_dir_path, username, password_sha256_hexdigest, control_port, passive_port):
  16. assert os.path.isdir(root_dir_path), root_dir_path
  17. authorizer = SHA256Authorizer()
  18. authorizer.add_user(
  19. username,
  20. password_sha256_hexdigest.lower(),
  21. homedir=root_dir_path,
  22. # https://pyftpdlib.readthedocs.io/en/latest/api.html#pyftpdlib.authorizers.DummyAuthorizer.add_user
  23. # e: change dir
  24. # m: mkdir
  25. # w: write
  26. perm='emw',
  27. msg_login='renshi ni hen gaoxing',
  28. msg_quit='zaijian',
  29. )
  30. handler = pyftpdlib.handlers.FTPHandler
  31. handler.authorizer = authorizer
  32. handler.banner = 'ni hao'
  33. # handler.masquerade_address = '192.168.1.1'
  34. handler.passive_ports = (passive_port,)
  35. server = pyftpdlib.servers.FTPServer((None, control_port), handler)
  36. # apparently requires +1 for unknown reasons
  37. server.max_cons = 1 + 1
  38. server.serve_forever()
  39. def _init_argparser():
  40. import argparse
  41. argparser = argparse.ArgumentParser()
  42. argparser.add_argument(
  43. '--root', '--root-dir',
  44. metavar='path',
  45. dest='root_dir_path',
  46. default=os.getcwd(),
  47. help='default: %(default)s',
  48. )
  49. argparser.add_argument(
  50. '--user', '--username',
  51. metavar='username',
  52. dest='username',
  53. required=True,
  54. )
  55. argparser.add_argument(
  56. '--pwd-hash', '--password-hash',
  57. metavar='sha256_hexdigest',
  58. dest='password_sha256_hexdigest',
  59. required=True,
  60. )
  61. argparser.add_argument(
  62. '--ctrl-port', '--control-port',
  63. metavar='port',
  64. dest='control_port',
  65. default=2121,
  66. )
  67. argparser.add_argument(
  68. '--pasv-port', '--passive-port',
  69. metavar='port',
  70. dest='passive_port',
  71. default=62121,
  72. )
  73. return argparser
  74. def main(argv):
  75. argparser = _init_argparser()
  76. args = argparser.parse_args(argv[1:])
  77. serve(**vars(args))
  78. return 0
  79. if __name__ == "__main__":
  80. import sys
  81. sys.exit(main(sys.argv))