mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-12 01:23:52 +00:00
Merge pull request #520 from pybricks/dlech
firmware checksum validation
This commit is contained in:
+9
-1
@@ -4,6 +4,12 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
- Fix flashing firmware on Android [support#403].
|
||||
|
||||
### Changed
|
||||
- Checksum is now validated as firmware flash progresses instead of just at the
|
||||
end [support#433].
|
||||
|
||||
## [1.1.0-beta.3] - 2021-07-20
|
||||
|
||||
@@ -46,13 +52,15 @@
|
||||
Prerelease changes are documented at [support#48].
|
||||
|
||||
|
||||
<!-- let's try to keep this list sorted -->
|
||||
<!-- let's try to keep this list sorted alphabetically -->
|
||||
[issue#470]: https://github.com/pybricks/pybricks-code/issues/470
|
||||
[issue#471]: https://github.com/pybricks/pybricks-code/issues/471
|
||||
[issue#472]: https://github.com/pybricks/pybricks-code/issues/472
|
||||
[support#48]: https://github.com/pybricks/support/issues/48
|
||||
[support#375]: https://github.com/pybricks/support/issues/375
|
||||
[support#378]: https://github.com/pybricks/support/issues/378
|
||||
[support#403]: https://github.com/pybricks/support/issues/403
|
||||
[support#433]: https://github.com/pybricks/support/issues/433
|
||||
[v3.0.0]: https://github.com/pybricks/pybricks-micropython/blob/master/CHANGELOG.md#300---2021-06-08
|
||||
[v3.1.0a1]: https://github.com/pybricks/pybricks-micropython/blob/master/CHANGELOG.md#310a1---2021-06-23
|
||||
[v3.1.0a2]: https://github.com/pybricks/pybricks-micropython/blob/master/CHANGELOG.md#310a2---2021-07-06
|
||||
|
||||
@@ -1386,6 +1386,7 @@ describe('flashFirmware', () => {
|
||||
|
||||
const dummyPayload = new ArrayBuffer(0);
|
||||
let id = 2;
|
||||
|
||||
for (let count = 1, offset = 0; ; count++, offset += 14) {
|
||||
action = await saga.take();
|
||||
expect(action).toEqual(
|
||||
@@ -1413,7 +1414,7 @@ describe('flashFirmware', () => {
|
||||
expect(action).toEqual(checksumRequest(++id));
|
||||
|
||||
saga.put(didRequest(id));
|
||||
saga.put(checksumResponse(0));
|
||||
saga.put(checksumResponse(0x9b));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+36
-8
@@ -53,7 +53,7 @@ import {
|
||||
compile,
|
||||
} from '../mpy/actions';
|
||||
import { RootState } from '../reducers';
|
||||
import { defined, maybe } from '../utils';
|
||||
import { defined, hex, maybe } from '../utils';
|
||||
import { fmod, sumComplement32 } from '../utils/math';
|
||||
import { isAndroid } from '../utils/os';
|
||||
import {
|
||||
@@ -381,8 +381,16 @@ function* flashFirmware(action: FlashFirmwareFlashAction): Generator {
|
||||
const maxDataSize =
|
||||
(!isAndroid() && MaxProgramFlashSize.get(info.hubType)) || 14;
|
||||
|
||||
let runningChecksum = 0xff;
|
||||
|
||||
for (let count = 1, offset = 0; ; count++) {
|
||||
const payload = firmware.slice(offset, offset + maxDataSize);
|
||||
|
||||
runningChecksum = payload.reduce(
|
||||
(prev, curr) => prev ^ curr,
|
||||
runningChecksum,
|
||||
);
|
||||
|
||||
const programAction = yield* put(
|
||||
programRequest(
|
||||
nextMessageId(),
|
||||
@@ -407,13 +415,33 @@ function* flashFirmware(action: FlashFirmwareFlashAction): Generator {
|
||||
// the hub is not known and could vary by device.
|
||||
if (count % 10 === 0) {
|
||||
const checksumAction = yield* put(checksumRequest(nextMessageId()));
|
||||
yield* all({
|
||||
|
||||
const { response } = yield* all({
|
||||
sent: waitForDidRequest(checksumAction.id),
|
||||
checksum: waitForResponse<BootloaderChecksumResponseAction>(
|
||||
response: waitForResponse<BootloaderChecksumResponseAction>(
|
||||
BootloaderResponseActionType.Checksum,
|
||||
5000,
|
||||
),
|
||||
});
|
||||
|
||||
if (response.checksum !== runningChecksum) {
|
||||
// istanbul ignore next
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
console.error(
|
||||
`checksum: got ${hex(response.checksum, 2)} expected ${hex(
|
||||
runningChecksum,
|
||||
2,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
yield* put(
|
||||
didFailToFinish(
|
||||
FailToFinishReasonType.HubError,
|
||||
HubError.ChecksumMismatch,
|
||||
),
|
||||
);
|
||||
yield* disconnectAndCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,14 +460,14 @@ function* flashFirmware(action: FlashFirmwareFlashAction): Generator {
|
||||
yield* disconnectAndCancel();
|
||||
}
|
||||
|
||||
const checksum = firmware.reduce((prev, curr) => prev ^ curr, 0xff);
|
||||
if (flash.checksum !== checksum) {
|
||||
if (flash.checksum !== runningChecksum) {
|
||||
// istanbul ignore next
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
console.error(
|
||||
'checksum:',
|
||||
flash.checksum.toString(16).padStart(2, '0').padStart(4, '0x'),
|
||||
checksum.toString(16).padStart(2, '0').padStart(4, '0x'),
|
||||
`final checksum: got ${hex(flash.checksum, 2)} expected ${hex(
|
||||
runningChecksum,
|
||||
2,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
yield* put(
|
||||
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Serve local build with https for testing.
|
||||
|
||||
This is useful, e.g. for Android (WebBluetooth doesn't work without https).
|
||||
|
||||
Usage:
|
||||
|
||||
yarn build
|
||||
./tools/serve.py
|
||||
|
||||
Browse to https://localhost:8443 on the local machine or
|
||||
https://<name-or-address>:8443 on a remote device.
|
||||
|
||||
The browser will complain about the self-signed certificate, but this can be
|
||||
bypassed (click "Advanced" in browser).
|
||||
"""
|
||||
|
||||
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
||||
from pathlib import Path
|
||||
import os
|
||||
import ssl
|
||||
|
||||
THIS_DIR = Path(__file__).parent
|
||||
TEST_CERT = (THIS_DIR / 'test.pem').absolute()
|
||||
BUILD_DIR = (THIS_DIR / '..' / 'build').absolute()
|
||||
|
||||
# HTTPServer serves the current directory.
|
||||
os.chdir(BUILD_DIR)
|
||||
|
||||
httpd = HTTPServer(('', 8443), SimpleHTTPRequestHandler)
|
||||
httpd.socket = ssl.wrap_socket(httpd.socket, certfile=TEST_CERT, server_side=True)
|
||||
httpd.serve_forever()
|
||||
@@ -0,0 +1,48 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDLpTko58nNd2cE
|
||||
q8MaB1Wv4xren/xiNomDwf44QK9jZGzvHqnXCKTQ0KsLxtZt7Ne6PU1WdIA3bf6/
|
||||
nVzVUhauP0+DF8t6bTH4GSlvLXKGFW6dkCkTMw8ginh73PkZL+OaQvaMVJd42CW9
|
||||
bPhFMF6tXsLq661ObXwTE+vBopSim4EEzy+VKXB8BHvMYvfMcWiJihKJhCPLZE9p
|
||||
iHBO3yByMs0fLe6UQ/MAHXFVprxnXJ+P2mMe5s/c0BEcTK1deNy9ngKcUvKGCcfj
|
||||
T19xtkS4IHS0csz0fkZ+93tGjTm9eCLAOmyvKRljhOMFZKV4J1w4We3Y2b+xHN9w
|
||||
psukl2+JAgMBAAECggEBAKacuEZaVYYQQa3VpZs/EwEDavFnrYLhIeM1rXtymMxV
|
||||
1rZQvR4ciVP61WaeOMPY+ar7CrJIQLqY+MrmwZQaREotrC0SI703Z6GXXIoEgeVn
|
||||
1Yd98c0ughraj7avVPIhdzK3xKWNdBw/o6j2Za2d5Ggt1oWDath2xQOK0eEr1jWu
|
||||
VNfZNMvjyvevbyzuBLlF2970ZbOKAi/nrqtmw8mlhqDK5hy+j0K37hAbxizVDmU6
|
||||
vZfGhgmgBqXCla59T4rN3StK6zYVfmZKuGHWQbBxbWuLpFA+m09WKF599rUgZG7e
|
||||
l5RC1dOXCa4bOv8yVRULb5LSIyBHxIfPiqShw/gUm3ECgYEA5/QkAOw4M2RSpaGb
|
||||
K0yaoAKkZ5whX3rzudOVocQkeMKETpiPcLRZpO/z3A/bRjDg5YG7FNhbBI2nqGHR
|
||||
ShkZIZlx7OeZPsT4IpciKDGOjoWhfk2a3gaUj+24hUO13hK1DrudI0t+USb6wjfP
|
||||
C+hWoonEOjGK9jzPj1fwKMwHbYUCgYEA4MHN8RkXP6AgdLleKB+/AE613Ozmc54F
|
||||
I0uL5xXUny+udhYcflsF357ztj3vWZzWOhVvp84O7puJu9J84wQQtG/v6kD+pIA7
|
||||
TKJAcJ8eL/gZgbEAEbw1fBZLFkpis6sD06tDiCRx3qWez3pr/UiPLw4ldIsNnyZu
|
||||
RfqL8LjspzUCgYEAqDfl+IlYBOVoDtkR+Kf4p7zi0IVpqp43rffl18ixDqc7XujD
|
||||
dmBFdxnSiDEzvEbsg2W/cNGryLSW98XhC9UB5d0rwzz/ZYdh0Ww8CFxQX8pIIZpU
|
||||
i1rIWU10+ajud5ynlIS55IP2mxIi38GrtZ4NXpl9JxsRBZ16hiGneV7msCUCgYEA
|
||||
iZAVLGve/uJS+x45svU7QkTqqr2Uj084ddHXXyjNamEUttHxvqSXg7cWE4T06jRE
|
||||
KmjUXjCQkxo/wuWh6pCiaM3aWdZOBQE3SkBEkKnTICkJ84cSM8iuM7SxYINGxhD1
|
||||
1qgMPVeRGmTkPrj/P5cZjANsiVhSjgZHmC0xWbTVo8ECgYBh6R7N4B/xYH+UgV1U
|
||||
qyzFjLjsBQoIuhx5JpHCXmzZV3B/TV9mi3D1hcl4oS6nnww/j5WKggdUq6542975
|
||||
iVsnw8OFCSpU/R9P6crPwDEkdZt9miv1BOdh95AqxpmLEJrfXuVNYur0yur7Yv+E
|
||||
AVMgdBof4DtucX+v+sLxuHAppA==
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDSzCCAjOgAwIBAgIUM9tef51ph3HVoJqF1h7ch5XmOQowDQYJKoZIhvcNAQEL
|
||||
BQAwNTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAoM
|
||||
CFB5YnJpY2tzMB4XDTIxMDgxMzE0NDQyOFoXDTQ4MTIyOTE0NDQyOFowNTELMAkG
|
||||
A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAoMCFB5YnJpY2tz
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy6U5KOfJzXdnBKvDGgdV
|
||||
r+Ma3p/8YjaJg8H+OECvY2Rs7x6p1wik0NCrC8bWbezXuj1NVnSAN23+v51c1VIW
|
||||
rj9PgxfLem0x+Bkpby1yhhVunZApEzMPIIp4e9z5GS/jmkL2jFSXeNglvWz4RTBe
|
||||
rV7C6uutTm18ExPrwaKUopuBBM8vlSlwfAR7zGL3zHFoiYoSiYQjy2RPaYhwTt8g
|
||||
cjLNHy3ulEPzAB1xVaa8Z1yfj9pjHubP3NARHEytXXjcvZ4CnFLyhgnH409fcbZE
|
||||
uCB0tHLM9H5Gfvd7Ro05vXgiwDpsrykZY4TjBWSleCdcOFnt2Nm/sRzfcKbLpJdv
|
||||
iQIDAQABo1MwUTAdBgNVHQ4EFgQUm+DZlQWXqhjtS6ATH3Ns0fzchs0wHwYDVR0j
|
||||
BBgwFoAUm+DZlQWXqhjtS6ATH3Ns0fzchs0wDwYDVR0TAQH/BAUwAwEB/zANBgkq
|
||||
hkiG9w0BAQsFAAOCAQEAlpu1OrX9wb8m2eaZOVumjNna4Xx4pYJG13AdfWx5D4qR
|
||||
PqbxdUfxnlk3F6pD15ELK1NK94k6/XarScBxDwMexSxKVPPeU5aOG2JRUkWaN4wg
|
||||
NIYo7xQeoorgcNqnV8pIZMh3IUKnL3i9BFrMlhBIZCb/y0XdmJbvb5P9yU3x+z9C
|
||||
w1hPKjyhEIYIGnjTh1Rj5feciQSxcouDVOZSgi2iscGePK5734rAzO3zZzbi4lbs
|
||||
R2rK2RVrX/s51njLgCHpwPonfEqy8TrMSJvCtH0OG7wQCNbnFOakfzvChpWI/1bI
|
||||
Qlai98tuzS49ekXd/dL6lXZi8z7c9Necj21mMgePKQ==
|
||||
-----END CERTIFICATE-----
|
||||
Reference in New Issue
Block a user