@futpib/parser 1.0.0 → 1.0.1

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.
Files changed (171) hide show
  1. package/build/apk.d.ts +29 -3
  2. package/build/apkParser.d.ts +15 -2
  3. package/build/apkParser.js +70 -41
  4. package/build/apkParser.test.js +2 -2
  5. package/build/apkUnparser.d.ts +4 -0
  6. package/build/apkUnparser.js +90 -0
  7. package/build/apkUnparser.test.d.ts +1 -0
  8. package/build/apkUnparser.test.js +26 -0
  9. package/build/arbitraryFileSystemEntry.js +1 -1
  10. package/build/arbitraryZip.d.ts +1 -1
  11. package/build/arbitraryZip.js +13 -19
  12. package/build/arbitraryZipPermissions.d.ts +1 -8
  13. package/build/arbitraryZipPermissions.js +1 -16
  14. package/build/arbitraryZipStream.d.ts +1 -1
  15. package/build/arbitraryZipStream.js +3 -3
  16. package/build/arrayParser.d.ts +1 -1
  17. package/build/arrayParser.js +2 -2
  18. package/build/arrayParser.test.js +2 -2
  19. package/build/arrayUnparser.d.ts +2 -0
  20. package/build/arrayUnparser.js +8 -0
  21. package/build/bsonParser.test.js +2 -2
  22. package/build/customInvariant.d.ts +4 -0
  23. package/build/customInvariant.js +11 -0
  24. package/build/debugLogParser.d.ts +1 -1
  25. package/build/debugLogParser.js +1 -1
  26. package/build/elementParser.d.ts +2 -2
  27. package/build/elementParser.js +1 -1
  28. package/build/endOfInputParser.d.ts +2 -2
  29. package/build/exactElementParser.d.ts +1 -1
  30. package/build/exactSequenceParser.js +1 -1
  31. package/build/index.d.ts +5 -2
  32. package/build/index.js +3 -0
  33. package/build/inputReader.d.ts +3 -3
  34. package/build/inputReader.js +6 -6
  35. package/build/inputReader.test.js +7 -7
  36. package/build/javaKeyStore.d.ts +1 -0
  37. package/build/javaKeyStore.js +1 -0
  38. package/build/javaKeyStoreParser.d.ts +2 -0
  39. package/build/javaKeyStoreParser.js +67 -0
  40. package/build/javaKeyStoreParser.test.d.ts +1 -0
  41. package/build/javaKeyStoreParser.test.js +16 -0
  42. package/build/javaKeystoreParser.d.ts +2 -0
  43. package/build/javaKeystoreParser.js +7 -0
  44. package/build/jsonParser.js +3 -2
  45. package/build/jsonParser.test.js +2 -2
  46. package/build/listParser.d.ts +1 -1
  47. package/build/listParser.js +5 -5
  48. package/build/negativeLookahead.d.ts +1 -1
  49. package/build/negativeLookahead.js +16 -18
  50. package/build/negativeLookaheadParser.d.ts +2 -0
  51. package/build/negativeLookaheadParser.js +18 -0
  52. package/build/optionalParser.d.ts +1 -1
  53. package/build/optionalParser.js +2 -2
  54. package/build/parser.d.ts +3 -3
  55. package/build/parser.js +3 -3
  56. package/build/parser.test.js +16 -16
  57. package/build/parserAccessorParser.d.ts +1 -1
  58. package/build/parserConsumedSequenceParser.d.ts +2 -0
  59. package/build/parserConsumedSequenceParser.js +17 -0
  60. package/build/parserContext.d.ts +6 -6
  61. package/build/parserContext.js +15 -14
  62. package/build/parserContext.test.js +7 -7
  63. package/build/parserCreatorCompose.d.ts +3 -3
  64. package/build/parserCreatorCompose.js +2 -2
  65. package/build/parserImplementationInvariant.d.ts +1 -1
  66. package/build/parserImplementationInvariant.js +2 -2
  67. package/build/parserInputCompanion.d.ts +20 -0
  68. package/build/parserInputCompanion.js +30 -0
  69. package/build/parserInvariant.d.ts +1 -1
  70. package/build/parserInvariant.js +1 -1
  71. package/build/quantifierParser.d.ts +2 -0
  72. package/build/quantifierParser.js +17 -0
  73. package/build/sequenceBuffer.d.ts +3 -3
  74. package/build/sequenceBuffer.js +6 -6
  75. package/build/sequenceBuffer.test.js +2 -2
  76. package/build/sequenceUnparser.d.ts +2 -0
  77. package/build/sequenceUnparser.js +6 -0
  78. package/build/sliceBoundedParser.d.ts +1 -1
  79. package/build/sliceBoundedParser.js +1 -1
  80. package/build/sliceBoundedParser.test.js +2 -2
  81. package/build/terminatedArrayParser.d.ts +1 -1
  82. package/build/terminatedArrayParser.js +3 -3
  83. package/build/uint8Array.d.ts +1 -0
  84. package/build/uint8Array.js +7 -0
  85. package/build/unparser.d.ts +8 -0
  86. package/build/unparser.js +104 -0
  87. package/build/unparser.test.d.ts +1 -0
  88. package/build/unparser.test.js +150 -0
  89. package/build/unparserContext.d.ts +31 -0
  90. package/build/unparserContext.js +74 -0
  91. package/build/unparserError.d.ts +9 -0
  92. package/build/unparserError.js +9 -0
  93. package/build/unparserImplementationInvariant.d.ts +2 -0
  94. package/build/unparserImplementationInvariant.js +5 -0
  95. package/build/unparserInputCompanion.d.ts +15 -0
  96. package/build/unparserInputCompanion.js +13 -0
  97. package/build/unparserOutputCompanion.d.ts +15 -0
  98. package/build/unparserOutputCompanion.js +13 -0
  99. package/build/zip.d.ts +9 -17
  100. package/build/zipParser.d.ts +13 -10
  101. package/build/zipParser.js +48 -60
  102. package/build/zipParser.test.js +2 -7
  103. package/build/zipUnparser.d.ts +5 -0
  104. package/build/zipUnparser.js +171 -0
  105. package/build/zipUnparser.test.d.ts +1 -0
  106. package/build/zipUnparser.test.js +80 -0
  107. package/package.json +4 -2
  108. package/src/apk.ts +35 -3
  109. package/src/apkParser.test.ts +2 -2
  110. package/src/apkParser.test.ts.md +114 -111
  111. package/src/apkParser.test.ts.snap +0 -0
  112. package/src/apkParser.ts +150 -85
  113. package/src/apkUnparser.test.ts +37 -0
  114. package/src/apkUnparser.ts +120 -0
  115. package/src/arbitraryFileSystemEntry.ts +2 -4
  116. package/src/arbitraryZip.ts +20 -27
  117. package/src/arbitraryZipPermissions.ts +0 -25
  118. package/src/arbitraryZipStream.ts +4 -4
  119. package/src/arrayParser.test.ts +3 -3
  120. package/src/arrayParser.ts +3 -2
  121. package/src/arrayUnparser.ts +13 -0
  122. package/src/bsonParser.test.ts +2 -2
  123. package/src/bsonParser.ts +3 -3
  124. package/src/{parserInvariant.ts → customInvariant.ts} +1 -1
  125. package/src/debugLogParser.ts +1 -1
  126. package/src/elementParser.ts +3 -3
  127. package/src/endOfInputParser.ts +4 -4
  128. package/src/exactElementParser.ts +1 -1
  129. package/src/exactSequenceParser.ts +2 -2
  130. package/src/index.ts +15 -2
  131. package/src/inputReader.test.ts +7 -7
  132. package/src/inputReader.ts +5 -5
  133. package/src/javaKeyStore.ts +0 -0
  134. package/src/javaKeyStoreParser.test.ts +23 -0
  135. package/src/javaKeyStoreParser.test.ts.md +103 -0
  136. package/src/javaKeyStoreParser.test.ts.snap +0 -0
  137. package/src/javaKeyStoreParser.ts +136 -0
  138. package/src/jsonParser.test.ts +2 -2
  139. package/src/jsonParser.ts +13 -12
  140. package/src/listParser.ts +6 -6
  141. package/src/negativeLookaheadParser.ts +24 -0
  142. package/src/optionalParser.ts +3 -3
  143. package/src/parser.test.ts +19 -17
  144. package/src/parser.ts +7 -7
  145. package/src/parserAccessorParser.ts +1 -1
  146. package/src/parserConsumedSequenceParser.ts +20 -0
  147. package/src/parserContext.test.ts +7 -7
  148. package/src/parserContext.ts +18 -14
  149. package/src/parserCreatorCompose.ts +6 -6
  150. package/src/parserImplementationInvariant.ts +2 -2
  151. package/src/{inputCompanion.ts → parserInputCompanion.ts} +10 -6
  152. package/src/quantifierParser.ts +25 -0
  153. package/src/sequenceBuffer.test.ts +2 -2
  154. package/src/sequenceBuffer.ts +5 -5
  155. package/src/sequenceUnparser.ts +9 -0
  156. package/src/sliceBoundedParser.test.ts +2 -2
  157. package/src/sliceBoundedParser.ts +2 -2
  158. package/src/terminatedArrayParser.ts +3 -3
  159. package/src/uint8Array.ts +10 -0
  160. package/src/unparser.test.ts +221 -0
  161. package/src/unparser.ts +209 -0
  162. package/src/unparserContext.ts +127 -0
  163. package/src/unparserError.ts +12 -0
  164. package/src/unparserImplementationInvariant.ts +6 -0
  165. package/src/unparserOutputCompanion.ts +24 -0
  166. package/src/zip.ts +10 -22
  167. package/src/zipParser.test.ts +2 -8
  168. package/src/zipParser.ts +147 -129
  169. package/src/zipUnparser.test.ts +119 -0
  170. package/src/zipUnparser.ts +239 -0
  171. package/src/negativeLookahead.ts +0 -26
package/src/apkParser.ts CHANGED
@@ -1,17 +1,30 @@
1
- import { createArrayParser } from "./arrayParser.js";
2
- import { createOptionalParser } from "./optionalParser.js";
3
- import { Parser, setParserName } from "./parser.js";
4
- import { promiseCompose } from "./promiseCompose.js";
5
- import { createTupleParser } from "./tupleParser.js";
6
- import { zip64EndOfCentralDirectoryLocatorParser, zip64EndOfCentralDirectoryRecordParser, zipArchiveDecryptionHeaderParser, zipArchiveExtraDataRecordParser, zipCentralDirectoryHeaderParser, zipEndOfCentralDirectoryRecordParser, zipFromZipSegments, zipLocalFileParser } from "./zipParser.js";
7
- import { Apk, ApkSigningBlock, ApkSigningBlockPair } from "./apk.js";
8
- import { createFixedLengthSequenceParser } from "./fixedLengthSequenceParser.js";
9
- import { parserCreatorCompose } from "./parserCreatorCompose.js";
10
- import { createExactSequenceParser } from "./exactSequenceParser.js";
11
- import { createSliceBoundedParser } from "./sliceBoundedParser.js";
12
- import { createDisjunctionParser } from "./disjunctionParser.js";
13
- import invariant from "invariant";
14
- import { createExactElementParser } from "./exactElementParser.js";
1
+ import invariant from 'invariant';
2
+ import { createArrayParser } from './arrayParser.js';
3
+ import { createOptionalParser } from './optionalParser.js';
4
+ import { type Parser, setParserName } from './parser.js';
5
+ import { promiseCompose } from './promiseCompose.js';
6
+ import { createTupleParser } from './tupleParser.js';
7
+ import {
8
+ zip64EndOfCentralDirectoryLocatorParser,
9
+ zip64EndOfCentralDirectoryRecordParser,
10
+ zipArchiveDecryptionHeaderParser,
11
+ zipArchiveExtraDataRecordParser,
12
+ ZipCentralDirectoryHeader,
13
+ zipCentralDirectoryHeaderParser,
14
+ ZipEndOfCentralDirectoryRecord,
15
+ zipEndOfCentralDirectoryRecordParser,
16
+ zipFromZipSegments,
17
+ ZipLocalFile,
18
+ zipLocalFileParser,
19
+ } from './zipParser.js';
20
+ import { ApkSignatureV2AdditionalAttribute, ApkSignatureV2Digest, ApkSignatureV2Signature, ApkSignatureV2SignedData, ApkSignatureV2Signer, type Apk, type ApkSigningBlock, type ApkSigningBlockPair } from './apk.js';
21
+ import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
22
+ import { parserCreatorCompose } from './parserCreatorCompose.js';
23
+ import { createExactSequenceParser } from './exactSequenceParser.js';
24
+ import { createSliceBoundedParser } from './sliceBoundedParser.js';
25
+ import { createDisjunctionParser } from './disjunctionParser.js';
26
+ import { createExactElementParser } from './exactElementParser.js';
27
+ import { createParserConsumedSequenceParser } from './parserConsumedSequenceParser.js';
15
28
 
16
29
  // https://source.android.com/docs/security/features/apksigning/v2#apk-signing-block
17
30
 
@@ -46,8 +59,8 @@ const createUint32LengthPrefixedSliceBoundedParser = <T>(innerParser: Parser<T,
46
59
  const createUint32LengthPrefixedSliceBoundedArrayParser = <T>(innerParser: Parser<T, Uint8Array>): Parser<T[], Uint8Array> => createUint32LengthPrefixedSliceBoundedParser(createArrayParser(innerParser));
47
60
 
48
61
  type ApkSigningBlockZeroPaddingPair = {
49
- type: 'zeroPadding',
50
- length: number,
62
+ type: 'zeroPadding';
63
+ length: number;
51
64
  };
52
65
 
53
66
  const createApkSigningBlockZeroPaddingPairInnerParser = (length: number): Parser<ApkSigningBlockZeroPaddingPair, Uint8Array> => promiseCompose(
@@ -59,15 +72,15 @@ const createApkSigningBlockZeroPaddingPairInnerParser = (length: number): Parser
59
72
  );
60
73
 
61
74
  type ApkSigningBlockSignatureV2Pair = {
62
- type: 'signatureV2',
63
- signers: ApkSignatureSchemeV2Signer[],
75
+ type: 'signatureV2';
76
+ signers: ApkSignatureV2Signer[];
64
77
  };
65
78
 
66
79
  const createApkSigningBlockSignatureV2PairInnerParser = (length: number): Parser<ApkSigningBlockSignatureV2Pair, Uint8Array> => {
67
80
  const apkSigningBlockSignatureV2PairInnerParser = promiseCompose(
68
81
  createTupleParser([
69
82
  createExactSequenceParser<Uint8Array>(Buffer.from('1a870971', 'hex')),
70
- apkSignatureSchemeV2SignersParser,
83
+ apkSignatureV2SignersParser,
71
84
  ]),
72
85
  ([ _magic, signers = [] ]) => ({ type: 'signatureV2' as const, signers }),
73
86
  );
@@ -76,8 +89,8 @@ const createApkSigningBlockSignatureV2PairInnerParser = (length: number): Parser
76
89
  };
77
90
 
78
91
  type ApkSigningBlockGenericPair = {
79
- type: 'generic',
80
- pair: ApkSigningBlockPair,
92
+ type: 'generic';
93
+ pair: ApkSigningBlockPair;
81
94
  };
82
95
 
83
96
  const createApkSigningBlockGenericPairInnerParser = (length: number): Parser<ApkSigningBlockGenericPair, Uint8Array> => promiseCompose(
@@ -108,14 +121,14 @@ setParserName(apkSigningBlockPairParser, 'apkSigningBlockPairParser');
108
121
 
109
122
  const apkSigningBlockPairsParser: Parser<ApkSigningBlockPairType[], Uint8Array> = createArrayParser(apkSigningBlockPairParser);
110
123
 
111
- const apkSigningBlockParser: Parser<ApkSigningBlock, Uint8Array> = createUint64LengthPrefixedParser(
124
+ export const apkSigningBlockParser: Parser<ApkSigningBlock, Uint8Array> = createUint64LengthPrefixedParser(
112
125
  sizeOfBlock => promiseCompose(
113
126
  createTupleParser([
114
127
  apkSigningBlockPairsParser,
115
128
  uint64LEParser,
116
129
  createExactSequenceParser<Uint8Array>(Buffer.from('APK Sig Block 42', 'utf8')),
117
130
  ]),
118
- async ([ pairs, sizeOfBlockRepeated, _magic ]) => {
131
+ async ([ pairs, sizeOfBlockRepeated, _magic ]): Promise<ApkSigningBlock> => {
119
132
  invariant(sizeOfBlock === sizeOfBlockRepeated, 'Size of block mismatch: %s !== %s.', sizeOfBlock, sizeOfBlockRepeated);
120
133
 
121
134
  const zeroPaddingPair = pairs.find(pair => pair.type === 'zeroPadding');
@@ -135,19 +148,16 @@ const apkSigningBlockParser: Parser<ApkSigningBlock, Uint8Array> = createUint64L
135
148
 
136
149
  return {
137
150
  zeroPaddingLength: zeroPaddingPair?.length,
138
- signatureV2: signatureV2Pair?.signers,
151
+ signatureV2: signatureV2Pair ? {
152
+ signers: signatureV2Pair?.signers,
153
+ } : undefined,
139
154
  pairs: genericPairs,
140
155
  };
141
156
  },
142
157
  ),
143
158
  );
144
159
 
145
- type ApkSignatureSchemeV2Digest = {
146
- signatureAlgorithmId: number,
147
- digest: Uint8Array,
148
- };
149
-
150
- const apkSignatureSchemeV2DigestParser = createUint32LengthPrefixedParser<ApkSignatureSchemeV2Digest>(
160
+ const apkSignatureV2DigestParser = createUint32LengthPrefixedParser<ApkSignatureV2Digest>(
151
161
  pairLength => promiseCompose(
152
162
  createTupleParser([
153
163
  uint32LEParser,
@@ -159,24 +169,19 @@ const apkSignatureSchemeV2DigestParser = createUint32LengthPrefixedParser<ApkSig
159
169
  ),
160
170
  );
161
171
 
162
- const apkSignatureSchemeV2DigestsParser = createUint32LengthPrefixedSliceBoundedArrayParser(
163
- apkSignatureSchemeV2DigestParser
172
+ const apkSignatureV2DigestsParser = createUint32LengthPrefixedSliceBoundedArrayParser(
173
+ apkSignatureV2DigestParser,
164
174
  );
165
175
 
166
- const apkSignatureSchemeV2CertificateParser = createUint32LengthPrefixedParser(
176
+ const apkSignatureV2CertificateParser = createUint32LengthPrefixedParser(
167
177
  certificateLength => createFixedLengthSequenceParser(certificateLength),
168
178
  );
169
179
 
170
- const apkSignatureSchemeV2CertificatesParser = createUint32LengthPrefixedSliceBoundedArrayParser(
171
- apkSignatureSchemeV2CertificateParser,
180
+ const apkSignatureV2CertificatesParser = createUint32LengthPrefixedSliceBoundedArrayParser(
181
+ apkSignatureV2CertificateParser,
172
182
  );
173
183
 
174
- type ApkSignatureSchemeV2AdditionalAttribute = {
175
- id: number,
176
- value: Uint8Array,
177
- };
178
-
179
- const apkSignatureSchemeV2AdditionalAttributeParser = createUint32LengthPrefixedParser<ApkSignatureSchemeV2AdditionalAttribute>(
184
+ const apkSignatureV2AdditionalAttributeParser = createUint32LengthPrefixedParser<ApkSignatureV2AdditionalAttribute>(
180
185
  pairLength => promiseCompose(
181
186
  createTupleParser([
182
187
  uint32LEParser,
@@ -186,44 +191,39 @@ const apkSignatureSchemeV2AdditionalAttributeParser = createUint32LengthPrefixed
186
191
  ),
187
192
  );
188
193
 
189
- const apkSignatureSchemeV2AdditionalAttributesParser = createUint32LengthPrefixedSliceBoundedArrayParser(
190
- apkSignatureSchemeV2AdditionalAttributeParser,
194
+ setParserName(apkSignatureV2AdditionalAttributeParser, 'apkSignatureV2AdditionalAttributeParser');
195
+
196
+ const apkSignatureV2AdditionalAttributesParser = createUint32LengthPrefixedSliceBoundedArrayParser(
197
+ apkSignatureV2AdditionalAttributeParser,
191
198
  );
192
199
 
193
- type ApkSignatureSchemeV2SignedData = {
194
- digests: ApkSignatureSchemeV2Digest[],
195
- certificates: Uint8Array[],
196
- additionalAttributes: ApkSignatureSchemeV2AdditionalAttribute[],
197
- };
200
+ setParserName(apkSignatureV2AdditionalAttributesParser, 'apkSignatureV2AdditionalAttributesParser');
198
201
 
199
- const apkSignatureSchemeV2SignedDataParser = createUint32LengthPrefixedSliceBoundedParser(
202
+ const apkSignatureV2SignedDataParser = createUint32LengthPrefixedSliceBoundedParser(
200
203
  promiseCompose(
201
204
  createTupleParser([
202
- apkSignatureSchemeV2DigestsParser,
203
- apkSignatureSchemeV2CertificatesParser,
204
- createOptionalParser(apkSignatureSchemeV2AdditionalAttributesParser),
205
+ apkSignatureV2DigestsParser,
206
+ apkSignatureV2CertificatesParser,
207
+ apkSignatureV2AdditionalAttributesParser,
205
208
  createArrayParser(createExactElementParser(0)),
206
209
  ]),
207
210
  ([
208
- digests = [],
209
- certificates = [],
210
- additionalAttributes = [],
211
- ]): ApkSignatureSchemeV2SignedData => ({
212
211
  digests,
213
212
  certificates,
214
213
  additionalAttributes,
214
+ zeroPadding,
215
+ ]): ApkSignatureV2SignedData => ({
216
+ digests,
217
+ certificates,
218
+ additionalAttributes,
219
+ zeroPaddingLength: zeroPadding.length,
215
220
  }),
216
221
  ),
217
222
  );
218
223
 
219
- setParserName(apkSignatureSchemeV2SignedDataParser, 'apkSignatureSchemeV2SignedDataParser');
224
+ setParserName(apkSignatureV2SignedDataParser, 'apkSignatureV2SignedDataParser');
220
225
 
221
- type ApkSignatureSchemeV2Signature = {
222
- signatureAlgorithmId: number,
223
- signature: Uint8Array,
224
- };
225
-
226
- const apkSignatureSchemeV2SignatureParser = createUint32LengthPrefixedParser(
226
+ const apkSignatureV2SignatureParser = createUint32LengthPrefixedParser(
227
227
  signatureLength => promiseCompose(
228
228
  createTupleParser([
229
229
  uint32LEParser,
@@ -234,43 +234,37 @@ const apkSignatureSchemeV2SignatureParser = createUint32LengthPrefixedParser(
234
234
  ([
235
235
  signatureAlgorithmId,
236
236
  signature,
237
- ]): ApkSignatureSchemeV2Signature => ({
237
+ ]): ApkSignatureV2Signature => ({
238
238
  signatureAlgorithmId,
239
239
  signature,
240
240
  }),
241
241
  ),
242
242
  );
243
243
 
244
- const apkSignatureSchemeV2SignaturesParser = createUint32LengthPrefixedSliceBoundedArrayParser(
245
- apkSignatureSchemeV2SignatureParser,
244
+ const apkSignatureV2SignaturesParser = createUint32LengthPrefixedSliceBoundedArrayParser(
245
+ apkSignatureV2SignatureParser,
246
246
  );
247
247
 
248
- setParserName(apkSignatureSchemeV2SignaturesParser, 'apkSignatureSchemeV2SignaturesParser');
248
+ setParserName(apkSignatureV2SignaturesParser, 'apkSignatureV2SignaturesParser');
249
249
 
250
- const apkSignatureSchemeV2PublicKeyParser = createUint32LengthPrefixedParser(
250
+ const apkSignatureV2PublicKeyParser = createUint32LengthPrefixedParser(
251
251
  publicKeyLength => createFixedLengthSequenceParser(publicKeyLength),
252
252
  );
253
253
 
254
- setParserName(apkSignatureSchemeV2PublicKeyParser, 'apkSignatureSchemeV2PublicKeyParser');
254
+ setParserName(apkSignatureV2PublicKeyParser, 'apkSignatureV2PublicKeyParser');
255
255
 
256
- type ApkSignatureSchemeV2Signer = {
257
- signedData: ApkSignatureSchemeV2SignedData,
258
- signatures: ApkSignatureSchemeV2Signature[],
259
- publicKey?: Uint8Array,
260
- };
261
-
262
- const apkSignatureSchemeV2SignerParser = createUint32LengthPrefixedSliceBoundedParser(
256
+ const apkSignatureV2SignerParser = createUint32LengthPrefixedSliceBoundedParser(
263
257
  promiseCompose(
264
258
  createTupleParser([
265
- apkSignatureSchemeV2SignedDataParser,
266
- apkSignatureSchemeV2SignaturesParser,
267
- apkSignatureSchemeV2PublicKeyParser,
259
+ apkSignatureV2SignedDataParser,
260
+ apkSignatureV2SignaturesParser,
261
+ apkSignatureV2PublicKeyParser,
268
262
  ]),
269
263
  ([
270
264
  signedData,
271
265
  signatures = [],
272
- publicKey
273
- ]): ApkSignatureSchemeV2Signer => ({
266
+ publicKey,
267
+ ]): ApkSignatureV2Signer => ({
274
268
  signedData,
275
269
  signatures,
276
270
  publicKey,
@@ -278,13 +272,13 @@ const apkSignatureSchemeV2SignerParser = createUint32LengthPrefixedSliceBoundedP
278
272
  ),
279
273
  );
280
274
 
281
- setParserName(apkSignatureSchemeV2SignerParser, 'apkSignatureSchemeV2SignerParser');
275
+ setParserName(apkSignatureV2SignerParser, 'apkSignatureV2SignerParser');
282
276
 
283
- const apkSignatureSchemeV2SignersParser = createUint32LengthPrefixedSliceBoundedArrayParser(
284
- apkSignatureSchemeV2SignerParser,
277
+ const apkSignatureV2SignersParser = createUint32LengthPrefixedSliceBoundedArrayParser(
278
+ apkSignatureV2SignerParser,
285
279
  );
286
280
 
287
- setParserName(apkSignatureSchemeV2SignersParser, 'apkSignatureSchemeV2SignersParser');
281
+ setParserName(apkSignatureV2SignersParser, 'apkSignatureV2SignersParser');
288
282
 
289
283
  const apkParser_ = createTupleParser([
290
284
  createArrayParser(zipLocalFileParser),
@@ -325,3 +319,74 @@ export const apkParser: Parser<Apk, Uint8Array> = promiseCompose(
325
319
  );
326
320
 
327
321
  setParserName(apkParser, 'apkParser');
322
+
323
+ export type ApkSignableSections = {
324
+ zipLocalFiles: ZipLocalFile[];
325
+ apkSigningBlock?: ApkSigningBlock;
326
+ zipCentralDirectory: ZipCentralDirectoryHeader[];
327
+ zipEndOfCentralDirectory: ZipEndOfCentralDirectoryRecord;
328
+
329
+ zipLocalFilesUint8Array: Uint8Array;
330
+ apkSigningBlockUint8Array?: Uint8Array;
331
+ zipCentralDirectoryUint8Array: Uint8Array;
332
+ zipEndOfCentralDirectoryUint8Array: Uint8Array;
333
+ }
334
+
335
+ export const apkSignableSectionsParser: Parser<ApkSignableSections, Uint8Array> = promiseCompose(
336
+ createTupleParser([
337
+ createParserConsumedSequenceParser(
338
+ createTupleParser([
339
+ createArrayParser(zipLocalFileParser),
340
+ createOptionalParser(zipArchiveDecryptionHeaderParser),
341
+ createOptionalParser(zipArchiveExtraDataRecordParser),
342
+ ]),
343
+ ),
344
+ createOptionalParser(
345
+ createParserConsumedSequenceParser(
346
+ apkSigningBlockParser
347
+ ),
348
+ ),
349
+ createParserConsumedSequenceParser(
350
+ createTupleParser([
351
+ createArrayParser(zipCentralDirectoryHeaderParser),
352
+ createOptionalParser(zip64EndOfCentralDirectoryRecordParser),
353
+ createOptionalParser(zip64EndOfCentralDirectoryLocatorParser),
354
+ ]),
355
+ ),
356
+ createParserConsumedSequenceParser(
357
+ zipEndOfCentralDirectoryRecordParser,
358
+ ),
359
+ ]),
360
+ async ([
361
+ [
362
+ [
363
+ zipLocalFiles,
364
+ ],
365
+ zipLocalFilesUint8Array,
366
+ ],
367
+ [
368
+ apkSigningBlock = undefined,
369
+ apkSigningBlockUint8Array = undefined,
370
+ ] = [],
371
+ [
372
+ [
373
+ zipCentralDirectory,
374
+ ],
375
+ zipCentralDirectoryUint8Array,
376
+ ],
377
+ [
378
+ zipEndOfCentralDirectory,
379
+ zipEndOfCentralDirectoryUint8Array,
380
+ ],
381
+ ]) => ({
382
+ zipLocalFiles,
383
+ apkSigningBlock,
384
+ zipCentralDirectory,
385
+ zipEndOfCentralDirectory,
386
+
387
+ zipLocalFilesUint8Array,
388
+ apkSigningBlockUint8Array,
389
+ zipCentralDirectoryUint8Array,
390
+ zipEndOfCentralDirectoryUint8Array,
391
+ }),
392
+ );
@@ -0,0 +1,37 @@
1
+ import test from 'ava';
2
+ import { uint8ArrayParserInputCompanion } from './parserInputCompanion.js';
3
+ import { runParser } from './parser.js';
4
+ import { apkParser, apkSigningBlockParser } from './apkParser.js';
5
+ import { runUnparser } from './unparser.js';
6
+ import { apkSigningBlockUnparser } from './apkUnparser.js';
7
+ import { uint8ArrayUnparserOutputCompanion } from './unparserOutputCompanion.js';
8
+ import invariant from 'invariant';
9
+
10
+ for (const apkCid of [
11
+ 'bafkreicckcmzrdxwoc3w2in3tivpyxrdtcfpct4zwauq3igew3nkpvfapu',
12
+ ]) {
13
+ test(
14
+ 'apk ' + apkCid,
15
+ async t => {
16
+ const apkResponse = await fetch('https://ipfs.io/ipfs/' + apkCid);
17
+
18
+ const apkStream = apkResponse.body!;
19
+
20
+ const apk = await runParser(apkParser, apkStream, uint8ArrayParserInputCompanion, {
21
+ errorJoinMode: 'all',
22
+ });
23
+
24
+ const apkSigningBlock = apk.signingBlock;
25
+
26
+ invariant(apkSigningBlock, 'APK has no signing block');
27
+
28
+ const apkSigningBlockStream = runUnparser(apkSigningBlockUnparser, apkSigningBlock, uint8ArrayUnparserOutputCompanion);
29
+
30
+ const actual = await runParser(apkSigningBlockParser, apkSigningBlockStream, uint8ArrayParserInputCompanion, {
31
+ errorJoinMode: 'all',
32
+ });
33
+
34
+ t.deepEqual(actual, apkSigningBlock);
35
+ },
36
+ );
37
+ }
@@ -0,0 +1,120 @@
1
+ import { ApkSignatureV2AdditionalAttribute, ApkSignatureV2Digest, ApkSignatureV2Signature, ApkSignatureV2SignedData, ApkSignatureV2Signer, ApkSigningBlock } from "./apk.js";
2
+ import { createArrayUnparser } from "./arrayUnparser.js";
3
+ import { createSequenceUnparser } from "./sequenceUnparser.js";
4
+ import { Unparser } from "./unparser.js";
5
+
6
+ const uint8ArrayUnparser = createSequenceUnparser<Uint8Array>();
7
+
8
+ const uint32LEUnparser: Unparser<number, Uint8Array> = async function * (input) {
9
+ const buffer = Buffer.alloc(4);
10
+ buffer.writeUInt32LE(input);
11
+ yield buffer;
12
+ }
13
+
14
+ const uint64LEUnparser: Unparser<number | bigint, Uint8Array> = async function * (input) {
15
+ const buffer = Buffer.alloc(8);
16
+ buffer.writeBigUInt64LE(BigInt(input));
17
+ yield buffer;
18
+ };
19
+
20
+ const createUint32LengthPrefixedUnparser = <T>(innerUnparser: Unparser<T, Uint8Array>): Unparser<T, Uint8Array> => async function * (input, unparserContext) {
21
+ const length = yield * unparserContext.writeLater(4);
22
+ yield * innerUnparser(input, unparserContext);
23
+ yield * unparserContext.writeEarlier(length, uint32LEUnparser, unparserContext.position - length.positionEnd);
24
+ };
25
+
26
+ const createUint64LengthPrefixedUnparser = <T>(innerUnparser: Unparser<T, Uint8Array>): Unparser<T, Uint8Array> => async function * (input, unparserContext) {
27
+ const length = yield * unparserContext.writeLater(8);
28
+ yield * innerUnparser(input, unparserContext);
29
+ yield * unparserContext.writeEarlier(length, uint64LEUnparser, unparserContext.position - length.positionEnd);
30
+ };
31
+
32
+ const apkSignatureV2DigestUnparser: Unparser<ApkSignatureV2Digest, Uint8Array> = createUint32LengthPrefixedUnparser(async function * (input, unparserContext) {
33
+ yield * uint32LEUnparser(input.signatureAlgorithmId, unparserContext);
34
+ yield * uint32LEUnparser(input.digest.length, unparserContext);
35
+ yield input.digest;
36
+ });
37
+
38
+ const apkSignatureV2DigestsUnparser = createUint32LengthPrefixedUnparser(createArrayUnparser(apkSignatureV2DigestUnparser));
39
+
40
+ const apkSignatureV2CertificateUnparser = createUint32LengthPrefixedUnparser(uint8ArrayUnparser);
41
+
42
+ const apkSignatureV2CertificatesUnparser = createUint32LengthPrefixedUnparser(createArrayUnparser(apkSignatureV2CertificateUnparser));
43
+
44
+ const apkSignatureV2AdditionalAttributeUnparser: Unparser<ApkSignatureV2AdditionalAttribute, Uint8Array> = createUint32LengthPrefixedUnparser(async function * (input, unparserContext) {
45
+ yield * uint32LEUnparser(input.id, unparserContext);
46
+ yield input.value;
47
+ });
48
+
49
+ const apkSignatureV2AdditionalAttributesUnparser = createUint32LengthPrefixedUnparser(createArrayUnparser(apkSignatureV2AdditionalAttributeUnparser));
50
+
51
+ export const apkSignatureV2SignedDataUnparser: Unparser<ApkSignatureV2SignedData, Uint8Array> = createUint32LengthPrefixedUnparser(async function * (input, unparserContext) {
52
+ yield * apkSignatureV2DigestsUnparser(input.digests, unparserContext);
53
+ yield * apkSignatureV2CertificatesUnparser(input.certificates, unparserContext);
54
+ yield * apkSignatureV2AdditionalAttributesUnparser(input.additionalAttributes, unparserContext);
55
+ if (input.zeroPaddingLength) {
56
+ yield Buffer.alloc(input.zeroPaddingLength);
57
+ }
58
+ });
59
+
60
+ const apkSignatureV2SignatureUnparser: Unparser<ApkSignatureV2Signature, Uint8Array> = createUint32LengthPrefixedUnparser(async function * (input, unparserContext) {
61
+ yield * uint32LEUnparser(input.signatureAlgorithmId, unparserContext);
62
+ yield * uint32LEUnparser(input.signature.length, unparserContext);
63
+ yield input.signature;
64
+ });
65
+
66
+ const apkSignatureV2SignaturesUnparser = createUint32LengthPrefixedUnparser(createArrayUnparser(apkSignatureV2SignatureUnparser));
67
+
68
+ const apkSignatureV2PublicKeyUnparser = createUint32LengthPrefixedUnparser(uint8ArrayUnparser);
69
+
70
+ const apkSignatureV2SignerUnparser: Unparser<ApkSignatureV2Signer, Uint8Array> = createUint32LengthPrefixedUnparser(async function * (input, unparserContext) {
71
+ yield * apkSignatureV2SignedDataUnparser(input.signedData, unparserContext);
72
+ yield * apkSignatureV2SignaturesUnparser(input.signatures, unparserContext);
73
+ yield * apkSignatureV2PublicKeyUnparser(input.publicKey, unparserContext);
74
+ });
75
+
76
+ const apkSignatureV2SignersUnparser = createUint32LengthPrefixedUnparser(createArrayUnparser(apkSignatureV2SignerUnparser));
77
+
78
+ type ApkSigningBlockPair = {
79
+ id: number;
80
+ value: Uint8Array | ApkSignatureV2Signer[];
81
+ };
82
+
83
+ const apkSigningBlockPairUnparser: Unparser<ApkSigningBlockPair, Uint8Array> = createUint64LengthPrefixedUnparser(async function * (input, unparserContext) {
84
+ yield * uint32LEUnparser(input.id, unparserContext);
85
+ if (input.value instanceof Uint8Array) {
86
+ yield input.value;
87
+ } else {
88
+ yield * apkSignatureV2SignersUnparser(input.value, unparserContext);
89
+ }
90
+ });
91
+
92
+ const apkSigningBlockPairsUnparser = createArrayUnparser(apkSigningBlockPairUnparser);
93
+
94
+ export const apkSigningBlockUnparser: Unparser<ApkSigningBlock, Uint8Array> = async function * (
95
+ input,
96
+ unparserContext,
97
+ ) {
98
+ const pairs = [
99
+ ...input.pairs,
100
+ ...(input.signatureV2 ? [
101
+ {
102
+ id: 0x7109871a,
103
+ value: input.signatureV2!.signers,
104
+ },
105
+ ] : []),
106
+ ...(input.zeroPaddingLength ? [
107
+ {
108
+ id: 0x42726577,
109
+ value: Buffer.alloc(input.zeroPaddingLength),
110
+ },
111
+ ] : []),
112
+ ];
113
+
114
+ const sizeOfBlockWriteLater = yield * unparserContext.writeLater(8);
115
+ yield * apkSigningBlockPairsUnparser(pairs, unparserContext);
116
+ const sizeOfBlock = unparserContext.position - sizeOfBlockWriteLater.position + 16;
117
+ yield * uint64LEUnparser(sizeOfBlock, unparserContext);
118
+ yield * unparserContext.writeEarlier(sizeOfBlockWriteLater, uint64LEUnparser, sizeOfBlock);
119
+ yield Buffer.from('APK Sig Block 42', 'utf8');
120
+ };
@@ -14,10 +14,8 @@ type FileSystemFile = {
14
14
 
15
15
  export type FileSystemEntry =
16
16
  | FileSystemFile
17
- | FileSystemDirectory
18
- ;
19
-
20
- export const arbitraryFileSystemEntry = fc.letrec((tie) => ({
17
+ | FileSystemDirectory;
18
+ export const arbitraryFileSystemEntry = fc.letrec(tie => ({
21
19
  entry: fc.oneof<[
22
20
  fc.Arbitrary<FileSystemFile>,
23
21
  fc.Arbitrary<FileSystemDirectory>,
@@ -1,10 +1,13 @@
1
1
  import * as fc from 'fast-check';
2
- import { Zip, ZipDirectoryEntry, ZipEntry, ZipFileEntry } from './zip.js';
3
- import { arbitraryDosDateTime } from './arbitraryDosDateTime.js';
4
- import { createArbitraryZipPermissions } from './arbitraryZipPermissions.js';
5
2
  import invariant from 'invariant';
6
-
7
- const DOS_DIRECTORY_FLAG = 0b00010000;
3
+ import {
4
+ type Zip,
5
+ type ZipDirectoryEntry,
6
+ type ZipFileEntry,
7
+ type ZipEntry,
8
+ type ZipEntryAttributes,
9
+ } from './zip.js';
10
+ import { arbitraryDosDateTime } from './arbitraryDosDateTime.js';
8
11
 
9
12
  const arbitraryPath = fc.string({ minLength: 1 }).filter(path => {
10
13
  const pathSegments = path.split('/');
@@ -26,7 +29,10 @@ const createArbitraryZipEntry = (platform: 'unix' | 'dos') => fc.oneof<[
26
29
  path: arbitraryPath,
27
30
  date: arbitraryDosDateTime,
28
31
  comment: fc.string(),
29
- permissions: createArbitraryZipPermissions(platform),
32
+ hostSystem: fc.constant(platform),
33
+ attributes: fc.record<ZipEntryAttributes>({
34
+ directory: fc.constant(false),
35
+ }),
30
36
  compression: fc.oneof(
31
37
  fc.constant('store' as const),
32
38
  fc.constant('deflate' as const),
@@ -40,13 +46,6 @@ const createArbitraryZipEntry = (platform: 'unix' | 'dos') => fc.oneof<[
40
46
  return false;
41
47
  }
42
48
 
43
- if (
44
- zipFileEntry.permissions.type === 'dos'
45
- && zipFileEntry.permissions.dosPermissions & DOS_DIRECTORY_FLAG
46
- ) {
47
- return false;
48
- }
49
-
50
49
  return true;
51
50
  }),
52
51
  fc.record<ZipDirectoryEntry>({
@@ -54,16 +53,10 @@ const createArbitraryZipEntry = (platform: 'unix' | 'dos') => fc.oneof<[
54
53
  path: arbitraryPath,
55
54
  date: arbitraryDosDateTime,
56
55
  comment: fc.string(),
57
- permissions: createArbitraryZipPermissions(platform),
58
- }).filter(zipDirectoryEntry => {
59
- if (
60
- zipDirectoryEntry.permissions.type === 'dos'
61
- && !(zipDirectoryEntry.permissions.dosPermissions & DOS_DIRECTORY_FLAG)
62
- ) {
63
- return false;
64
- }
65
-
66
- return true;
56
+ hostSystem: fc.constant(platform),
57
+ attributes: fc.record<ZipEntryAttributes>({
58
+ directory: fc.constant(false),
59
+ }),
67
60
  }),
68
61
  );
69
62
 
@@ -106,10 +99,10 @@ const createArbitraryZipEntries = (platform: 'unix' | 'dos') => (
106
99
  path: directoryPath,
107
100
  date: entry.date,
108
101
  comment: '',
109
- permissions: entry.permissions.type === 'dos' ? {
110
- type: 'dos',
111
- dosPermissions: entry.permissions.dosPermissions | DOS_DIRECTORY_FLAG,
112
- } : entry.permissions,
102
+ hostSystem: platform,
103
+ attributes: {
104
+ directory: true,
105
+ },
113
106
  });
114
107
 
115
108
  seenDirectoryPaths.add(directoryPath);
@@ -1,25 +0,0 @@
1
- import * as fc from 'fast-check';
2
- import { ZipDosPermissions, ZipUnixPermissions } from './zip.js';
3
-
4
- const arbitraryZipUnixPermissions = fc.record<ZipUnixPermissions>({
5
- type: fc.constant('unix'),
6
- unixPermissions: (
7
- fc.nat({ max: 0b0000000111111111 })
8
- .filter((unixPermissions) => unixPermissions > 0)
9
- ),
10
- });
11
-
12
- const arbitraryZipDosPermissions = fc.record<ZipDosPermissions>({
13
- type: fc.constant('dos'),
14
- dosPermissions: (
15
- fc.nat({ max: 0b00111111 })
16
- ),
17
- });
18
-
19
- export const createArbitraryZipPermissions = (type: 'unix' | 'dos') => {
20
- if (type === 'unix') {
21
- return arbitraryZipUnixPermissions;
22
- }
23
-
24
- return arbitraryZipDosPermissions;
25
- };
@@ -1,13 +1,13 @@
1
1
  import JSZip from 'jszip';
2
- import { ZipEntry } from './zip.js';
2
+ import { type ZipEntry } from './zip.js';
3
3
  import { arbitraryZip } from './arbitraryZip.js';
4
4
 
5
5
  function addZipEntryToZip(zip: JSZip, zipEntry: ZipEntry) {
6
6
  const options = {
7
7
  comment: zipEntry.comment,
8
8
  date: zipEntry.date,
9
- unixPermissions: zipEntry.permissions.type === 'unix' ? zipEntry.permissions.unixPermissions : undefined,
10
- dosPermissions: zipEntry.permissions.type === 'dos' ? zipEntry.permissions.dosPermissions : undefined,
9
+ // unixPermissions: zipEntry.permissions.type === 'unix' ? zipEntry.permissions.unixPermissions : undefined,
10
+ // dosPermissions: zipEntry.permissions.type === 'dos' ? zipEntry.permissions.dosPermissions : undefined,
11
11
  };
12
12
 
13
13
  if (zipEntry.type === 'file') {
@@ -35,7 +35,7 @@ export const arbitraryZipStream = arbitraryZip.map(zip => {
35
35
  const zipInternalStream = jsZip.generateInternalStream({
36
36
  type: 'uint8array',
37
37
  comment: zip.comment,
38
- platform: zip.entries.at(0)?.permissions.type.toUpperCase() as any,
38
+ platform: zip.entries.at(0)?.hostSystem.toUpperCase() as any,
39
39
  });
40
40
 
41
41
  const zipStream = new ReadableStream<Uint8Array>({