integrity.js 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. const crypto = require('crypto')
  2. const fs = require('fs')
  3. const stream = require('stream')
  4. const { promisify } = require('util')
  5. const ALGORITHM = 'SHA256'
  6. // 4MB default block size
  7. const BLOCK_SIZE = 4 * 1024 * 1024
  8. const pipeline = promisify(stream.pipeline)
  9. function hashBlock (block) {
  10. return crypto.createHash(ALGORITHM).update(block).digest('hex')
  11. }
  12. async function getFileIntegrity (path) {
  13. const fileHash = crypto.createHash(ALGORITHM)
  14. const blocks = []
  15. let currentBlockSize = 0
  16. let currentBlock = []
  17. await pipeline(
  18. fs.createReadStream(path),
  19. new stream.PassThrough({
  20. decodeStrings: false,
  21. transform (_chunk, encoding, callback) {
  22. fileHash.update(_chunk)
  23. function handleChunk (chunk) {
  24. const diffToSlice = Math.min(BLOCK_SIZE - currentBlockSize, chunk.byteLength)
  25. currentBlockSize += diffToSlice
  26. currentBlock.push(chunk.slice(0, diffToSlice))
  27. if (currentBlockSize === BLOCK_SIZE) {
  28. blocks.push(hashBlock(Buffer.concat(currentBlock)))
  29. currentBlock = []
  30. currentBlockSize = 0
  31. }
  32. if (diffToSlice < chunk.byteLength) {
  33. handleChunk(chunk.slice(diffToSlice))
  34. }
  35. }
  36. handleChunk(_chunk)
  37. callback()
  38. },
  39. flush (callback) {
  40. blocks.push(hashBlock(Buffer.concat(currentBlock)))
  41. currentBlock = []
  42. callback()
  43. }
  44. })
  45. )
  46. return {
  47. algorithm: ALGORITHM,
  48. hash: fileHash.digest('hex'),
  49. blockSize: BLOCK_SIZE,
  50. blocks: blocks
  51. }
  52. }
  53. module.exports = getFileIntegrity