@@ -27,106 +27,109 @@ https://github.com/DWTechs/Hashitaka.js
2727import { getHashes , timingSafeEqual , createHmac , pbkdf2Sync , randomBytes } from 'node:crypto' ;
2828import { isBase64 , isString , isValidInteger , isIn } from '@dwtechs/checkard' ;
2929
30- const HASHITAKA_PREFIX = "Hashitaka: " ;
30+ const HASHITAKA_PREFIX = "Hashitaka - " ;
31+ function chainMessage ( message , err ) {
32+ return `${ message } - caused by: ${ err . message } ` ;
33+ }
3134class HashitakaError extends Error {
32- constructor ( message ) {
33- super ( message ) ;
34- this . name = this . constructor . name ;
35+ constructor ( message , causedBy ) {
36+ super ( causedBy ? chainMessage ( message , causedBy ) : message ) ;
37+ this . name = ` ${ HASHITAKA_PREFIX } ${ this . constructor . name } ` ;
3538 if ( Error . captureStackTrace )
3639 Error . captureStackTrace ( this , this . constructor ) ;
3740 }
3841}
3942class HashLengthMismatchError extends HashitakaError {
40- constructor ( message = ` ${ HASHITAKA_PREFIX } Hashes must have the same byte length to be compared` ) {
43+ constructor ( message = " Hashes must have the same byte length to be compared" ) {
4144 super ( message ) ;
4245 this . code = "HASH_LENGTH_MISMATCH" ;
4346 this . statusCode = 400 ;
4447 }
4548}
4649class InvalidBase64ToDecodeError extends HashitakaError {
47- constructor ( urlSafe ) {
48- const message = `${ HASHITAKA_PREFIX } Invalid base64 ${ urlSafe ? 'URL-safe' : 'non URL-safe' } string to decode` ;
49- super ( message ) ;
50+ constructor ( urlSafe , causedBy ) {
51+ const message = `Invalid base64 ${ urlSafe ? 'URL-safe' : 'non URL-safe' } string to decode` ;
52+ super ( message , causedBy ) ;
5053 this . code = "INVALID_BASE64_TO_DECODE" ;
5154 this . statusCode = 400 ;
5255 }
5356}
5457class InvalidStringToEncodeError extends HashitakaError {
55- constructor ( ) {
56- const message = ` ${ HASHITAKA_PREFIX } Invalid string to encode in base64` ;
57- super ( message ) ;
58+ constructor ( causedBy ) {
59+ const message = " Invalid string to encode in base64" ;
60+ super ( message , causedBy ) ;
5861 this . code = "INVALID_STRING_TO_ENCODE" ;
5962 this . statusCode = 400 ;
6063 }
6164}
6265class InvalidStringToCompareError extends HashitakaError {
63- constructor ( ) {
64- const message = ` ${ HASHITAKA_PREFIX } Invalid string for hash comparison` ;
65- super ( message ) ;
66+ constructor ( causedBy ) {
67+ const message = " Invalid string for hash comparison" ;
68+ super ( message , causedBy ) ;
6669 this . code = "INVALID_STRING_TO_COMPARE" ;
6770 this . statusCode = 400 ;
6871 }
6972}
7073class InvalidHashToCompareError extends HashitakaError {
71- constructor ( ) {
72- const message = ` ${ HASHITAKA_PREFIX } Invalid hash for comparison` ;
73- super ( message ) ;
74+ constructor ( causedBy ) {
75+ const message = " Invalid hash for comparison" ;
76+ super ( message , causedBy ) ;
7477 this . code = "INVALID_HASH_TO_COMPARE" ;
7578 this . statusCode = 400 ;
7679 }
7780}
7881class InvalidSaltRoundsError extends HashitakaError {
79- constructor ( min , max ) {
80- const message = `${ HASHITAKA_PREFIX } Invalid salt rounds, must be between ${ min } and ${ max } ` ;
81- super ( message ) ;
82+ constructor ( min , max , causedBy ) {
83+ const message = `Invalid salt rounds, must be between ${ min } and ${ max } ` ;
84+ super ( message , causedBy ) ;
8285 this . code = "INVALID_SALT_ROUNDS" ;
8386 this . statusCode = 400 ;
8487 }
8588}
8689class InvalidKeyLengthError extends HashitakaError {
87- constructor ( min , max ) {
88- const message = `${ HASHITAKA_PREFIX } Invalid key length, must be between ${ min } and ${ max } ` ;
89- super ( message ) ;
90+ constructor ( min , max , causedBy ) {
91+ const message = `Invalid key length, must be between ${ min } and ${ max } ` ;
92+ super ( message , causedBy ) ;
9093 this . code = "INVALID_KEY_LENGTH" ;
9194 this . statusCode = 400 ;
9295 }
9396}
9497class InvalidDigestFunctionError extends HashitakaError {
95- constructor ( ) {
96- const message = ` ${ HASHITAKA_PREFIX } Invalid hash digest function` ;
97- super ( message ) ;
98+ constructor ( causedBy ) {
99+ const message = " Invalid hash digest function" ;
100+ super ( message , causedBy ) ;
98101 this . code = "INVALID_DIGEST_FUNCTION" ;
99102 this . statusCode = 400 ;
100103 }
101104}
102105class HmacCreationError extends HashitakaError {
103- constructor ( ) {
104- const message = ` ${ HASHITAKA_PREFIX } Failed to create HMAC hash` ;
105- super ( message ) ;
106+ constructor ( causedBy ) {
107+ const message = " Failed to create HMAC hash" ;
108+ super ( message , causedBy ) ;
106109 this . code = "HMAC_CREATION_FAILED" ;
107110 this . statusCode = 500 ;
108111 }
109112}
110113class Pbkdf2DerivationError extends HashitakaError {
111- constructor ( ) {
112- const message = ` ${ HASHITAKA_PREFIX } Failed to derive key using PBKDF2` ;
113- super ( message ) ;
114+ constructor ( causedBy ) {
115+ const message = " Failed to derive key using PBKDF2" ;
116+ super ( message , causedBy ) ;
114117 this . code = "PBKDF2_DERIVATION_FAILED" ;
115118 this . statusCode = 500 ;
116119 }
117120}
118121class InvalidStringToEncryptError extends HashitakaError {
119- constructor ( ) {
120- const message = ` ${ HASHITAKA_PREFIX } Invalid string to encrypt` ;
121- super ( message ) ;
122+ constructor ( causedBy ) {
123+ const message = " Invalid string to encrypt" ;
124+ super ( message , causedBy ) ;
122125 this . code = "INVALID_STRING_TO_ENCRYPT" ;
123126 this . statusCode = 400 ;
124127 }
125128}
126129class InvalidSecretToEncryptError extends HashitakaError {
127- constructor ( ) {
128- const message = ` ${ HASHITAKA_PREFIX } Invalid base64 secret for encryption` ;
129- super ( message ) ;
130+ constructor ( causedBy ) {
131+ const message = " Invalid base64 secret for encryption" ;
132+ super ( message , causedBy ) ;
130133 this . code = "INVALID_SECRET_TO_ENCRYPT" ;
131134 this . statusCode = 400 ;
132135 }
@@ -137,9 +140,7 @@ function b64Decode(str, urlSafe = true) {
137140 isBase64 ( str , urlSafe , true ) ;
138141 }
139142 catch ( err ) {
140- const e = new InvalidBase64ToDecodeError ( urlSafe ) ;
141- e . cause = err ;
142- throw e ;
143+ throw new InvalidBase64ToDecodeError ( urlSafe , err ) ;
143144 }
144145 if ( urlSafe )
145146 str = str . replace ( / - / g, "+" ) . replace ( / _ / g, "/" ) ;
@@ -150,9 +151,7 @@ function b64Encode(str, urlSafe = true) {
150151 isString ( str , "!0" , null , true ) ;
151152 }
152153 catch ( err ) {
153- const e = new InvalidStringToEncodeError ( ) ;
154- e . cause = err ;
155- throw e ;
154+ throw new InvalidStringToEncodeError ( err ) ;
156155 }
157156 let b64 = Buffer . from ( str ) . toString ( "base64" ) ;
158157 if ( urlSafe )
@@ -192,9 +191,7 @@ function setSaltRounds(rnds) {
192191 isValidInteger ( rnds , MIN_SALT_RNDS , MAX_SALT_RNDS , true , true ) ;
193192 }
194193 catch ( err ) {
195- const e = new InvalidSaltRoundsError ( MIN_SALT_RNDS , MAX_SALT_RNDS ) ;
196- e . cause = err ;
197- throw e ;
194+ throw new InvalidSaltRoundsError ( MIN_SALT_RNDS , MAX_SALT_RNDS , err ) ;
198195 }
199196 saltRnds = rnds ;
200197 return true ;
@@ -207,9 +204,7 @@ function setKeyLen(len) {
207204 isValidInteger ( len , MIN_KEY_LEN , MAX_KEY_LEN , true , true ) ;
208205 }
209206 catch ( err ) {
210- const e = new InvalidKeyLengthError ( MIN_KEY_LEN , MAX_KEY_LEN ) ;
211- e . cause = err ;
212- throw e ;
207+ throw new InvalidKeyLengthError ( MIN_KEY_LEN , MAX_KEY_LEN , err ) ;
213208 }
214209 keyLen = len ;
215210 return true ;
@@ -222,9 +217,7 @@ function setDigest(func) {
222217 isIn ( digests , func , undefined , true ) ;
223218 }
224219 catch ( err ) {
225- const e = new InvalidDigestFunctionError ( ) ;
226- e . cause = err ;
227- throw e ;
220+ throw new InvalidDigestFunctionError ( err ) ;
228221 }
229222 digest = func ;
230223 return true ;
@@ -237,9 +230,7 @@ function hash(str, secret) {
237230 return createHmac ( digest , secret ) . update ( str ) . digest ( "base64url" ) ;
238231 }
239232 catch ( err ) {
240- const e = new HmacCreationError ( ) ;
241- e . cause = err ;
242- throw e ;
233+ throw new HmacCreationError ( err ) ;
243234 }
244235}
245236function randomSalt ( ) {
@@ -250,28 +241,22 @@ function pbkdf2(str, secret, salt) {
250241 return pbkdf2Sync ( hash ( str , secret ) , salt , saltRnds , keyLen , digest ) ;
251242 }
252243 catch ( err ) {
253- const e = new Pbkdf2DerivationError ( ) ;
254- e . cause = err ;
255- throw e ;
244+ throw new Pbkdf2DerivationError ( err ) ;
256245 }
257246}
258247function encrypt ( str , b64Secret ) {
259248 try {
260249 isString ( str , "!0" , null , true ) ;
261250 }
262251 catch ( err ) {
263- const e = new InvalidStringToEncryptError ( ) ;
264- e . cause = err ;
265- throw e ;
252+ throw new InvalidStringToEncryptError ( err ) ;
266253 }
267254 let secret ;
268255 try {
269256 secret = b64Decode ( b64Secret , true ) ;
270257 }
271258 catch ( err ) {
272- const e = new InvalidSecretToEncryptError ( ) ;
273- e . cause = err ;
274- throw e ;
259+ throw new InvalidSecretToEncryptError ( err ) ;
275260 }
276261 const salt = randomSalt ( ) ;
277262 return salt + pbkdf2 ( str , secret , salt ) . toString ( "hex" ) ;
@@ -282,17 +267,13 @@ function compare(str, hash, b64Secret, urlSafe = false) {
282267 isString ( str , "!0" , null , true ) ;
283268 }
284269 catch ( err ) {
285- const e = new InvalidStringToCompareError ( ) ;
286- e . cause = err ;
287- throw e ;
270+ throw new InvalidStringToCompareError ( err ) ;
288271 }
289272 try {
290273 isString ( hash , "!0" , null , true ) ;
291274 }
292275 catch ( err ) {
293- const e = new InvalidHashToCompareError ( ) ;
294- e . cause = err ;
295- throw e ;
276+ throw new InvalidHashToCompareError ( err ) ;
296277 }
297278 const secret = b64Decode ( b64Secret , urlSafe ) ;
298279 const salt = hash . slice ( 0 , 32 ) ;
0 commit comments