summaryrefslogtreecommitdiff
path: root/desktop/node_modules/@electron/asar/lib/integrity.js
blob: 6fabee4f001eb7d08e44b82ea59b4e63dc9abb0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
const crypto = require('crypto')
const fs = require('fs')
const stream = require('stream')
const { promisify } = require('util')

const ALGORITHM = 'SHA256'
// 4MB default block size
const BLOCK_SIZE = 4 * 1024 * 1024

const pipeline = promisify(stream.pipeline)

function hashBlock (block) {
  return crypto.createHash(ALGORITHM).update(block).digest('hex')
}

async function getFileIntegrity (path) {
  const fileHash = crypto.createHash(ALGORITHM)

  const blocks = []
  let currentBlockSize = 0
  let currentBlock = []

  await pipeline(
    fs.createReadStream(path),
    new stream.PassThrough({
      decodeStrings: false,
      transform (_chunk, encoding, callback) {
        fileHash.update(_chunk)

        function handleChunk (chunk) {
          const diffToSlice = Math.min(BLOCK_SIZE - currentBlockSize, chunk.byteLength)
          currentBlockSize += diffToSlice
          currentBlock.push(chunk.slice(0, diffToSlice))
          if (currentBlockSize === BLOCK_SIZE) {
            blocks.push(hashBlock(Buffer.concat(currentBlock)))
            currentBlock = []
            currentBlockSize = 0
          }
          if (diffToSlice < chunk.byteLength) {
            handleChunk(chunk.slice(diffToSlice))
          }
        }
        handleChunk(_chunk)
        callback()
      },
      flush (callback) {
        blocks.push(hashBlock(Buffer.concat(currentBlock)))
        currentBlock = []
        callback()
      }
    })
  )

  return {
    algorithm: ALGORITHM,
    hash: fileHash.digest('hex'),
    blockSize: BLOCK_SIZE,
    blocks: blocks
  }
}

module.exports = getFileIntegrity