Skip to content

Commit da39812

Browse files
committed
Update esptool-js to 0.6.0, replace crypto-js with inline MD5
Remove the esptool-js patch (no longer needed with Vite 8/Rolldown), drop crypto-js dependency, and add a lightweight Uint8Array-based MD5 implementation for firmware flash verification.
1 parent e977c15 commit da39812

6 files changed

Lines changed: 211 additions & 58 deletions

File tree

package.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,18 @@
3232
"@sveltejs/vite-plugin-svelte": "^7.0.0",
3333
"@tailwindcss/vite": "^4.2.2",
3434
"@tanstack/table-core": "^8.21.3",
35-
"@types/crypto-js": "^4.2.2",
3635
"@types/node": "^25.5.0",
3736
"@types/semver": "^7.7.1",
3837
"@types/w3c-web-serial": "^1.0.8",
3938
"bits-ui": "2.16.3",
4039
"boxen": "^8.0.1",
4140
"chalk": "^5.6.2",
4241
"clsx": "^2.1.1",
43-
"crypto-js": "^4.2.0",
4442
"eslint": "^10.1.0",
4543
"eslint-config-prettier": "^10.1.8",
4644
"eslint-plugin-compat": "^7.0.1",
4745
"eslint-plugin-svelte": "^3.16.0",
46+
"esptool-js": "0.6.0",
4847
"formsnap": "^2.0.1",
4948
"globals": "^17.4.0",
5049
"husky": "^9.1.7",
@@ -71,7 +70,6 @@
7170
"vitest": "^4.1.1"
7271
},
7372
"dependencies": {
74-
"esptool-js": "^0.5.7",
7573
"vite": "^8.0.2"
7674
},
7775
"engines": {
@@ -93,8 +91,7 @@
9391
"workerd"
9492
],
9593
"patchedDependencies": {
96-
"@microsoft/signalr@10.0.0": "patches/signalr.patch",
97-
"esptool-js@0.5.7": "patches/esptool.patch"
94+
"@microsoft/signalr@10.0.0": "patches/signalr.patch"
9895
},
9996
"overrides": {
10097
"cookie@<0.7.0": ">=0.7.0",

patches/esptool.patch

Lines changed: 0 additions & 12 deletions
This file was deleted.

pnpm-lock.yaml

Lines changed: 6 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/utils/md5.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { md5 } from './md5';
3+
4+
function fromString(s: string): Uint8Array {
5+
return new TextEncoder().encode(s);
6+
}
7+
8+
describe('md5', () => {
9+
it('hashes an empty input', () => {
10+
expect(md5(new Uint8Array([]))).toBe('d41d8cd98f00b204e9800998ecf8427e');
11+
});
12+
13+
it('hashes "hello"', () => {
14+
expect(md5(fromString('hello'))).toBe('5d41402abc4b2a76b9719d911017c592');
15+
});
16+
17+
it('hashes "abc"', () => {
18+
expect(md5(fromString('abc'))).toBe('900150983cd24fb0d6963f7d28e17f72');
19+
});
20+
21+
it('hashes a string exactly 55 bytes (just fits in one block with padding)', () => {
22+
const input = 'a'.repeat(55);
23+
expect(md5(fromString(input))).toBe('ef1772b6dff9a122358552954ad0df65');
24+
});
25+
26+
it('hashes a string of 56 bytes (forces a second block for padding)', () => {
27+
const input = 'a'.repeat(56);
28+
expect(md5(fromString(input))).toBe('3b0c8ac703f828b04c6c197006d17218');
29+
});
30+
31+
it('hashes a string exactly 64 bytes (one full block)', () => {
32+
const input = 'a'.repeat(64);
33+
expect(md5(fromString(input))).toBe('014842d480b571495a4a0363793f7367');
34+
});
35+
36+
it('hashes arbitrary binary data', () => {
37+
const data = new Uint8Array([0xde, 0xad, 0xbe, 0xef]);
38+
expect(md5(data)).toBe('2f249230a8e7c2bf6005ccd2679259ec');
39+
});
40+
41+
it('hashes a longer message spanning multiple blocks', () => {
42+
const input = 'The quick brown fox jumps over the lazy dog';
43+
expect(md5(fromString(input))).toBe('9e107d9d372bb6826bd81d3542a419d6');
44+
});
45+
});

src/lib/utils/md5.ts

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// MD5 implementation adapted from Joseph Myers' public domain code
2+
// https://www.myersdaily.org/joseph/javascript/md5-text.html
3+
4+
function add32(a: number, b: number): number {
5+
return (a + b) & 0xffffffff;
6+
}
7+
8+
function cmn(q: number, a: number, b: number, x: number, s: number, t: number): number {
9+
a = add32(add32(a, q), add32(x, t));
10+
return add32((a << s) | (a >>> (32 - s)), b);
11+
}
12+
13+
function ff(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
14+
return cmn((b & c) | (~b & d), a, b, x, s, t);
15+
}
16+
17+
function gg(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
18+
return cmn((b & d) | (c & ~d), a, b, x, s, t);
19+
}
20+
21+
function hh(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
22+
return cmn(b ^ c ^ d, a, b, x, s, t);
23+
}
24+
25+
function ii(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
26+
return cmn(c ^ (b | ~d), a, b, x, s, t);
27+
}
28+
29+
function md5blk(data: Uint8Array, offset: number): number[] {
30+
const blks: number[] = [];
31+
for (let i = 0; i < 64; i += 4) {
32+
blks[i >> 2] =
33+
data[offset + i] |
34+
(data[offset + i + 1] << 8) |
35+
(data[offset + i + 2] << 16) |
36+
(data[offset + i + 3] << 24);
37+
}
38+
return blks;
39+
}
40+
41+
function md5cycle(state: number[], blk: number[]) {
42+
let a = state[0],
43+
b = state[1],
44+
c = state[2],
45+
d = state[3];
46+
47+
a = ff(a, b, c, d, blk[0], 7, -680876936);
48+
d = ff(d, a, b, c, blk[1], 12, -389564586);
49+
c = ff(c, d, a, b, blk[2], 17, 606105819);
50+
b = ff(b, c, d, a, blk[3], 22, -1044525330);
51+
a = ff(a, b, c, d, blk[4], 7, -176418897);
52+
d = ff(d, a, b, c, blk[5], 12, 1200080426);
53+
c = ff(c, d, a, b, blk[6], 17, -1473231341);
54+
b = ff(b, c, d, a, blk[7], 22, -45705983);
55+
a = ff(a, b, c, d, blk[8], 7, 1770035416);
56+
d = ff(d, a, b, c, blk[9], 12, -1958414417);
57+
c = ff(c, d, a, b, blk[10], 17, -42063);
58+
b = ff(b, c, d, a, blk[11], 22, -1990404162);
59+
a = ff(a, b, c, d, blk[12], 7, 1804603682);
60+
d = ff(d, a, b, c, blk[13], 12, -40341101);
61+
c = ff(c, d, a, b, blk[14], 17, -1502002290);
62+
b = ff(b, c, d, a, blk[15], 22, 1236535329);
63+
64+
a = gg(a, b, c, d, blk[1], 5, -165796510);
65+
d = gg(d, a, b, c, blk[6], 9, -1069501632);
66+
c = gg(c, d, a, b, blk[11], 14, 643717713);
67+
b = gg(b, c, d, a, blk[0], 20, -373897302);
68+
a = gg(a, b, c, d, blk[5], 5, -701558691);
69+
d = gg(d, a, b, c, blk[10], 9, 38016083);
70+
c = gg(c, d, a, b, blk[15], 14, -660478335);
71+
b = gg(b, c, d, a, blk[4], 20, -405537848);
72+
a = gg(a, b, c, d, blk[9], 5, 568446438);
73+
d = gg(d, a, b, c, blk[14], 9, -1019803690);
74+
c = gg(c, d, a, b, blk[3], 14, -187363961);
75+
b = gg(b, c, d, a, blk[8], 20, 1163531501);
76+
a = gg(a, b, c, d, blk[13], 5, -1444681467);
77+
d = gg(d, a, b, c, blk[2], 9, -51403784);
78+
c = gg(c, d, a, b, blk[7], 14, 1735328473);
79+
b = gg(b, c, d, a, blk[12], 20, -1926607734);
80+
81+
a = hh(a, b, c, d, blk[5], 4, -378558);
82+
d = hh(d, a, b, c, blk[8], 11, -2022574463);
83+
c = hh(c, d, a, b, blk[11], 16, 1839030562);
84+
b = hh(b, c, d, a, blk[14], 23, -35309556);
85+
a = hh(a, b, c, d, blk[1], 4, -1530992060);
86+
d = hh(d, a, b, c, blk[4], 11, 1272893353);
87+
c = hh(c, d, a, b, blk[7], 16, -155497632);
88+
b = hh(b, c, d, a, blk[10], 23, -1094730640);
89+
a = hh(a, b, c, d, blk[13], 4, 681279174);
90+
d = hh(d, a, b, c, blk[0], 11, -358537222);
91+
c = hh(c, d, a, b, blk[3], 16, -722521979);
92+
b = hh(b, c, d, a, blk[6], 23, 76029189);
93+
a = hh(a, b, c, d, blk[9], 4, -640364487);
94+
d = hh(d, a, b, c, blk[12], 11, -421815835);
95+
c = hh(c, d, a, b, blk[15], 16, 530742520);
96+
b = hh(b, c, d, a, blk[2], 23, -995338651);
97+
98+
a = ii(a, b, c, d, blk[0], 6, -198630844);
99+
d = ii(d, a, b, c, blk[7], 10, 1126891415);
100+
c = ii(c, d, a, b, blk[14], 15, -1416354905);
101+
b = ii(b, c, d, a, blk[5], 21, -57434055);
102+
a = ii(a, b, c, d, blk[12], 6, 1700485571);
103+
d = ii(d, a, b, c, blk[3], 10, -1894986606);
104+
c = ii(c, d, a, b, blk[10], 15, -1051523);
105+
b = ii(b, c, d, a, blk[1], 21, -2054922799);
106+
a = ii(a, b, c, d, blk[8], 6, 1873313359);
107+
d = ii(d, a, b, c, blk[15], 10, -30611744);
108+
c = ii(c, d, a, b, blk[6], 15, -1560198380);
109+
b = ii(b, c, d, a, blk[13], 21, 1309151649);
110+
a = ii(a, b, c, d, blk[4], 6, -145523070);
111+
d = ii(d, a, b, c, blk[11], 10, -1120210379);
112+
c = ii(c, d, a, b, blk[2], 15, 718787259);
113+
b = ii(b, c, d, a, blk[9], 21, -343485551);
114+
115+
state[0] = add32(a, state[0]);
116+
state[1] = add32(b, state[1]);
117+
state[2] = add32(c, state[2]);
118+
state[3] = add32(d, state[3]);
119+
}
120+
121+
const HEX_CHARS = '0123456789abcdef';
122+
123+
function rhex(n: number): string {
124+
let s = '';
125+
for (let j = 0; j < 4; j++) {
126+
s += HEX_CHARS[(n >> (j * 8 + 4)) & 0x0f] + HEX_CHARS[(n >> (j * 8)) & 0x0f];
127+
}
128+
return s;
129+
}
130+
131+
export function md5(data: Uint8Array): string {
132+
const n = data.length;
133+
const state = [1732584193, -271733879, -1732584194, 271733878];
134+
135+
let i: number;
136+
for (i = 64; i <= n; i += 64) {
137+
md5cycle(state, md5blk(data, i - 64));
138+
}
139+
140+
const tail = new Array<number>(16).fill(0);
141+
const rem = n % 64;
142+
const offset = n - rem;
143+
for (i = 0; i < rem; i++) {
144+
tail[i >> 2] |= data[offset + i] << ((i % 4) << 3);
145+
}
146+
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
147+
if (i > 55) {
148+
md5cycle(state, tail);
149+
tail.fill(0);
150+
}
151+
tail[14] = n * 8;
152+
md5cycle(state, tail);
153+
154+
return state.map(rhex).join('');
155+
}

0 commit comments

Comments
 (0)