@rowsncolumns/toolkit 24.4.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.
- package/LICENSE.md +100 -0
- package/Readme.md +27 -0
- package/dist/cjs/autofilter-condition.d.ts +43 -0
- package/dist/cjs/autofilter-condition.d.ts.map +1 -0
- package/dist/cjs/autofilter-condition.js +155 -0
- package/dist/cjs/csv-export.d.ts +49 -0
- package/dist/cjs/csv-export.d.ts.map +1 -0
- package/dist/cjs/csv-export.js +142 -0
- package/dist/cjs/csv-import-worker.d.ts +16 -0
- package/dist/cjs/csv-import-worker.d.ts.map +1 -0
- package/dist/cjs/csv-import-worker.js +60 -0
- package/dist/cjs/csv-import.d.ts +38 -0
- package/dist/cjs/csv-import.d.ts.map +1 -0
- package/dist/cjs/csv-import.js +166 -0
- package/dist/cjs/csv-parser/helpers.d.ts +14 -0
- package/dist/cjs/csv-parser/helpers.d.ts.map +1 -0
- package/dist/cjs/csv-parser/helpers.js +145 -0
- package/dist/cjs/csv-parser/types.d.ts +66 -0
- package/dist/cjs/csv-parser/types.d.ts.map +1 -0
- package/dist/cjs/csv-parser/types.js +14 -0
- package/dist/cjs/csv-parser/worker.d.ts +2 -0
- package/dist/cjs/csv-parser/worker.d.ts.map +1 -0
- package/dist/cjs/csv-parser/worker.js +200 -0
- package/dist/cjs/excel-export.d.ts +11 -0
- package/dist/cjs/excel-export.d.ts.map +1 -0
- package/dist/cjs/excel-export.js +22 -0
- package/dist/cjs/excel-import-session.d.ts +51 -0
- package/dist/cjs/excel-import-session.d.ts.map +1 -0
- package/dist/cjs/excel-import-session.js +307 -0
- package/dist/cjs/excel-import-worker.d.ts +7 -0
- package/dist/cjs/excel-import-worker.d.ts.map +1 -0
- package/dist/cjs/excel-import-worker.js +119 -0
- package/dist/cjs/excel-parser/builtin-numfmts.d.ts +24 -0
- package/dist/cjs/excel-parser/builtin-numfmts.d.ts.map +1 -0
- package/dist/cjs/excel-parser/builtin-numfmts.js +63 -0
- package/dist/cjs/excel-parser/cfb-decryptor.d.ts +53 -0
- package/dist/cjs/excel-parser/cfb-decryptor.d.ts.map +1 -0
- package/dist/cjs/excel-parser/cfb-decryptor.js +553 -0
- package/dist/cjs/excel-parser/cfb-encryptor.d.ts +23 -0
- package/dist/cjs/excel-parser/cfb-encryptor.d.ts.map +1 -0
- package/dist/cjs/excel-parser/cfb-encryptor.js +200 -0
- package/dist/cjs/excel-parser/dv-cell-stamp.d.ts +29 -0
- package/dist/cjs/excel-parser/dv-cell-stamp.d.ts.map +1 -0
- package/dist/cjs/excel-parser/dv-cell-stamp.js +239 -0
- package/dist/cjs/excel-parser/helpers.d.ts +28 -0
- package/dist/cjs/excel-parser/helpers.d.ts.map +1 -0
- package/dist/cjs/excel-parser/helpers.js +188 -0
- package/dist/cjs/excel-parser/interface.d.ts +179 -0
- package/dist/cjs/excel-parser/interface.d.ts.map +1 -0
- package/dist/cjs/excel-parser/interface.js +1 -0
- package/dist/cjs/excel-parser/plugins/base/index.d.ts +31 -0
- package/dist/cjs/excel-parser/plugins/base/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/base/index.js +101 -0
- package/dist/cjs/excel-parser/plugins/ods/conditional-formatting.d.ts +16 -0
- package/dist/cjs/excel-parser/plugins/ods/conditional-formatting.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/conditional-formatting.js +488 -0
- package/dist/cjs/excel-parser/plugins/ods/data-validations.d.ts +15 -0
- package/dist/cjs/excel-parser/plugins/ods/data-validations.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/data-validations.js +353 -0
- package/dist/cjs/excel-parser/plugins/ods/formula.d.ts +8 -0
- package/dist/cjs/excel-parser/plugins/ods/formula.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/formula.js +82 -0
- package/dist/cjs/excel-parser/plugins/ods/index.d.ts +122 -0
- package/dist/cjs/excel-parser/plugins/ods/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/index.js +3642 -0
- package/dist/cjs/excel-parser/plugins/ods/sparklines.d.ts +25 -0
- package/dist/cjs/excel-parser/plugins/ods/sparklines.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/sparklines.js +221 -0
- package/dist/cjs/excel-parser/plugins/ods/styles.d.ts +60 -0
- package/dist/cjs/excel-parser/plugins/ods/styles.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/styles.js +808 -0
- package/dist/cjs/excel-parser/plugins/ods/types.d.ts +7 -0
- package/dist/cjs/excel-parser/plugins/ods/types.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/types.js +1 -0
- package/dist/cjs/excel-parser/plugins/xls/index.d.ts +5 -0
- package/dist/cjs/excel-parser/plugins/xls/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xls/index.js +19 -0
- package/dist/cjs/excel-parser/plugins/xlsb/biff-record-reader.d.ts +13 -0
- package/dist/cjs/excel-parser/plugins/xlsb/biff-record-reader.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsb/biff-record-reader.js +49 -0
- package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts +117 -0
- package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsb/index.js +2972 -0
- package/dist/cjs/excel-parser/plugins/xlsb/rgce-parser.d.ts +18 -0
- package/dist/cjs/excel-parser/plugins/xlsb/rgce-parser.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsb/rgce-parser.js +527 -0
- package/dist/cjs/excel-parser/plugins/xlsm/index.d.ts +5 -0
- package/dist/cjs/excel-parser/plugins/xlsm/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsm/index.js +10 -0
- package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts +60 -0
- package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/charts.js +2178 -0
- package/dist/cjs/excel-parser/plugins/xlsx/conditional-formatting.d.ts +18 -0
- package/dist/cjs/excel-parser/plugins/xlsx/conditional-formatting.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/conditional-formatting.js +620 -0
- package/dist/cjs/excel-parser/plugins/xlsx/data-validations.d.ts +4 -0
- package/dist/cjs/excel-parser/plugins/xlsx/data-validations.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/data-validations.js +515 -0
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts +39 -0
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.js +941 -0
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts +320 -0
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/index.js +6056 -0
- package/dist/cjs/excel-parser/plugins/xlsx/numfmt.d.ts +2 -0
- package/dist/cjs/excel-parser/plugins/xlsx/numfmt.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/numfmt.js +3 -0
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.d.ts +40 -0
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.js +342 -0
- package/dist/cjs/excel-parser/plugins/xlsx/relationships.d.ts +8 -0
- package/dist/cjs/excel-parser/plugins/xlsx/relationships.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/relationships.js +26 -0
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.d.ts +26 -0
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.js +59 -0
- package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts +44 -0
- package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/styles.js +1377 -0
- package/dist/cjs/excel-parser/plugins/xlsx/theme.d.ts +50 -0
- package/dist/cjs/excel-parser/plugins/xlsx/theme.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/theme.js +150 -0
- package/dist/cjs/excel-parser/plugins/xlsx/threaded-comments.d.ts +47 -0
- package/dist/cjs/excel-parser/plugins/xlsx/threaded-comments.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/threaded-comments.js +141 -0
- package/dist/cjs/excel-parser/plugins/xlsx/value-type-detection.d.ts +44 -0
- package/dist/cjs/excel-parser/plugins/xlsx/value-type-detection.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/value-type-detection.js +407 -0
- package/dist/cjs/excel-parser/registry.d.ts +5 -0
- package/dist/cjs/excel-parser/registry.d.ts.map +1 -0
- package/dist/cjs/excel-parser/registry.js +21 -0
- package/dist/cjs/excel-parser/style-registry.d.ts +51 -0
- package/dist/cjs/excel-parser/style-registry.d.ts.map +1 -0
- package/dist/cjs/excel-parser/style-registry.js +175 -0
- package/dist/cjs/excel-parser/theme-default.d.ts +3 -0
- package/dist/cjs/excel-parser/theme-default.d.ts.map +1 -0
- package/dist/cjs/excel-parser/theme-default.js +19 -0
- package/dist/cjs/excel-parser/types.d.ts +365 -0
- package/dist/cjs/excel-parser/types.d.ts.map +1 -0
- package/dist/cjs/excel-parser/types.js +59 -0
- package/dist/cjs/excel-parser/utils.d.ts +6 -0
- package/dist/cjs/excel-parser/utils.d.ts.map +1 -0
- package/dist/cjs/excel-parser/utils.js +30 -0
- package/dist/cjs/excel-parser/workbook.d.ts +51 -0
- package/dist/cjs/excel-parser/workbook.d.ts.map +1 -0
- package/dist/cjs/excel-parser/workbook.js +317 -0
- package/dist/cjs/excel-parser/worker.d.ts +2 -0
- package/dist/cjs/excel-parser/worker.d.ts.map +1 -0
- package/dist/cjs/excel-parser/worker.js +1149 -0
- package/dist/cjs/excel-parser/zip-parser-streaming.d.ts +13 -0
- package/dist/cjs/excel-parser/zip-parser-streaming.d.ts.map +1 -0
- package/dist/cjs/excel-parser/zip-parser-streaming.js +200 -0
- package/dist/cjs/excel-parser/zip-parser.d.ts +11 -0
- package/dist/cjs/excel-parser/zip-parser.d.ts.map +1 -0
- package/dist/cjs/excel-parser/zip-parser.js +49 -0
- package/dist/cjs/exporter/invalid-data-validation.d.ts +19 -0
- package/dist/cjs/exporter/invalid-data-validation.d.ts.map +1 -0
- package/dist/cjs/exporter/invalid-data-validation.js +39 -0
- package/dist/cjs/exporter/ods/ods-export.d.ts +26 -0
- package/dist/cjs/exporter/ods/ods-export.d.ts.map +1 -0
- package/dist/cjs/exporter/ods/ods-export.js +3714 -0
- package/dist/cjs/exporter/ods/sparkline-builder.d.ts +33 -0
- package/dist/cjs/exporter/ods/sparkline-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/ods/sparkline-builder.js +221 -0
- package/dist/cjs/exporter/xlsx/chart-builder.d.ts +3 -0
- package/dist/cjs/exporter/xlsx/chart-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/chart-builder.js +1901 -0
- package/dist/cjs/exporter/xlsx/chart-templates.d.ts +1781 -0
- package/dist/cjs/exporter/xlsx/chart-templates.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/chart-templates.js +1798 -0
- package/dist/cjs/exporter/xlsx/future-functions.d.ts +10 -0
- package/dist/cjs/exporter/xlsx/future-functions.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/future-functions.js +264 -0
- package/dist/cjs/exporter/xlsx/pivot-builder.d.ts +58 -0
- package/dist/cjs/exporter/xlsx/pivot-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/pivot-builder.js +277 -0
- package/dist/cjs/exporter/xlsx/power-query-builder.d.ts +26 -0
- package/dist/cjs/exporter/xlsx/power-query-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/power-query-builder.js +306 -0
- package/dist/cjs/exporter/xlsx/slicer-builder.d.ts +11 -0
- package/dist/cjs/exporter/xlsx/slicer-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/slicer-builder.js +87 -0
- package/dist/cjs/exporter/xlsx/sparkline-builder.d.ts +61 -0
- package/dist/cjs/exporter/xlsx/sparkline-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/sparkline-builder.js +489 -0
- package/dist/cjs/exporter/xlsx/style-builder.d.ts +93 -0
- package/dist/cjs/exporter/xlsx/style-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/style-builder.js +813 -0
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.d.ts +58 -0
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.js +189 -0
- package/dist/cjs/exporter/xlsx/xlsx-export.d.ts +121 -0
- package/dist/cjs/exporter/xlsx/xlsx-export.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/xlsx-export.js +4596 -0
- package/dist/cjs/helpers/theme-xml-generator.d.ts +8 -0
- package/dist/cjs/helpers/theme-xml-generator.d.ts.map +1 -0
- package/dist/cjs/helpers/theme-xml-generator.js +33 -0
- package/dist/cjs/helpers.d.ts +34 -0
- package/dist/cjs/helpers.d.ts.map +1 -0
- package/dist/cjs/helpers.js +189 -0
- package/dist/cjs/index.d.ts +16 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +15 -0
- package/dist/cjs/indexed-colors.d.ts +2 -0
- package/dist/cjs/indexed-colors.d.ts.map +1 -0
- package/dist/cjs/indexed-colors.js +75 -0
- package/dist/cjs/ods-export.d.ts +24 -0
- package/dist/cjs/ods-export.d.ts.map +1 -0
- package/dist/cjs/ods-export.js +23 -0
- package/dist/cjs/parse.d.ts +24 -0
- package/dist/cjs/parse.d.ts.map +1 -0
- package/dist/cjs/parse.js +68 -0
- package/dist/cjs/power-query.d.ts +41 -0
- package/dist/cjs/power-query.d.ts.map +1 -0
- package/dist/cjs/power-query.js +22 -0
- package/dist/cjs/server.d.ts +9 -0
- package/dist/cjs/server.d.ts.map +1 -0
- package/dist/cjs/server.js +8 -0
- package/dist/cjs/theme1.d.ts +3 -0
- package/dist/cjs/theme1.d.ts.map +1 -0
- package/dist/cjs/theme1.js +2 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/cjs/types.d.ts +14 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +14 -0
- package/dist/cjs/vitest.config.d.ts +3 -0
- package/dist/cjs/vitest.config.d.ts.map +1 -0
- package/dist/cjs/vitest.config.js +16 -0
- package/dist/esm/autofilter-condition.d.ts +43 -0
- package/dist/esm/autofilter-condition.d.ts.map +1 -0
- package/dist/esm/autofilter-condition.js +145 -0
- package/dist/esm/csv-export.d.ts +49 -0
- package/dist/esm/csv-export.d.ts.map +1 -0
- package/dist/esm/csv-export.js +126 -0
- package/dist/esm/csv-import-worker.d.ts +16 -0
- package/dist/esm/csv-import-worker.d.ts.map +1 -0
- package/dist/esm/csv-import-worker.js +60 -0
- package/dist/esm/csv-import.d.ts +38 -0
- package/dist/esm/csv-import.d.ts.map +1 -0
- package/dist/esm/csv-import.js +132 -0
- package/dist/esm/csv-parser/helpers.d.ts +14 -0
- package/dist/esm/csv-parser/helpers.d.ts.map +1 -0
- package/dist/esm/csv-parser/helpers.js +0 -0
- package/dist/esm/csv-parser/types.d.ts +66 -0
- package/dist/esm/csv-parser/types.d.ts.map +1 -0
- package/dist/esm/csv-parser/types.js +14 -0
- package/dist/esm/csv-parser/worker.d.ts +2 -0
- package/dist/esm/csv-parser/worker.d.ts.map +1 -0
- package/dist/esm/csv-parser/worker.js +154 -0
- package/dist/esm/excel-export.d.ts +11 -0
- package/dist/esm/excel-export.d.ts.map +1 -0
- package/dist/esm/excel-export.js +13 -0
- package/dist/esm/excel-import-session.d.ts +51 -0
- package/dist/esm/excel-import-session.d.ts.map +1 -0
- package/dist/esm/excel-import-session.js +255 -0
- package/dist/esm/excel-import-worker.d.ts +7 -0
- package/dist/esm/excel-import-worker.d.ts.map +1 -0
- package/dist/esm/excel-import-worker.js +116 -0
- package/dist/esm/excel-parser/builtin-numfmts.d.ts +24 -0
- package/dist/esm/excel-parser/builtin-numfmts.d.ts.map +1 -0
- package/dist/esm/excel-parser/builtin-numfmts.js +59 -0
- package/dist/esm/excel-parser/cfb-decryptor.d.ts +53 -0
- package/dist/esm/excel-parser/cfb-decryptor.d.ts.map +1 -0
- package/dist/esm/excel-parser/cfb-decryptor.js +493 -0
- package/dist/esm/excel-parser/cfb-encryptor.d.ts +23 -0
- package/dist/esm/excel-parser/cfb-encryptor.d.ts.map +1 -0
- package/dist/esm/excel-parser/cfb-encryptor.js +181 -0
- package/dist/esm/excel-parser/dv-cell-stamp.d.ts +29 -0
- package/dist/esm/excel-parser/dv-cell-stamp.d.ts.map +1 -0
- package/dist/esm/excel-parser/dv-cell-stamp.js +155 -0
- package/dist/esm/excel-parser/helpers.d.ts +28 -0
- package/dist/esm/excel-parser/helpers.d.ts.map +1 -0
- package/dist/esm/excel-parser/helpers.js +160 -0
- package/dist/esm/excel-parser/interface.d.ts +179 -0
- package/dist/esm/excel-parser/interface.d.ts.map +1 -0
- package/dist/esm/excel-parser/interface.js +1 -0
- package/dist/esm/excel-parser/plugins/base/index.d.ts +31 -0
- package/dist/esm/excel-parser/plugins/base/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/base/index.js +64 -0
- package/dist/esm/excel-parser/plugins/ods/conditional-formatting.d.ts +16 -0
- package/dist/esm/excel-parser/plugins/ods/conditional-formatting.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/conditional-formatting.js +405 -0
- package/dist/esm/excel-parser/plugins/ods/data-validations.d.ts +15 -0
- package/dist/esm/excel-parser/plugins/ods/data-validations.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/data-validations.js +331 -0
- package/dist/esm/excel-parser/plugins/ods/formula.d.ts +8 -0
- package/dist/esm/excel-parser/plugins/ods/formula.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/formula.js +82 -0
- package/dist/esm/excel-parser/plugins/ods/index.d.ts +122 -0
- package/dist/esm/excel-parser/plugins/ods/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/index.js +2896 -0
- package/dist/esm/excel-parser/plugins/ods/sparklines.d.ts +25 -0
- package/dist/esm/excel-parser/plugins/ods/sparklines.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/sparklines.js +188 -0
- package/dist/esm/excel-parser/plugins/ods/styles.d.ts +60 -0
- package/dist/esm/excel-parser/plugins/ods/styles.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/styles.js +732 -0
- package/dist/esm/excel-parser/plugins/ods/types.d.ts +7 -0
- package/dist/esm/excel-parser/plugins/ods/types.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/types.js +1 -0
- package/dist/esm/excel-parser/plugins/xls/index.d.ts +5 -0
- package/dist/esm/excel-parser/plugins/xls/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xls/index.js +7 -0
- package/dist/esm/excel-parser/plugins/xlsb/biff-record-reader.d.ts +13 -0
- package/dist/esm/excel-parser/plugins/xlsb/biff-record-reader.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsb/biff-record-reader.js +48 -0
- package/dist/esm/excel-parser/plugins/xlsb/index.d.ts +117 -0
- package/dist/esm/excel-parser/plugins/xlsb/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsb/index.js +2339 -0
- package/dist/esm/excel-parser/plugins/xlsb/rgce-parser.d.ts +18 -0
- package/dist/esm/excel-parser/plugins/xlsb/rgce-parser.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsb/rgce-parser.js +522 -0
- package/dist/esm/excel-parser/plugins/xlsm/index.d.ts +5 -0
- package/dist/esm/excel-parser/plugins/xlsm/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsm/index.js +6 -0
- package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts +60 -0
- package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/charts.js +2036 -0
- package/dist/esm/excel-parser/plugins/xlsx/conditional-formatting.d.ts +18 -0
- package/dist/esm/excel-parser/plugins/xlsx/conditional-formatting.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/conditional-formatting.js +621 -0
- package/dist/esm/excel-parser/plugins/xlsx/data-validations.d.ts +4 -0
- package/dist/esm/excel-parser/plugins/xlsx/data-validations.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/data-validations.js +493 -0
- package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts +39 -0
- package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/drawing.js +905 -0
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts +320 -0
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/index.js +4654 -0
- package/dist/esm/excel-parser/plugins/xlsx/numfmt.d.ts +2 -0
- package/dist/esm/excel-parser/plugins/xlsx/numfmt.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/numfmt.js +3 -0
- package/dist/esm/excel-parser/plugins/xlsx/pivots.d.ts +40 -0
- package/dist/esm/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/pivots.js +254 -0
- package/dist/esm/excel-parser/plugins/xlsx/relationships.d.ts +8 -0
- package/dist/esm/excel-parser/plugins/xlsx/relationships.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/relationships.js +13 -0
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.d.ts +26 -0
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.js +64 -0
- package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts +44 -0
- package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/styles.js +1365 -0
- package/dist/esm/excel-parser/plugins/xlsx/theme.d.ts +50 -0
- package/dist/esm/excel-parser/plugins/xlsx/theme.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/theme.js +127 -0
- package/dist/esm/excel-parser/plugins/xlsx/threaded-comments.d.ts +47 -0
- package/dist/esm/excel-parser/plugins/xlsx/threaded-comments.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/threaded-comments.js +103 -0
- package/dist/esm/excel-parser/plugins/xlsx/value-type-detection.d.ts +44 -0
- package/dist/esm/excel-parser/plugins/xlsx/value-type-detection.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/value-type-detection.js +399 -0
- package/dist/esm/excel-parser/registry.d.ts +5 -0
- package/dist/esm/excel-parser/registry.d.ts.map +1 -0
- package/dist/esm/excel-parser/registry.js +20 -0
- package/dist/esm/excel-parser/style-registry.d.ts +51 -0
- package/dist/esm/excel-parser/style-registry.d.ts.map +1 -0
- package/dist/esm/excel-parser/style-registry.js +163 -0
- package/dist/esm/excel-parser/theme-default.d.ts +3 -0
- package/dist/esm/excel-parser/theme-default.d.ts.map +1 -0
- package/dist/esm/excel-parser/theme-default.js +19 -0
- package/dist/esm/excel-parser/types.d.ts +365 -0
- package/dist/esm/excel-parser/types.d.ts.map +1 -0
- package/dist/esm/excel-parser/types.js +59 -0
- package/dist/esm/excel-parser/utils.d.ts +6 -0
- package/dist/esm/excel-parser/utils.d.ts.map +1 -0
- package/dist/esm/excel-parser/utils.js +25 -0
- package/dist/esm/excel-parser/workbook.d.ts +51 -0
- package/dist/esm/excel-parser/workbook.d.ts.map +1 -0
- package/dist/esm/excel-parser/workbook.js +192 -0
- package/dist/esm/excel-parser/worker.d.ts +2 -0
- package/dist/esm/excel-parser/worker.d.ts.map +1 -0
- package/dist/esm/excel-parser/worker.js +862 -0
- package/dist/esm/excel-parser/zip-parser-streaming.d.ts +13 -0
- package/dist/esm/excel-parser/zip-parser-streaming.d.ts.map +1 -0
- package/dist/esm/excel-parser/zip-parser-streaming.js +119 -0
- package/dist/esm/excel-parser/zip-parser.d.ts +11 -0
- package/dist/esm/excel-parser/zip-parser.d.ts.map +1 -0
- package/dist/esm/excel-parser/zip-parser.js +43 -0
- package/dist/esm/exporter/invalid-data-validation.d.ts +19 -0
- package/dist/esm/exporter/invalid-data-validation.d.ts.map +1 -0
- package/dist/esm/exporter/invalid-data-validation.js +37 -0
- package/dist/esm/exporter/ods/ods-export.d.ts +26 -0
- package/dist/esm/exporter/ods/ods-export.d.ts.map +1 -0
- package/dist/esm/exporter/ods/ods-export.js +3238 -0
- package/dist/esm/exporter/ods/sparkline-builder.d.ts +33 -0
- package/dist/esm/exporter/ods/sparkline-builder.d.ts.map +1 -0
- package/dist/esm/exporter/ods/sparkline-builder.js +165 -0
- package/dist/esm/exporter/xlsx/chart-builder.d.ts +3 -0
- package/dist/esm/exporter/xlsx/chart-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/chart-builder.js +1805 -0
- package/dist/esm/exporter/xlsx/chart-templates.d.ts +1781 -0
- package/dist/esm/exporter/xlsx/chart-templates.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/chart-templates.js +1798 -0
- package/dist/esm/exporter/xlsx/future-functions.d.ts +10 -0
- package/dist/esm/exporter/xlsx/future-functions.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/future-functions.js +264 -0
- package/dist/esm/exporter/xlsx/pivot-builder.d.ts +58 -0
- package/dist/esm/exporter/xlsx/pivot-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/pivot-builder.js +230 -0
- package/dist/esm/exporter/xlsx/power-query-builder.d.ts +26 -0
- package/dist/esm/exporter/xlsx/power-query-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/power-query-builder.js +257 -0
- package/dist/esm/exporter/xlsx/slicer-builder.d.ts +11 -0
- package/dist/esm/exporter/xlsx/slicer-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/slicer-builder.js +84 -0
- package/dist/esm/exporter/xlsx/sparkline-builder.d.ts +61 -0
- package/dist/esm/exporter/xlsx/sparkline-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/sparkline-builder.js +437 -0
- package/dist/esm/exporter/xlsx/style-builder.d.ts +93 -0
- package/dist/esm/exporter/xlsx/style-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/style-builder.js +795 -0
- package/dist/esm/exporter/xlsx/threaded-comments-builder.d.ts +58 -0
- package/dist/esm/exporter/xlsx/threaded-comments-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/threaded-comments-builder.js +175 -0
- package/dist/esm/exporter/xlsx/xlsx-export.d.ts +121 -0
- package/dist/esm/exporter/xlsx/xlsx-export.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/xlsx-export.js +4062 -0
- package/dist/esm/helpers/theme-xml-generator.d.ts +8 -0
- package/dist/esm/helpers/theme-xml-generator.d.ts.map +1 -0
- package/dist/esm/helpers/theme-xml-generator.js +33 -0
- package/dist/esm/helpers.d.ts +34 -0
- package/dist/esm/helpers.d.ts.map +1 -0
- package/dist/esm/helpers.js +182 -0
- package/dist/esm/index.d.ts +16 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/indexed-colors.d.ts +2 -0
- package/dist/esm/indexed-colors.d.ts.map +1 -0
- package/dist/esm/indexed-colors.js +75 -0
- package/dist/esm/ods-export.d.ts +24 -0
- package/dist/esm/ods-export.d.ts.map +1 -0
- package/dist/esm/ods-export.js +12 -0
- package/dist/esm/parse.d.ts +24 -0
- package/dist/esm/parse.d.ts.map +1 -0
- package/dist/esm/parse.js +55 -0
- package/dist/esm/power-query.d.ts +41 -0
- package/dist/esm/power-query.d.ts.map +1 -0
- package/dist/esm/power-query.js +19 -0
- package/dist/esm/server.d.ts +9 -0
- package/dist/esm/server.d.ts.map +1 -0
- package/dist/esm/server.js +8 -0
- package/dist/esm/theme1.d.ts +3 -0
- package/dist/esm/theme1.d.ts.map +1 -0
- package/dist/esm/theme1.js +2 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/esm/types.d.ts +14 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +14 -0
- package/dist/esm/vitest.config.d.ts +3 -0
- package/dist/esm/vitest.config.d.ts.map +1 -0
- package/dist/esm/vitest.config.js +16 -0
- package/package.json +62 -0
- package/xlsx.d.ts +52 -0
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
/// <reference path="../xlsx.d.ts" />
|
|
2
|
+
import { CFB } from "xlsx/xlsx.mjs";
|
|
3
|
+
import { sha1 } from "@noble/hashes/sha1";
|
|
4
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
5
|
+
import { sha384, sha512 } from "@noble/hashes/sha512";
|
|
6
|
+
import { cbc, ecb } from "@noble/ciphers/aes";
|
|
7
|
+
const BLOCK_KEY_VERIFIER_INPUT = new Uint8Array([
|
|
8
|
+
0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79,
|
|
9
|
+
]);
|
|
10
|
+
const BLOCK_KEY_VERIFIER_HASH = new Uint8Array([
|
|
11
|
+
0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e,
|
|
12
|
+
]);
|
|
13
|
+
const BLOCK_KEY_ENCRYPTION_KEY = new Uint8Array([
|
|
14
|
+
0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6,
|
|
15
|
+
]);
|
|
16
|
+
export const LEGACY_XLS_UNSUPPORTED_MESSAGE = "This file is a legacy Excel 97-2003 (.xls) workbook, which is not supported. Please open it in Excel and save it as .xlsx, then try again.";
|
|
17
|
+
/**
|
|
18
|
+
* Inspects a CFB container's directory to decide whether it is an
|
|
19
|
+
* Office-encrypted OOXML package (`EncryptionInfo` stream present) or an
|
|
20
|
+
* unencrypted legacy BIFF `.xls` workbook (`Workbook`/`Book` stream present
|
|
21
|
+
* without `EncryptionInfo`). Returns "unknown" for anything else, including
|
|
22
|
+
* containers that fail to parse — callers should fall back to their existing
|
|
23
|
+
* behavior in that case.
|
|
24
|
+
*/
|
|
25
|
+
export const detectCfbContainerKind = async (source) => {
|
|
26
|
+
try {
|
|
27
|
+
const buffer = source instanceof File ? await source.arrayBuffer() : source;
|
|
28
|
+
const cfb = CFB.read(new Uint8Array(buffer), { type: "array" });
|
|
29
|
+
const streamNames = new Set(cfb.FileIndex.map((entry) => entry.name));
|
|
30
|
+
if (streamNames.has("EncryptionInfo")) {
|
|
31
|
+
return "encrypted-ooxml";
|
|
32
|
+
}
|
|
33
|
+
if (streamNames.has("Workbook") || streamNames.has("Book")) {
|
|
34
|
+
return "legacy-xls";
|
|
35
|
+
}
|
|
36
|
+
return "unknown";
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return "unknown";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
export class CFBDecryptor {
|
|
43
|
+
/**
|
|
44
|
+
* Decrypts a CFB-encrypted XLSX file
|
|
45
|
+
* @param source The encrypted file or array buffer
|
|
46
|
+
* @param password The password to decrypt with
|
|
47
|
+
* @returns The decrypted XLSX data as ArrayBuffer
|
|
48
|
+
*/
|
|
49
|
+
static async decrypt(source, password) {
|
|
50
|
+
// Read CFB structure
|
|
51
|
+
const buffer = source instanceof File ? await source.arrayBuffer() : source;
|
|
52
|
+
const uint8Array = new Uint8Array(buffer);
|
|
53
|
+
const cfb = CFB.read(uint8Array, { type: "array" });
|
|
54
|
+
// Dispatch on the EncryptionInfo version (MS-OFFCRYPTO): agile (4.4), standard AES (x.2 + fAES),
|
|
55
|
+
// or RC4 CryptoAPI (x.2 + fCryptoAPI). Extensible (x.3) and legacy schemes are unsupported.
|
|
56
|
+
const infoContent = this.getEncryptionInfoContent(cfb);
|
|
57
|
+
if (!infoContent) {
|
|
58
|
+
throw new Error("Could not parse encryption information");
|
|
59
|
+
}
|
|
60
|
+
const view = new DataView(infoContent.buffer, infoContent.byteOffset, infoContent.byteLength);
|
|
61
|
+
const versionMajor = view.getUint16(0, true);
|
|
62
|
+
const versionMinor = view.getUint16(2, true);
|
|
63
|
+
if (versionMajor === 4 && versionMinor === 4) {
|
|
64
|
+
return this.decryptAgile(cfb, password);
|
|
65
|
+
}
|
|
66
|
+
if (versionMinor === 2 && versionMajor >= 2 && versionMajor <= 4) {
|
|
67
|
+
return this.decryptStandardFamily(cfb, infoContent, password);
|
|
68
|
+
}
|
|
69
|
+
const detail = versionMinor === 3 ? " (extensible encryption)" : "";
|
|
70
|
+
throw new Error(`Unsupported workbook encryption version ${versionMajor}.${versionMinor}${detail}. ` +
|
|
71
|
+
`Supported: agile (4.4), standard AES (x.2), RC4 CryptoAPI.`);
|
|
72
|
+
}
|
|
73
|
+
static decryptAgile(cfb, password) {
|
|
74
|
+
const encryptionInfo = this.parseEncryptionInfo(cfb);
|
|
75
|
+
if (!encryptionInfo) {
|
|
76
|
+
throw new Error("Could not parse encryption information");
|
|
77
|
+
}
|
|
78
|
+
// Derive key from password
|
|
79
|
+
const passwordDerivedKey = this.deriveKey(password, encryptionInfo);
|
|
80
|
+
// Verify password by decrypting verifier
|
|
81
|
+
const isValid = this.verifyPassword(passwordDerivedKey, encryptionInfo);
|
|
82
|
+
if (!isValid) {
|
|
83
|
+
throw new Error("Incorrect password");
|
|
84
|
+
}
|
|
85
|
+
// Decrypt the encrypted key value to get the actual encryption key
|
|
86
|
+
const encryptionKey = this.decryptEncryptedKey(passwordDerivedKey, encryptionInfo);
|
|
87
|
+
// Decrypt the package using the decrypted encryption key
|
|
88
|
+
const encryptedPackage = this.getEncryptedPackage(cfb);
|
|
89
|
+
return this.decryptPackage(encryptedPackage, encryptionKey, encryptionInfo);
|
|
90
|
+
}
|
|
91
|
+
static getEncryptionInfoContent(cfb) {
|
|
92
|
+
const entry = cfb.FileIndex.find((e) => e.name === "EncryptionInfo");
|
|
93
|
+
if (!entry || !entry.content) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const contentArray = entry.content;
|
|
97
|
+
return contentArray instanceof Uint8Array
|
|
98
|
+
? contentArray
|
|
99
|
+
: new Uint8Array(contentArray);
|
|
100
|
+
}
|
|
101
|
+
// ── Standard (MS-OFFCRYPTO §2.3.4.5-9) & RC4 CryptoAPI (§2.3.5) ──────────────────
|
|
102
|
+
static decryptStandardFamily(cfb, infoContent, password) {
|
|
103
|
+
// `body` begins at the EncryptionHeaderFlags dword (after the 4-byte version).
|
|
104
|
+
const body = infoContent.subarray(4);
|
|
105
|
+
const dv = new DataView(body.buffer, body.byteOffset, body.byteLength);
|
|
106
|
+
const headerSize = dv.getUint32(4, true);
|
|
107
|
+
const header = body.subarray(8, 8 + headerSize);
|
|
108
|
+
const hdv = new DataView(header.buffer, header.byteOffset, header.byteLength);
|
|
109
|
+
const algId = hdv.getUint32(8, true);
|
|
110
|
+
const keySizeBits = hdv.getUint32(16, true);
|
|
111
|
+
const verifier = body.subarray(8 + headerSize);
|
|
112
|
+
const salt = verifier.subarray(4, 20);
|
|
113
|
+
const encryptedVerifier = verifier.subarray(20, 36);
|
|
114
|
+
// AES uses a 32-byte encrypted verifier hash (SHA1 padded to two blocks); RC4 uses 20.
|
|
115
|
+
const isAes = (algId & 0xff00) === 0x6600;
|
|
116
|
+
const isRc4 = algId === 0x6801 || algId === 0;
|
|
117
|
+
if (!isAes && !isRc4) {
|
|
118
|
+
throw new Error(`Unsupported workbook encryption cipher (algId 0x${algId.toString(16)}).`);
|
|
119
|
+
}
|
|
120
|
+
const vhashLen = isAes ? 32 : 20;
|
|
121
|
+
const encryptedVerifierHash = verifier.subarray(40, 40 + vhashLen);
|
|
122
|
+
const encryptedPackage = this.getEncryptedPackage(cfb);
|
|
123
|
+
if (isAes) {
|
|
124
|
+
const keyBytes = keySizeBits !== 0
|
|
125
|
+
? keySizeBits / 8
|
|
126
|
+
: algId === 0x660e
|
|
127
|
+
? 16
|
|
128
|
+
: algId === 0x660f
|
|
129
|
+
? 24
|
|
130
|
+
: 32;
|
|
131
|
+
const key = this.standardKey(password, salt, keyBytes);
|
|
132
|
+
const verifierPlain = this.aesEcbDecrypt(encryptedVerifier, key);
|
|
133
|
+
const expected = this.hash(verifierPlain, "SHA1");
|
|
134
|
+
const stored = this.aesEcbDecrypt(encryptedVerifierHash, key);
|
|
135
|
+
if (!this.bytesEqual(expected, stored.subarray(0, expected.length))) {
|
|
136
|
+
throw new Error("Incorrect password");
|
|
137
|
+
}
|
|
138
|
+
return this.decryptStandardPackage(encryptedPackage, key);
|
|
139
|
+
}
|
|
140
|
+
// RC4 CryptoAPI: 40-bit keys are 5 significant bytes zero-padded to 16.
|
|
141
|
+
const keyBytes = keySizeBits === 40 || keySizeBits === 0 ? 5 : keySizeBits / 8;
|
|
142
|
+
const key0 = this.rc4CryptoApiKey(password, salt, keyBytes, 0);
|
|
143
|
+
const combined = this.rc4(key0, this.concatArrays(encryptedVerifier, encryptedVerifierHash));
|
|
144
|
+
const verifierPlain = combined.subarray(0, encryptedVerifier.length);
|
|
145
|
+
const storedHash = combined.subarray(encryptedVerifier.length);
|
|
146
|
+
if (!this.bytesEqual(this.hash(verifierPlain, "SHA1"), storedHash)) {
|
|
147
|
+
throw new Error("Incorrect password");
|
|
148
|
+
}
|
|
149
|
+
return this.decryptRc4Package(encryptedPackage, password, salt, keyBytes);
|
|
150
|
+
}
|
|
151
|
+
/** Standard key derivation (MS-OFFCRYPTO §2.3.4.7): iterated SHA1 then the X1‖X2 final block. */
|
|
152
|
+
static standardKey(password, salt, keyBytes) {
|
|
153
|
+
const SPIN_COUNT = 50000;
|
|
154
|
+
let h = this.hash(this.concatArrays(salt, this.stringToUtf16LE(password)), "SHA1");
|
|
155
|
+
for (let i = 0; i < SPIN_COUNT; i++) {
|
|
156
|
+
h = this.hash(this.concatArrays(this.le32(i), h), "SHA1");
|
|
157
|
+
}
|
|
158
|
+
const hfinal = this.hash(this.concatArrays(h, this.le32(0)), "SHA1");
|
|
159
|
+
const buf1 = new Uint8Array(64).fill(0x36);
|
|
160
|
+
const buf2 = new Uint8Array(64).fill(0x5c);
|
|
161
|
+
for (let i = 0; i < 20; i++) {
|
|
162
|
+
buf1[i] ^= hfinal[i];
|
|
163
|
+
buf2[i] ^= hfinal[i];
|
|
164
|
+
}
|
|
165
|
+
const x1 = this.hash(buf1, "SHA1");
|
|
166
|
+
const x2 = this.hash(buf2, "SHA1");
|
|
167
|
+
return this.concatArrays(x1, x2).slice(0, keyBytes);
|
|
168
|
+
}
|
|
169
|
+
static decryptStandardPackage(encryptedPackage, key) {
|
|
170
|
+
const sizeView = new DataView(encryptedPackage.buffer, encryptedPackage.byteOffset, 8);
|
|
171
|
+
const packageSize = Number(sizeView.getBigUint64(0, true));
|
|
172
|
+
const decrypted = this.aesEcbDecrypt(encryptedPackage.subarray(8), key);
|
|
173
|
+
const trimmed = decrypted.subarray(0, packageSize);
|
|
174
|
+
const result = new ArrayBuffer(trimmed.byteLength);
|
|
175
|
+
new Uint8Array(result).set(trimmed);
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
/** RC4 CryptoAPI key derivation (MS-OFFCRYPTO §2.3.5.2). */
|
|
179
|
+
static rc4CryptoApiKey(password, salt, keyBytes, block) {
|
|
180
|
+
const h0 = this.hash(this.concatArrays(salt, this.stringToUtf16LE(password)), "SHA1");
|
|
181
|
+
const hfinal = this.hash(this.concatArrays(h0, this.le32(block)), "SHA1");
|
|
182
|
+
if (keyBytes === 5) {
|
|
183
|
+
const key = new Uint8Array(16);
|
|
184
|
+
key.set(hfinal.subarray(0, 5));
|
|
185
|
+
return key;
|
|
186
|
+
}
|
|
187
|
+
return hfinal.subarray(0, keyBytes);
|
|
188
|
+
}
|
|
189
|
+
static decryptRc4Package(encryptedPackage, password, salt, keyBytes) {
|
|
190
|
+
const RC4_BLOCK_LENGTH = 512;
|
|
191
|
+
const sizeView = new DataView(encryptedPackage.buffer, encryptedPackage.byteOffset, 8);
|
|
192
|
+
const packageSize = Number(sizeView.getBigUint64(0, true));
|
|
193
|
+
const data = encryptedPackage.subarray(8);
|
|
194
|
+
const out = new Uint8Array(data.length);
|
|
195
|
+
// RC4 re-keys every 512 bytes of the encrypted package, using the block index.
|
|
196
|
+
for (let block = 0; block * RC4_BLOCK_LENGTH < data.length; block++) {
|
|
197
|
+
const start = block * RC4_BLOCK_LENGTH;
|
|
198
|
+
const end = Math.min(start + RC4_BLOCK_LENGTH, data.length);
|
|
199
|
+
const key = this.rc4CryptoApiKey(password, salt, keyBytes, block);
|
|
200
|
+
out.set(this.rc4(key, data.subarray(start, end)), start);
|
|
201
|
+
}
|
|
202
|
+
const trimmed = out.subarray(0, packageSize);
|
|
203
|
+
const result = new ArrayBuffer(trimmed.byteLength);
|
|
204
|
+
new Uint8Array(result).set(trimmed);
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
/** AES-ECB block decrypt (no padding). Trailing sub-block bytes are ignored. */
|
|
208
|
+
static aesEcbDecrypt(data, key) {
|
|
209
|
+
const aligned = data.length - (data.length % 16);
|
|
210
|
+
const cipher = ecb(key, { disablePadding: true });
|
|
211
|
+
return cipher.decrypt(data.subarray(0, aligned));
|
|
212
|
+
}
|
|
213
|
+
/** RC4 stream cipher (KSA + PRGA). Symmetric — the same op encrypts and decrypts. */
|
|
214
|
+
static rc4(key, data) {
|
|
215
|
+
const s = new Uint8Array(256);
|
|
216
|
+
for (let i = 0; i < 256; i++)
|
|
217
|
+
s[i] = i;
|
|
218
|
+
let j = 0;
|
|
219
|
+
for (let i = 0; i < 256; i++) {
|
|
220
|
+
j = (j + s[i] + key[i % key.length]) & 0xff;
|
|
221
|
+
const t = s[i];
|
|
222
|
+
s[i] = s[j];
|
|
223
|
+
s[j] = t;
|
|
224
|
+
}
|
|
225
|
+
const out = new Uint8Array(data.length);
|
|
226
|
+
let a = 0;
|
|
227
|
+
let b = 0;
|
|
228
|
+
for (let k = 0; k < data.length; k++) {
|
|
229
|
+
a = (a + 1) & 0xff;
|
|
230
|
+
b = (b + s[a]) & 0xff;
|
|
231
|
+
const t = s[a];
|
|
232
|
+
s[a] = s[b];
|
|
233
|
+
s[b] = t;
|
|
234
|
+
out[k] = data[k] ^ s[(s[a] + s[b]) & 0xff];
|
|
235
|
+
}
|
|
236
|
+
return out;
|
|
237
|
+
}
|
|
238
|
+
static le32(n) {
|
|
239
|
+
const b = new Uint8Array(4);
|
|
240
|
+
new DataView(b.buffer).setUint32(0, n >>> 0, true);
|
|
241
|
+
return b;
|
|
242
|
+
}
|
|
243
|
+
static bytesEqual(a, b) {
|
|
244
|
+
if (a.length !== b.length)
|
|
245
|
+
return false;
|
|
246
|
+
for (let i = 0; i < a.length; i++) {
|
|
247
|
+
if (a[i] !== b[i])
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
static parseEncryptionInfo(cfb) {
|
|
253
|
+
// Find EncryptionInfo stream
|
|
254
|
+
const encInfoEntry = cfb.FileIndex.find((entry) => entry.name === "EncryptionInfo");
|
|
255
|
+
if (!encInfoEntry || !encInfoEntry.content) {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
// CFB library returns content as array, convert to Uint8Array with proper buffer
|
|
259
|
+
const contentArray = encInfoEntry.content;
|
|
260
|
+
const content = contentArray instanceof Uint8Array
|
|
261
|
+
? contentArray
|
|
262
|
+
: new Uint8Array(contentArray);
|
|
263
|
+
// Create a new buffer to ensure we have a proper ArrayBuffer
|
|
264
|
+
const buffer = new ArrayBuffer(content.length);
|
|
265
|
+
const bufferView = new Uint8Array(buffer);
|
|
266
|
+
bufferView.set(content);
|
|
267
|
+
const view = new DataView(buffer);
|
|
268
|
+
// Read version info
|
|
269
|
+
const versionMajor = view.getUint16(0, true);
|
|
270
|
+
const versionMinor = view.getUint16(2, true);
|
|
271
|
+
// Only support Agile encryption (version 4.4)
|
|
272
|
+
if (versionMajor !== 4 || versionMinor !== 4) {
|
|
273
|
+
throw new Error(`Unsupported encryption version: ${versionMajor}.${versionMinor}. Only Agile encryption (4.4) is supported.`);
|
|
274
|
+
}
|
|
275
|
+
// Parse XML encryption descriptor (starts at byte 8)
|
|
276
|
+
const xmlBytes = content.slice(8);
|
|
277
|
+
const xmlString = new TextDecoder().decode(xmlBytes);
|
|
278
|
+
const encInfo = this.parseAgileEncryptionXml(xmlString);
|
|
279
|
+
return encInfo;
|
|
280
|
+
}
|
|
281
|
+
static parseAgileEncryptionXml(xml) {
|
|
282
|
+
// Simple XML parsing for encryption parameters
|
|
283
|
+
const getAttr = (tag, attr) => {
|
|
284
|
+
// Match tag with optional namespace prefix (p:, x:, etc.)
|
|
285
|
+
// Use non-greedy match to avoid consuming the target attribute
|
|
286
|
+
const regex = new RegExp(`<(?:\\w+:)?${tag}[^>]*?\\s+${attr}="([^"]*)"`, "i");
|
|
287
|
+
const match = xml.match(regex);
|
|
288
|
+
if (!match) {
|
|
289
|
+
console.warn(`Failed to find attribute ${attr} on tag ${tag}`);
|
|
290
|
+
// Try alternative: attribute might be first after tag name
|
|
291
|
+
const altRegex = new RegExp(`<(?:\\w+:)?${tag}\\s+${attr}="([^"]*)"`, "i");
|
|
292
|
+
const altMatch = xml.match(altRegex);
|
|
293
|
+
return altMatch ? altMatch[1] : "";
|
|
294
|
+
}
|
|
295
|
+
return match ? match[1] : "";
|
|
296
|
+
};
|
|
297
|
+
const getBase64 = (tag, attr) => {
|
|
298
|
+
const base64 = getAttr(tag, attr);
|
|
299
|
+
if (!base64) {
|
|
300
|
+
console.warn(`No base64 value found for ${tag}.${attr}`);
|
|
301
|
+
return new Uint8Array(0);
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
const binary = atob(base64);
|
|
305
|
+
const bytes = new Uint8Array(binary.length);
|
|
306
|
+
for (let i = 0; i < binary.length; i++) {
|
|
307
|
+
bytes[i] = binary.charCodeAt(i);
|
|
308
|
+
}
|
|
309
|
+
return bytes;
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
console.error(`Failed to decode base64 for ${tag}.${attr}:`, error);
|
|
313
|
+
return new Uint8Array(0);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
const algorithm = getAttr("keyData", "cipherAlgorithm") || "AES";
|
|
317
|
+
const keySize = parseInt(getAttr("keyData", "keyBits") || "256") / 8;
|
|
318
|
+
const blockSize = parseInt(getAttr("keyData", "blockSize") || "16");
|
|
319
|
+
const hashAlgorithm = getAttr("keyData", "hashAlgorithm") || "SHA512";
|
|
320
|
+
const hashSize = parseInt(getAttr("keyData", "hashSize") || "64");
|
|
321
|
+
const saltSize = parseInt(getAttr("keyData", "saltSize") || "16");
|
|
322
|
+
// TWO different salts are used:
|
|
323
|
+
// 1. passwordSalt from encryptedKey - for password derivation and verification
|
|
324
|
+
// 2. packageSalt from keyData - for package decryption IVs
|
|
325
|
+
const passwordSalt = getBase64("encryptedKey", "saltValue");
|
|
326
|
+
const packageSalt = getBase64("keyData", "saltValue");
|
|
327
|
+
// Get values from p:encryptedKey element
|
|
328
|
+
const spinCount = parseInt(getAttr("encryptedKey", "spinCount") || "100000");
|
|
329
|
+
const encryptedVerifierHashInput = getBase64("encryptedKey", "encryptedVerifierHashInput");
|
|
330
|
+
const encryptedVerifierHashValue = getBase64("encryptedKey", "encryptedVerifierHashValue");
|
|
331
|
+
const encryptedKeyValue = getBase64("encryptedKey", "encryptedKeyValue");
|
|
332
|
+
// Validate that all required values were parsed
|
|
333
|
+
if (!passwordSalt.length || !packageSalt.length) {
|
|
334
|
+
throw new Error("Failed to parse salt values from encryption info");
|
|
335
|
+
}
|
|
336
|
+
if (!encryptedVerifierHashInput.length ||
|
|
337
|
+
!encryptedVerifierHashValue.length ||
|
|
338
|
+
!encryptedKeyValue.length) {
|
|
339
|
+
throw new Error("Failed to parse encrypted verifier values from encryption info");
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
algorithm,
|
|
343
|
+
keySize,
|
|
344
|
+
blockSize,
|
|
345
|
+
hashAlgorithm,
|
|
346
|
+
hashSize,
|
|
347
|
+
saltSize,
|
|
348
|
+
passwordSalt,
|
|
349
|
+
packageSalt,
|
|
350
|
+
encryptedVerifierHashInput,
|
|
351
|
+
encryptedVerifierHashValue,
|
|
352
|
+
encryptedKeyValue,
|
|
353
|
+
spinCount,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
static deriveKey(password, info) {
|
|
357
|
+
// Convert password to UTF-16LE
|
|
358
|
+
const passwordBytes = this.stringToUtf16LE(password);
|
|
359
|
+
// Initial hash H0 = H(passwordSalt + password)
|
|
360
|
+
// Use passwordSalt from encryptedKey, NOT packageSalt from keyData
|
|
361
|
+
let hash = this.hash(this.concatArrays(info.passwordSalt, passwordBytes), info.hashAlgorithm);
|
|
362
|
+
// Spin iteration: H(iterator + H(n-1))
|
|
363
|
+
for (let i = 0; i < info.spinCount; i++) {
|
|
364
|
+
const iterator = new Uint8Array(4);
|
|
365
|
+
new DataView(iterator.buffer).setUint32(0, i, true);
|
|
366
|
+
hash = this.hash(this.concatArrays(iterator, hash), info.hashAlgorithm);
|
|
367
|
+
}
|
|
368
|
+
// Return H_final (the result after spin iterations)
|
|
369
|
+
// Individual keys are derived from this using block keys
|
|
370
|
+
return hash;
|
|
371
|
+
}
|
|
372
|
+
static decryptEncryptedKey(passwordDerivedKey, info) {
|
|
373
|
+
const keyForKeyValue = this.deriveAgileBlockKey(passwordDerivedKey, BLOCK_KEY_ENCRYPTION_KEY, info);
|
|
374
|
+
// Agile encryption uses raw CBC block decryption (no PKCS padding).
|
|
375
|
+
const decryptedKey = this.decryptAESNoPadding(info.encryptedKeyValue, keyForKeyValue, info.passwordSalt.slice(0, 16));
|
|
376
|
+
return decryptedKey.slice(0, info.keySize);
|
|
377
|
+
}
|
|
378
|
+
static verifyPassword(passwordDerivedKey, info) {
|
|
379
|
+
try {
|
|
380
|
+
const keyForVerifierInput = this.deriveAgileBlockKey(passwordDerivedKey, BLOCK_KEY_VERIFIER_INPUT, info);
|
|
381
|
+
// Decrypt verifier hash input
|
|
382
|
+
const verifierHashInput = this.decryptAESNoPadding(info.encryptedVerifierHashInput, keyForVerifierInput, info.passwordSalt.slice(0, 16));
|
|
383
|
+
// Hash the decrypted verifier
|
|
384
|
+
const verifierHash = this.hash(verifierHashInput.slice(0, 16), info.hashAlgorithm);
|
|
385
|
+
const keyForVerifierValue = this.deriveAgileBlockKey(passwordDerivedKey, BLOCK_KEY_VERIFIER_HASH, info);
|
|
386
|
+
// Decrypt verifier hash value
|
|
387
|
+
const decryptedVerifierHash = this.decryptAESNoPadding(info.encryptedVerifierHashValue, keyForVerifierValue, info.passwordSalt.slice(0, 16));
|
|
388
|
+
// Compare hashes
|
|
389
|
+
const expectedHashLength = Math.min(info.hashSize, verifierHash.length, decryptedVerifierHash.length);
|
|
390
|
+
for (let i = 0; i < expectedHashLength; i++) {
|
|
391
|
+
if (verifierHash[i] !== decryptedVerifierHash[i]) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
console.error("Password verification error:", error);
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
static getEncryptedPackage(cfb) {
|
|
403
|
+
const entry = cfb.FileIndex.find((e) => e.name === "EncryptedPackage" || e.name === "0EncryptedPackage");
|
|
404
|
+
if (!entry || !entry.content) {
|
|
405
|
+
throw new Error("EncryptedPackage stream not found");
|
|
406
|
+
}
|
|
407
|
+
// CFB library returns content as array, convert to proper Uint8Array
|
|
408
|
+
const contentArray = entry.content;
|
|
409
|
+
return contentArray instanceof Uint8Array
|
|
410
|
+
? contentArray
|
|
411
|
+
: new Uint8Array(contentArray);
|
|
412
|
+
}
|
|
413
|
+
static decryptPackage(encrypted, key, info) {
|
|
414
|
+
// Read the package size from the first 8 bytes
|
|
415
|
+
const sizeView = new DataView(encrypted.buffer, encrypted.byteOffset, 8);
|
|
416
|
+
const packageSize = Number(sizeView.getBigUint64(0, true));
|
|
417
|
+
// Skip the first 8 bytes (package size) to get encrypted data
|
|
418
|
+
const encryptedData = encrypted.slice(8);
|
|
419
|
+
// MS-OFFCRYPTO uses segmented decryption with 4096-byte blocks
|
|
420
|
+
const SEGMENT_LENGTH = 4096;
|
|
421
|
+
const totalSegments = Math.ceil(encryptedData.length / SEGMENT_LENGTH);
|
|
422
|
+
const decryptedSegments = [];
|
|
423
|
+
for (let i = 0; i < totalSegments; i++) {
|
|
424
|
+
const start = i * SEGMENT_LENGTH;
|
|
425
|
+
const end = Math.min(start + SEGMENT_LENGTH, encryptedData.length);
|
|
426
|
+
const segment = encryptedData.slice(start, end);
|
|
427
|
+
// Generate IV for this segment: hash(packageSalt + block number)
|
|
428
|
+
// Use packageSalt from keyData, NOT passwordSalt from encryptedKey
|
|
429
|
+
const blockNumber = new Uint8Array(4);
|
|
430
|
+
new DataView(blockNumber.buffer).setUint32(0, i, true);
|
|
431
|
+
const ivInput = this.concatArrays(info.packageSalt, blockNumber);
|
|
432
|
+
const ivHash = this.hash(ivInput, info.hashAlgorithm);
|
|
433
|
+
const iv = ivHash.slice(0, 16); // Use first 16 bytes as IV
|
|
434
|
+
// Decrypt this segment
|
|
435
|
+
const decryptedSegment = this.decryptAESNoPadding(segment, key, iv);
|
|
436
|
+
decryptedSegments.push(decryptedSegment);
|
|
437
|
+
}
|
|
438
|
+
// Concatenate all decrypted segments
|
|
439
|
+
const totalLength = decryptedSegments.reduce((sum, seg) => sum + seg.length, 0);
|
|
440
|
+
const allDecrypted = new Uint8Array(totalLength);
|
|
441
|
+
let offset = 0;
|
|
442
|
+
for (const seg of decryptedSegments) {
|
|
443
|
+
allDecrypted.set(seg, offset);
|
|
444
|
+
offset += seg.length;
|
|
445
|
+
}
|
|
446
|
+
// Trim to actual package size (remove padding)
|
|
447
|
+
const trimmed = allDecrypted.slice(0, packageSize);
|
|
448
|
+
// Create a proper ArrayBuffer from the decrypted data
|
|
449
|
+
const result = new ArrayBuffer(trimmed.byteLength);
|
|
450
|
+
new Uint8Array(result).set(trimmed);
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
static decryptAESNoPadding(data, key, iv) {
|
|
454
|
+
const cipher = cbc(key, iv, { disablePadding: true });
|
|
455
|
+
return cipher.decrypt(data);
|
|
456
|
+
}
|
|
457
|
+
static deriveAgileBlockKey(passwordDerivedKey, blockKey, info) {
|
|
458
|
+
return this.hash(this.concatArrays(passwordDerivedKey, blockKey), info.hashAlgorithm).slice(0, info.keySize);
|
|
459
|
+
}
|
|
460
|
+
static hash(data, algorithm) {
|
|
461
|
+
switch (algorithm.toUpperCase()) {
|
|
462
|
+
case "SHA1":
|
|
463
|
+
return sha1(data);
|
|
464
|
+
case "SHA256":
|
|
465
|
+
return sha256(data);
|
|
466
|
+
case "SHA384":
|
|
467
|
+
return sha384(data);
|
|
468
|
+
case "SHA512":
|
|
469
|
+
return sha512(data);
|
|
470
|
+
default:
|
|
471
|
+
throw new Error(`Unsupported hash algorithm: ${algorithm}`);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
static stringToUtf16LE(str) {
|
|
475
|
+
const bytes = new Uint8Array(str.length * 2);
|
|
476
|
+
for (let i = 0; i < str.length; i++) {
|
|
477
|
+
const code = str.charCodeAt(i);
|
|
478
|
+
bytes[i * 2] = code & 0xff;
|
|
479
|
+
bytes[i * 2 + 1] = (code >> 8) & 0xff;
|
|
480
|
+
}
|
|
481
|
+
return bytes;
|
|
482
|
+
}
|
|
483
|
+
static concatArrays(...arrays) {
|
|
484
|
+
const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
|
|
485
|
+
const result = new Uint8Array(totalLength);
|
|
486
|
+
let offset = 0;
|
|
487
|
+
for (const arr of arrays) {
|
|
488
|
+
result.set(arr, offset);
|
|
489
|
+
offset += arr.length;
|
|
490
|
+
}
|
|
491
|
+
return result;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type EncryptOptions = {
|
|
2
|
+
spinCount?: number;
|
|
3
|
+
};
|
|
4
|
+
export declare class CFBEncryptor {
|
|
5
|
+
static encrypt(source: ArrayBuffer | Uint8Array, password: string, options?: EncryptOptions): Promise<Uint8Array>;
|
|
6
|
+
private static buildEncryptionInfoStream;
|
|
7
|
+
private static buildEncryptedPackageStream;
|
|
8
|
+
private static encryptPackage;
|
|
9
|
+
private static buildEncryptionXml;
|
|
10
|
+
private static derivePasswordKey;
|
|
11
|
+
private static deriveAgileBlockKey;
|
|
12
|
+
private static encryptDataIntegrityValue;
|
|
13
|
+
private static encryptAESNoPadding;
|
|
14
|
+
private static sha512Hash;
|
|
15
|
+
private static hmacSha512;
|
|
16
|
+
private static toBase64;
|
|
17
|
+
private static padToBlockSize;
|
|
18
|
+
private static stringToUtf16LE;
|
|
19
|
+
private static concatArrays;
|
|
20
|
+
private static randomBytes;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=cfb-encryptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cfb-encryptor.d.ts","sourceRoot":"","sources":["../../../excel-parser/cfb-encryptor.ts"],"names":[],"mappings":"AAMA,KAAK,cAAc,GAAG;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAwBF,qBAAa,YAAY;WACV,OAAO,CAClB,MAAM,EAAE,WAAW,GAAG,UAAU,EAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,UAAU,CAAC;IA4FtB,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAWxC,OAAO,CAAC,MAAM,CAAC,2BAA2B;IAW1C,OAAO,CAAC,MAAM,CAAC,cAAc;IA0B7B,OAAO,CAAC,MAAM,CAAC,kBAAkB;IA6CjC,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAehC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAUlC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAiBxC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IASlC,OAAO,CAAC,MAAM,CAAC,UAAU;IAIzB,OAAO,CAAC,MAAM,CAAC,UAAU;IAIzB,OAAO,CAAC,MAAM,CAAC,QAAQ;IAQvB,OAAO,CAAC,MAAM,CAAC,cAAc;IAW7B,OAAO,CAAC,MAAM,CAAC,eAAe;IAU9B,OAAO,CAAC,MAAM,CAAC,YAAY;IAW3B,OAAO,CAAC,MAAM,CAAC,WAAW;CAc3B"}
|