Pairing and passthrough mostly working, except it's too slow
This commit is contained in:
parent
6af635bd41
commit
e16515bb64
4 changed files with 78 additions and 56 deletions
32
hexnoise.py
32
hexnoise.py
|
|
@ -31,6 +31,9 @@ class ReportType(enum.Enum):
|
|||
PAIRING_SUCESS = 4
|
||||
PAIRING_ERROR = 5
|
||||
|
||||
class ProtocolError(Exception):
|
||||
pass
|
||||
|
||||
class Packetizer:
|
||||
def __init__(self, serial, debug=False, width=16):
|
||||
self.ser, self.debug, self.width = serial, debug, width
|
||||
|
|
@ -55,11 +58,11 @@ class Packetizer:
|
|||
|
||||
pkt_type, data = PacketType(data[0]), data[1:]
|
||||
if pkt_type is PacketType.COMM_ERROR:
|
||||
raise ValueError('Device-side serial communication error')
|
||||
raise ProtocolError('Device-side serial communication error')
|
||||
elif pkt_type is PacketType.CRYPTO_ERROR:
|
||||
raise ValueError('Device-side cryptographic error')
|
||||
raise ProtocolError('Device-side cryptographic error')
|
||||
elif pkt_type is PacketType.TOO_MANY_FAILS:
|
||||
raise ValueError('Device reports too many failed handshake attempts')
|
||||
raise ProtocolError('Device reports too many failed handshake attempts')
|
||||
else:
|
||||
return pkt_type, data
|
||||
|
||||
|
|
@ -222,7 +225,7 @@ class NoiseEngine:
|
|||
if pkt_type is PacketType.HANDSHAKE:
|
||||
self.proto.read_message(payload)
|
||||
else:
|
||||
raise ValueError(f'Incorrect packet type {pkt_type}. Ignoring since this is only test code.')
|
||||
raise ProtocolError(f'Incorrect packet type {pkt_type}. Ignoring since this is only test code.')
|
||||
if self.debug:
|
||||
print('Handshake finished, handshake hash:')
|
||||
hexdump(print, self.proto.get_handshake_hash())
|
||||
|
|
@ -291,19 +294,26 @@ class NoiseEngine:
|
|||
break
|
||||
|
||||
elif msg_type == ReportType.PAIRING_ERROR:
|
||||
raise ValueError('Device-side pairing error') # FIXME find better exception subclass here
|
||||
raise ProtocolError('Device-side pairing error') # FIXME find better exception subclass here
|
||||
|
||||
else:
|
||||
raise ValueError('Invalid report type')
|
||||
raise ProtocolError('Invalid report type')
|
||||
|
||||
def uinput_passthrough(self):
|
||||
with uinput.Device(KeyMapper.ALL_KEYS) as ui:
|
||||
old_kcs = set()
|
||||
for msg_type, payload in noise.receive_loop():
|
||||
if msg_type == ReportType.KEYBOARD:
|
||||
modbyte, _reserved, *keycodes = payload
|
||||
for msg_type, payload in self.receive_loop():
|
||||
report_len, *report = payload
|
||||
if report_len != 8:
|
||||
raise ValueError('Unsupported report length', report_len)
|
||||
|
||||
if msg_type is ReportType.KEYBOARD:
|
||||
modbyte, _reserved, *keycodes = report
|
||||
print(' payload:', payload)
|
||||
print(' modifier:', list(KeyMapper.map_modifiers(modbyte)))
|
||||
print(' regular:', list(KeyMapper.map_regulars(keycodes)))
|
||||
keys = { *KeyMapper.map_modifiers(modbyte), *KeyMapper.map_regulars(keycodes) }
|
||||
if args.debug:
|
||||
if self.debug:
|
||||
print('Emitting:', keys)
|
||||
|
||||
for key in keys - old_kcs:
|
||||
|
|
@ -313,7 +323,7 @@ class NoiseEngine:
|
|||
ui.syn()
|
||||
old_kcs = keys
|
||||
|
||||
elif msg_type == ReportType.MOUSE:
|
||||
elif msg_type is ReportType.MOUSE:
|
||||
# FIXME unhandled
|
||||
pass
|
||||
|
||||
|
|
|
|||
65
pairing.py
65
pairing.py
|
|
@ -5,8 +5,7 @@ import re
|
|||
import serial
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('Pango', '1.0')
|
||||
from gi.repository import Gtk, Pango
|
||||
from gi.repository import Gtk, Gdk, Pango, GLib
|
||||
|
||||
import hexnoise
|
||||
|
||||
|
|
@ -27,39 +26,27 @@ class PairingWindow(Gtk.Window):
|
|||
self.label.set_markup('<b>Step 1</b>\n\nContacting device...')
|
||||
self.vbox.pack_start(self.label, True, True, 0)
|
||||
|
||||
self.textview = Gtk.TextView()
|
||||
self.textview.set_editable(False)
|
||||
self.textbuffer = self.textview.get_buffer()
|
||||
self.tag_nomatch = self.textbuffer.create_tag("nomatch", weight=Pango.Weight.BOLD)
|
||||
self.tag_match = self.textbuffer.create_tag("match", background='#AAFFAA', weight=Pango.Weight.BOLD)
|
||||
|
||||
self.vbox.pack_start(self.textview, True, True, 0)
|
||||
self.entry = Gtk.Entry()
|
||||
self.entry.set_editable(False)
|
||||
self.vbox.pack_start(self.entry, True, True, 0)
|
||||
|
||||
self.add(self.vbox)
|
||||
|
||||
self.handshaker = threading.Thread(target=self.run_handshake, daemon=True)
|
||||
self.handshaker = threading.Thread(target=self.pair, daemon=True)
|
||||
self.handshaker.start()
|
||||
|
||||
@classmethod
|
||||
def matchlen(self, ref, text):
|
||||
words = ref.split()
|
||||
parts = text.split()
|
||||
clean = lambda b: re.sub('^[^a-zA-Z0-9-]*', '', re.sub('[^a-zA-Z0-9-]*$', '', b)).lower()
|
||||
|
||||
good = ''
|
||||
for a, b in zip(words[:-1], parts[:-1]):
|
||||
if a == clean(b):
|
||||
good = f'{good}b '
|
||||
|
||||
rest = clean(parts[-1])
|
||||
if words[-1].startswith(rest):
|
||||
good = f'{good} {rest}'
|
||||
return len(good)
|
||||
|
||||
def run_handshake(self):
|
||||
def pair(self):
|
||||
self.packetizer = hexnoise.Packetizer(self.serial, debug=self.debug)
|
||||
self.noise = hexnoise.NoiseEngine(self.packetizer, debug=self.debug)
|
||||
|
||||
for i in range(10):
|
||||
try:
|
||||
self.run_handshake()
|
||||
break
|
||||
except hexnoise.ProtocolError as e:
|
||||
print(e)
|
||||
|
||||
def run_handshake(self):
|
||||
self.noise.perform_handshake()
|
||||
|
||||
binding_incantation = self.noise.channel_binding_incantation()
|
||||
|
|
@ -67,19 +54,25 @@ class PairingWindow(Gtk.Window):
|
|||
f'Enter the following incantation, then press enter.\n'
|
||||
f'<b>{binding_incantation}</b>')
|
||||
|
||||
for user_input in self.noise.pairing_messages():
|
||||
print('got:', user_input)
|
||||
self.textbuffer.set_text(user_input)
|
||||
#i1, i2 = self.textbuffer.get_start_iter(), self.textbuffer.get_end_iter()
|
||||
#self.textbuffer.apply_tag(self.tag_nomatch, i1, i2)
|
||||
def update_text(text):
|
||||
self.entry.set_text(text)
|
||||
self.entry.set_position(len(text))
|
||||
|
||||
#i1, i2 = self.textbuffer.get_start_iter(), self.textbuffer.get_start_iter()
|
||||
#i2.forward_chars(self.matchlen(binding_incantation, user_input))
|
||||
#self.textbuffer.apply_tag(self.tag_match, i1, i2)
|
||||
clean = lambda s: re.sub('[^a-z0-9-]', '', s.lower())
|
||||
if clean(binding_incantation).startswith(clean(text)):
|
||||
color = 0.9, 1.0, 0.9 # light red
|
||||
else:
|
||||
color = 1.0, 0.9, 0.9 # light green
|
||||
self.entry.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(*color, 1.0))
|
||||
|
||||
for user_input in self.noise.pairing_messages():
|
||||
print(f'User input: "{user_input}"')
|
||||
GLib.idle_add(update_text, user_input)
|
||||
|
||||
self.label.set_markup(f'<b>Done!</b>')
|
||||
|
||||
#noise.uinput_passthrough()
|
||||
# FIXME demo
|
||||
self.noise.uinput_passthrough()
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
|
|
|
|||
34
src/demo.c
34
src/demo.c
|
|
@ -144,14 +144,36 @@ int pairing_check(struct NoiseState *st, const char *buf) {
|
|||
const char *p = buf;
|
||||
int idx = 0;
|
||||
do {
|
||||
/* Skip over most special chars */
|
||||
while (*p) {
|
||||
char c = *p;
|
||||
if ('0' <= c && c <= '9') break;
|
||||
if ('a' <= c && c <= 'z') break;
|
||||
if ('A' <= c && c <= 'Z') break;
|
||||
if (c == '-') break;
|
||||
p++;
|
||||
}
|
||||
|
||||
const char *found = strchr(p, ' ');
|
||||
size_t plen = found ? (size_t)(found - p) : strlen(p); /* p >= found */
|
||||
|
||||
while (plen > 0) {
|
||||
char c = p[plen];
|
||||
if ('0' <= c && c <= '9') break;
|
||||
if ('a' <= c && c <= 'z') break;
|
||||
if ('A' <= c && c <= 'Z') break;
|
||||
if (c == '-') break;
|
||||
plen--;
|
||||
}
|
||||
plen++;
|
||||
//LOG_PRINTF("matching: \"%s\" - \"%s\" %d\n", p, p+plen, plen);
|
||||
|
||||
if (strncasecmp(p, "and", plen)) { /* ignore "and" */
|
||||
int num = -1;
|
||||
/* FIXME ignore "and", ignore commata and dots */
|
||||
for (int i=0; i<256; i++) {
|
||||
if ((!strncasecmp(p, adjectives[i], plen)) || (!strncasecmp(p, nouns[i], plen))) {
|
||||
if ((!strncasecmp(p, adjectives[i], plen) && plen == strlen(adjectives[i]))
|
||||
|| (!strncasecmp(p, nouns[i], plen) && plen == strlen(nouns[i] ))) {
|
||||
//LOG_PRINTF(" idx=%02d h=%02x i=%02x adj=%s n=%s plen=%d s=%s\n", idx, st->handshake_hash[idx], i, adjectives[i], nouns[i], plen, p);
|
||||
num = i;
|
||||
break;
|
||||
|
|
@ -218,12 +240,8 @@ void pairing_input(uint8_t modbyte, uint8_t keycode) {
|
|||
for (size_t i=0; keycode_mapping[i].kc != KEY_NONE; i++) {
|
||||
if (keycode_mapping[i].kc == keycode) {
|
||||
ch = keycode_mapping[i].ch[level];
|
||||
if (!(('a' <= ch && ch <= 'z') ||
|
||||
('A' <= ch && ch <= 'Z') ||
|
||||
('0' <= ch && ch <= '9') ||
|
||||
(ch == ' ') ||
|
||||
(ch == '-')))
|
||||
break; /* ignore special chars */
|
||||
if (!ch)
|
||||
break;
|
||||
|
||||
if (pairing_buf_pos < sizeof(pairing_buf)-1) /* allow for terminating null byte */ {
|
||||
pairing_buf[pairing_buf_pos++] = ch;
|
||||
|
|
@ -242,7 +260,7 @@ void pairing_input(uint8_t modbyte, uint8_t keycode) {
|
|||
}
|
||||
|
||||
if (ch) {
|
||||
LOG_PRINTF("Input: %s\n", pairing_buf);
|
||||
//LOG_PRINTF("Input: %s\n", pairing_buf);
|
||||
struct hid_report_packet pkt = {
|
||||
.type = REPORT_PAIRING_INPUT,
|
||||
.pairing_input = { .c = ch }
|
||||
|
|
|
|||
|
|
@ -25,10 +25,11 @@ struct dma_usart_file usart2_out_s = {
|
|||
struct dma_usart_file *usart2_out = &usart2_out_s;
|
||||
|
||||
void dma1_stream6_isr(void) {
|
||||
static unsigned int fifo_errors = 0; /* debug */
|
||||
if (dma_get_interrupt_flag(usart2_out->dma, usart2_out->stream, DMA_FEIF)) {
|
||||
/* Ignore FIFO errors as they're 100% non-critical for UART applications */
|
||||
dma_clear_interrupt_flags(usart2_out->dma, usart2_out->stream, DMA_FEIF);
|
||||
LOG_PRINTF("USART2 DMA FIFO error\n");
|
||||
fifo_errors++;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue