pyftpd-sink 2.6 KB

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