diff --git a/.gitignore b/.gitignore index 82f9275..4c607cb 100644 --- a/.gitignore +++ b/.gitignore @@ -85,7 +85,7 @@ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: -# .python-version +.python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. @@ -160,3 +160,8 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +# SSH Keys +ssh_host_key +*.key +*.pub diff --git a/ssh_server.py b/ssh_server.py new file mode 100644 index 0000000..86579a6 --- /dev/null +++ b/ssh_server.py @@ -0,0 +1,60 @@ +# To run this program, the file ``ssh_host_key`` must exist with an SSH +# private key in it to use as a server host key. An SSH host certificate +# can optionally be provided in the file ``ssh_host_key-cert.pub``. + +import asyncio, asyncssh, crypt, sys +from typing import Optional + +passwords = {'guest': '', # guest account with no password + 'user123': 'qV2iEadIGV2rw' # password of 'secretpw' + } + +async def handle_client(process: asyncssh.SSHServerProcess) -> None: + process.stdout.write('Welcome to my SSH server, %s!\n' % + process.get_extra_info('username')) + + try: + async for line in process.stdin: + line = line.rstrip('\n') + if line: + process.stdout.write('You entered: %s\n' % line) + except asyncssh.BreakReceived: + pass + + process.exit(0) + +class MySSHServer(asyncssh.SSHServer): + def connection_made(self, conn: asyncssh.SSHServerConnection) -> None: + print('SSH connection received from %s.' % + conn.get_extra_info('peername')[0]) + + def connection_lost(self, exc: Optional[Exception]) -> None: + if exc: + print('SSH connection error: ' + str(exc), file=sys.stderr) + else: + print('SSH connection closed.') + + def begin_auth(self, username: str) -> bool: + # If the user's password is the empty string, no auth is required + return passwords.get(username) != '' + + def password_auth_supported(self) -> bool: + return True + + def validate_password(self, username: str, password: str) -> bool: + pw = passwords.get(username, '*') + return crypt.crypt(password, pw) == pw + +async def start_server() -> None: + await asyncssh.create_server(MySSHServer, '', 8022, + server_host_keys=['ssh_host_key'], + process_factory=handle_client) + +loop = asyncio.get_event_loop() + +try: + loop.run_until_complete(start_server()) +except (OSError, asyncssh.Error) as exc: + sys.exit('Error starting server: ' + str(exc)) + +loop.run_forever() \ No newline at end of file