From cd2a054b465bddc206fe6a64fe861864c769c5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20D=C3=B6rre?= Date: Thu, 29 Feb 2024 16:37:39 +0000 Subject: [PATCH] webrepl: Changes for more webrepl features while making it smaller. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change: - Moves the password checking to python - Removes the special file transfer protocol - Moves the REPL data to websocket binary packages Signed-off-by: Felix Dörre --- micropython/net/webrepl/manifest.py | 2 +- micropython/net/webrepl/webrepl.py | 74 ++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/micropython/net/webrepl/manifest.py b/micropython/net/webrepl/manifest.py index 20527db4f..6674d06c1 100644 --- a/micropython/net/webrepl/manifest.py +++ b/micropython/net/webrepl/manifest.py @@ -1,4 +1,4 @@ -metadata(description="WebREPL server.", version="0.1.0") +metadata(description="WebREPL server.", version="1.0.0") module("webrepl.py", opt=3) module("webrepl_setup.py", opt=3) diff --git a/micropython/net/webrepl/webrepl.py b/micropython/net/webrepl/webrepl.py index 48c181968..ebacc5619 100644 --- a/micropython/net/webrepl/webrepl.py +++ b/micropython/net/webrepl/webrepl.py @@ -7,15 +7,68 @@ import socket import sys import websocket -import _webrepl +import io listen_s = None client_s = None DEBUG = 0 -_DEFAULT_STATIC_HOST = const("https://micropython.org/webrepl/") +_DEFAULT_STATIC_HOST = const("https://felix.dogcraft.de/webrepl/") +_WELCOME_PROMPT = const("\r\nWebREPL connected\r\n>>> ") static_host = _DEFAULT_STATIC_HOST +webrepl_pass = None + + +class WebreplWrapper(io.IOBase): + def __init__(self, sock): + self.sock = sock + self.sock.ioctl(9, 2) + if webrepl_pass is not None: + self.pw = bytearray(16) + self.pwPos = 0 + self.sock.write("Password: ") + else: + self.pw = None + self.sock.write(_WELCOME_PROMPT) + + def readinto(self, buf): + if self.pw is not None: + buf = bytearray(1) + while True: + l = self.sock.readinto(buf) + if l is None: + continue + if l <= 0: + return l + if buf[0] == 10 or buf[0] == 13: + if bytes(self.pw[0 : self.pwPos]) == webrepl_pass: + self.pw = None + del self.pwPos + self.sock.write(_WELCOME_PROMPT) + break + else: + self.sock.write("\r\nAccess denied\r\n") + return 0 + else: + if self.pwPos < len(self.pw): + self.pw[self.pwPos] = buf[0] + self.pwPos = self.pwPos + 1 + return self.sock.readinto(buf) + + def write(self, buf): + if self.pw is not None: + return len(buf) + return self.sock.write(buf) + + def ioctl(self, kind, arg): + if kind == 4: + self.sock.close() + return 0 + return -1 + + def close(self): + self.sock.close() def server_handshake(cl): @@ -84,7 +137,7 @@ def send_html(cl): cl.send(static_host) cl.send( b"""\">\r -\r +\r """ ) cl.close() @@ -95,10 +148,7 @@ def setup_conn(port, accept_handler): listen_s = socket.socket() listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - ai = socket.getaddrinfo("0.0.0.0", port) - addr = ai[0][4] - - listen_s.bind(addr) + listen_s.bind(("", port)) listen_s.listen(1) if accept_handler: listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) @@ -127,7 +177,7 @@ def accept_conn(listen_sock): client_s = cl ws = websocket.websocket(cl, True) - ws = _webrepl._webrepl(ws) + ws = WebreplWrapper(ws) cl.setblocking(False) # notify REPL on socket incoming data (ESP32/ESP8266-only) if hasattr(os, "dupterm_notify"): @@ -147,10 +197,10 @@ def stop(): def start(port=8266, password=None, accept_handler=accept_conn): - global static_host + global static_host, webrepl_pass stop() webrepl_pass = password - if webrepl_pass is None: + if password is None: try: import webrepl_cfg @@ -160,7 +210,9 @@ def start(port=8266, password=None, accept_handler=accept_conn): except: print("WebREPL is not configured, run 'import webrepl_setup'") - _webrepl.password(webrepl_pass) + if webrepl_pass is not None: + webrepl_pass = webrepl_pass.encode() + s = setup_conn(port, accept_handler) if accept_handler is None: