4
4
from micropython import const , schedule
5
5
import uasyncio as asyncio
6
6
import binascii
7
+ import ustruct
7
8
import json
8
9
9
10
from .core import log_info , log_warn , ble , register_irq_handler
31
32
_modified = False
32
33
_path = None
33
34
35
+ connected_sec = None
36
+ gatt_svc = None
37
+
34
38
35
39
# Must call this before stack startup.
36
40
def load_secrets (path = None ):
@@ -45,9 +49,10 @@ def load_secrets(path=None):
45
49
try :
46
50
with open (_path , "r" ) as f :
47
51
entries = json .load (f )
48
- for sec_type , key , value in entries :
52
+ for sec_type , key , value , * digest in entries :
53
+ digest = digest [0 ] or None
49
54
# Decode bytes from hex.
50
- _secrets .append (((sec_type , binascii .a2b_base64 (key )), binascii .a2b_base64 (value )))
55
+ _secrets .append (((sec_type , binascii .a2b_base64 (key )), binascii .a2b_base64 (value ), digest ))
51
56
except :
52
57
log_warn ("No secrets available" )
53
58
@@ -66,15 +71,15 @@ def _save_secrets(arg=None):
66
71
# Convert bytes to hex strings (otherwise JSON will treat them like
67
72
# strings).
68
73
json_secrets = [
69
- (sec_type , binascii .b2a_base64 (key ), binascii .b2a_base64 (value ))
70
- for (sec_type , key ), value in _secrets
74
+ (sec_type , binascii .b2a_base64 (key ), binascii .b2a_base64 (value ), digest )
75
+ for (sec_type , key ), value , digest in _secrets
71
76
]
72
77
json .dump (json_secrets , f )
73
78
_modified = False
74
79
75
80
76
81
def _security_irq (event , data ):
77
- global _modified
82
+ global _modified , connected_sec , gatt_svc
78
83
79
84
if event == _IRQ_ENCRYPTION_UPDATE :
80
85
# Connection has updated (usually due to pairing).
@@ -89,6 +94,19 @@ def _security_irq(event, data):
89
94
if encrypted and connection ._pair_event :
90
95
connection ._pair_event .set ()
91
96
97
+ if bonded and \
98
+ None not in (gatt_svc , connected_sec ) and \
99
+ connected_sec [2 ] != gatt_svc .hexdigest :
100
+ gatt_svc .send_changed (connection )
101
+
102
+ # Update the hash in the database
103
+ _secrets .remove (connected_sec )
104
+ updated_sec = connected_sec [:- 1 ] + (gatt_svc .hexdigest ,)
105
+ _secrets .insert (0 , updated_sec )
106
+ # Queue up a save (don't synchronously write to flash).
107
+ _modified = True
108
+ schedule (_save_secrets , None )
109
+
92
110
elif event == _IRQ_SET_SECRET :
93
111
sec_type , key , value = data
94
112
key = sec_type , bytes (key )
@@ -99,15 +117,16 @@ def _security_irq(event, data):
99
117
if value is None :
100
118
# Delete secret.
101
119
i = None
102
- for i , k , v in enumerate (_secrets ):
120
+ for i , k , v , d in enumerate (_secrets ):
103
121
if k == key :
104
122
break
105
123
if i is not None :
106
124
_secrets .pop (i )
107
125
108
126
else :
109
127
# Save secret.
110
- _secrets .insert (0 , (key , value ))
128
+ current_digest = gatt_svc .hexdigest if gatt_svc else None
129
+ _secrets .insert (0 , (key , value , current_digest ))
111
130
112
131
# Queue up a save (don't synchronously write to flash).
113
132
_modified = True
@@ -123,7 +142,7 @@ def _security_irq(event, data):
123
142
if key is None :
124
143
# Return the index'th secret of this type.
125
144
i = 0
126
- for (t , _key ), value in _secrets . items () :
145
+ for (t , _key ), value , digest in _secrets :
127
146
if t == sec_type :
128
147
if i == index :
129
148
return value
@@ -133,8 +152,11 @@ def _security_irq(event, data):
133
152
# Return the secret for this key (or None).
134
153
key = sec_type , bytes (key )
135
154
136
- for k , v in _secrets :
155
+ for k , v , d in _secrets :
156
+ log_info (f"get secret: { k = } " )
137
157
if k == key :
158
+ connected_sec = k , v , d
159
+ log_info ("get secret: found key" )
138
160
return v
139
161
return None
140
162
0 commit comments