Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.venv/
settings.ini
38 changes: 26 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,49 @@
# ssh_tunnel_wrapper

wrapper for opening web app using ssh tunnel

Wrapper is a tool that users can run on their PC or laptop. It creates an SSH tunnel and opens the web app behind ssh in its window automatically.

## Pyinstaller

### Linux

To compile for Linux (Ubuntu), run:

```shell
sudo apt-get install libpython3.12-dev

pip install pyinstaller

pyinstaller --enable-shared --onefile ssh_tunnel_wrapper.py
```

### Windows

Windows:

```powershell
pyinstaller --hidden-import=babel --hidden-import=babel.numbers ssh_tunnel_wrapper.py

```

settings.ini format:
## Python venv module

[DEFAULT]
```shell
cd ssh_tunnel_wrapper/
python3 -m venv .venv/
.venv/bin/activate
pip3 install -r requirements.txt
```

ssh_host = ssh_host
## Configuration

ssh_user = ssh_user
Configuration is based on your ```~/.ssh/config``` file.

local_port = local_port
Create file `settings.ini`

remote_host = remote_host # internal IP address behind ssh
```dosini
[DEFAULT]

remote_port = remote_port # port of web app
ssh_host = ssh_host # as defined in ssh_config
local_port = local_port # Port listened on 127.0.0.1
remote_host = remote_host # internal IP address or hostname
remote_port = remote_port # port of web app

ssh_private_key_path = /home/user1/.ssh/id_rsa
```
5 changes: 5 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
PyQt5
PyQtWebEngine
sshtunnel
Babel
paramiko
7 changes: 0 additions & 7 deletions settings.ini

This file was deleted.

74 changes: 1 addition & 73 deletions ssh_tunnel_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,6 @@ def settings_check_alert(InformativeText):
print(f"ssh tunnel wrapper | application version: {formatted_date}")
exit(1)

def is_positive_integer(value):
try:
int_value = int(value)
if int_value > 0:
return True
else:
return False
except ValueError:
return False

def is_valid_ip(ssh_host):
try:
ipaddress.ip_address(ssh_host)
return True
except ValueError:
return False

def is_valid_private_key(path):
try:
key = paramiko.RSAKey(filename=path)
return True
except paramiko.SSHException:
return False

def is_valid_unix_username(username):
if re.match(r'^[a-z][a-z0-9_-]{0,31}$', username):
return True
else:
return False

def format_date_now():
suffix = None
now = datetime.now()
Expand Down Expand Up @@ -91,54 +61,12 @@ def load_url(self):
config.read('settings.ini')

ssh_host = config.get('DEFAULT', 'ssh_host')
ssh_user = config.get('DEFAULT', 'ssh_user')
local_port = config.get('DEFAULT', 'local_port')
remote_host = config.get('DEFAULT', 'remote_host')
remote_port = config.get('DEFAULT', 'remote_port')
ssh_private_key_path = config.get('DEFAULT', 'ssh_private_key_path')

if ssh_host == 'ssh_host':
settings_check_alert(InformativeText = "The 'ssh_host' in file 'settings.ini' is not set!")
if ssh_user == 'ssh_user':
settings_check_alert(InformativeText = "The 'ssh_user' in file 'settings.ini' is not set!")
if local_port == 'local_port':
settings_check_alert(InformativeText = "The 'local_port' in file 'settings.ini' is not set!")
if remote_host == 'remote_host':
settings_check_alert(InformativeText = "The 'remote_host' in file 'settings.ini' is not set!")
if remote_port == 'remote_port':
settings_check_alert(InformativeText = "The 'remote_port' in file 'settings.ini' is not set!")
if ssh_private_key_path == 'ssh_private_key_path':
settings_check_alert(InformativeText = "The 'ssh_private_key_path' in file 'settings.ini' is not set!")

if is_positive_integer(local_port):
local_port = int(local_port)
else:
settings_check_alert(InformativeText = "The 'local_port' in file 'settings.ini' must be positive integer!")

if is_positive_integer(remote_port):
remote_port = int(remote_port)
else:
settings_check_alert(InformativeText = "The 'remote_port' in file 'settings.ini' must be positive integer!")

if not is_valid_ip(ssh_host):
settings_check_alert(InformativeText = "The 'ssh_host' in file 'settings.ini' must be valid IP address!")

if not is_valid_ip(remote_host):
settings_check_alert(InformativeText = "The 'remote_host' in file 'settings.ini' must be valid IP address!")

if not os.path.isfile(ssh_private_key_path):
settings_check_alert(InformativeText = f"The file {ssh_private_key_path} does not exist!")

if not is_valid_private_key(ssh_private_key_path):
settings_check_alert(InformativeText = f"The file {ssh_private_key_path} should be valid private ssh key!")

if not is_valid_unix_username(ssh_user):
settings_check_alert(InformativeText = f"The 'ssh_user' should be valid unix username!")

with SSHTunnelForwarder(
(ssh_host, 22),
ssh_username=ssh_user,
ssh_private_key=ssh_private_key_path,
ssh_host,
remote_bind_address=(remote_host, remote_port),
local_bind_address=('127.0.0.1', local_port)
) as tunnel:
Expand Down