Skip to content

Commit

Permalink
Update the readme and the package architecture
Browse files Browse the repository at this point in the history
  • Loading branch information
sleep-written committed Feb 21, 2022
1 parent ef9a993 commit 281ebf6
Show file tree
Hide file tree
Showing 17 changed files with 192 additions and 63 deletions.
21 changes: 21 additions & 0 deletions LICENCE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2021 sleep-written

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
77 changes: 56 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ Simply add this project as a local dependency to your project:
$ npm i --save argon2-hasher
```

## Object to Hash
## Hash anything

You can generate hashes from any json plain object. If you want to use a random salt generated with a fixed length, simply give to the `JsonHasher` constructor a number with the desired length _(in bytes)_ of the random salt, and the new instance will has been generated with a new random salt:

```ts
import { JsonHasher } from 'argon2-json-hasher';
import { Hasher } from 'argon2-hasher';

// A function that receive an object
async function program(obj: any): Promise<void> {
// Create a new JsonHasher instance, with
// Create a new Hasher instance, with
// a random salt length of 32 bytes.
const hasher = new JsonHasher(32);
const hasher = new Hasher(32);

// Hashes the incoming object
const hashed = await hasher.hash(obj);
Expand All @@ -38,12 +38,12 @@ async function program(obj: any): Promise<void> {
In cases when you need to use an existing salt (as a `Buffer`), you can give that as a constructor parameter:

```ts
import { JsonHasher } from 'argon2-json-hasher';
import { Hasher } from 'argon2-hasher';

// A function that receive an object and the salt
async function program(obj: any, salt: Buffer): Promise<void> {
// Create a new JsonHasher instance with an existing salt
const hasher = new JsonHasher(salt);
// Create a new Hasher instance with an existing salt
const hasher = new Hasher(salt);

// Hashes the incoming object
const hashed = await hasher.hash(obj);
Expand All @@ -60,15 +60,15 @@ If you need to check if 2 complex objects are the same, you can use this library


```ts
import { JsonHasher } from 'argon2-json-hasher';
import { Hasher } from 'argon2-hasher';

// A function that receive an object
async function program(objA: any, objB: any): Promise<void> {
// Create a new JsonHasher instance
const hasher = new JsonHasher(32);
// Create a new Hasher instance
const hasher = new Hasher(32);

// Compare both objects (the result is an boolean)
const areEqual = await hasher.areEqual(objA, objB);
const areEqual = await hasher.compare(objA, objB);

// Use that boolean as you want
if (areEqual) {
Expand All @@ -79,29 +79,64 @@ async function program(objA: any, objB: any): Promise<void> {
}
```

## Save your configuration
## Save and load your configuration

If you want to save the configuration of your current instance, now you have the `HasherFile` class for that purpose:

```ts
import { JsonHasher, HasherFile } from 'argon2-json-hasher';
### Save configuration

With an instance of `HasherFile` you can save the Hasher current configuration simply using a single method:

// Create an instance to manage your configuration file
const hasherFile = new HasherFile('./secret.argon2');
```ts
import { Hasher, HasherFile } from 'argon2-hasher';

// An async function with the program
async function program(): Promise<void> {
// Here's your JsonHasher instance
const originalHasher = new JsonHasher(32, {
// A Hasher instance with a custom configuration
const originalHasher = new Hasher(32, {
hashLength: 256,
memoryCost: 3660
});

// To save your current configuration:
// Create a new instance to manage your configuration file
const hasherFile = new HasherFile('./secret.argon2');

// Save the current configuration
await hasherFile.save(originalHasher);
}
```

### Load configuration

With `HasherFile` you have 2 ways to load the configuration. One way is using an instance of `HasherFile`:

```ts
import { Hasher, HasherFile } from 'argon2-hasher';

// An async function with the program
async function program(): Promise<void> {
// The configuration manager
const hasherFile = new HasherFile('./secret.argon2');

// Load the current configuration
const hasher = await hasherFile.load();

// To load the configuration:
const theSameHasher = await hasherFile.load();
// Now you can hash everything
const hashed = hasher.hash('jajAJjajaj');
}
```

...or using the static method of the same class:

```ts
import { Hasher, HasherFile } from 'argon2-hasher';

// An async function with the program
async function program(): Promise<void> {
// Load the current configuration using the static method
const hasher = await HasherFile.load('./secret.argon2');

// Now you can hash everything
const hashed = hasher.hash('jajAJjajaj');
}
```
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "argon2-hasher",
"version": "0.1.0",
"version": "0.1.1",
"description": "This is a wrapper for argon2 npm module, for making mass hashing generation and comparing objects.",
"main": "dist/index.js",
"scripts": {
Expand All @@ -26,6 +26,7 @@
"recursive"
],
"author": "sleep-written",
"license": "MIT",
"devDependencies": {
"@types/chai": "^4.3.0",
"@types/mocha": "^9.1.0",
Expand Down
3 changes: 0 additions & 3 deletions src/get-type/index.ts

This file was deleted.

13 changes: 13 additions & 0 deletions src/hasher-file/file-not-found-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export class FileNotFoundError extends Error {
constructor(path?: string) {
super();

if (path) {
this.message = `The configuration file with path "${path}" `
+ 'wasn\'t not found.';
} else {
this.message = `The configuration file requested `
+ 'wasn\'t not found.';
}
}
}
41 changes: 30 additions & 11 deletions src/hasher-file/hasher-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import { access, readFile, writeFile } from 'fs/promises';
import { resolve } from 'path';

import { Hasher, Options, Variants } from '../hasher';
import { FileNotFoundError } from './file-not-found-error';

export class HasherFile {
static load(path: string): Promise<Hasher> {
const file = new HasherFile(path);
return file.load();
}

private _path: string;
get path(): string {
return this._path;
Expand Down Expand Up @@ -38,8 +44,12 @@ export class HasherFile {
try {
await access(this._path);
return true;
} catch {
return false;
} catch (err: any) {
if (err.code === 'ENOENT') {
return false;
} else {
throw err;
}
}
}

Expand All @@ -64,15 +74,24 @@ export class HasherFile {
}

async load(): Promise<Hasher> {
const byte = await readFile(this._path);
const opts: Partial<Options> = {};
opts.type = this._bufferToNumber(byte, 0, 1);
opts.hashLength = this._bufferToNumber(byte, (8 * 0) + 1, 8);
opts.memoryCost = this._bufferToNumber(byte, (8 * 1) + 1, 8);
opts.parallelism = this._bufferToNumber(byte, (8 * 2) + 1, 8);
opts.timeCost = this._bufferToNumber(byte, (8 * 3) + 1, 8);
try {
const byte = await readFile(this._path);
const opts: Partial<Options> = {};
opts.type = this._bufferToNumber(byte, 0, 1);
opts.hashLength = this._bufferToNumber(byte, (8 * 0) + 1, 8);
opts.memoryCost = this._bufferToNumber(byte, (8 * 1) + 1, 8);
opts.parallelism = this._bufferToNumber(byte, (8 * 2) + 1, 8);
opts.timeCost = this._bufferToNumber(byte, (8 * 3) + 1, 8);

const salt = byte.slice((8 * 4) + 1);
return new Hasher(salt, opts);

const salt = byte.slice((8 * 4) + 1);
return new Hasher(salt, opts);
} catch (err: any) {
if (err.code === 'ENOENT') {
throw new FileNotFoundError(this._path);
} else {
throw err;
}
}
}
}
1 change: 1 addition & 0 deletions src/hasher-file/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { HasherFile } from './hasher-file';
export { FileNotFoundError } from './file-not-found-error';
25 changes: 23 additions & 2 deletions src/hasher/hasher.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { assert } from 'chai';
import { randomBytes } from 'crypto';
import { Hasher } from './hasher';

describe('Testing "./hasher"', () => {
describe('Hash operations', () => {
it('Hash "jajaja"', async () => {
const input = 'jajaja';
it('Hash randomBytes(32)', async () => {
const input = randomBytes(32);
const hasher = new Hasher(64);
const hashed = await hasher.hash(input);

assert.isTrue(await Hasher.verify(hashed, input));
assert.isFalse(await Hasher.verify(hashed, randomBytes(32)));
});

it('Hash "The cake is a lie"', async () => {
Expand All @@ -17,6 +19,25 @@ describe('Testing "./hasher"', () => {
const hashed = await hasher.hash(input);

assert.isTrue(await Hasher.verify(hashed, input));
assert.isFalse(await Hasher.verify(hashed, 'the cake is a lie'));
});

it("Hash [ 5, 6, 5, 6, 4 ]", async () => {
const input = [ 5, 6, 5, 6, 4 ];
const hasher = new Hasher(64);
const hashed = await hasher.hash(input);

assert.isTrue(await Hasher.verify(hashed, input));
assert.isFalse(await Hasher.verify(hashed, [ 5, 6, 5, 6, 5 ]));
});

it("Hash { id: 66, value: 'JajajJA' }", async () => {
const input = { id: 66, value: 'JajajJA' };
const hasher = new Hasher(64);
const hashed = await hasher.hash(input);

assert.isTrue(await Hasher.verify(hashed, input));
assert.isFalse(await Hasher.verify(hashed, { id: 66, value: 'JajajJa' }));
});
});

Expand Down
35 changes: 26 additions & 9 deletions src/hasher/hasher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ export class Hasher {
};
}

static verify(digested: string, input: string | Buffer): Promise<boolean>;
static verify(hashed: Hashed, input: string | Buffer): Promise<boolean>;
static verify(arg: string | Hashed, input: string | Buffer): Promise<boolean> {
static verify(digested: string, input: any): Promise<boolean>;
static verify(hashed: Hashed, input: any): Promise<boolean>;
static verify(arg: string | Hashed, input: any): Promise<boolean> {
// Process the hashed object or the digest
let digested: string;
if (arg instanceof HasherResponse) {
digested = arg.digest();
Expand All @@ -47,7 +48,19 @@ export class Hasher {
throw new InvalidHashParamError();
}

return verify(digested, input);
// Process the input parameter
let rawInput: Buffer;
if (Buffer.isBuffer(input)) {
rawInput = input;
} else if (typeof input === 'string') {
rawInput = Buffer.from(input, 'utf-8');
} else {
const str = stringify(input);
rawInput = Buffer.from(str, 'utf-8');
}

// Execute the real verify method
return verify(digested, rawInput);
}

async compare(a: any, b: any): Promise<boolean> {
Expand All @@ -60,12 +73,15 @@ export class Hasher {
return Buffer.compare(hashedA.hash, hashedB.hash) === 0;
}

async hash(input: string | Buffer): Promise<Hashed> {
async hash(input: any): Promise<Hashed> {
let value: Buffer;
if (typeof input === 'string') {
if (Buffer.isBuffer(input)) {
value = input;
} else if (typeof input === 'string') {
value = Buffer.from(input, 'utf-8');
} else {
value = input;
const str = stringify(input);
value = Buffer.from(str, 'utf-8');
}

const byte = await hash(value, {
Expand All @@ -78,8 +94,9 @@ export class Hasher {
return new HasherResponse(byte, this._salt, this._options);
}

verify(hash: Buffer, input: string | Buffer): Promise<boolean> {
verify(hash: Buffer, input: any): Promise<boolean> {
const hashed = new HasherResponse(hash, this._salt, this._options);
return verify(hashed.digest(), input);
const digest = hashed.digest();
return verify(digest, input);
}
}
11 changes: 6 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export { HasherFile } from './hasher-file';
export { UnsupportedTypeError } from './get-type';
export * from './hasher';
export * from './hasher-file';

export {
Hasher, Hashed, Options,
Variants, InvalidHashParamError
} from './hasher';
InputTypes,
getInputType,
UnsupportedTypeError
} from './stringify';
Loading

0 comments on commit 281ebf6

Please sign in to comment.