Skip to content

Commit 0bff27f

Browse files
committed
fix(typescript): add explicit type annotations and fix ESLint errors 🔥
1 parent 4f50d9e commit 0bff27f

File tree

10 files changed

+124
-95
lines changed

10 files changed

+124
-95
lines changed

eslint.config.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,21 @@ export default [
142142
'@typescript-eslint/restrict-template-expressions': 'error',
143143
'@typescript-eslint/strict-boolean-expressions': 'error',
144144

145+
// Explicit type definitions
146+
'@typescript-eslint/typedef': [
147+
'error',
148+
{
149+
'arrowParameter': true,
150+
'variableDeclaration': true,
151+
'variableDeclarationIgnoreFunction': false,
152+
'memberVariableDeclaration': true,
153+
'objectDestructuring': true,
154+
'parameter': true,
155+
'propertyDeclaration': true,
156+
'arrayDestructuring': true
157+
}
158+
],
159+
145160
// Naming conventions
146161
'@typescript-eslint/naming-convention': [
147162
'error',

src/algorithms/AES128GCM.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createCipheriv, createDecipheriv } from 'node:crypto'
1+
import { createCipheriv, createDecipheriv, type CipherGCM, type DecipherGCM } from 'node:crypto'
22
import { ErrorHandler } from '@utils/index'
33
import type { TokenEncrypted, EncryptionAlgo, IEncryptionAlgo } from '@interfaces/index'
44

@@ -8,7 +8,7 @@ import type { TokenEncrypted, EncryptionAlgo, IEncryptionAlgo } from '@interface
88
*/
99
export default class AES128GCM implements IEncryptionAlgo {
1010
/** Algorithm name constant */
11-
private readonly algorithm = 'aes-128-gcm'
11+
private readonly algorithm: string = 'aes-128-gcm'
1212

1313
/**
1414
* Encrypts data using AES-128-GCM
@@ -19,11 +19,11 @@ export default class AES128GCM implements IEncryptionAlgo {
1919
* @returns Object containing encrypted data, IV, and authentication tag
2020
*/
2121
encrypt(data: string, key: Buffer, iv: Buffer, version: string): TokenEncrypted {
22-
const cipher = createCipheriv(this.algorithm, key, iv)
22+
const cipher: CipherGCM = createCipheriv(this.algorithm, key, iv) as CipherGCM
2323
cipher.setAAD(Buffer.from(`secure-jwt-${version}`, 'utf8'))
24-
let encrypted = cipher.update(data, 'utf8', 'hex')
24+
let encrypted: string = cipher.update(data, 'utf8', 'hex')
2525
encrypted += cipher.final('hex')
26-
const tag = cipher.getAuthTag()
26+
const tag: Buffer = cipher.getAuthTag()
2727
ErrorHandler.validateAuthTag(tag)
2828
return {
2929
encrypted,
@@ -40,10 +40,14 @@ export default class AES128GCM implements IEncryptionAlgo {
4040
* @returns Decrypted string data
4141
*/
4242
decrypt(tokenEncrypted: TokenEncrypted, key: Buffer, version: string): string {
43-
const decipher = createDecipheriv(this.algorithm, key, Buffer.from(tokenEncrypted.iv, 'hex'))
43+
const decipher: DecipherGCM = createDecipheriv(
44+
this.algorithm,
45+
key,
46+
Buffer.from(tokenEncrypted.iv, 'hex')
47+
) as DecipherGCM
4448
decipher.setAAD(Buffer.from(`secure-jwt-${version}`, 'utf8'))
4549
decipher.setAuthTag(Buffer.from(tokenEncrypted.tag, 'hex'))
46-
let decrypted = decipher.update(tokenEncrypted.encrypted, 'hex', 'utf8')
50+
let decrypted: string = decipher.update(tokenEncrypted.encrypted, 'hex', 'utf8')
4751
decrypted += decipher.final('utf8')
4852
return decrypted
4953
}
@@ -69,6 +73,6 @@ export default class AES128GCM implements IEncryptionAlgo {
6973
* @returns Algorithm name string
7074
*/
7175
getAlgoName(): EncryptionAlgo {
72-
return this.algorithm
76+
return this.algorithm as EncryptionAlgo
7377
}
7478
}

src/algorithms/AES256GCM.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createCipheriv, createDecipheriv } from 'node:crypto'
1+
import { createCipheriv, createDecipheriv, type CipherGCM, type DecipherGCM } from 'node:crypto'
22
import { ErrorHandler } from '@utils/index'
33
import type { TokenEncrypted, EncryptionAlgo, IEncryptionAlgo } from '@interfaces/index'
44

@@ -8,7 +8,7 @@ import type { TokenEncrypted, EncryptionAlgo, IEncryptionAlgo } from '@interface
88
*/
99
export default class AES256GCM implements IEncryptionAlgo {
1010
/** Algorithm name constant */
11-
private readonly algorithm = 'aes-256-gcm'
11+
private readonly algorithm: string = 'aes-256-gcm'
1212

1313
/**
1414
* Encrypts data using AES-256-GCM
@@ -19,11 +19,11 @@ export default class AES256GCM implements IEncryptionAlgo {
1919
* @returns Object containing encrypted data, IV, and authentication tag
2020
*/
2121
encrypt(data: string, key: Buffer, iv: Buffer, version: string): TokenEncrypted {
22-
const cipher = createCipheriv(this.algorithm, key, iv)
22+
const cipher: CipherGCM = createCipheriv(this.algorithm, key, iv) as CipherGCM
2323
cipher.setAAD(Buffer.from(`secure-jwt-${version}`, 'utf8'))
24-
let encrypted = cipher.update(data, 'utf8', 'hex')
24+
let encrypted: string = cipher.update(data, 'utf8', 'hex')
2525
encrypted += cipher.final('hex')
26-
const tag = cipher.getAuthTag()
26+
const tag: Buffer = cipher.getAuthTag()
2727
ErrorHandler.validateAuthTag(tag)
2828
return {
2929
encrypted,
@@ -40,10 +40,14 @@ export default class AES256GCM implements IEncryptionAlgo {
4040
* @returns Decrypted string data
4141
*/
4242
decrypt(tokenEncrypted: TokenEncrypted, key: Buffer, version: string): string {
43-
const decipher = createDecipheriv(this.algorithm, key, Buffer.from(tokenEncrypted.iv, 'hex'))
43+
const decipher: DecipherGCM = createDecipheriv(
44+
this.algorithm,
45+
key,
46+
Buffer.from(tokenEncrypted.iv, 'hex')
47+
) as DecipherGCM
4448
decipher.setAAD(Buffer.from(`secure-jwt-${version}`, 'utf8'))
4549
decipher.setAuthTag(Buffer.from(tokenEncrypted.tag, 'hex'))
46-
let decrypted = decipher.update(tokenEncrypted.encrypted, 'hex', 'utf8')
50+
let decrypted: string = decipher.update(tokenEncrypted.encrypted, 'hex', 'utf8')
4751
decrypted += decipher.final('utf8')
4852
return decrypted
4953
}
@@ -69,6 +73,6 @@ export default class AES256GCM implements IEncryptionAlgo {
6973
* @returns Algorithm name string
7074
*/
7175
getAlgoName(): EncryptionAlgo {
72-
return this.algorithm
76+
return this.algorithm as EncryptionAlgo
7377
}
7478
}

src/algorithms/ChaCha20.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createCipheriv, createDecipheriv } from 'node:crypto'
1+
import { createCipheriv, createDecipheriv, type CipherGCM, type DecipherGCM } from 'node:crypto'
22
import { ErrorHandler } from '@utils/index'
33
import type { TokenEncrypted, EncryptionAlgo, IEncryptionAlgo } from '@interfaces/index'
44

@@ -8,7 +8,7 @@ import type { TokenEncrypted, EncryptionAlgo, IEncryptionAlgo } from '@interface
88
*/
99
export default class ChaCha20 implements IEncryptionAlgo {
1010
/** Algorithm name constant */
11-
private readonly algorithm = 'chacha20-poly1305'
11+
private readonly algorithm: string = 'chacha20-poly1305'
1212

1313
/**
1414
* Encrypts data using ChaCha20-Poly1305
@@ -19,11 +19,11 @@ export default class ChaCha20 implements IEncryptionAlgo {
1919
* @returns Object containing encrypted data, IV, and authentication tag
2020
*/
2121
encrypt(data: string, key: Buffer, iv: Buffer, version: string): TokenEncrypted {
22-
const cipher = createCipheriv(this.algorithm, key, iv)
22+
const cipher: CipherGCM = createCipheriv(this.algorithm, key, iv) as CipherGCM
2323
cipher.setAAD(Buffer.from(`secure-jwt-${version}`, 'utf8'), { plaintextLength: data.length })
24-
let encrypted = cipher.update(data, 'utf8', 'hex')
24+
let encrypted: string = cipher.update(data, 'utf8', 'hex')
2525
encrypted += cipher.final('hex')
26-
const tag = cipher.getAuthTag()
26+
const tag: Buffer = cipher.getAuthTag()
2727
ErrorHandler.validateAuthTag(tag)
2828
return {
2929
encrypted,
@@ -40,12 +40,16 @@ export default class ChaCha20 implements IEncryptionAlgo {
4040
* @returns Decrypted string data
4141
*/
4242
decrypt(tokenEncrypted: TokenEncrypted, key: Buffer, version: string): string {
43-
const decipher = createDecipheriv(this.algorithm, key, Buffer.from(tokenEncrypted.iv, 'hex'))
43+
const decipher: DecipherGCM = createDecipheriv(
44+
this.algorithm,
45+
key,
46+
Buffer.from(tokenEncrypted.iv, 'hex')
47+
) as DecipherGCM
4448
decipher.setAAD(Buffer.from(`secure-jwt-${version}`, 'utf8'), {
4549
plaintextLength: tokenEncrypted.encrypted.length / 2
4650
})
4751
decipher.setAuthTag(Buffer.from(tokenEncrypted.tag, 'hex'))
48-
let decrypted = decipher.update(tokenEncrypted.encrypted, 'hex', 'utf8')
52+
let decrypted: string = decipher.update(tokenEncrypted.encrypted, 'hex', 'utf8')
4953
decrypted += decipher.final('utf8')
5054
return decrypted
5155
}
@@ -71,6 +75,6 @@ export default class ChaCha20 implements IEncryptionAlgo {
7175
* @returns Algorithm name string
7276
*/
7377
getAlgoName(): EncryptionAlgo {
74-
return this.algorithm
78+
return this.algorithm as EncryptionAlgo
7579
}
7680
}

src/algorithms/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export default class Algorithms {
2525
* @returns Buffer containing derived key
2626
*/
2727
static getDerivedKeyBasic(secret: string): Buffer {
28-
const salt = this.getRandomBytes(32)
28+
const salt: Buffer = this.getRandomBytes(32)
2929
return Buffer.concat([salt, Buffer.from(secret, 'utf8')])
3030
}
3131

@@ -36,7 +36,7 @@ export default class Algorithms {
3636
* @returns Buffer containing derived key
3737
*/
3838
static getDerivedKeyPBKDF2(secret: string, iterations: number = 50000): Buffer {
39-
const salt = this.getRandomBytes(32)
39+
const salt: Buffer = this.getRandomBytes(32)
4040
return pbkdf2Sync(secret, salt, iterations, 32, 'sha256')
4141
}
4242

src/index.ts

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ export default class SecureJWT {
9292
*/
9393
private encrypt(data: string): TokenEncrypted {
9494
ErrorHandler.validateEncryptionData(data)
95-
const keyLength = this.#algorithm.getKeyLength()
96-
const key = this.#secret.subarray(0, keyLength)
95+
const keyLength: number = this.#algorithm.getKeyLength()
96+
const key: Buffer = this.#secret.subarray(0, keyLength)
9797
ErrorHandler.validateKeyLength(key)
98-
const iv = Algorithms.getRandomBytes(this.#algorithm.getIVLength())
98+
const iv: Buffer = Algorithms.getRandomBytes(this.#algorithm.getIVLength())
9999
return this.#algorithm.encrypt(data, key, iv, this.#version)
100100
}
101101

@@ -107,8 +107,8 @@ export default class SecureJWT {
107107
private decrypt(tokenEncrypted: TokenEncrypted): string {
108108
try {
109109
ErrorHandler.validateTokenEncrypted(tokenEncrypted)
110-
const keyLength = this.#algorithm.getKeyLength()
111-
const key = this.#secret.subarray(0, keyLength)
110+
const keyLength: number = this.#algorithm.getKeyLength()
111+
const key: Buffer = this.#secret.subarray(0, keyLength)
112112
ErrorHandler.validateKeyLength(key)
113113
ErrorHandler.validateIVFormat(tokenEncrypted.iv)
114114
ErrorHandler.validateTagFormat(tokenEncrypted.tag)
@@ -131,18 +131,18 @@ export default class SecureJWT {
131131
sign(data: unknown): string {
132132
try {
133133
ErrorHandler.validateData(data)
134-
const now = Math.floor(Date.now() / 1000)
135-
const exp = now + (this.#expireInMs < 1000 ? 1 : Math.ceil(this.#expireInMs / 1000))
134+
const now: number = Math.floor(Date.now() / 1000)
135+
const exp: number = now + (this.#expireInMs < 1000 ? 1 : Math.ceil(this.#expireInMs / 1000))
136136
ErrorHandler.validateExpiration(exp, now + 365 * 24 * 60 * 60)
137137
const payload: PayloadData = {
138138
data,
139139
exp,
140140
iat: now,
141141
version: this.#version
142142
}
143-
const payloadString = JSON.stringify(payload)
143+
const payloadString: string = JSON.stringify(payload)
144144
ErrorHandler.validatePayloadSize(payloadString)
145-
const tokenEncrypted = this.encrypt(payloadString)
145+
const tokenEncrypted: TokenEncrypted = this.encrypt(payloadString)
146146
const tokenData: TokenData = {
147147
encrypted: tokenEncrypted.encrypted,
148148
iv: tokenEncrypted.iv,
@@ -151,7 +151,7 @@ export default class SecureJWT {
151151
iat: now,
152152
version: this.#version
153153
}
154-
const tokenString = JSON.stringify(tokenData)
154+
const tokenString: string = JSON.stringify(tokenData)
155155
return Buffer.from(tokenString).toString('base64')
156156
} catch (error) {
157157
if (
@@ -174,19 +174,19 @@ export default class SecureJWT {
174174
*/
175175
verify(token: string): boolean {
176176
try {
177-
const cachedResult = this.#verifyCache.get(token)
177+
const cachedResult: boolean | undefined = this.#verifyCache.get(token)
178178
if (cachedResult !== undefined) {
179179
return cachedResult
180180
}
181-
const tokenData = this.validateAndParseToken(token)
181+
const tokenData: TokenData = this.validateAndParseToken(token)
182182
const tokenEncrypted: TokenEncrypted = {
183183
encrypted: tokenData.encrypted,
184184
iv: tokenData.iv,
185185
tag: tokenData.tag
186186
}
187-
const decryptedPayload = this.decrypt(tokenEncrypted)
188-
const payload = ErrorHandler.validateJSONParse<PayloadData>(
189-
decryptedPayload,
187+
const payloadDecrypted: string = this.decrypt(tokenEncrypted)
188+
const payload: PayloadData = ErrorHandler.validateJSONParse<PayloadData>(
189+
payloadDecrypted,
190190
getErrorMessage('INVALID_PAYLOAD_STRUCTURE')
191191
)
192192
if (!isValidPayloadData(payload)) {
@@ -213,15 +213,15 @@ export default class SecureJWT {
213213
* @throws {VersionMismatchError} When token version is incompatible
214214
*/
215215
verifyStrict(token: string): void {
216-
const tokenData = this.validateAndParseToken(token)
216+
const tokenData: TokenData = this.validateAndParseToken(token)
217217
const tokenEncrypted: TokenEncrypted = {
218218
encrypted: tokenData.encrypted,
219219
iv: tokenData.iv,
220220
tag: tokenData.tag
221221
}
222-
const decryptedPayload = this.decrypt(tokenEncrypted)
223-
const payload = ErrorHandler.validateJSONParse<PayloadData>(
224-
decryptedPayload,
222+
const payloadDecrypted: string = this.decrypt(tokenEncrypted)
223+
const payload: PayloadData = ErrorHandler.validateJSONParse<PayloadData>(
224+
payloadDecrypted,
225225
getErrorMessage('INVALID_PAYLOAD_STRUCTURE')
226226
)
227227
if (!isValidPayloadData(payload)) {
@@ -243,19 +243,19 @@ export default class SecureJWT {
243243
*/
244244
decode(token: string): unknown {
245245
try {
246-
const cachedResult = this.#payloadCache.get(token)
246+
const cachedResult: unknown = this.#payloadCache.get(token)
247247
if (cachedResult !== undefined) {
248248
return cachedResult
249249
}
250-
const tokenData = this.validateAndParseToken(token)
250+
const tokenData: TokenData = this.validateAndParseToken(token)
251251
const tokenEncrypted: TokenEncrypted = {
252252
encrypted: tokenData.encrypted,
253253
iv: tokenData.iv,
254254
tag: tokenData.tag
255255
}
256-
const decryptedPayload = this.decrypt(tokenEncrypted)
257-
const payload = ErrorHandler.validateJSONParse<PayloadData>(
258-
decryptedPayload,
256+
const payloadDecrypted: string = this.decrypt(tokenEncrypted)
257+
const payload: PayloadData = ErrorHandler.validateJSONParse<PayloadData>(
258+
payloadDecrypted,
259259
getErrorMessage('INVALID_PAYLOAD_STRUCTURE')
260260
)
261261
if (!isValidPayloadData(payload)) {
@@ -293,11 +293,11 @@ export default class SecureJWT {
293293
private validateAndParseToken(token: string): TokenData {
294294
ErrorHandler.validateToken(token)
295295
ErrorHandler.validateTokenIntegrity(token)
296-
const decoded = ErrorHandler.validateBase64Decode(
296+
const decoded: string = ErrorHandler.validateBase64Decode(
297297
token,
298298
getErrorMessage('INVALID_TOKEN_FORMAT')
299299
)
300-
const tokenData = ErrorHandler.validateJSONParse<TokenData>(
300+
const tokenData: TokenData = ErrorHandler.validateJSONParse<TokenData>(
301301
decoded,
302302
getErrorMessage('INVALID_TOKEN_STRUCTURE')
303303
)

0 commit comments

Comments
 (0)