Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ workflows:
run_tests_with_coverage:
jobs:
- cover:
version: "10"
version: '10'
- cover:
version: "lts"
version: 'lts'
- cover:
version: "current"
version: 'current'

jobs:
cover:
Expand All @@ -26,9 +26,9 @@ jobs:
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "package.json" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- v1-dependencies-{{ checksum "package.json" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-

- run: npm install

Expand Down
25 changes: 19 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Create a hash checksum over a folder or a file.
The hashes are propagated upwards, the hash that is returned for a folder is generated over all the hashes of its children.
Create a hash checksum over a folder or a file.
The hashes are propagated upwards, the hash that is returned for a folder is generated over all the hashes of its children.
The hashes are generated with the _sha1_ algorithm and returned in _base64_ encoding by default.

Each file returns a name and a hash, and each folder returns additionally an array of children (file or folder elements).
Expand All @@ -10,7 +10,7 @@ First, install folder-hash with `npm install --save folder-hash` or `yarn add fo

### Simple example

To see differences to the last version of this package, I would create hashes over all _.js_ and _.json_ files. But ignore everything inside folders starting with a dot, and also from the folders _node_modules_, _test_coverage_. The structure of the options object is documented <a href="#options">below.</a>
To see differences to the last version of this package, I would create hashes over all _.js_ and _.json_ files. But ignore everything inside folders starting with a dot, and also from the folders _node_modules_, _test_coverage_. The structure of the options object is documented <a href="#options">below.</a>
This example is also stored in [./examples/readme-example1.js](/examples/readme-example1.js).

```js
Expand Down Expand Up @@ -56,7 +56,7 @@ Creating a hash over the current folder:

And the structure may be traversed to e.g. create incremental backups.

It is also possible to only match the full path and not the basename. The same configuration could look like this:
It is also possible to only match the full path and not the basename. The same configuration could look like this:
_You should be aware that \*nix and Windows behave differently, so please use caution._

```js
Expand Down Expand Up @@ -138,6 +138,7 @@ const options = {
```js
{
algo: 'sha1', // see crypto.getHashes() for options in your node.js REPL
algoOptions: {}, // see https://nodejs.org/api/crypto.html#cryptocreatehashalgorithm-options -- only valid in node v12.8 and higher
encoding: 'base64', // 'base64', 'base64url', 'hex' or 'binary'
files: {
exclude: [],
Expand Down Expand Up @@ -336,7 +337,7 @@ const options = {

### Symlink options

Configure, how symbolic links should be hashed.
Configure, how symbolic links should be hashed.
To understand how the options can be combined to create a specific behavior, look into [test/symbolic-links.js](https://github.com/marc136/node-folder-hash/blob/master/test/symbolic-links.js).

<table>
Expand Down Expand Up @@ -509,11 +510,23 @@ hashElement(__dirname, options, (error, hash) => {
console.log(hash.toString());
}
});

// pass algoOptions (example: shake256)
// see https://nodejs.org/api/crypto.html#cryptocreatehashalgorithm-options -- only valid in node v12.8 and higher
const options = { algo: 'shake256', algoOptions:{ outputLength: 5 }, files: { exclude: ['.*'], matchBasename: true } };
hashElement(__dirname, options, (error, hash) => {
if (error) {
return console.error('hashing failed:', error);
} else {
console.log('Result for folder "' + __dirname + '":');
console.log(hash.toString());
}
});
```

## Behavior

The behavior is documented and verified in the unit tests. Execute `npm test` or `mocha test`, and have a look at the _test_ subfolder.
The behavior is documented and verified in the unit tests. Execute `npm test` or `mocha test`, and have a look at the _test_ subfolder.
You can also have a look at the [CircleCI report. ![CircleCI](https://circleci.com/gh/marc136/node-folder-hash/tree/master.svg?style=svg)](https://circleci.com/gh/marc136/node-folder-hash/tree/master)

### Creating hashes over files (with default options)
Expand Down
12 changes: 7 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

const defaultOptions = {
algo: 'sha1', // see crypto.getHashes() for options
algoOptions: {},
encoding: 'base64', // 'base64', 'base64url', 'hex' or 'binary'
files: {
exclude: [],
Expand Down Expand Up @@ -167,7 +168,7 @@ function prep(fs) {

return new Promise((resolve, reject) => {
try {
const hash = crypto.createHash(options.algo);
const hash = crypto.createHash(options.algo, options.algoOptions);
if (
options.files.ignoreBasename ||
options.ignoreBasenameOnce ||
Expand Down Expand Up @@ -213,7 +214,7 @@ function prep(fs) {
function symLinkIgnoreTargetContent(name, target, options, isRootElement) {
delete options.skipMatching; // only used for the root level
log.symlink('ignoring symbolic link target content');
const hash = crypto.createHash(options.algo);
const hash = crypto.createHash(options.algo, options.algoOptions);
if (!options.symbolicLinks.ignoreBasename && !(isRootElement && options.files.ignoreRootName)) {
log.symlink('hash basename');
hash.update(name);
Expand All @@ -237,7 +238,7 @@ function prep(fs) {
const temp = await hashElementPromise(stats, dir, options, isRootElement);

if (!options.symbolicLinks.ignoreTargetPath) {
const hash = crypto.createHash(options.algo);
const hash = crypto.createHash(options.algo, options.algoOptions);
hash.update(temp.hash);
log.symlink('hash targetpath');
hash.update(target);
Expand All @@ -247,7 +248,7 @@ function prep(fs) {
} catch (err) {
if (options.symbolicLinks.ignoreTargetContentAfterError) {
log.symlink(`Ignoring error "${err.code}" when hashing symbolic link ${name}`, err);
const hash = crypto.createHash(options.algo);
const hash = crypto.createHash(options.algo, options.algoOptions);
if (
!options.symbolicLinks.ignoreBasename &&
!(isRootElement && options.files.ignoreRootName)
Expand Down Expand Up @@ -314,6 +315,7 @@ function parseParameters(args) {
if (!isObject(options_)) options_ = {};
const options = {
algo: options_.algo || defaultOptions.algo,
algoOptions: options_.algoOptions || defaultOptions.algoOptions,
encoding: options_.encoding || defaultOptions.encoding,
files: Object.assign({}, defaultOptions.files, options_.files),
folders: Object.assign({}, defaultOptions.folders, options_.folders),
Expand All @@ -334,7 +336,7 @@ const HashedFolder = function HashedFolder(name, children, options, isRootElemen
this.name = name;
this.children = children;

const hash = crypto.createHash(options.algo);
const hash = crypto.createHash(options.algo, options.algoOptions);
if (
options.folders.ignoreBasename ||
options.ignoreBasenameOnce ||
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "folder-hash",
"version": "4.0.4",
"version": "4.0.5",
"description": "Create a hash checksum over a folder and its content - its children and their content",
"main": "index.js",
"bin": {
Expand Down
30 changes: 30 additions & 0 deletions test/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,36 @@ describe('Should generate hashes', function () {
};
return hashElement(basename, dir, options).then(checkHash);
});

it('with algoOptions passed', function () {
// base our expected hash on node version behavior
// algo options were not available until v12.8
var v = process.version.split('.');
var major = parseInt(v[0].replace('v', ''));
var minor = parseInt(v[1]);
var expectedHash =
major > 12 || (major === 12 && minor >= 8)
? 'd89f885449'
: 'd89f8854493c06a3bea8deffaee1c43d7e29e8b140122f17829bb8ad73950cbc';

const checkAlgoOptionHash = result => {
should.exist(result);
should.exist(result.hash);
result.hash.should.equal(expectedHash);
};

var options = {
algo: 'shake256',
algoOptions: { outputLength: 5 },
encoding: 'hex',
excludes: [],
match: {
basename: false,
path: false,
},
};
return hashElement(basename, dir, options).then(checkAlgoOptionHash);
});
});

describe('when executed with an error-first callback', function () {
Expand Down