neozipkit 0.1.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 (135) hide show
  1. package/README.md +400 -0
  2. package/contracts/Lock.sol +34 -0
  3. package/contracts/bytecode.txt +1 -0
  4. package/contracts/compile-contract.js +168 -0
  5. package/contracts/deploy/deploy-both-contracts.js +286 -0
  6. package/contracts/deploy/deploy-enhanced-contract.js +197 -0
  7. package/contracts/deploy/deploy-private-contract.js +190 -0
  8. package/contracts/deploy/deploy-public-clean.js +1063 -0
  9. package/contracts/deploy/deploy-public-contract.js +1107 -0
  10. package/contracts/deployment.config.example.js +25 -0
  11. package/contracts/remix-compile.js +222 -0
  12. package/contracts/setup-deployment.js +51 -0
  13. package/contracts/src/NZIP-NFT-Private.sol +350 -0
  14. package/contracts/src/NZIP-NFT.sol +265 -0
  15. package/contracts/src/ZipFileNFT-DEPRECATED-6field.sol +260 -0
  16. package/contracts/src/ZipFileNFT-DEPRECATED-Enhanced.sol +289 -0
  17. package/dist/browser/CertificateGeneratorBrowser.d.ts +75 -0
  18. package/dist/browser/CertificateGeneratorBrowser.js +433 -0
  19. package/dist/browser/TokenVerifierBrowser.d.ts +76 -0
  20. package/dist/browser/TokenVerifierBrowser.js +299 -0
  21. package/dist/browser/ZipKitBrowser.d.ts +18 -0
  22. package/dist/browser/ZipKitBrowser.js +250 -0
  23. package/dist/browser/ZipKitStampBrowser.d.ts +2 -0
  24. package/dist/browser/ZipKitStampBrowser.js +12 -0
  25. package/dist/browser-index.d.ts +21 -0
  26. package/dist/browser-index.js +58 -0
  27. package/dist/browser.d.ts +21 -0
  28. package/dist/browser.js +58 -0
  29. package/dist/index.d.ts +29 -0
  30. package/dist/index.js +76 -0
  31. package/dist/server/blockchain/CertificateToken.d.ts +48 -0
  32. package/dist/server/blockchain/CertificateToken.js +386 -0
  33. package/dist/server/blockchain/NFTMinter.d.ts +41 -0
  34. package/dist/server/blockchain/NFTMinter.js +323 -0
  35. package/dist/server/blockchain/TokenQuerier.d.ts +31 -0
  36. package/dist/server/blockchain/TokenQuerier.js +259 -0
  37. package/dist/server/blockchain/TokenVerifier.d.ts +20 -0
  38. package/dist/server/blockchain/TokenVerifier.js +395 -0
  39. package/dist/server/blockchain/WalletAnalyzer.d.ts +81 -0
  40. package/dist/server/blockchain/WalletAnalyzer.js +356 -0
  41. package/dist/server/blockchain/WalletFormatter.d.ts +39 -0
  42. package/dist/server/blockchain/WalletFormatter.js +196 -0
  43. package/dist/server/blockchain/WalletManager.d.ts +46 -0
  44. package/dist/server/blockchain/WalletManager.js +294 -0
  45. package/dist/server/blockchain/ZipMetadata.d.ts +27 -0
  46. package/dist/server/blockchain/ZipMetadata.js +131 -0
  47. package/dist/server/blockchain/ZipTokenProcessor.d.ts +44 -0
  48. package/dist/server/blockchain/ZipTokenProcessor.js +204 -0
  49. package/dist/server/blockchain/constants.d.ts +102 -0
  50. package/dist/server/blockchain/constants.js +968 -0
  51. package/dist/server/blockchain/index.d.ts +9 -0
  52. package/dist/server/blockchain/index.js +44 -0
  53. package/dist/server/blockchain/test-certificate.d.ts +8 -0
  54. package/dist/server/blockchain/test-certificate.js +100 -0
  55. package/dist/server/blockchain/types.d.ts +69 -0
  56. package/dist/server/blockchain/types.js +51 -0
  57. package/dist/server/platform/server/ZipKitServer.d.ts +105 -0
  58. package/dist/server/platform/server/ZipKitServer.js +437 -0
  59. package/dist/server/platform/servercomponents/ZipKitOTS.d.ts +91 -0
  60. package/dist/server/platform/servercomponents/ZipKitOTS.js +271 -0
  61. package/dist/shared/ZipEntry.d.ts +131 -0
  62. package/dist/shared/ZipEntry.js +686 -0
  63. package/dist/shared/ZipKit.d.ts +249 -0
  64. package/dist/shared/ZipKit.js +789 -0
  65. package/dist/shared/components/CertificateOTS.d.ts +15 -0
  66. package/dist/shared/components/CertificateOTS.js +116 -0
  67. package/dist/shared/components/FileSys.d.ts +2 -0
  68. package/dist/shared/components/FileSys.js +113 -0
  69. package/dist/shared/components/HashAccumulator.d.ts +55 -0
  70. package/dist/shared/components/HashAccumulator.js +100 -0
  71. package/dist/shared/components/Support.d.ts +63 -0
  72. package/dist/shared/components/Support.js +70 -0
  73. package/dist/shared/components/Util.d.ts +21 -0
  74. package/dist/shared/components/Util.js +115 -0
  75. package/dist/shared/components/ZipCrypto.d.ts +3 -0
  76. package/dist/shared/components/ZipCrypto.js +78 -0
  77. package/dist/shared/components/merkleTree.d.ts +66 -0
  78. package/dist/shared/components/merkleTree.js +136 -0
  79. package/dist/shared/constants/Errors.d.ts +53 -0
  80. package/dist/shared/constants/Errors.js +69 -0
  81. package/dist/shared/constants/Headers.d.ts +167 -0
  82. package/dist/shared/constants/Headers.js +191 -0
  83. package/dist/shared/types/index.d.ts +21 -0
  84. package/dist/shared/types/index.js +3 -0
  85. package/dist/shared/types.d.ts +33 -0
  86. package/dist/shared/types.js +8 -0
  87. package/dist/shared/version.d.ts +4 -0
  88. package/dist/shared/version.js +7 -0
  89. package/dist/types/index.d.ts +21 -0
  90. package/dist/types/index.js +3 -0
  91. package/examples/unzip-token.ts +488 -0
  92. package/examples/zip-token.ts +604 -0
  93. package/package.json +117 -0
  94. package/src/browser/CertificateGeneratorBrowser.ts +498 -0
  95. package/src/browser/TokenVerifierBrowser.ts +344 -0
  96. package/src/browser/ZipKitBrowser.ts +242 -0
  97. package/src/browser/ZipKitStampBrowser.ts +9 -0
  98. package/src/browser-index.ts +36 -0
  99. package/src/index.ts +48 -0
  100. package/src/server/blockchain/CertificateToken.ts +444 -0
  101. package/src/server/blockchain/NFTMinter.ts +357 -0
  102. package/src/server/blockchain/TokenQuerier.ts +287 -0
  103. package/src/server/blockchain/TokenVerifier.ts +453 -0
  104. package/src/server/blockchain/WalletAnalyzer.ts +397 -0
  105. package/src/server/blockchain/WalletFormatter.ts +206 -0
  106. package/src/server/blockchain/WalletManager.ts +294 -0
  107. package/src/server/blockchain/ZipMetadata.ts +117 -0
  108. package/src/server/blockchain/ZipTokenProcessor.ts +234 -0
  109. package/src/server/blockchain/constants.ts +969 -0
  110. package/src/server/blockchain/index.ts +42 -0
  111. package/src/server/blockchain/test-certificate.ts +137 -0
  112. package/src/server/blockchain/types.ts +134 -0
  113. package/src/server/platform/server/ZipKitServer.ts +459 -0
  114. package/src/server/platform/servercomponents/ZipKitOTS.ts +313 -0
  115. package/src/server/platform/servercomponents/opentimestamps.d.ts +23 -0
  116. package/src/shared/ZipEntry.ts +767 -0
  117. package/src/shared/ZipKit.ts +899 -0
  118. package/src/shared/components/CertificateOTS.ts +132 -0
  119. package/src/shared/components/FileSys.ts +87 -0
  120. package/src/shared/components/HashAccumulator.ts +113 -0
  121. package/src/shared/components/Support.ts +77 -0
  122. package/src/shared/components/Util.ts +113 -0
  123. package/src/shared/components/ZipCrypto.ts +91 -0
  124. package/src/shared/components/merkleTree.ts +162 -0
  125. package/src/shared/constants/Errors.ts +82 -0
  126. package/src/shared/constants/Headers.ts +203 -0
  127. package/src/shared/types/index.ts +25 -0
  128. package/src/shared/types/modules.d.ts +22 -0
  129. package/src/shared/types/opentimestamps.d.ts +23 -0
  130. package/src/shared/types.d.ts +8 -0
  131. package/src/shared/types.ts +43 -0
  132. package/src/shared/version.ts +4 -0
  133. package/src/types/index.ts +25 -0
  134. package/src/types/modules.d.ts +22 -0
  135. package/src/types/opentimestamps.d.ts +23 -0
@@ -0,0 +1,789 @@
1
+ "use strict";
2
+ // ======================================
3
+ // ZipKit.ts
4
+ // Copyright (c) 2025 NeoWare, Inc. All rights reserved.
5
+ // ======================================
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.HDR_ID = exports.CENTRAL_DIRECTORY_END = exports.CENTRAL_FILE_HEADER = exports.LOCAL_FILE_HEADER = exports.GP_FLAG = exports.ZIP64_CENTRAL_DIR = exports.ZIP64_CENTRAL_END = exports.CENTRAL_DIR = exports.CENTRAL_END = exports.ENCRYPT_HDR_SIZE = exports.LOCAL_HDR = exports.TOKENIZED_METADATA = exports.TIMESTAMP_SUBMITTED = exports.TIMESTAMP_METADATA = exports.CMP_METHOD = exports.Errors = exports.ZipEntry = void 0;
11
+ const ZipEntry_1 = __importDefault(require("./ZipEntry"));
12
+ exports.ZipEntry = ZipEntry_1.default;
13
+ const Errors_1 = __importDefault(require("./constants/Errors"));
14
+ exports.Errors = Errors_1.default;
15
+ const Util_1 = require("./components/Util");
16
+ const ZipCrypto_1 = require("./components/ZipCrypto");
17
+ const Support_1 = __importDefault(require("./components/Support"));
18
+ const pako_1 = __importDefault(require("pako"));
19
+ const Headers_1 = require("./constants/Headers");
20
+ Object.defineProperty(exports, "LOCAL_HDR", { enumerable: true, get: function () { return Headers_1.LOCAL_HDR; } });
21
+ Object.defineProperty(exports, "ENCRYPT_HDR_SIZE", { enumerable: true, get: function () { return Headers_1.ENCRYPT_HDR_SIZE; } });
22
+ Object.defineProperty(exports, "CMP_METHOD", { enumerable: true, get: function () { return Headers_1.CMP_METHOD; } });
23
+ Object.defineProperty(exports, "CENTRAL_END", { enumerable: true, get: function () { return Headers_1.CENTRAL_END; } });
24
+ Object.defineProperty(exports, "CENTRAL_DIR", { enumerable: true, get: function () { return Headers_1.CENTRAL_DIR; } });
25
+ Object.defineProperty(exports, "ZIP64_CENTRAL_END", { enumerable: true, get: function () { return Headers_1.ZIP64_CENTRAL_END; } });
26
+ Object.defineProperty(exports, "ZIP64_CENTRAL_DIR", { enumerable: true, get: function () { return Headers_1.ZIP64_CENTRAL_DIR; } });
27
+ Object.defineProperty(exports, "GP_FLAG", { enumerable: true, get: function () { return Headers_1.GP_FLAG; } });
28
+ Object.defineProperty(exports, "TIMESTAMP_SUBMITTED", { enumerable: true, get: function () { return Headers_1.TIMESTAMP_SUBMITTED; } });
29
+ Object.defineProperty(exports, "TIMESTAMP_METADATA", { enumerable: true, get: function () { return Headers_1.TIMESTAMP_METADATA; } });
30
+ Object.defineProperty(exports, "TOKENIZED_METADATA", { enumerable: true, get: function () { return Headers_1.TOKENIZED_METADATA; } });
31
+ Object.defineProperty(exports, "LOCAL_FILE_HEADER", { enumerable: true, get: function () { return Headers_1.LOCAL_FILE_HEADER; } });
32
+ Object.defineProperty(exports, "CENTRAL_FILE_HEADER", { enumerable: true, get: function () { return Headers_1.CENTRAL_FILE_HEADER; } });
33
+ Object.defineProperty(exports, "CENTRAL_DIRECTORY_END", { enumerable: true, get: function () { return Headers_1.CENTRAL_DIRECTORY_END; } });
34
+ Object.defineProperty(exports, "HDR_ID", { enumerable: true, get: function () { return Headers_1.HDR_ID; } });
35
+ const HashAccumulator_1 = __importDefault(require("./components/HashAccumulator"));
36
+ const zstd_js_1 = require("@oneidentity/zstd-js");
37
+ const types_1 = require("./types");
38
+ // We'll initialize zstd when needed
39
+ let zstdCodec = null;
40
+ // Async initialization function for zstd
41
+ async function initZstd() {
42
+ if (!zstdCodec) {
43
+ zstdCodec = await (0, zstd_js_1.ZstdInit)();
44
+ }
45
+ return zstdCodec;
46
+ }
47
+ /**
48
+ * Main class for ZIP file operations including compression, extraction, and encryption
49
+ */
50
+ class ZipKit {
51
+ /**
52
+ * Creates a new ZipKit instance
53
+ */
54
+ constructor() {
55
+ this.inBuffer = null;
56
+ this.zipEntries = [];
57
+ this.sortName = false;
58
+ // Central End Directory values for existing Zip file
59
+ this.centralDirSize = 0;
60
+ this.centralDirOffset = 0;
61
+ // Timestamp values
62
+ this.stampEntry = null;
63
+ this.zipComment = null;
64
+ }
65
+ /**
66
+ * Resets all ZIP-related data to initial state
67
+ */
68
+ resetZipData() {
69
+ this.inBuffer = null;
70
+ this.zipEntries = [];
71
+ this.centralDirSize = 0;
72
+ this.centralDirOffset = 0;
73
+ this.zipComment = null;
74
+ }
75
+ /**
76
+ * Loads a ZIP file from a buffer
77
+ * @param inBuf - Buffer containing ZIP file data
78
+ */
79
+ loadZip(inBuf) {
80
+ this.resetZipData();
81
+ this.inBuffer = inBuf;
82
+ }
83
+ /**
84
+ * Tests if data matches the CRC32 checksum
85
+ * @param entry - ZIP entry to check
86
+ * @param data - Data buffer to verify
87
+ * @returns boolean indicating if CRC matches
88
+ */
89
+ testCRC32(entry, data) {
90
+ // if bit 3 (0x08) of the general-purpose flags field is set, then the CRC-32 and file sizes are not known when the header is written
91
+ if ((entry.bitFlags & 0x8) !== 0x8) {
92
+ const _crc = (0, Util_1.crc32)(data);
93
+ // console.log(' CRC: '+ sprintf("%08x", _crc));
94
+ // console.log('ent.CRC: ' + sprintf("%08x", entry.crc));
95
+ if (_crc !== entry.crc) {
96
+ return false;
97
+ }
98
+ }
99
+ else {
100
+ // @TODO: load and check data descriptor header
101
+ // The fields in the local header are filled with zero, and the CRC-32 and size are appended in a 12-byte structure
102
+ // (optionally preceded by a 4-byte signature) immediately after the compressed data:
103
+ }
104
+ return true;
105
+ }
106
+ /**
107
+ * Tests if data matches the SHA256 hash
108
+ * @param entry - ZIP entry to check
109
+ * @param data - Data buffer to verify
110
+ * @returns boolean indicating if SHA256 matches
111
+ * @throws Error if entry has no SHA256 hash
112
+ */
113
+ testSHA256(entry, data) {
114
+ if (!entry.sha256) {
115
+ throw new Error(Errors_1.default.UNKNOWN_SHA256);
116
+ }
117
+ const _sha256 = (0, ZipCrypto_1.sha256)(data);
118
+ return _sha256 === entry.sha256;
119
+ }
120
+ /**
121
+ * Locates and parses the central end directory
122
+ * @param inBuffer - Buffer containing ZIP file data
123
+ * @returns Number of entries in ZIP file
124
+ * @throws Error if central directory is invalid
125
+ */
126
+ getCentralEnd(inBuffer) {
127
+ let i = inBuffer.length - Headers_1.CENTRAL_END.SIZE;
128
+ let max = Math.max(0, i - 0xffff); // 0xFFFF is the max zip file comment length
129
+ let endStart = inBuffer.length;
130
+ let endOffset = -1; // Start offset of the END header
131
+ let commentEnd = 0;
132
+ let volEntries = 0;
133
+ let totalEntries = 0;
134
+ for (let n = max; i >= n; i--) {
135
+ if (inBuffer[i] !== 0x50)
136
+ continue; // quick check that the byte is 'P'
137
+ if (inBuffer.readUInt32LE(i) === Headers_1.CENTRAL_END.SIGNATURE) {
138
+ // "PK\005\006"
139
+ endOffset = i;
140
+ commentEnd = i;
141
+ endStart = i + Headers_1.CENTRAL_END.SIZE;
142
+ // We already found a regular signature, let's look just a bit further to check if there's any zip64 signature
143
+ n = i - Headers_1.ZIP64_CENTRAL_END.SIZE;
144
+ continue;
145
+ }
146
+ if (inBuffer.readUInt32LE(i) === Headers_1.ZIP64_CENTRAL_END.SIGNATURE) {
147
+ // Found a zip64 signature, let's continue reading the whole zip64 record
148
+ n = max;
149
+ continue;
150
+ }
151
+ if (inBuffer.readUInt32LE(i) === Headers_1.ZIP64_CENTRAL_DIR.SIGNATURE) {
152
+ // Found the zip64 record, let's determine it's size
153
+ endOffset = i;
154
+ endStart = i + (0, Util_1.readBigUInt64LE)(inBuffer, i + Headers_1.ZIP64_CENTRAL_DIR.SIZE) + Headers_1.ZIP64_CENTRAL_DIR.LEAD;
155
+ break;
156
+ }
157
+ }
158
+ if (!~endOffset)
159
+ throw new Error(Errors_1.default.INVALID_FORMAT);
160
+ let data = inBuffer.subarray(endOffset, endStart);
161
+ if (data.readUInt32LE(0) == Headers_1.CENTRAL_END.SIGNATURE) {
162
+ // number of entries on this volume
163
+ volEntries = data.readUInt16LE(Headers_1.CENTRAL_END.VOL_ENTRIES);
164
+ // total number of entries
165
+ totalEntries = data.readUInt16LE(Headers_1.CENTRAL_END.TOTAL_ENTRIES);
166
+ // central directory size in bytes
167
+ this.centralDirSize = data.readUInt32LE(Headers_1.CENTRAL_END.CENTRAL_DIR_SIZE);
168
+ // offset of first CEN header
169
+ this.centralDirOffset = data.readUInt32LE(Headers_1.CENTRAL_END.CENTRAL_DIR_OFFSET);
170
+ }
171
+ else {
172
+ // number of entries on this volume
173
+ volEntries = (0, Util_1.readBigUInt64LE)(data, Headers_1.ZIP64_CENTRAL_DIR.VOL_ENTRIES);
174
+ // total number of entries
175
+ totalEntries = (0, Util_1.readBigUInt64LE)(data, Headers_1.ZIP64_CENTRAL_DIR.TOTAL_ENTRIES);
176
+ // central directory size in bytes
177
+ this.centralDirSize = (0, Util_1.readBigUInt64LE)(data, Headers_1.ZIP64_CENTRAL_DIR.CENTRAL_DIR_SIZE);
178
+ // offset of first CEN header
179
+ this.centralDirOffset = (0, Util_1.readBigUInt64LE)(data, Headers_1.ZIP64_CENTRAL_DIR.CENTRAL_DIR_OFFSET);
180
+ }
181
+ // zip file comment length
182
+ let commentLength = data.readUInt16LE(Headers_1.CENTRAL_END.ZIP_COMMENT_LEN);
183
+ if (commentLength > 0) {
184
+ this.zipComment = inBuffer.subarray(endStart, endStart + commentLength).toString();
185
+ }
186
+ // console.log('totalEntries: ', totalEntries);
187
+ // console.log('centralDirSize; ', this.centralDirSize);
188
+ // console.log('centralDirOffset: ', this.centralDirOffset);
189
+ // console.log('commentLength: ', commentLength);
190
+ // console.log('zipComment: ', this.zipComment);
191
+ return totalEntries;
192
+ }
193
+ /**
194
+ * Creates the central end directory header
195
+ * @param centralDirSize - Size of central directory
196
+ * @param centralDirOffset - Offset to central directory
197
+ * @returns Buffer containing end directory header
198
+ */
199
+ centralEndHdr(centralDirSize, centralDirOffset) {
200
+ const commentLen = this.zipComment ? this.zipComment.length : 0;
201
+ const data = Buffer.alloc(Headers_1.CENTRAL_END.SIZE + commentLen);
202
+ // "PK\005\006"
203
+ data.writeUInt32LE(Headers_1.CENTRAL_END.SIGNATURE, 0);
204
+ // number of this disk
205
+ data.writeUInt16LE(0, Headers_1.CENTRAL_END.VOL_NUM);
206
+ // number of the volume/disk with start of the Central Directory
207
+ data.writeUInt16LE(0, Headers_1.CENTRAL_END.VOLDIR_START);
208
+ // number of entries on this volume/disk
209
+ data.writeUInt16LE(0, Headers_1.CENTRAL_END.VOL_ENTRIES);
210
+ // total number of entries on this disk
211
+ data.writeUInt16LE(this.zipEntries.length, Headers_1.CENTRAL_END.TOTAL_ENTRIES);
212
+ // central directory size in bytes
213
+ data.writeUInt32LE(centralDirSize, Headers_1.CENTRAL_END.CENTRAL_DIR_SIZE);
214
+ // offset of first Central Directory Entry
215
+ data.writeUInt32LE(centralDirOffset, Headers_1.CENTRAL_END.CENTRAL_DIR_OFFSET);
216
+ // Zip file comment length
217
+ data.writeUInt16LE(commentLen, Headers_1.CENTRAL_END.ZIP_COMMENT_LEN);
218
+ if (commentLen > 0 && this.zipComment) {
219
+ const zipCommentBuf = Buffer.from(this.zipComment, 'utf8');
220
+ zipCommentBuf.copy(data, Headers_1.CENTRAL_END.SIZE);
221
+ }
222
+ return data;
223
+ }
224
+ /**
225
+ * Reads and parses the ZIP file directory
226
+ * @param debug - Enable debug logging
227
+ * @returns Array of ZIP entries
228
+ */
229
+ getDirectory(debug) {
230
+ if (this.zipEntries.length > 0) {
231
+ return this.zipEntries;
232
+ }
233
+ const buffer = this.ensureBuffer();
234
+ // Add this check for empty buffers - if empty, there's no need to try parsing
235
+ if (buffer.length === 0) {
236
+ // This is a new ZIP file, so we return an empty array
237
+ return this.zipEntries;
238
+ }
239
+ const entries = this.getCentralEnd(buffer);
240
+ if (entries === 0)
241
+ return [];
242
+ var entryData = buffer.subarray(this.centralDirOffset, this.centralDirOffset + this.centralDirSize);
243
+ if (entryData.readUInt32LE(0) !== Headers_1.CENTRAL_DIR.SIGNATURE)
244
+ throw new Error(Errors_1.default.INVALID_CEN);
245
+ const entryList = [];
246
+ for (var i = 0; i < entries; i++) {
247
+ let entry = new ZipEntry_1.default(null, null, debug);
248
+ entryData = entry.readZipEntry(entryData);
249
+ entryList.push(entry);
250
+ // entry.outputZipEntry();
251
+ }
252
+ this.zipEntries = entryList;
253
+ // Sort Zip Entries if sortName option set
254
+ if (this.sortName && this.zipEntries.length > 1)
255
+ this.zipEntries.sort((a, b) => {
256
+ return (a.filename || '').toLowerCase()
257
+ .localeCompare((b.filename || '').toLowerCase());
258
+ });
259
+ return this.zipEntries;
260
+ }
261
+ /**
262
+ * Gets a ZIP entry by filename
263
+ * @param fname - Filename to search for
264
+ * @returns ZipEntry if found, null otherwise
265
+ */
266
+ getZipEntry(fname) {
267
+ try {
268
+ const centralDir = this.getDirectory();
269
+ if (centralDir) {
270
+ for (const entry of centralDir) {
271
+ if (entry.filename === fname) {
272
+ return entry;
273
+ }
274
+ }
275
+ }
276
+ return null;
277
+ }
278
+ catch (error) {
279
+ // If we get here, treat as a new file (no existing entry)
280
+ return null;
281
+ }
282
+ }
283
+ /**
284
+ * Creates a new ZIP entry
285
+ * @param fname - Filename for new entry
286
+ * @param comment - Optional entry comment
287
+ * @returns Created ZipEntry
288
+ */
289
+ createZipEntry(fname, comment) {
290
+ const entry = new ZipEntry_1.default(fname, comment);
291
+ this.zipEntries.push(entry);
292
+ return entry;
293
+ }
294
+ /**
295
+ * Deletes an entry from the ZIP file
296
+ * @param fname - Filename to delete
297
+ * @returns boolean indicating if file was deleted
298
+ */
299
+ deleteFile(fname) {
300
+ const entries = this.ensureZipEntries();
301
+ const index = entries.findIndex(zipEntry => zipEntry.filename === fname);
302
+ if (index < 0)
303
+ return false;
304
+ entries.splice(index, 1);
305
+ return true;
306
+ }
307
+ /**
308
+ * Parses local header and returns entry data
309
+ * @param entry - ZIP entry to parse
310
+ * @param withLocalHdrData - Include header in returned data
311
+ * @returns Buffer containing entry data
312
+ * @throws Error if header is invalid
313
+ */
314
+ parseLocalHeader(entry, withLocalHdrData) {
315
+ const buffer = this.ensureBuffer();
316
+ const localData = buffer.subarray(entry.localHdrOffset);
317
+ // data should be 30 bytes and start with "PK 03 04"
318
+ if (localData.readUInt32LE(0) !== Headers_1.LOCAL_HDR.SIGNATURE) {
319
+ throw new Error(Errors_1.default.INVALID_CEN);
320
+ }
321
+ // Check for Data Descriptor Flag
322
+ let _encryptLen = 0;
323
+ const _bitFlags = localData.readUInt16LE(Headers_1.LOCAL_HDR.FLAGS);
324
+ if (_bitFlags & Headers_1.GP_FLAG.ENCRYPTED) {
325
+ _encryptLen = Headers_1.ENCRYPT_HDR_SIZE;
326
+ }
327
+ if (_bitFlags & Headers_1.GP_FLAG.DATA_DESC) {
328
+ entry.bitFlags |= Headers_1.GP_FLAG.DATA_DESC;
329
+ entry.lastModTimeDate = localData.readUInt32LE(Headers_1.LOCAL_HDR.TIMEDATE_DOS);
330
+ }
331
+ let _fnameLen = localData.readUInt16LE(Headers_1.LOCAL_HDR.FNAME_LEN);
332
+ let _extraLen = localData.readUInt16LE(Headers_1.LOCAL_HDR.EXTRA_LEN);
333
+ let _localSize = Headers_1.LOCAL_HDR.SIZE + _fnameLen + _extraLen;
334
+ if (_encryptLen != 0) {
335
+ entry.encryptHdr = Buffer.from(localData.subarray(_localSize, _localSize + _encryptLen));
336
+ }
337
+ if (withLocalHdrData)
338
+ return localData.subarray(0, _localSize + entry.compressedSize);
339
+ return localData.subarray(_localSize + _encryptLen, _localSize + entry.compressedSize);
340
+ }
341
+ /**
342
+ * Copies an entry's data from source ZIP
343
+ * @param entry - Entry to copy
344
+ * @returns Buffer containing entry data with headers
345
+ */
346
+ copyEntry(entry) {
347
+ return this.parseLocalHeader(entry, true);
348
+ }
349
+ /**
350
+ * Compresses data for a ZIP entry
351
+ * @param entry - ZIP entry to compress
352
+ * @param data - Data to compress
353
+ * @param options - Compression options
354
+ * @returns Buffer containing compressed data
355
+ */
356
+ async compressData(entry, data, options) {
357
+ // Initialize with empty buffer instead of null
358
+ let buffer = Buffer.alloc(0);
359
+ // Determine compression method based on options
360
+ if (options?.level === 0) {
361
+ // Level 0 means "store" (no compression)
362
+ entry.cmpMethod = Headers_1.CMP_METHOD.STORED;
363
+ buffer = data;
364
+ }
365
+ else if (options?.useZstd) {
366
+ // Use Zstandard compression
367
+ if (data.length < 100) {
368
+ // ZStd requires at least 100 bytes, store it without compression
369
+ entry.cmpMethod = Headers_1.CMP_METHOD.STORED;
370
+ buffer = data;
371
+ }
372
+ else {
373
+ entry.cmpMethod = Headers_1.CMP_METHOD.ZSTD;
374
+ buffer = await this.zstdCompress(data, options);
375
+ }
376
+ }
377
+ else {
378
+ // Default to deflate
379
+ entry.cmpMethod = Headers_1.CMP_METHOD.DEFLATED;
380
+ buffer = this.deflate(data, options);
381
+ }
382
+ entry.crc = (0, Util_1.crc32)(data);
383
+ // console.log('CRC: '+ sprintf("%08x", entry.crc));
384
+ if (options?.useSHA256) {
385
+ entry.sha256 = (0, ZipCrypto_1.sha256)(data);
386
+ console.log('SHA256: ', entry.sha256);
387
+ }
388
+ ;
389
+ if (options?.password) {
390
+ entry.bitFlags = Headers_1.GP_FLAG.ENCRYPTED;
391
+ const _check = (entry.crc >> 24) & 0xff;
392
+ const encryptedBuffer = (0, ZipCrypto_1.encrypter)(buffer, _check, options.password);
393
+ // Handle potential null return from encrypter
394
+ if (!encryptedBuffer) {
395
+ throw new Error(Errors_1.default.ENCRYPT_FAILED);
396
+ }
397
+ buffer = encryptedBuffer;
398
+ }
399
+ entry.compressedSize = buffer.length;
400
+ return buffer;
401
+ }
402
+ /**
403
+ * Compresses data using deflate algorithm
404
+ * @param inbuf - Data to compress
405
+ * @param options - Compression options
406
+ * @returns Compressed data buffer
407
+ */
408
+ deflate(inbuf, options) {
409
+ if (options?.level == 0) {
410
+ return inbuf; // Store without compression
411
+ }
412
+ try {
413
+ const level = options?.level;
414
+ const result = pako_1.default.deflateRaw(inbuf, {
415
+ level: level ?? 6
416
+ });
417
+ return Buffer.from(result.buffer, result.byteOffset, result.byteLength);
418
+ }
419
+ catch (e) {
420
+ console.error('Error during compression:', e);
421
+ throw new Error(Errors_1.default.COMPRESSION_ERROR);
422
+ }
423
+ }
424
+ /**
425
+ * Compresses data using Zstandard (zstd) algorithm
426
+ * @param inbuf - Data to compress
427
+ * @param options - Compression options
428
+ * @returns Compressed data buffer
429
+ */
430
+ async zstdCompress(inbuf, options) {
431
+ if (options?.level == 0) {
432
+ return inbuf; // Store without compression
433
+ }
434
+ try {
435
+ // Ensure zstd is initialized
436
+ const codec = await initZstd();
437
+ // Zstd compression levels range from 1 (fastest) to 22 (highest compression)
438
+ // Map our 1-9 level to a reasonable zstd range (1-19)
439
+ const level = options?.level ?? 6;
440
+ const zstdLevel = Math.min(Math.max(1, Math.floor(level * 2.1)), 19);
441
+ // Compress the data with zstd
442
+ const compressedData = codec.ZstdSimple.compress(inbuf, zstdLevel);
443
+ return Buffer.from(compressedData);
444
+ }
445
+ catch (e) {
446
+ console.error('Error during zstd compression:', e);
447
+ throw new Error(Errors_1.default.COMPRESSION_ERROR);
448
+ }
449
+ }
450
+ /**
451
+ * Decompresses data using Zstandard (zstd) algorithm
452
+ * @param inbuf - Compressed data buffer
453
+ * @returns Decompressed data buffer
454
+ */
455
+ async zstdDecompress(inbuf) {
456
+ try {
457
+ // Ensure zstd is initialized
458
+ const codec = await initZstd();
459
+ const decompressedData = codec.ZstdSimple.decompress(inbuf);
460
+ return Buffer.from(decompressedData);
461
+ }
462
+ catch (e) {
463
+ console.error('Error during zstd decompression:', e);
464
+ throw new Error(Errors_1.default.DECOMPRESSION_ERROR);
465
+ }
466
+ }
467
+ // ======================================
468
+ // deflateAsync(inbuf: Buffer, callback: (result: Buffer) => void) {
469
+ // var opts = { chunkSize: ((inbuf.length >> 10) + 1) * 1024 };
470
+ // var tmp = zlib.createDeflateRaw(opts),
471
+ // parts = [],
472
+ // total = 0;
473
+ // tmp.on("data", function (data) {
474
+ // parts.push(data);
475
+ // total += data.length;
476
+ // });
477
+ // tmp.on("end", function () {
478
+ // var buf = Buffer.alloc(total),
479
+ // written = 0;
480
+ // buf.fill(0);
481
+ // for (var i = 0; i < parts.length; i++) {
482
+ // var part = parts[i];
483
+ // part.copy(buf, written);
484
+ // written += part.length;
485
+ // }
486
+ // callback && callback(buf);
487
+ // });
488
+ // tmp.end(inbuf);
489
+ // }
490
+ /**
491
+ * Creates new Zip data file with the passed ZipEntries
492
+ * @param cmpOptions - Compression options
493
+ * @param zipOptions - Create ZIP options
494
+ * @returns Promise<number> - The offset of the last entry
495
+ */
496
+ async createZipFileData(cmpOptions, zipOptions) {
497
+ const _onError = zipOptions?.onError || ((error) => { throw error; });
498
+ const _onEntryDone = zipOptions?.onEntryDone || (() => { });
499
+ const _onReadEntryData = zipOptions?.onReadEntryData ||
500
+ (() => { throw new Error('onReadEntryData callback is required'); });
501
+ const _onOutputBuffer = zipOptions?.onOutputBuffer || (() => { });
502
+ if (this.zipEntries.length === 0) {
503
+ _onError(new Error(Errors_1.default.NO_FILES));
504
+ return 0; // Return 0 instead of undefined
505
+ }
506
+ // console.log('Creating Zip File Data with ZipEntries: ', this.zipEntries);
507
+ let offset = 0;
508
+ let entryCnt = this.zipEntries.length;
509
+ for (let index = 0; index < entryCnt; index++) {
510
+ const entry = this.zipEntries[index];
511
+ // Remove any existing Timestamp Metadata entries
512
+ if (entry.filename === Headers_1.TIMESTAMP_METADATA || entry.filename === Headers_1.TIMESTAMP_SUBMITTED) {
513
+ this.zipEntries.splice(index, 1);
514
+ entryCnt--;
515
+ index--;
516
+ console.log('Deleting Timestamp Metadata entry: ', entry.filename);
517
+ continue;
518
+ }
519
+ if (!entry.isUpdated) {
520
+ console.log('Copying Entry: ', entry.filename);
521
+ const inData = this.copyEntry(entry);
522
+ entry.localHdrOffset = offset;
523
+ offset += inData.length;
524
+ _onOutputBuffer(inData);
525
+ _onEntryDone(entry, 'Copied ');
526
+ continue;
527
+ }
528
+ // Compress the file data to set all zipEntry fields correctly
529
+ const fileBuffer = _onReadEntryData(entry);
530
+ const cmpData = await this.compressData(entry, fileBuffer, cmpOptions);
531
+ // Create a local header data buffer
532
+ const localHdr = entry.createLocalHdr();
533
+ // Save local header offset for entry and calculate next offset
534
+ entry.localHdrOffset = offset;
535
+ offset += localHdr.length + cmpData.length;
536
+ // Write the data to the output file
537
+ _onOutputBuffer(localHdr);
538
+ _onOutputBuffer(cmpData);
539
+ _onEntryDone(entry, 'Written');
540
+ }
541
+ return offset;
542
+ }
543
+ /**
544
+ * Finishes Zip data file by adding any Metadata entries and the Central End Directory
545
+ * @param offset - The current offset in the zip data file
546
+ * @param onOutputBuffer - The callback function to output the data buffer
547
+ * @param metaEntry - The Metadata ZipEntry to add to the Zip file
548
+ */
549
+ async finishZipFileData(offset, onOutputBuffer, metaEntry) {
550
+ if (metaEntry && metaEntry.fileBuffer) {
551
+ const localHdr = metaEntry.createLocalHdr();
552
+ metaEntry.localHdrOffset = offset;
553
+ offset += localHdr.length + metaEntry.fileBuffer.length;
554
+ onOutputBuffer(localHdr);
555
+ onOutputBuffer(metaEntry.fileBuffer);
556
+ }
557
+ // Output ZipEntries as Central End Directory
558
+ const centralDirOffset = offset;
559
+ for (const entry of this.zipEntries) {
560
+ const centralDirEntry = entry.centralDirEntry();
561
+ offset += centralDirEntry.length;
562
+ onOutputBuffer(centralDirEntry);
563
+ }
564
+ const centralDirSize = offset - centralDirOffset;
565
+ const ceBuf = this.centralEndHdr(centralDirSize, centralDirOffset);
566
+ onOutputBuffer(ceBuf);
567
+ }
568
+ /**
569
+ * Unzips the data buffer using pako inflate method
570
+ * @param inbuf - Data buffer to inflate
571
+ * @returns Inflated data buffer
572
+ * @throws Error if extraction fails
573
+ */
574
+ inflate(inbuf) {
575
+ const result = pako_1.default.inflateRaw(inbuf);
576
+ return Buffer.from(result.buffer, result.byteOffset, result.byteLength);
577
+ }
578
+ /**
579
+ * Extracts the data from the ZipEntry and returns the data as a Buffer
580
+ * @param entry - ZIP entry to extract
581
+ * @param skipHashCheck - Whether to skip hash checking
582
+ * @returns Buffer containing extracted data or null if extraction fails
583
+ */
584
+ async extract(entry, skipHashCheck) {
585
+ const fdata = this.parseLocalHeader(entry);
586
+ if (fdata.length == 0) {
587
+ return null;
588
+ }
589
+ let outBuf = null;
590
+ switch (entry.cmpMethod) {
591
+ case Headers_1.CMP_METHOD.STORED:
592
+ outBuf = fdata;
593
+ break;
594
+ case Headers_1.CMP_METHOD.DEFLATED:
595
+ outBuf = this.inflate(fdata);
596
+ break;
597
+ case Headers_1.CMP_METHOD.ZSTD:
598
+ outBuf = await this.zstdDecompress(fdata);
599
+ break;
600
+ default:
601
+ throw new Error(Errors_1.default.UNKNOWN_METHOD);
602
+ }
603
+ // If no hash checking is requested, return the unmodified data
604
+ if (skipHashCheck) {
605
+ return outBuf;
606
+ }
607
+ // Verify integrity - use SHA256 if available, otherwise CRC32
608
+ if (entry.sha256) {
609
+ if (!this.testSHA256(entry, outBuf)) {
610
+ throw new Error(Errors_1.default.INVALID_SHA256);
611
+ }
612
+ }
613
+ else {
614
+ if (!this.testCRC32(entry, outBuf)) {
615
+ throw new Error(Errors_1.default.INVALID_CRC);
616
+ }
617
+ }
618
+ return outBuf;
619
+ }
620
+ /**
621
+ * Decrypts the entry data
622
+ * @param entry - ZIP entry to decrypt
623
+ * @param password - Password for decryption
624
+ * @returns Decrypted data buffer or null if decryption fails
625
+ */
626
+ decryptEntry(entry, password) {
627
+ if (!entry.isEncrypted)
628
+ return null;
629
+ if (entry.isStrongEncrypt)
630
+ throw new Error(Errors_1.default.STRONG_ENCRYPT_UNSUPPORTED);
631
+ if (!password)
632
+ return null;
633
+ // Read the encryption header at start of data
634
+ let _localData = this.parseLocalHeader(entry);
635
+ const _decrypt = (0, ZipCrypto_1.decrypter)(password);
636
+ const _encHdr = entry.encryptHdr;
637
+ if (!_encHdr)
638
+ return null;
639
+ const decryptedHeader = _decrypt(_encHdr);
640
+ const _check = (entry.bitFlags & Headers_1.GP_FLAG.DATA_DESC) ?
641
+ (entry.lastModTimeDate >> 8) & 0xff :
642
+ ((entry.crc >> 24) & 0xff);
643
+ if (decryptedHeader[11] !== _check)
644
+ return null;
645
+ _localData = _decrypt(_localData);
646
+ return _localData;
647
+ }
648
+ /**
649
+ * Checks if a filename is a blockchain metadata file that should be excluded from Merkle Root calculation
650
+ * @param filename - The filename to check
651
+ * @returns boolean - True if the file is a metadata file
652
+ */
653
+ isMetadataFile(filename) {
654
+ return filename === Headers_1.TIMESTAMP_SUBMITTED ||
655
+ filename === Headers_1.TIMESTAMP_METADATA ||
656
+ filename === Headers_1.TOKENIZED_METADATA;
657
+ }
658
+ /**
659
+ * Calculates the Merkle Root of the ZIP file
660
+ * Excludes blockchain metadata files (META-INF/*) to ensure consistent calculation
661
+ * @returns string - The Merkle Root of the ZIP file
662
+ */
663
+ getMerkleRoot() {
664
+ const zipEntries = this.getDirectory();
665
+ if (zipEntries.length === 0)
666
+ return null;
667
+ let _hashAccumulator = new HashAccumulator_1.default();
668
+ // Filter out blockchain metadata files to ensure consistent Merkle Root calculation
669
+ const contentEntries = zipEntries.filter(entry => !this.isMetadataFile(entry.filename));
670
+ for (const entry of contentEntries) {
671
+ if (entry.sha256) {
672
+ _hashAccumulator.addHash(entry.sha256);
673
+ }
674
+ }
675
+ const merkleRoot = _hashAccumulator.merkleRoot();
676
+ if (!merkleRoot)
677
+ return null;
678
+ return merkleRoot;
679
+ }
680
+ /**
681
+ * Checks if a ZIP file contains valid timestamp metadata
682
+ * @returns { merkleRoot: string | null, ots: Buffer | null }
683
+ * Returns the merkle root hash and timestamp metadata if found, null otherwise
684
+ */
685
+ checkForTimestamp() {
686
+ const zipEntries = this.getDirectory();
687
+ if (zipEntries.length === 0)
688
+ return null;
689
+ this.stampEntry = null;
690
+ let _hashAccumulator = new HashAccumulator_1.default();
691
+ for (const entry of zipEntries) {
692
+ if (entry.filename === Headers_1.TIMESTAMP_METADATA) {
693
+ this.stampEntry = entry;
694
+ }
695
+ else if (entry.filename === Headers_1.TIMESTAMP_SUBMITTED) {
696
+ if (this.stampEntry == null)
697
+ this.stampEntry = entry;
698
+ }
699
+ else if (!this.isMetadataFile(entry.filename) && entry.sha256) {
700
+ // Only include content files (non-metadata) in Merkle Root calculation
701
+ _hashAccumulator.addHash(entry.sha256);
702
+ }
703
+ }
704
+ if (!this.stampEntry)
705
+ return null;
706
+ const merkleRoot = _hashAccumulator.merkleRoot();
707
+ return merkleRoot;
708
+ }
709
+ /**
710
+ * Gets the OTS from the timestamp metadata entry
711
+ * @returns Promise<Buffer | null> - The OTS from the timestamp metadata entry or null if not found
712
+ */
713
+ async getOts() {
714
+ if (!this.stampEntry)
715
+ return null;
716
+ const ots = await this.extract(this.stampEntry);
717
+ return ots;
718
+ }
719
+ /**
720
+ * Creates a new timestamp metadata entry for the ZIP file
721
+ * Calculates merkle root from file hashes and obtains blockchain timestamp
722
+ * @returns Promise<ZipEntry | null> The created timestamp metadata entry or null if failed
723
+ */
724
+ createTimestampMetadataEntry(ots) {
725
+ if (!ots)
726
+ return null;
727
+ const tsEntry = this.createZipEntry(Headers_1.TIMESTAMP_SUBMITTED);
728
+ tsEntry.crc = (0, Util_1.crc32)(ots);
729
+ tsEntry.uncompressedSize = ots.length;
730
+ tsEntry.compressedSize = ots.length;
731
+ tsEntry.cmpMethod = Headers_1.CMP_METHOD.STORED;
732
+ tsEntry.fileBuffer = ots;
733
+ tsEntry.isMetaData = true;
734
+ return tsEntry;
735
+ }
736
+ /**
737
+ * Sets the ZIP file comment
738
+ * @param msg - Comment to set
739
+ */
740
+ setZipComment(msg) {
741
+ this.zipComment = msg;
742
+ }
743
+ /**
744
+ * Gets the ZIP file comment
745
+ * @returns string | null - The ZIP file comment
746
+ */
747
+ getZipComment() {
748
+ return this.zipComment;
749
+ }
750
+ /**
751
+ * Converts the compression method to a string
752
+ * @param cmpMethod - Compression method number
753
+ * @returns string - Compression method as a string
754
+ */
755
+ cmpMethodToString(cmpMethod) {
756
+ switch (cmpMethod) {
757
+ case 0: return 'Stored';
758
+ case 8: return 'Deflate';
759
+ case 93: return 'Zstd';
760
+ default: return 'Unknown';
761
+ }
762
+ }
763
+ /**
764
+ * Ensures ZIP entries are loaded
765
+ * @returns Array of ZIP entries
766
+ * @throws Error if no ZIP entries are loaded
767
+ */
768
+ ensureZipEntries() {
769
+ if (this.zipEntries.length === 0)
770
+ throw new Error('No ZIP entries loaded');
771
+ return this.zipEntries;
772
+ }
773
+ /**
774
+ * Ensures ZIP data buffer is loaded
775
+ * @returns Buffer containing ZIP data
776
+ * @throws Error if no ZIP data is loaded
777
+ */
778
+ ensureBuffer() {
779
+ if (!this.inBuffer) {
780
+ // Instead of throwing an error, return an empty buffer
781
+ this.inBuffer = Buffer.alloc(0);
782
+ }
783
+ return this.inBuffer;
784
+ }
785
+ }
786
+ ZipKit.version = types_1.NEOZIPKIT_INFO.version;
787
+ ZipKit.releaseDate = types_1.NEOZIPKIT_INFO.releaseDate;
788
+ ZipKit.support = Support_1.default;
789
+ exports.default = ZipKit;