pyftpd-sink 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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: current working directory',
  48. )
  49. argparser.add_argument(
  50. '--user', '--username',
  51. metavar='username',
  52. dest='username',
  53. required=not os.environ.get('FTP_USERNAME'),
  54. default=os.environ.get('FTP_USERNAME'),
  55. help='default: env var $FTP_USERNAME',
  56. )
  57. argparser.add_argument(
  58. '--pwd-hash', '--password-hash',
  59. metavar='sha256_hexdigest',
  60. dest='password_sha256_hexdigest',
  61. required=not os.environ.get('FTP_PASSWORD_SHA256'),
  62. default=os.environ.get('FTP_PASSWORD_SHA256'),
  63. help='default: env var $FTP_PASSWORD_SHA256',
  64. )
  65. argparser.add_argument(
  66. '--ctrl-port', '--control-port',
  67. metavar='port',
  68. dest='control_port',
  69. default=2121,
  70. )
  71. argparser.add_argument(
  72. '--pasv-port', '--passive-port',
  73. metavar='port',
  74. dest='passive_port',
  75. default=62121,
  76. )
  77. return argparser
  78. def main(argv):
  79. argparser = _init_argparser()
  80. args = argparser.parse_args(argv[1:])
  81. serve(**vars(args))
  82. return 0
  83. if __name__ == "__main__":
  84. import sys
  85. sys.exit(main(sys.argv))