-
Notifications
You must be signed in to change notification settings - Fork 36
feat: support xz #112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat: support xz #112
Changes from 1 commit
b104f8f
58055ea
9b17e98
d80454e
ee421a6
e8465b5
4f0f447
8d9380f
b167355
b3cb500
d6a07f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -199,3 +199,25 @@ export namespace zip { | |||||
} | ||||||
|
||||||
} | ||||||
|
||||||
export namespace xz { | ||||||
function compressFile(source: sourceType, dest: destType, opts?: any): Promise<void> | ||||||
function uncompress(source: sourceType, dest: destType, opts?: any): Promise<void> | ||||||
function decompress(source: sourceType, dest: destType, opts?: any): Promise<void> | ||||||
|
||||||
export class FileStream extends ReadStream { | ||||||
constructor(opts?: { | ||||||
lzma?: object, | ||||||
source: sourceType | ||||||
}); | ||||||
} | ||||||
|
||||||
export class UncompressStream extends WriteStream { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Suggested change
|
||||||
constructor(opts?: { | ||||||
lzma?: object, | ||||||
source: sourceType | ||||||
}); | ||||||
on(event: string, listener: (...args: any[]) => void): this | ||||||
on(event: 'error', listener: (err: Error) => void): this | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
'use strict'; | ||
|
||
const fs = require('fs'); | ||
const lzma = require('lzma-native'); | ||
const utils = require('../utils'); | ||
const streamifier = require('streamifier'); | ||
const stream = require('stream'); | ||
|
||
class XzFileStream extends stream.Transform { | ||
constructor(opts) { | ||
opts = opts || {}; | ||
super(opts); | ||
|
||
const sourceType = utils.sourceType(opts.source); | ||
const compressor = lzma.createCompressor(opts.lzma); | ||
|
||
compressor.on('error', err => this.emit('error', err)); | ||
compressor.on('end', () => this.push(null)); | ||
compressor.on('data', chunk => this.push(chunk)); | ||
|
||
if (sourceType === 'file') { | ||
const stream = fs.createReadStream(opts.source, opts.fs); | ||
stream.on('error', err => this.emit('error', err)); | ||
stream.pipe(compressor); | ||
return; | ||
} | ||
|
||
if (sourceType === 'buffer') { | ||
const stream = streamifier.createReadStream(opts.source, opts.streamifier); | ||
stream.on('error', err => this.emit('error', err)); | ||
stream.pipe(compressor); | ||
return; | ||
} | ||
|
||
if (sourceType === 'stream') { | ||
opts.source.on('error', err => this.emit('error', err)); | ||
opts.source.pipe(compressor); | ||
return; | ||
} | ||
|
||
// For streaming input | ||
this.on('pipe', srcStream => { | ||
srcStream.unpipe(srcStream); | ||
fengmk2 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
srcStream.pipe(compressor); | ||
}); | ||
} | ||
|
||
_transform(chunk, encoding, callback) { | ||
// This will be handled by the compressor stream | ||
callback(); | ||
} | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
module.exports = XzFileStream; | ||
Check failure on line 54 in lib/xz/file_stream.js
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,11 @@ | ||||||||||||||
'use strict'; | ||||||||||||||
|
||||||||||||||
const utils = require('../utils'); | ||||||||||||||
const XzFileStream = require('./file_stream'); | ||||||||||||||
const XzUncompressStream = require('./uncompress_stream'); | ||||||||||||||
|
||||||||||||||
exports.FileStream = XzFileStream; | ||||||||||||||
exports.UncompressStream = XzUncompressStream; | ||||||||||||||
exports.compressFile = utils.makeFileProcessFn(XzFileStream); | ||||||||||||||
exports.uncompress = utils.makeFileProcessFn(XzUncompressStream); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nitpick] The
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||
exports.decompress = utils.makeFileProcessFn(XzUncompressStream); | ||||||||||||||
Check failure on line 11 in lib/xz/index.js
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
'use strict'; | ||
|
||
const fs = require('fs'); | ||
const lzma = require('lzma-native'); | ||
const utils = require('../utils'); | ||
const streamifier = require('streamifier'); | ||
const { PassThrough } = require('stream'); | ||
|
||
class XzUncompressStream extends PassThrough { | ||
constructor(opts) { | ||
opts = opts || {}; | ||
super(opts); | ||
|
||
const sourceType = utils.sourceType(opts.source); | ||
const decompressor = lzma.createDecompressor(opts.lzma); | ||
|
||
decompressor.on('error', err => this.emit('error', err)); | ||
decompressor.on('end', () => this.end()); | ||
|
||
// Handle single file decompression | ||
if (sourceType === 'file') { | ||
const stream = fs.createReadStream(opts.source, opts.fs); | ||
stream.on('error', err => this.emit('error', err)); | ||
stream.pipe(decompressor).pipe(this); | ||
return; | ||
} | ||
|
||
if (sourceType === 'buffer') { | ||
const stream = streamifier.createReadStream(opts.source, opts.streamifier); | ||
stream.on('error', err => this.emit('error', err)); | ||
stream.pipe(decompressor).pipe(this); | ||
return; | ||
} | ||
|
||
if (sourceType === 'stream') { | ||
opts.source.on('error', err => this.emit('error', err)); | ||
opts.source.pipe(decompressor).pipe(this); | ||
return; | ||
} | ||
|
||
// For streaming input | ||
this.on('pipe', srcStream => { | ||
srcStream.unpipe(srcStream); | ||
fengmk2 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
srcStream.pipe(decompressor).pipe(this); | ||
}); | ||
} | ||
fengmk2 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
module.exports = XzUncompressStream; | ||
Check failure on line 49 in lib/xz/uncompress_stream.js
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,7 @@ | |
"flushwritable": "^1.0.0", | ||
"get-ready": "^1.0.0", | ||
"iconv-lite": "^0.5.0", | ||
"lzma-native": "^8.0.5", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainVerify the lzma-native dependency version for security and compatibility. The addition of 🌐 Web query:
💡 Result: The latest version of lzma-native npm package is 8.0.6, which was published approximately 3 years ago (as of January 2022)[1]. As for lzma-native version 8.0.5, there is some security information available. According to ReversingLabs Spectra Assure Community, the package is not widely used, having about 20 million recorded downloads. However, they caution that a package's popularity is not necessarily an indicator of its safety[4]. While there are no direct vulnerabilities explicitly mentioned for lzma-native version 8.0.5 specifically, it's important to note that the underlying liblzma library (which lzma-native provides bindings to) has had a significant security issue. In early 2024, a critical vulnerability known as CVE-2024-3094 was discovered in the xz/liblzma library[6][7]. This vulnerability resulted from a supply chain attack where malicious code was embedded in the form of .m4 files in tarball distributions. The vulnerability affected primarily versions 5.6.0 and 5.6.1 of the xz/liblzma library, with the backdoor specifically targeting systems running SSH servers and using liblzma[7]. However, according to available information, lzma-native appears to come with binary version 5.2.3, which is considered safe from this particular vulnerability[8]. For any npm package, it's generally recommended to run security audits using tools like Citations:
Upgrade lzma-native to 8.0.6 and audit for security The current dependency ( • In package.json (line 45), change 🤖 Prompt for AI Agents
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, please change it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @fengmk2 I'll plan the code change to update the lzma-native dependency version. Another agent will come along and actually execute the changes. flowchart TB
A["Update lzma-native dependency"]
A --> B["Modify package.json"]
B --> C["Change version from ^8.0.5 to ^8.0.6"]
⏳ Preparing changes... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A summary of the edits CodeRabbit can apply:
A plan of each step that CodeRabbit will take in order to execute the edits for each file (with inline rough draft snippets): ✏️ package.jsonOpen package.json and navigate to line 45, which currently reads: "lzma-native": "^8.0.5", Replace the version string on line 45 with the updated version: -"lzma-native": "^8.0.5",
+"lzma-native": "^8.0.6", Save your changes to package.json. Run npm install to update package-lock.json and install lzma-native@^8.0.6. Execute npm audit to identify any security vulnerabilities in the updated dependency tree. Run the full test suite, including any compression/uncompression integration tests, to verify compatibility with the supported Node.js versions. A summary of the context that CodeRabbit is considering across the codebase:
|
||
"mkdirp": "^0.5.1", | ||
"pump": "^3.0.0", | ||
"streamifier": "^0.1.1", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const assert = require('assert'); | ||
const compressing = require('../..'); | ||
|
||
describe('test/xz/file_stream.test.js', () => { | ||
const sourceFile = path.join(__dirname, '../fixtures/xx.log'); | ||
const xzFile = path.join(__dirname, '../fixtures/xx.log.xz'); | ||
|
||
it('should compress file to xz', done => { | ||
const dest = path.join(__dirname, '../fixtures/xx.log.xz.tmp'); | ||
compressing.xz.compressFile(sourceFile, dest) | ||
.then(() => { | ||
assert(fs.existsSync(dest)); | ||
// 文件大小应该小于原始文件 | ||
assert(fs.statSync(dest).size < fs.statSync(sourceFile).size); | ||
fs.unlinkSync(dest); | ||
done(); | ||
}) | ||
.catch(done); | ||
}); | ||
|
||
it('should decompress xz file to log', done => { | ||
const dest = path.join(__dirname, '../fixtures/xx.log.tmp'); | ||
compressing.xz.uncompress(xzFile, dest) | ||
.then(() => { | ||
assert(fs.existsSync(dest)); | ||
// 内容应该一致 | ||
const raw = fs.readFileSync(sourceFile); | ||
const out = fs.readFileSync(dest); | ||
assert(raw.equals(out)); | ||
fs.unlinkSync(dest); | ||
done(); | ||
}) | ||
.catch(done); | ||
}); | ||
|
||
it('should compress buffer to xz', done => { | ||
const buf = fs.readFileSync(sourceFile); | ||
const dest = path.join(__dirname, '../fixtures/xx.log.xz.tmp'); | ||
compressing.xz.compressFile(buf, dest) | ||
.then(() => { | ||
assert(fs.existsSync(dest)); | ||
fs.unlinkSync(dest); | ||
done(); | ||
}) | ||
.catch(done); | ||
}); | ||
|
||
it('should decompress xz buffer to log', done => { | ||
const buf = fs.readFileSync(xzFile); | ||
const dest = path.join(__dirname, '../fixtures/xx.log.tmp'); | ||
compressing.xz.uncompress(buf, dest) | ||
.then(() => { | ||
assert(fs.existsSync(dest)); | ||
const raw = fs.readFileSync(sourceFile); | ||
const out = fs.readFileSync(dest); | ||
assert(raw.equals(out)); | ||
fs.unlinkSync(dest); | ||
done(); | ||
}) | ||
.catch(done); | ||
}); | ||
|
||
it('should compress stream to xz', done => { | ||
const src = fs.createReadStream(sourceFile); | ||
const dest = path.join(__dirname, '../fixtures/xx.log.xz.tmp'); | ||
compressing.xz.compressFile(src, dest) | ||
.then(() => { | ||
assert(fs.existsSync(dest)); | ||
fs.unlinkSync(dest); | ||
done(); | ||
}) | ||
.catch(done); | ||
}); | ||
|
||
it('should decompress xz stream to log', done => { | ||
const src = fs.createReadStream(xzFile); | ||
const dest = path.join(__dirname, '../fixtures/xx.log.tmp'); | ||
compressing.xz.uncompress(src, dest) | ||
.then(() => { | ||
assert(fs.existsSync(dest)); | ||
const raw = fs.readFileSync(sourceFile); | ||
const out = fs.readFileSync(dest); | ||
assert(raw.equals(out)); | ||
fs.unlinkSync(dest); | ||
done(); | ||
}) | ||
.catch(done); | ||
}); | ||
}); | ||
Check failure on line 91 in test/xz/file_stream.test.js
|
Uh oh!
There was an error while loading. Please reload this page.