Skip to content

Commit

Permalink
Merge pull request #1 from zurmokeeper/feature/add_decryption_func
Browse files Browse the repository at this point in the history
Feature/add decryption func
  • Loading branch information
zurmokeeper committed Jun 5, 2023
2 parents b213631 + 5c62b82 commit f9249c0
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 35 deletions.
1 change: 0 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"node": true
},
"rules": {
"import/extensions": ["error", { "ignorePackages": true }],
"arrow-parens": ["error", "as-needed"],
"class-methods-use-this": ["off"],
"comma-dangle": ["error", {"arrays": "always-multiline", "objects": "always-multiline", "imports": "always-multiline", "exports": "always-multiline", "functions": "never"}],
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2159,18 +2159,30 @@ faster or more resilient.
// read from a file
const workbook = new Excel.Workbook();
await workbook.xlsx.readFile(filename);

// read from a file, decrypt excel files encrypted with password
const workbook = new Excel.Workbook();
await workbook.xlsx.readFile(filename, {password:'123456'});
// ... use workbook


// read from a stream
const workbook = new Excel.Workbook();
await workbook.xlsx.read(stream);

// read from a stream, decrypt excel files encrypted with password
const workbook = new Excel.Workbook();
await workbook.xlsx.read(stream, {password:'123456'});
// ... use workbook


// load from buffer
const workbook = new Excel.Workbook();
await workbook.xlsx.load(data);

// load from buffer, decrypt excel files encrypted with password
const workbook = new Excel.Workbook();
await workbook.xlsx.load(data, {password:'123456'});
// ... use workbook
```

Expand Down
12 changes: 12 additions & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -2049,18 +2049,30 @@ worksheet.unprotect();
// 从文件读取
const workbook = new Excel.Workbook();
await workbook.xlsx.readFile(filename);

// 从文件读取, 解密使用密码加密的excel文件
const workbook = new Excel.Workbook();
await workbook.xlsx.readFile(filename, {password:'123456'});
// ... 使用 workbook


// 从流读取
const workbook = new Excel.Workbook();
await workbook.xlsx.read(stream);

// 从流读取, 解密使用密码加密的excel文件
const workbook = new Excel.Workbook();
await workbook.xlsx.read(stream, {password:'123456'});
// ... 使用 workbook


// 从 buffer 加载
const workbook = new Excel.Workbook();
await workbook.xlsx.load(data);

// 从 buffer 加载, 解密使用密码加密的excel文件
const workbook = new Excel.Workbook();
await workbook.xlsx.load(data, {password:'123456'});
// ... 使用 workbook
```

Expand Down
32 changes: 29 additions & 3 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1453,23 +1453,49 @@ export interface XlsxWriteOptions extends stream.xlsx.WorkbookWriterOptions {
zip: Partial<JSZipGeneratorOptions>;
}

export interface XlsxReadOptions {
/**
* @desc Decrypted passwords, maximum length is 255
* optional
*/
password: string;

/**
* @desc This parameter indicates that the input is a base64-encoded buffer. Only valid for the load method
* optional
*/
base64: boolean;

/**
* @desc TODO:
* optional
*/
maxRows: number;

/**
* @desc TODO:
* optional
*/
maxCols: number;
}

export interface Xlsx {
/**
* read from a file
*/
readFile(path: string): Promise<Workbook>;
readFile(path: string, options?: Partial<XlsxReadOptions>): Promise<Workbook>;

/**
* read from a stream
* @param stream
*/
read(stream: import('stream').Stream): Promise<Workbook>;
read(stream: import('stream').Stream, options?: Partial<XlsxReadOptions>): Promise<Workbook>;

/**
* load from an array buffer
* @param buffer
*/
load(buffer: Buffer): Promise<Workbook>;
load(buffer: Buffer, options?: Partial<XlsxReadOptions>): Promise<Workbook>;

/**
* write to a buffer
Expand Down
27 changes: 18 additions & 9 deletions lib/xlsx/xlsx.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const fs = require('fs');
const JSZip = require('jszip');
const {PassThrough} = require('readable-stream');
const officeCrypto = require('officecrypto-tool');
const ZipStream = require('../utils/zip-stream');
const StreamBuf = require('../utils/stream-buf');

Expand All @@ -22,6 +23,7 @@ const TableXform = require('./xform/table/table-xform');
const CommentsXform = require('./xform/comment/comments-xform');
const VmlNotesXform = require('./xform/comment/vml-notes-xform');

// eslint-disable-next-line import/extensions
const theme1Xml = require('./xml/theme1.js');

function fsReadFileAsync(filename, options) {
Expand Down Expand Up @@ -276,6 +278,10 @@ class XLSX {
vmlDrawings: {},
};

if (options && options.password) {
buffer = await officeCrypto.decrypt(buffer, {password: options.password});
}

const zip = await JSZip.loadAsync(buffer);
for (const entry of Object.values(zip.files)) {
/* eslint-disable no-await-in-loop */
Expand All @@ -285,9 +291,11 @@ class XLSX {
entryName = entryName.substr(1);
}
let stream;
if (entryName.match(/xl\/media\//) ||
if (
entryName.match(/xl\/media\//) ||
// themes are not parsed as stream
entryName.match(/xl\/theme\/([a-zA-Z0-9]+)[.]xml/)) {
entryName.match(/xl\/theme\/([a-zA-Z0-9]+)[.]xml/)
) {
stream = new PassThrough();
stream.write(await entry.async('nodebuffer'));
} else {
Expand Down Expand Up @@ -597,8 +605,7 @@ class XLSX {
model.created = model.created || new Date();
model.modified = model.modified || new Date();

model.useSharedStrings =
options.useSharedStrings !== undefined ? options.useSharedStrings : true;
model.useSharedStrings = options.useSharedStrings !== undefined ? options.useSharedStrings : true;
model.useStyles = options.useStyles !== undefined ? options.useStyles : true;

// Manage the shared strings
Expand Down Expand Up @@ -673,11 +680,13 @@ class XLSX {
reject(error);
});

this.write(stream, options).then(() => {
stream.end();
}).catch(err=>{
reject(err);
});
this.write(stream, options)
.then(() => {
stream.end();
})
.catch(err => {
reject(err);
});
});
}

Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zurmokeeper/exceljs",
"version": "4.3.0",
"version": "4.4.0",
"description": "Excel Workbook Manager - Read and Write xlsx and csv Files.",
"private": false,
"license": "MIT",
Expand Down Expand Up @@ -93,13 +93,17 @@
"views",
"frozen",
"split",
"pageSetup"
"pageSetup",
"cfb",
"ecma376_standard",
"ecma376_agile"
],
"dependencies": {
"archiver": "^5.0.0",
"dayjs": "^1.8.34",
"fast-csv": "^4.3.1",
"jszip": "^3.10.1",
"officecrypto-tool": "0.0.3",
"readable-stream": "^3.6.0",
"saxes": "^5.0.1",
"tmp": "^0.2.0",
Expand Down
File renamed without changes.
Binary file not shown.
98 changes: 98 additions & 0 deletions spec/integration/issues/issue-2247-cryptor.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const ExcelJS = verquire('exceljs');
const fs = require('fs');

const TEST_2247_STD_XLSX_FILE_NAME =
'./spec/integration/data/emca376-standard-123456.xlsx';
const TEST_2247_AGILE_XLSX_FILE_NAME =
'./spec/integration/data/emca376-agile-123456.xlsx';

describe('pr related issues', () => {
describe('pr add the function of reading encrypted xlsx ', () => {
it('workbook.xlsx.readFile, ecma376_standard encryption method decrypted successfully', async () => {
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.readFile(TEST_2247_STD_XLSX_FILE_NAME, {
password: '123456',
});
const sheetName = workbook.getWorksheet(1).name;
expect(sheetName).to.equal('Sheet1');
});

it('workbook.xlsx.readFile, ecma376_agile encryption method decrypted successfully', async () => {
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.readFile(TEST_2247_AGILE_XLSX_FILE_NAME, {
password: '123456',
});
const sheetName = workbook.getWorksheet(1).name;
expect(sheetName).to.equal('Sheet1');
});

it('workbook.xlsx.load, ecma376_standard encryption method decrypted successfully ', async () => {
const workbook = new ExcelJS.Workbook();

await workbook.xlsx.load(fs.readFileSync(TEST_2247_STD_XLSX_FILE_NAME), {
password: '123456',
});
const sheetName = workbook.getWorksheet(1).name;
expect(sheetName).to.equal('Sheet1');
});

it('workbook.xlsx.load, ecma376_agile encryption method decrypted successfully ', async () => {
const workbook = new ExcelJS.Workbook();

await workbook.xlsx.load(
fs.readFileSync(TEST_2247_AGILE_XLSX_FILE_NAME),
{
password: '123456',
}
);
const sheetName = workbook.getWorksheet(1).name;
expect(sheetName).to.equal('Sheet1');
});

it('workbook.xlsx.load, options.base64 = true, ecma376_standard encryption method decrypted successfully ', async () => {
const workbook = new ExcelJS.Workbook();
const input = fs
.readFileSync(TEST_2247_STD_XLSX_FILE_NAME)
.toString('base64');
await workbook.xlsx.load(input, {
password: '123456',
base64: true,
});
const sheetName = workbook.getWorksheet(1).name;
expect(sheetName).to.equal('Sheet1');
});

it('workbook.xlsx.load, options.base64 = true, ecma376_agile encryption method decrypted successfully ', async () => {
const workbook = new ExcelJS.Workbook();
const input = fs
.readFileSync(TEST_2247_AGILE_XLSX_FILE_NAME)
.toString('base64');
await workbook.xlsx.load(input, {
password: '123456',
base64: true,
});
const sheetName = workbook.getWorksheet(1).name;
expect(sheetName).to.equal('Sheet1');
});

it('workbook.xlsx.read, ecma376_standard encryption method decrypted successfully ', async () => {
const workbook = new ExcelJS.Workbook();
const input = fs.createReadStream(TEST_2247_STD_XLSX_FILE_NAME);
await workbook.xlsx.read(input, {
password: '123456',
});
const sheetName = workbook.getWorksheet(1).name;
expect(sheetName).to.equal('Sheet1');
});

it('workbook.xlsx.read, ecma376_agile encryption method decrypted successfully ', async () => {
const workbook = new ExcelJS.Workbook();
const input = fs.createReadStream(TEST_2247_AGILE_XLSX_FILE_NAME);
await workbook.xlsx.read(input, {
password: '123456',
});
const sheetName = workbook.getWorksheet(1).name;
expect(sheetName).to.equal('Sheet1');
});
});
});
20 changes: 0 additions & 20 deletions spec/integration/issues/issue-2247-encrytor.spec.js

This file was deleted.

0 comments on commit f9249c0

Please sign in to comment.