-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat(json-hash): add new package json-hash
- Loading branch information
1 parent
955db95
commit e57fc53
Showing
4 changed files
with
273 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
"name": "json-hash", | ||
"version": "1.0.0", | ||
"description": "Hash JS objects reliablly on both Node.js and browser", | ||
"main": "dist/index.js", | ||
"scripts": { | ||
"build": "node ../../scripts/esbuild.config.js", | ||
"build:watch": "bash ../../scripts/esbuild.watch.sh", | ||
"bump-version": "bash ../../scripts/bump-version.sh --name=@sliit-foss/json-hash", | ||
"lint": "bash ../../scripts/lint.sh", | ||
"release": "bash ../../scripts/release.sh", | ||
"test": "bash ../../scripts/test/test.sh" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/sliit-foss/npm-catalogue.git" | ||
}, | ||
"dependencies": { | ||
"json-stable-stringify": "1.1.1" | ||
}, | ||
"devDependencies": { | ||
"lodash": "4.17.10" | ||
}, | ||
"keywords": [ | ||
"json", | ||
"hash", | ||
"hashing", | ||
"object-hash" | ||
], | ||
"author": "SLIIT FOSS", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/sliit-foss/npm-catalogue/issues" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
export const algos = { | ||
"SHA-1": "sha1", | ||
"SHA-256": "sha256", | ||
"SHA-384": "sha384", | ||
"SHA-512": "sha512" | ||
}; | ||
|
||
export const getNodeJSAlgoName = (algorithm) => { | ||
return algos[algorithm]; | ||
}; | ||
|
||
export const isAvailableAlgo = (algorithm) => { | ||
if (Object.prototype.hasOwnProperty.call(algos, algorithm)) { | ||
return true; | ||
} | ||
|
||
return false; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { getNodeJSAlgoName, isAvailableAlgo } from "./algorithms.js"; | ||
|
||
export const computeHash = async (obj, { algorithm = "SHA-1", sort = false }) => { | ||
if (!isAvailableAlgo(algorithm)) { | ||
throw new Error("Provided algorithm is not available"); | ||
} | ||
|
||
if (typeof obj !== "string") { | ||
if (sort) { | ||
const { default: stringify } = await import("json-stable-stringify"); | ||
obj = stringify(obj); | ||
} else { | ||
obj = JSON.stringify(obj); | ||
} | ||
} | ||
|
||
// For browser | ||
// eslint-disable-next-line no-undef | ||
if (typeof window !== "undefined" && window.crypto && window.crypto.subtle) { | ||
const msgUint8 = new TextEncoder().encode(obj); // encode as (utf-8) Uint8Array | ||
|
||
// eslint-disable-next-line no-undef | ||
const hashBuffer = await window.crypto.subtle.digest(algorithm, msgUint8); // hash data | ||
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array | ||
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join(""); // convert bytes to hex string | ||
return hashHex; | ||
} | ||
|
||
// For Node.js | ||
if (typeof global !== "undefined" && global.crypto) { | ||
const { createHash } = await import("crypto"); | ||
const hash = createHash(getNodeJSAlgoName(algorithm)).update(obj).digest("hex"); | ||
return hash; | ||
} | ||
}; | ||
|
||
// (async () => { | ||
// const obj = { name: "John", age: 30 }; | ||
// const algorithm = "SHA-256"; | ||
|
||
// try { | ||
// const hash = await computeHash(obj, { algorithm, sort: true }); | ||
// console.log(`Hash (${algorithm}):`, hash); | ||
// } catch (error) { | ||
// console.error(error); | ||
// } | ||
// })(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
import { cloneDeep } from "lodash"; | ||
import { computeHash } from "../src"; | ||
import { getNodeJSAlgoName, isAvailableAlgo } from "../src/algorthms"; | ||
|
||
describe("json-hash-node-js", () => { | ||
const objectToHash = { name: "Siri", age: 30, country: "Sri Lanka" }; | ||
|
||
beforeAll(() => { | ||
global.unit_tests_running = true; | ||
}); | ||
|
||
afterAll(() => { | ||
global.unit_tests_running = false; | ||
}); | ||
|
||
//tests for getNodeJSAlgoName | ||
it("should-get-node-js-algo-name", () => { | ||
expect(getNodeJSAlgoName("SHA-1")).toBe("sha1"); | ||
expect(getNodeJSAlgoName("SHA-256")).toBe("sha256"); | ||
expect(getNodeJSAlgoName("SHA-384")).toBe("sha384"); | ||
expect(getNodeJSAlgoName("SHA-512")).toBe("sha512"); | ||
}); | ||
|
||
it("should-not-throw-error-for-invalid-algo-name", () => { | ||
expect(getNodeJSAlgoName("NIKE")).toBe(undefined); | ||
expect(getNodeJSAlgoName("")).toBe(undefined); | ||
}); | ||
|
||
//tests for isAvailableAlgo | ||
it("should-return-true-if-algo-name-is-available", () => { | ||
expect(isAvailableAlgo("SHA-1")).toBe(true); | ||
}); | ||
|
||
it("should-return-false-if-algo-name-is-not-available", () => { | ||
expect(isAvailableAlgo("NIKE")).toBe(false); | ||
}); | ||
|
||
// tests for compute hash | ||
|
||
// without sorting | ||
it("should-compute-hash-with-SHA-1", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-1" })).toBe("9edcbfaaba0af491b8f73961416a250655bf483c"); | ||
}); | ||
|
||
it("should-compute-hash-with-SHA-256", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-256" })).toBe( | ||
"f17f5b4a7b8d4f7258cfedff4b78982f6d472d856d1fc1a9da3562d633ffff72" | ||
); | ||
}); | ||
|
||
it("should-compute-hash-with-SHA-384", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-384" })).toBe( | ||
"8096ba11adb69941ad3ff5cbfc8c4b00d9b8d092de640e8abf8b54e1fcb7ddfdeaa3f5df0f03af50ca2648e76ed704b5" | ||
); | ||
}); | ||
|
||
it("should-compute-hash-with-SHA-512", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-512" })).toBe( | ||
"e6dc6e4edb2de44db04a6611ce3bb7127d9c5e93d8cc8c2092fca748db04d676ebf12dd06f6819eb6b7b20f957025e2da490918511adf34775e869e17619180e" | ||
); | ||
}); | ||
|
||
// with sorting | ||
it("should-sort-and-compute-hash-with-SHA-1", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-1", sort: true })).toBe( | ||
"10e3e5df394451377f778d7402b62b5134dca39a" | ||
); | ||
}); | ||
|
||
it("should-sort-and-compute-hash-with-SHA-256", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-256", sort: true })).toBe( | ||
"37d0042f1f11c95c8563b530cc8769d4229ef48b5a31f763e2f841783216d6f2" | ||
); | ||
}); | ||
|
||
it("should-sort-and-compute-hash-with-SHA-384", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-384", sort: true })).toBe( | ||
"f43ccfc81ea4e92fc11bed100e7cd82a665ad359faf91ff666e51a947cba8a7c5e3931ed6e7cebaef1a66b4b3c0c5d41" | ||
); | ||
}); | ||
|
||
it("should-sort-and-compute-hash-with-SHA-512", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-512", sort: true })).toBe( | ||
"f6a03a2a8cf61713c4c2fc3bae86736f6f8322d5271d1c2b3046268871f3d6ca434b1414b910990c9ba2f13cbe629f54646b7430880f1e60a4a899c94f45b6b1" | ||
); | ||
}); | ||
}); | ||
|
||
describe("json-hash-browser", () => { | ||
const window = cloneDeep(global.window); | ||
|
||
const objectToHash = { name: "Siri", age: 30, country: "Sri Lanka" }; | ||
|
||
beforeAll(() => { | ||
global.unit_tests_running = true; | ||
}); | ||
|
||
afterAll(() => { | ||
global.unit_tests_running = false; | ||
}); | ||
|
||
//tests for getNodeJSAlgoName | ||
it("should-get-node-js-algo-name", () => { | ||
expect(getNodeJSAlgoName("SHA-1")).toBe("sha1"); | ||
expect(getNodeJSAlgoName("SHA-256")).toBe("sha256"); | ||
expect(getNodeJSAlgoName("SHA-384")).toBe("sha384"); | ||
expect(getNodeJSAlgoName("SHA-512")).toBe("sha512"); | ||
}); | ||
|
||
it("should-not-throw-error-for-invalid-algo-name", () => { | ||
expect(getNodeJSAlgoName("NIKE")).toBe(undefined); | ||
expect(getNodeJSAlgoName("")).toBe(undefined); | ||
}); | ||
|
||
//tests for isAvailableAlgo | ||
it("should-return-true-if-algo-name-is-available", () => { | ||
expect(isAvailableAlgo("SHA-1")).toBe(true); | ||
}); | ||
|
||
it("should-return-false-if-algo-name-is-not-available", () => { | ||
expect(isAvailableAlgo("NIKE")).toBe(false); | ||
}); | ||
|
||
// tests for compute hash | ||
|
||
// without sorting | ||
it("should-compute-hash-with-SHA-1", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-1" })).toBe("9edcbfaaba0af491b8f73961416a250655bf483c"); | ||
}); | ||
|
||
it("should-compute-hash-with-SHA-256", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-256" })).toBe( | ||
"f17f5b4a7b8d4f7258cfedff4b78982f6d472d856d1fc1a9da3562d633ffff72" | ||
); | ||
}); | ||
|
||
it("should-compute-hash-with-SHA-384", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-384" })).toBe( | ||
"8096ba11adb69941ad3ff5cbfc8c4b00d9b8d092de640e8abf8b54e1fcb7ddfdeaa3f5df0f03af50ca2648e76ed704b5" | ||
); | ||
}); | ||
|
||
it("should-compute-hash-with-SHA-512", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-512" })).toBe( | ||
"e6dc6e4edb2de44db04a6611ce3bb7127d9c5e93d8cc8c2092fca748db04d676ebf12dd06f6819eb6b7b20f957025e2da490918511adf34775e869e17619180e" | ||
); | ||
}); | ||
|
||
// with sorting | ||
it("should-sort-and-compute-hash-with-SHA-1", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-1", sort: true })).toBe( | ||
"10e3e5df394451377f778d7402b62b5134dca39a" | ||
); | ||
}); | ||
|
||
it("should-sort-and-compute-hash-with-SHA-256", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-256", sort: true })).toBe( | ||
"37d0042f1f11c95c8563b530cc8769d4229ef48b5a31f763e2f841783216d6f2" | ||
); | ||
}); | ||
|
||
it("should-sort-and-compute-hash-with-SHA-384", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-384", sort: true })).toBe( | ||
"f43ccfc81ea4e92fc11bed100e7cd82a665ad359faf91ff666e51a947cba8a7c5e3931ed6e7cebaef1a66b4b3c0c5d41" | ||
); | ||
}); | ||
|
||
it("should-sort-and-compute-hash-with-SHA-512", () => { | ||
expect(computeHash(objectToHash, { algorithm: "SHA-512", sort: true })).toBe( | ||
"f6a03a2a8cf61713c4c2fc3bae86736f6f8322d5271d1c2b3046268871f3d6ca434b1414b910990c9ba2f13cbe629f54646b7430880f1e60a4a899c94f45b6b1" | ||
); | ||
}); | ||
}); |