Skip to content

Commit f4dd11e

Browse files
committed
[update] extmod/crypto-algorithms extmod/re1.5 add extmod/webrepl
1 parent 30adcd6 commit f4dd11e

File tree

7 files changed

+264
-2
lines changed

7 files changed

+264
-2
lines changed

extmod/crypto-algorithms/sha256.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/*********************************************************************
2+
* Source: https://github.com/B-Con/crypto-algorithms
23
* Filename: sha256.c
34
* Author: Brad Conte (brad AT bradconte.com)
4-
* Copyright:
5+
* Copyright: This code is released into the public domain.
56
* Disclaimer: This code is presented "as is" without any guarantees.
67
* Details: Implementation of the SHA-256 hashing algorithm.
78
SHA-256 is one of the three algorithms in the SHA2

extmod/crypto-algorithms/sha256.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/*********************************************************************
2+
* Source: https://github.com/B-Con/crypto-algorithms
23
* Filename: sha256.h
34
* Author: Brad Conte (brad AT bradconte.com)
4-
* Copyright:
5+
* Copyright: This code is released into the public domain.
56
* Disclaimer: This code is presented "as is" without any guarantees.
67
* Details: Defines the API for the corresponding SHA1 implementation.
78
*********************************************************************/

extmod/re1.5/compilecode.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode)
5353
PC++; // Skip # of pair byte
5454
prog->len++;
5555
for (cnt = 0; *re != ']'; re++, cnt++) {
56+
if (*re == '\\') {
57+
++re;
58+
}
5659
if (!*re) return NULL;
5760
EMIT(PC++, *re);
5861
if (re[1] == '-' && re[2] != ']') {

extmod/webrepl/manifest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
freeze('.', ('webrepl.py', 'webrepl_setup.py', 'websocket_helper.py',))

extmod/webrepl/webrepl.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# This module should be imported from REPL, not run from command line.
2+
import socket
3+
import uos
4+
import network
5+
import uwebsocket
6+
import websocket_helper
7+
import _webrepl
8+
9+
listen_s = None
10+
client_s = None
11+
12+
def setup_conn(port, accept_handler):
13+
global listen_s
14+
listen_s = socket.socket()
15+
listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
16+
17+
ai = socket.getaddrinfo("0.0.0.0", port)
18+
addr = ai[0][4]
19+
20+
listen_s.bind(addr)
21+
listen_s.listen(1)
22+
if accept_handler:
23+
listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler)
24+
for i in (network.AP_IF, network.STA_IF):
25+
iface = network.WLAN(i)
26+
if iface.active():
27+
print("WebREPL daemon started on ws://%s:%d" % (iface.ifconfig()[0], port))
28+
return listen_s
29+
30+
31+
def accept_conn(listen_sock):
32+
global client_s
33+
cl, remote_addr = listen_sock.accept()
34+
prev = uos.dupterm(None)
35+
uos.dupterm(prev)
36+
if prev:
37+
print("\nConcurrent WebREPL connection from", remote_addr, "rejected")
38+
cl.close()
39+
return
40+
print("\nWebREPL connection from:", remote_addr)
41+
client_s = cl
42+
websocket_helper.server_handshake(cl)
43+
ws = uwebsocket.websocket(cl, True)
44+
ws = _webrepl._webrepl(ws)
45+
cl.setblocking(False)
46+
# notify REPL on socket incoming data (ESP32/ESP8266-only)
47+
if hasattr(uos, 'dupterm_notify'):
48+
cl.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify)
49+
uos.dupterm(ws)
50+
51+
52+
def stop():
53+
global listen_s, client_s
54+
uos.dupterm(None)
55+
if client_s:
56+
client_s.close()
57+
if listen_s:
58+
listen_s.close()
59+
60+
61+
def start(port=8266, password=None):
62+
stop()
63+
if password is None:
64+
try:
65+
import webrepl_cfg
66+
_webrepl.password(webrepl_cfg.PASS)
67+
setup_conn(port, accept_conn)
68+
print("Started webrepl in normal mode")
69+
except:
70+
print("WebREPL is not configured, run 'import webrepl_setup'")
71+
else:
72+
_webrepl.password(password)
73+
setup_conn(port, accept_conn)
74+
print("Started webrepl in manual override mode")
75+
76+
77+
def start_foreground(port=8266):
78+
stop()
79+
s = setup_conn(port, None)
80+
accept_conn(s)

extmod/webrepl/webrepl_setup.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import sys
2+
#import uos as os
3+
import os
4+
import machine
5+
6+
RC = "./boot.py"
7+
CONFIG = "./webrepl_cfg.py"
8+
9+
def input_choice(prompt, choices):
10+
while 1:
11+
resp = input(prompt)
12+
if resp in choices:
13+
return resp
14+
15+
def getpass(prompt):
16+
return input(prompt)
17+
18+
def input_pass():
19+
while 1:
20+
passwd1 = getpass("New password (4-9 chars): ")
21+
if len(passwd1) < 4 or len(passwd1) > 9:
22+
print("Invalid password length")
23+
continue
24+
passwd2 = getpass("Confirm password: ")
25+
if passwd1 == passwd2:
26+
return passwd1
27+
print("Passwords do not match")
28+
29+
30+
def exists(fname):
31+
try:
32+
with open(fname):
33+
pass
34+
return True
35+
except OSError:
36+
return False
37+
38+
39+
def get_daemon_status():
40+
with open(RC) as f:
41+
for l in f:
42+
if "webrepl" in l:
43+
if l.startswith("#"):
44+
return False
45+
return True
46+
return None
47+
48+
49+
def change_daemon(action):
50+
LINES = ("import webrepl", "webrepl.start()")
51+
with open(RC) as old_f, open(RC + ".tmp", "w") as new_f:
52+
found = False
53+
for l in old_f:
54+
for patt in LINES:
55+
if patt in l:
56+
found = True
57+
if action and l.startswith("#"):
58+
l = l[1:]
59+
elif not action and not l.startswith("#"):
60+
l = "#" + l
61+
new_f.write(l)
62+
if not found:
63+
new_f.write("import webrepl\nwebrepl.start()\n")
64+
# FatFs rename() is not POSIX compliant, will raise OSError if
65+
# dest file exists.
66+
os.remove(RC)
67+
os.rename(RC + ".tmp", RC)
68+
69+
70+
def main():
71+
status = get_daemon_status()
72+
73+
print("WebREPL daemon auto-start status:", "enabled" if status else "disabled")
74+
print("\nWould you like to (E)nable or (D)isable it running on boot?")
75+
print("(Empty line to quit)")
76+
resp = input("> ").upper()
77+
78+
if resp == "E":
79+
if exists(CONFIG):
80+
resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", ""))
81+
else:
82+
print("To enable WebREPL, you must set password for it")
83+
resp2 = "y"
84+
85+
if resp2 == "y":
86+
passwd = input_pass()
87+
with open(CONFIG, "w") as f:
88+
f.write("PASS = %r\n" % passwd)
89+
90+
91+
if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status):
92+
print("No further action required")
93+
sys.exit()
94+
95+
change_daemon(resp == "E")
96+
97+
print("Changes will be activated after reboot")
98+
resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", ""))
99+
if resp == "y":
100+
machine.reset()
101+
102+
main()

extmod/webrepl/websocket_helper.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import sys
2+
try:
3+
import ubinascii as binascii
4+
except:
5+
import binascii
6+
try:
7+
import uhashlib as hashlib
8+
except:
9+
import hashlib
10+
11+
DEBUG = 0
12+
13+
def server_handshake(sock):
14+
clr = sock.makefile("rwb", 0)
15+
l = clr.readline()
16+
#sys.stdout.write(repr(l))
17+
18+
webkey = None
19+
20+
while 1:
21+
l = clr.readline()
22+
if not l:
23+
raise OSError("EOF in headers")
24+
if l == b"\r\n":
25+
break
26+
# sys.stdout.write(l)
27+
h, v = [x.strip() for x in l.split(b":", 1)]
28+
if DEBUG:
29+
print((h, v))
30+
if h == b'Sec-WebSocket-Key':
31+
webkey = v
32+
33+
if not webkey:
34+
raise OSError("Not a websocket request")
35+
36+
if DEBUG:
37+
print("Sec-WebSocket-Key:", webkey, len(webkey))
38+
39+
d = hashlib.sha1(webkey)
40+
d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
41+
respkey = d.digest()
42+
respkey = binascii.b2a_base64(respkey)[:-1]
43+
if DEBUG:
44+
print("respkey:", respkey)
45+
46+
sock.send(b"""\
47+
HTTP/1.1 101 Switching Protocols\r
48+
Upgrade: websocket\r
49+
Connection: Upgrade\r
50+
Sec-WebSocket-Accept: """)
51+
sock.send(respkey)
52+
sock.send("\r\n\r\n")
53+
54+
55+
# Very simplified client handshake, works for MicroPython's
56+
# websocket server implementation, but probably not for other
57+
# servers.
58+
def client_handshake(sock):
59+
cl = sock.makefile("rwb", 0)
60+
cl.write(b"""\
61+
GET / HTTP/1.1\r
62+
Host: echo.websocket.org\r
63+
Connection: Upgrade\r
64+
Upgrade: websocket\r
65+
Sec-WebSocket-Key: foo\r
66+
\r
67+
""")
68+
l = cl.readline()
69+
# print(l)
70+
while 1:
71+
l = cl.readline()
72+
if l == b"\r\n":
73+
break
74+
# sys.stdout.write(l)

0 commit comments

Comments
 (0)