Documentationcurrent version
Help us improve the docs by fixing typos and proposing enhancements.

Nikita

Action "fs.hash"

Retrieve the hash of a file or a directory in hexadecimal form.

If the target is a directory, the returned hash is the sum of all the hashs of the files it recursively contains. The default algorithm to compute the hash is md5.

If the target is a link, the returned hash is of the linked file.

It is possible to use to action to assert the target file by passing a hash used for comparaison.

Returned output

  • hash
    The hash of the file or directory identified by the "target" option.

Schema definitions

definitions =
  config:
    type: 'object'
    properties:
      'algo':
        type: 'string'
        default: 'md5'
        description: '''
        Any algorythm supported by `openssl` such as "md5", "sha1" and
        "sha256".
        '''
      'hash':
        type: 'string'
        description: '''
        Assert that the targeted content match a provided hash.
        '''
      'stats':
        typeof: 'object'
        description: '''
        Stat object of the target file. Short-circuit to avoid fetching the
        stat object associated with the target if one is already available.
        '''
      'target':
        type: 'string'
        description: '''
        The file or directory to compute the hash from.
        '''
    required: ['target']

Handler

handler = ({config}) ->
  {stats} = if config.stats
  then config.stats
  else await @fs.base.stat config.target
  unless utils.stats.isFile(stats.mode) or utils.stats.isDirectory(stats.mode)
    throw errors.NIKITA_FS_HASH_FILETYPE_UNSUPPORTED config: config, stats: stats
  hash = null
  try
    # Target is a directory
    if utils.stats.isDirectory stats.mode
      {files} = await @fs.glob  "#{config.target}/**", dot: true
      {stdout} = await @execute
        command: [
          'command -v openssl >/dev/null || exit 2'
          ...files.map (file) -> "[ -f #{file} ] && openssl dgst -#{config.algo} #{file} | sed 's/^.* \\([a-z0-9]*\\)$/\\1/g'"
          'exit 0'
        ].join '\n'
        trim: true
      hashs = utils.string.lines(stdout).filter( (line) -> /\w+/.test line ).sort()
      hash = if hashs.length is 0
      then crypto.createHash(config.algo).update('').digest('hex')
      else if hashs.length is 1 then hashs[0]
      else crypto.createHash(config.algo).update(hashs.join('')).digest('hex')
    # Target is a file
    else if utils.stats.isFile stats.mode
      {stdout} = await @execute
        command: """
        command -v openssl >/dev/null || exit 2
        openssl dgst -#{config.algo} #{config.target} | sed 's/^.* \\([a-z0-9]*\\)$/\\1/g'
        """
        trim: true
      hash = stdout
  catch err
    if err.exit_code is 2
      throw errors.NIKITA_FS_HASH_MISSING_OPENSSL()
    throw err if err
  if config.hash and config.hash isnt hash
    throw errors.NIKITA_FS_HASH_HASH_NOT_EQUAL config: config, hash: hash
  hash: hash

Exports

module.exports =
  handler: handler
  metadata:
    argument_to_config: 'target'
    shy: true
    definitions: definitions

Errors

errors =
  NIKITA_FS_HASH_FILETYPE_UNSUPPORTED: ({config, stats}) ->
    utils.error 'NIKITA_FS_HASH_FILETYPE_UNSUPPORTED', [
      'only "File" and "Directory" types are supported,'
      "got #{JSON.stringify utils.stats.type stats.mode},"
      "location is #{JSON.stringify config.target}"
    ], target: config.target
  NIKITA_FS_HASH_MISSING_OPENSSL: ->
    utils.error 'NIKITA_FS_HASH_MISSING_OPENSSL', [
      'the `openssl` command must be present on your system,'
      "please install it before pursuing"
    ]
  NIKITA_FS_HASH_HASH_NOT_EQUAL: ({config, hash}) ->
    utils.error 'NIKITA_FS_HASH_HASH_NOT_EQUAL', [
      'the target hash does not equal the execpted value,'
      "got #{JSON.stringify hash},"
      "expected #{JSON.stringify config.hash}"
    ], target: config.target
    

Dependencies

crypto = require 'crypto'
utils = require '../../utils'
Edit on GitHub
Navigate
About

Nikita is an open source project hosted on GitHub and developed by Adaltas.