Skip to content

Instantly share code, notes, and snippets.

@Bomberus
Last active May 5, 2020 23:21
Show Gist options
  • Save Bomberus/c53b1de1192ab349a55c750dacaf519e to your computer and use it in GitHub Desktop.
Save Bomberus/c53b1de1192ab349a55c750dacaf519e to your computer and use it in GitHub Desktop.
Remote Connection with Python + tigerVNC + ngrok + Telegram

beispiel

What it does

Present a simple python application. After clicking connect, the sysadmin gets the grok address to connect to client via vnc.

Prerequisites

  • TigerVNC needs to be installed
  • ngrok binary in path
  • Create VNC Authentication file: vncpasswd pass
  • Replace authtoken (telegram/ngrok) with your own!
  • set Telegram Chat ID

Run

pip install layoutx aiohttp

python ./main.py

Bundle

python -O -m PyInstaller 
--noconsole --icon="layoutx/resources/favicon.ico" --hidden-import="packaging.requirement
s" --hidden-import="pkg_resources.py2_warn" main.py --onefile
import os
from pathlib import Path
import json
import aiohttp
import asyncio
from layoutx import app
from layoutx.store import create_store
from layoutx.view import View, ResizeOption
home = str(Path.home())
ngrok_home = Path(home) / ".ngrok2"
if not Path(ngrok_home).exists():
Path(ngrok_home).mkdir( exist_ok=True )
with open(Path(ngrok_home) / "ngrok.yml", "w") as authToken:
authToken.write("authtoken: xxx")
authToken.write("\n")
authToken.write("region: eu")
processes = []
store = create_store({},{
"ipv4": "0.0.0.0",
"ipv6": "::0",
"hostname": "",
"vnc_status": False
})
async def _read_stream(stream, cb):
while True:
line = await stream.readline()
if line and cb:
cb(line)
else:
break
async def _stream_subprocess(cmd, stdout_cb, stderr_cb):
global processes
process = await asyncio.create_subprocess_exec(*cmd,
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
processes.append(process)
await asyncio.wait([
_read_stream(process.stdout, stdout_cb),
_read_stream(process.stderr, stderr_cb)
])
return await process.wait()
async def execute(cmd, stdout_cb, stderr_cb):
rc = await _stream_subprocess(
cmd,
stdout_cb,
stderr_cb,
)
return rc
async def sendMessage(text):
session = aiohttp.ClientSession()
await session.post("https://api.telegram.org/botxxx/sendMessage", data={ "chat_id": 0, "text": text })
await session.close()
async def get_ngrok():
await asyncio.sleep(5)
session = aiohttp.ClientSession()
async with session.get("http://127.0.0.1:4040/api/tunnels") as r:
ngrok = json.loads(await r.text())
hostname = ngrok["tunnels"][0]["public_url"]
await sendMessage(hostname)
store.dispatch("SET_VALUE", { "path": ["hostname"], "value": hostname })
await session.close()
class AppView(View):
geometry = "400x110+200+200"
title = "Remote Helper"
resizable = ResizeOption.NONE
template= """\
Box
Box(orient="horizontal")
Label Hostname:
Label {hostname}
Box(orient="horizontal")
Label IPv4:
Label {ipv4}
Box(orient="horizontal")
Label IPv6:
Label {ipv6}
Box(orient="horizontal")
Label VNC:
Label {vnc_status}
Button(if="{not vnc_status}" command="{contact_max}") Create remote
Button(if="{vnc_status}" command="{stop}") Stop
"""
async def contact_max(self):
#await execute(
# ["./ngrok", "tcp", "5900"],
# lambda x: print("STDOUT: %s" % x),
# lambda x: print("STDERR: %s" % x),
#)
store.dispatch("SET_VALUE", { "path": ["vnc_status"], "value": True })
await asyncio.gather( execute(
["x0vncserver", "-rfbauth", "pass"],
None,
None,
), execute(
["./ngrok", "tcp", "5900"],
lambda x: print("STDOUT: %s" % x),
lambda x: print("STDERR: %s" % x),
), get_ngrok())
store.dispatch("SET_VALUE", { "path": ["vnc_status"], "value": False })
async def stop(self):
global processes
for p in processes:
p.kill()
processes = []
loop = asyncio.get_event_loop()
async def get_ipv4():
session = aiohttp.ClientSession()
async with session.get("https://api.ipify.org?format=json") as resp:
store.dispatch("SET_VALUE", { "path": ["ipv4"], "value": json.loads(await resp.text())["ip"] })
await session.close()
async def get_ipv6():
session = aiohttp.ClientSession()
async with session.get("https://api6.ipify.org?format=json") as resp:
store.dispatch("SET_VALUE", { "path": ["ipv6"], "value": json.loads(await resp.text())["ip"] })
await session.close()
loop.create_task(get_ipv4())
loop.create_task(get_ipv6())
if __name__ == "__main__":
app.setup(store, AppView, style="black", loop=loop)
app.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment