diff --git a/boot_manager.py b/boot_manager.py index bf8feb2..302a98e 100644 --- a/boot_manager.py +++ b/boot_manager.py @@ -129,7 +129,7 @@ def connect_wifi(cfg, timeout=30): _show_state('WIFI_CONNECT', cfg['wifi_ssid']) wlan = network.WLAN(network.STA_IF) wlan.active(True) - utime.sleep(1) + utime.sleep(2) if not wlan.isconnected(): wlan.connect(cfg['wifi_ssid'], cfg['wifi_pass']) @@ -155,7 +155,7 @@ def connect_wifi(cfg, timeout=30): ip = wlan.ifconfig()[0] print('[wifi] connected:', ip) _show_state('WIFI_OK', ip) - utime.sleep(1) + utime.sleep(3) return wlan @@ -167,47 +167,92 @@ def do_checkin(cfg): _show_state('CHECKIN', '') from identity_iot import IdentityIoT + key = cfg['comm_key'].encode() if isinstance(cfg['comm_key'], str) else cfg['comm_key'] + iv = cfg['comm_iv'].encode() if isinstance(cfg['comm_iv'], str) else cfg['comm_iv'] + identity = IdentityIoT( base_url = cfg['identity_iot_url'], node_type = cfg.get('node_type', 'access_control'), node_label = cfg.get('node_label', ''), tenant_id = cfg['tenant_id'], - comm_key = cfg['comm_key'].encode() if isinstance(cfg['comm_key'], str) else cfg['comm_key'], - comm_iv = cfg['comm_iv'].encode() if isinstance(cfg['comm_iv'], str) else cfg['comm_iv'], + comm_key = key, + comm_iv = iv, wifi_ssid = cfg['wifi_ssid'], wifi_pass = cfg['wifi_pass'], ) - # Register (idempotent) - _show_state('CHECKIN', 'Registering...') + # Register — retry loop for attempt in range(3): try: + _show(['CHECKIN', 'Registering...', 'attempt ' + str(attempt+1) + '/3', '', '']) identity.ensure_registered() break except Exception as e: print('[checkin] register attempt', attempt + 1, ':', e) if attempt == 2: + _show_state('ERROR', 'Check network') raise utime.sleep(3) - # Authenticate - _show_state('CHECKIN', 'Signing...') + # Seconda chiamata idempotente + reg = identity.ensure_registered() + uid_short = reg.get('node_uid', '')[:12] + '...' + _show(['CHECKIN', 'Node ' + reg.get('result', ''), uid_short, '', '']) + utime.sleep(1) + + # Authenticate → JWT + _show(['CHECKIN', 'Challenge...', '', '', '']) + utime.sleep(0.5) + _show(['CHECKIN', 'Signing...', '', 'Please wait', '']) + token = identity.authenticate() + + if not token: + _show_state('ERROR', 'Auth failed') + raise Exception('authenticate returned no token') + + print('[checkin] JWT issued') + + # it_node_checkin su identity_tag con JWT + _show(['CHECKIN', 'Node checkin...', '', '', '']) + import urequests + from identity_iot_aes import aes_cbc_encrypt, aes_cbc_decrypt + + payload = ujson.dumps({ + 'request': 'it_node_checkin', + 'node_id': str(cfg.get('node_id', '')), + }) + cipher = aes_cbc_encrypt(payload, key, iv) + body = ujson.dumps({'data': cipher}) + for attempt in range(3): try: - token = identity.authenticate() - if token: - print('[checkin] ok — JWT issued') + resp = urequests.post( + cfg['identity_tag_url'], + headers={ + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + token, + }, + data=body, + timeout=20, + ) + raw = resp.text + resp.close() + outer = ujson.loads(raw) + clear = aes_cbc_decrypt(outer['data'], key, iv) + result = ujson.loads(clear) + if result.get('status') == 'ok': + print('[checkin] node checkin ok') _show_state('CHECKIN OK', cfg.get('node_label', '')) utime.sleep(1) return {'status': 'ok', 'token': token, 'identity': identity} - raise Exception('no token') + raise Exception('it_node_checkin: ' + str(result.get('code', 'error'))) except Exception as e: - print('[checkin] auth attempt', attempt + 1, ':', e) + print('[checkin] it_node_checkin attempt', attempt + 1, ':', e) if attempt == 2: raise utime.sleep(3) - raise Exception('checkin failed after 3 attempts') + raise Exception('it_node_checkin failed') # ============================================================================= @@ -284,6 +329,8 @@ def run(): # ------------------------------------------------------------------ elif state == 'CHECKIN': try: + import gc + gc.collect() checkin_result = do_checkin(cfg) identity = checkin_result.get('identity') state = 'OPERATIONAL' diff --git a/identity_iot.py b/identity_iot.py index 0ce28f2..9878591 100644 --- a/identity_iot.py +++ b/identity_iot.py @@ -163,9 +163,11 @@ class IdentityIoT: return f.read().strip() except OSError: pass - raw_uid = machine.unique_id() - h = uhashlib.sha256(raw_uid) - uid_hex = ubinascii.hexlify(h.digest()).decode() + # Fresh UID — hardware ID + random entropy so each new registration is unique + raw_uid = machine.unique_id() + entropy = bytes([urandom.getrandbits(8) for _ in range(16)]) + h = uhashlib.sha256(raw_uid + entropy) + uid_hex = ubinascii.hexlify(h.digest()).decode() with open(self._F_NODEID, 'w') as f: f.write(uid_hex) return uid_hex @@ -294,4 +296,4 @@ def _normalize_b64(s: str) -> str: class StateError(Exception): - pass + pass \ No newline at end of file