emusks 2.3.7 → 2.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/package.json +4 -3
- package/src/castle-profile.js +18 -0
- package/src/castle.js +72 -17
- package/src/flow-jetfuel.js +122 -48
- package/src/index.js +41 -17
- package/src/parsers/jetfuel-messages.js +121 -0
- package/src/vendor/castle-sdk.min.js +6 -3
- package/src/scripts/castle-mint-test.js +0 -8
- package/src/scripts/login-test.js +0 -28
- package/src/scripts/verify-session.js +0 -11
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export function decodeJetfuelMessages(input) {
|
|
2
|
+
const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
3
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
4
|
+
const strings = [];
|
|
5
|
+
const messages = [];
|
|
6
|
+
let offset = 0;
|
|
7
|
+
let end = bytes.length;
|
|
8
|
+
const take = (length) => {
|
|
9
|
+
if (offset + length > end) throw new Error("truncated jetfuel message");
|
|
10
|
+
const start = offset;
|
|
11
|
+
offset += length;
|
|
12
|
+
return start;
|
|
13
|
+
};
|
|
14
|
+
const u8 = () => view.getUint8(take(1));
|
|
15
|
+
const uint = () => {
|
|
16
|
+
let value = 0;
|
|
17
|
+
for (let shift = 0; shift < 49; shift += 7) {
|
|
18
|
+
const byte = u8();
|
|
19
|
+
value += (byte & 127) * 2 ** shift;
|
|
20
|
+
if (!(byte & 128)) return value;
|
|
21
|
+
}
|
|
22
|
+
throw new Error("invalid jetfuel integer");
|
|
23
|
+
};
|
|
24
|
+
const i16 = () => view.getInt16(take(2), true);
|
|
25
|
+
const i32 = () => view.getInt32(take(4), true);
|
|
26
|
+
const i64 = () => view.getBigInt64(take(8), true);
|
|
27
|
+
const f64 = () => view.getFloat64(take(8), true);
|
|
28
|
+
const bool = () => Boolean(u8());
|
|
29
|
+
const str = () => {
|
|
30
|
+
const length = uint();
|
|
31
|
+
const start = take(length);
|
|
32
|
+
const value = new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(start, start + length));
|
|
33
|
+
strings.push(value);
|
|
34
|
+
return value;
|
|
35
|
+
};
|
|
36
|
+
const tuple = (...readers) => () => readers.map((read) => read());
|
|
37
|
+
const list = (read) => () => {
|
|
38
|
+
const count = uint();
|
|
39
|
+
if (count > end - offset) throw new Error("invalid jetfuel list length");
|
|
40
|
+
return Array.from({ length: count }, read);
|
|
41
|
+
};
|
|
42
|
+
const dict = (key, value) => () => new Map(list(tuple(key, value))());
|
|
43
|
+
const optional = (read) => () => bool() ? read() : null;
|
|
44
|
+
const record = (fields) => () => Object.fromEntries(Object.entries(fields).map(([key, read]) => [key, read()]));
|
|
45
|
+
const constant = (value) => () => value;
|
|
46
|
+
const variant = (schema) => {
|
|
47
|
+
let readers;
|
|
48
|
+
const read = () => {
|
|
49
|
+
const tag = u8();
|
|
50
|
+
if (!readers[tag]) throw new Error(`unknown jetfuel tag ${tag}`);
|
|
51
|
+
return [tag, readers[tag]()];
|
|
52
|
+
};
|
|
53
|
+
readers = typeof schema === "function" ? schema(read) : schema;
|
|
54
|
+
return read;
|
|
55
|
+
};
|
|
56
|
+
const element = record({ type: i16, props: dict(i16, uint), children: list(uint), id: optional(i64), extend: optional(uint) });
|
|
57
|
+
const ref = variant({
|
|
58
|
+
0: record({ id: i64 }), 4: record({ id: i64, root: uint }),
|
|
59
|
+
1: record({ key: i16, root: uint }),
|
|
60
|
+
...Object.fromEntries([2, 3, 7, 8].map((tag) => [tag, record({ key: str, root: uint })])),
|
|
61
|
+
...Object.fromEntries([5, 6, 9, 10, 11].map((tag) => [tag, record({ root: uint })])),
|
|
62
|
+
});
|
|
63
|
+
const mutation = variant({
|
|
64
|
+
0: ref, 1: tuple(ref, uint), 2: tuple(ref, i16), 3: tuple(ref, str),
|
|
65
|
+
4: tuple(ref, uint, optional(i16)), 5: tuple(ref, uint),
|
|
66
|
+
6: tuple(ref, optional(tuple(uint, uint))), 7: tuple(ref, uint), 8: tuple(ref, uint),
|
|
67
|
+
});
|
|
68
|
+
const navigation = variant({
|
|
69
|
+
0: record({ url: uint, preview: optional(uint), replace: bool }),
|
|
70
|
+
9: record({ url: uint, preview: optional(uint), replace: bool }),
|
|
71
|
+
1: record({ url: uint, body: optional(uint), preview: optional(uint), replace: bool }),
|
|
72
|
+
8: record({ url: uint }), 7: record({ id: uint }),
|
|
73
|
+
...Object.fromEntries([2, 3, 4, 5, 6].map((tag) => [tag, constant(null)])),
|
|
74
|
+
});
|
|
75
|
+
const action = variant((self) => ({
|
|
76
|
+
0: mutation, 1: record({ ref: uint, action: self, cancel: optional(self) }),
|
|
77
|
+
2: list(self), 3: record({ url: uint, body: uint, complete: optional(self), error: optional(self), optimistic: optional(self) }),
|
|
78
|
+
4: record({ action: self, intensity: i16 }), 5: record({ ref: uint, type: u8 }),
|
|
79
|
+
21: record({ ref: uint, duration: i16, animation: bool }),
|
|
80
|
+
19: record({ ref: uint, type: u8, allowsRotation: bool }),
|
|
81
|
+
20: record({ ref: uint, overlay: uint, mode: str }), 6: navigation,
|
|
82
|
+
7: record({ type: u8, id: optional(i64) }), 8: str,
|
|
83
|
+
9: record({ urls: list(str), priority: u8 }), 10: record({ action: str, ref: uint }),
|
|
84
|
+
11: record({ type: u8, ref: uint }), 12: record({ action: self, delaySeconds: i16 }),
|
|
85
|
+
13: record({ data: str, secret: str, knownDeviceToken: str }),
|
|
86
|
+
14: record({ text: str, dismissText: optional(str) }), 15: record({ ref: uint, to: uint }),
|
|
87
|
+
16: record({ ref: uint, fields: list(str) }), 17: record({ ref: uint, using: uint }),
|
|
88
|
+
18: record({ ref: uint, field: str }),
|
|
89
|
+
}));
|
|
90
|
+
const condition = variant((self) => ({
|
|
91
|
+
0: record({ ref }), 15: record({ ref }),
|
|
92
|
+
...Object.fromEntries([1, 2, 5, 6, 7, 8].map((tag) => [tag, record({ ref, value: uint })])),
|
|
93
|
+
3: record({ ref, value: list(uint) }), 4: record({ ref, value: list(uint) }),
|
|
94
|
+
...Object.fromEntries([9, 10, 11].map((tag) => [tag, record({ ref, value: str })])),
|
|
95
|
+
12: tuple(self, self), 13: tuple(self, self), 14: self,
|
|
96
|
+
}));
|
|
97
|
+
const matrix = list(list(i32));
|
|
98
|
+
const property = variant({
|
|
99
|
+
0: str, 1: i32, 3: matrix, 25: list(tuple(matrix, condition)),
|
|
100
|
+
4: i64, 5: f64, 6: bool, 7: uint, 8: list(uint), 10: uint, 11: str,
|
|
101
|
+
12: list(tuple(u8, str, optional(str))), 14: i64, 15: uint,
|
|
102
|
+
16: dict(i16, uint), 17: dict(str, str),
|
|
103
|
+
18: record({ ref, prop_ref: uint, is_default: bool }), 31: record({ ref }),
|
|
104
|
+
19: action, 21: list(uint), 22: condition, 24: list(uint),
|
|
105
|
+
26: list(str), 27: list(i32), 28: list(f64), 29: list(bool),
|
|
106
|
+
30: tuple(str, dict(str, str), dict(str, str), str, u8), 13: constant(undefined),
|
|
107
|
+
});
|
|
108
|
+
const message = variant({
|
|
109
|
+
0: record({ els: list(element), props: list(property), ts: i32 }),
|
|
110
|
+
1: record({ ref: uint, t: optional(i32) }), 2: action,
|
|
111
|
+
});
|
|
112
|
+
while (offset < bytes.length) {
|
|
113
|
+
end = bytes.length;
|
|
114
|
+
const length = view.getUint32(take(4), true);
|
|
115
|
+
end = offset + length;
|
|
116
|
+
if (end > bytes.length) throw new Error("truncated jetfuel frame");
|
|
117
|
+
messages.push(message());
|
|
118
|
+
if (offset !== end) throw new Error("unexpected jetfuel frame data");
|
|
119
|
+
}
|
|
120
|
+
return { messages, strings };
|
|
121
|
+
}
|