Skip to content

Commit

Permalink
docs: adding doc blocks for auth package (#874)
Browse files Browse the repository at this point in the history
  • Loading branch information
manchuck authored Dec 4, 2023
1 parent c97d081 commit 0d33646
Show file tree
Hide file tree
Showing 20 changed files with 421 additions and 79 deletions.
111 changes: 93 additions & 18 deletions packages/auth/lib/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { tokenGenerate, GeneratorOptions } from '@vonage/jwt';
import { createHash, createHmac } from 'crypto';
import { existsSync, readFileSync } from 'fs';
import { PathLike, existsSync, readFileSync } from 'fs';
import {
AuthParams,
AuthQueryParams,
Expand All @@ -22,11 +22,37 @@ import debug from 'debug';
const log = debug('vonage:auth');

export class Auth implements AuthInterface {
/**
* @property {string} apiKey - The API key used for authentication.
*/
apiKey: string;

/**
* @property {string} apiSecret - The API secret used for authentication.
*/
apiSecret: string;
privateKey?: string;
applicationId?: string;
signature: SignedHashParams;

/**
* @property {string | null} [privateKey] - The private key used for JWT
* authentication, either as a string or read from a file.
*/
privateKey?: string | null;

/**
* @property {string | null} [applicationId] - The application ID used for
* JWT authentication.
*/
applicationId?: string | null;

/**
* @property {SignedHashParams | null} [signature] - The signature parameters
* used for signature authentication.
*/
signature?: SignedHashParams | null;

/**
* @property {GeneratorOptions} jwtOptions - Options used for generating JWTs.
*/
jwtOptions: GeneratorOptions;

constructor(opts?: AuthParams) {
Expand All @@ -36,17 +62,34 @@ export class Auth implements AuthInterface {
this.applicationId = opts?.applicationId || null;
this.jwtOptions = opts?.jwtOptions || {};

if (existsSync(opts.privateKey)) {
let privateKey = opts?.privateKey;
if (existsSync(opts?.privateKey as PathLike)) {
log('Reading private key file');
opts.privateKey = readFileSync(opts.privateKey).toString();
privateKey = readFileSync(opts?.privateKey as PathLike).toString();
}

this.privateKey
= opts.privateKey instanceof Buffer
? opts.privateKey.toString()
: opts.privateKey;
= privateKey instanceof Buffer
? privateKey.toString()
: (opts?.privateKey as string);
}

/**
* Generates query parameters for authentication, optionally merging with
* provided parameters.
*
*
* @param {T} [params] - Additional parameters to merge with the
* generated authentication query parameters.
*
* @return {Promise<AuthQueryParams>} - A promise that resolves
* with the merged authentication query parameters.
*
* @throws {MissingApiKeyError} - Thrown when the API key is missing.
* @throws {MissingApiSecretError} - Thrown when the API secret is missing.
* @throws {InvalidApiKeyError} - Thrown when the API key is not a valid string.
* @throws {InvalidApiSecretError} - Thrown when the API secret is not a valid string.
*/
getQueryParams = async <T>(
params?: AuthQueryParams & T,
): Promise<AuthQueryParams & T> => {
Expand All @@ -70,9 +113,20 @@ export class Auth implements AuthInterface {
...params,
api_key: this.apiKey,
api_secret: this.apiSecret,
};
} as AuthQueryParams & T;
};

/**
* Generates a basic authentication header.
*
* @return {Promise<string>} - A promise that resolves with the
* generated basic authentication header.
*
* @throws {MissingApiKeyError} - Thrown when the API key is missing.
* @throws {MissingApiSecretError} - Thrown when the API secret is missing.
* @throws {InvalidApiKeyError} - Thrown when the API key is not a valid string.
* @throws {InvalidApiSecretError} - Thrown when the API secret is not a valid string.
*/
createBasicHeader = async (): Promise<string> => {
log('Creating basic auth header');
if (!this.apiKey) {
Expand All @@ -95,15 +149,38 @@ export class Auth implements AuthInterface {
return `Basic ${buf.toString('base64')}`;
};

/**
* Generates a bearer authentication header.
*
* @return {Promise<string>} - A promise that resolves with the
* generated bearer authentication header.
*/
createBearerHeader = async (): Promise<string> => {
log('Creating bearer header');
return `Bearer ${tokenGenerate(
this.applicationId,
this.privateKey,
this.applicationId || '',
this.privateKey || '',
this.jwtOptions,
)}`;
};

/**
* Generates a signature hash for authentication, merging it with
* provided parameters.
*
* @template T - Type of the parameters to merge with.
* @param {T} params - Parameters to merge with the generated
* signature hash.
* @return {Promise<AuthSignedParams>} - A promise that resolves
* with the merged signature hash and parameters.
*
* @throws {MissingApiKeyError} - Thrown when the API key is missing.
* @throws {InvalidApiKeyError} - Thrown when the API key is not a valid string.
* @throws {MissingSignatureError} - Thrown when the signature algorithm is missing.
* @throws {MissingApiSecretError} - Thrown when the API secret is missing.
* @throws {InvalidApiSecretError} - Thrown when the API secret is not a valid string.
* @throws {InvalidSignatureAlgorithmError} - Thrown when an invalid signature algorithm is provided.
*/
createSignatureHash = async <T>(
params: AuthSignedParams & T,
): Promise<AuthSignedParams & T> => {
Expand All @@ -116,15 +193,15 @@ export class Auth implements AuthInterface {
throw new InvalidApiKeyError();
}

if (!this.signature.algorithm) {
if (!this.signature?.algorithm) {
throw new MissingSignatureError();
}

if (!this.signature.secret) {
if (!this.signature?.secret) {
throw new MissingApiSecretError();
}

if (typeof this.signature.secret !== 'string') {
if (typeof this.signature?.secret !== 'string') {
throw new InvalidApiSecretError();
}

Expand All @@ -150,9 +227,7 @@ export class Auth implements AuthInterface {
switch (this.signature.algorithm) {
case AlgorithmTypes.md5hash:
returnParams.sig = createHash('md5')
.update(
`${stringifiedParamsforSigning}${this.signature.secret}`,
)
.update(`${stringifiedParamsforSigning}${this.signature.secret}`)

Check failure

Code scanning / CodeQL

Use of a broken or weak cryptographic algorithm High

A broken or weak cryptographic algorithm
depends on
sensitive data from an access to secret
.
.digest('hex');
break;

Expand Down
32 changes: 27 additions & 5 deletions packages/auth/lib/enums/AlgroithmTypes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
/**
* Enumeration of supported algorithm types for HMAC hashing.
*
* @enum {string}
*
* @property {string} md5hash - Represents the MD5 hash algorithm.
*
* @property {string} md5hmac - Represents the HMAC-MD5 hash algorithm,
* which uses a secret key for hashing.
*
* @property {string} sha1hmac - Represents the HMAC-SHA1 hash algorithm,
* which uses a secret key for hashing.
*
* @property {string} sha256hmac - Represents the HMAC-SHA256 hash algorithm,
* which uses a secret key for hashing.
*
* @property {string} sha512hmac - Represents the HMAC-SHA512 hash algorithm,
* which uses a secret key for hashing.
*
* Note: Ensure to select an algorithm that adheres to your security
* requirements and is supported by the API endpoint you're interacting with.
*/
export enum AlgorithmTypes {
md5hash = 'MD5HASH',
md5hmac = 'MD5HMAC',
sha1hmac = 'SHA1HMAC',
sha256hmac = 'SHA256HMAC',
sha512hmac = 'SHA512HMAC',
md5hash = 'MD5HASH',
md5hmac = 'MD5HMAC',
sha1hmac = 'SHA1HMAC',
sha256hmac = 'SHA256HMAC',
sha512hmac = 'SHA512HMAC',
}
14 changes: 14 additions & 0 deletions packages/auth/lib/errors/InvalidApiKeyError.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
/**
* Error class representing a specific error scenario where an API key is
* provided but is not a valid string.
*
* This error is thrown when an API request is made with an API key that
* does not meet the expected format or type (string).
*
* @extends {Error}
*
* @example
* if (typeof apiKey !== 'string') {
* throw new InvalidApiKeyError();
* }
*/
export class InvalidApiKeyError extends Error {
constructor() {
super('API Key must be a string');
Expand Down
14 changes: 14 additions & 0 deletions packages/auth/lib/errors/InvalidApiSecretError.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
/**
* Error class representing a specific error scenario where an API secret is
* provided but is not a valid string.
*
* This error is thrown when an API request is made with an API secret that
* does not meet the expected format or type (string).
*
* @extends {Error}
*
* @example
* if (typeof apiSecret !== 'string') {
* throw new InvalidApiSecretError();
* }
*/
export class InvalidApiSecretError extends Error {
constructor() {
super('API Secret must be a string');
Expand Down
14 changes: 14 additions & 0 deletions packages/auth/lib/errors/InvalidSignatureAlgroithmError.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
/**
* Error class representing a specific error scenario where an invalid
* signature algorithm is provided.
*
* This error is thrown when an API request is made with a signature
* algorithm that is not supported or recognized.
*
* @extends {Error}
*
* @example
* if (!isAlgorithmSupported(algorithm)) {
* throw new InvalidSignatureAlgorithmError();
* }
*/
export class InvalidSignatureAlgorithmError extends Error {
constructor() {
super('Invalid Signature algorithm');
Expand Down
16 changes: 15 additions & 1 deletion packages/auth/lib/errors/InvalidSignatureError.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
export class InvalidSignatureAlgorithmError extends Error {
/**
* Error class representing a specific error scenario where a user selects
* an invalid or unsupported signature algorithm.
*
* This error is thrown when an API request is made with a signature
* algorithm that is not present in the AlgorithmTypes enum.
*
* @extends {Error}
*
* @example
* if (!Object.values(AlgorithmTypes).includes(algorithm)) {
* throw new InvalidSignatureError();
* }
*/
export class InvalidSignatureError extends Error {
constructor() {
super('Invalid Signature algorithm');
}
Expand Down
14 changes: 14 additions & 0 deletions packages/auth/lib/errors/MissingApiKeyError.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
/**
* Error class representing a specific error scenario where an API key is
* missing in the request.
*
* This error is thrown when an API request is made without providing the
* necessary API key for authentication.
*
* @extends {Error}
*
* @example
* if (!apiKey) {
* throw new MissingApiKeyError();
* }
*/
export class MissingApiKeyError extends Error {
constructor() {
super('Missing API Key');
Expand Down
14 changes: 14 additions & 0 deletions packages/auth/lib/errors/MissingApiSecretError.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
/**
* Error class representing a specific error scenario where an API secret is
* missing in the request.
*
* This error is thrown when an API request is made without providing the
* necessary API secret for authentication.
*
* @extends {Error}
*
* @example
* if (!apiSecret) {
* throw new MissingApiSecretError();
* }
*/
export class MissingApiSecretError extends Error {
constructor() {
super('Missing API Secret');
Expand Down
18 changes: 18 additions & 0 deletions packages/auth/lib/errors/MissingSignatureError.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
/**
* Error class representing a specific error scenario where a signature
* algorithm is expected but missing in the request.
*
* This error is thrown when an API request is made without providing the
* necessary signature algorithm for authentication.
*
* Users should select a value from the AlgorithmTypes enum.
*
* @extends {Error}
*
* @example
* if (!signatureAlgorithm) {
* throw new MissingSignatureError();
* }
*
* @see {@link AlgorithmTypes}
*/
export class MissingSignatureError extends Error {
constructor() {
super('Missing signature algorithm');
Expand Down
7 changes: 0 additions & 7 deletions packages/auth/lib/interfaces/AuthConstructor.ts

This file was deleted.

Loading

0 comments on commit 0d33646

Please sign in to comment.