Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
manchuck committed Nov 2, 2023
1 parent d069e28 commit adc9545
Show file tree
Hide file tree
Showing 76 changed files with 1,933 additions and 968 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@
"error",
{
"code": 80,
"comments": 120,
"ignoreUrls": true,
"ignoreTemplateLiterals": true,
"ignoreRegExpLiterals": true,
"ignorePattern": "^import.+|test"
"ignorePattern": "^import.+|test|@"
}
]
}
Expand Down
5 changes: 0 additions & 5 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,6 @@ const config: Config.InitialOptions = {
testMatch: ['<rootDir>/packages/verify2/__tests__/**/*.test.ts'],
coveragePathIgnorePatterns: ['node_modules', '__tests__'],
},
{
displayName: 'VETCH',
testMatch: ['<rootDir>/packages/vetch/__tests__/**/*.test.ts'],
coveragePathIgnorePatterns: ['node_modules', '__tests__'],
},
{
displayName: 'VIDEO',
testMatch: ['<rootDir>/packages/video/__tests__/**/*.test.ts'],
Expand Down
179 changes: 93 additions & 86 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,90 +1,97 @@
{
"name": "@vonage/server-sdk-monorepo",
"private": true,
"description": "Vonage Server SDK for Node.js. API support for SMS, Voice Calls, Text-to-Speech, Numbers, Verify (2FA) and more.",
"keywords": [
"sms",
"voice",
"vonage",
"verify",
"2fa",
"phone numbers"
"$schema": "https://json.schemastore.org/package.json",
"name": "@vonage/server-sdk-monorepo",
"private": true,
"description": "Vonage Server SDK for Node.js. API support for SMS, Voice Calls, Text-to-Speech, Numbers, Verify (2FA) and more.",
"keywords": [
"sms",
"voice",
"vonage",
"verify",
"2fa",
"phone numbers"
],
"homepage": "https://github.com/vonage/vonage-node-sdk",
"repository": {
"type": "git",
"url": "git://github.com/vonage/vonage-node-sdk.git"
},
"license": "Apache 2.0",
"author": "vonage",
"contributors": [
"kellyjandrews"
],
"workspaces": [
"packages/*"
],
"scripts": {
"bootstrap": "npx lerna bootstrap",
"build": "lerna run build",
"clean": "lerna run clean",
"compile": "lerna run compile",
"depcheck": "lerna exec --no-bail --stream --prefix npx depcheck -- --ignore-dirs=dist",
"eslint": "eslint",
"format": "prettier -- -w",
"jest": "jest",
"lerna": "lerna",
"lint": "eslint .",
"lint:fix": "eslint -- . --fix",
"prepare": "is-ci || husky install",
"publish": "lerna publish",
"test": "jest",
"test:watch": "jest --watch",
"tsc": "tsc"
},
"lint-staged": {
"package.json": [
"npx sort-package-json"
],
"homepage": "https://github.com/vonage/vonage-node-sdk",
"repository": {
"type": "git",
"url": "git://github.com/vonage/vonage-node-sdk.git"
},
"license": "Apache 2.0",
"author": "vonage",
"contributors": [
"kellyjandrews"
"*.js": [
"prettier -w",
"eslint --fix"
],
"workspaces": [
"packages/*"
],
"scripts": {
"bootstrap": "npx lerna bootstrap",
"build": "lerna run build",
"clean": "lerna run clean",
"compile": "lerna run compile",
"depcheck": "lerna exec --no-bail --stream --prefix npx depcheck -- --ignore-dirs=dist",
"eslint": "eslint",
"format": "prettier -- -w",
"jest": "jest",
"lerna": "lerna",
"lint": "eslint .",
"lint:fix": "eslint -- . --fix",
"prepare": "is-ci || husky install",
"publish": "lerna publish",
"test": "jest",
"test:watch": "jest --watch",
"tsc": "tsc"
},
"lint-staged": {
"package.json": [
"npx sort-package-json"
],
"*.js": [
"prettier -w",
"eslint --fix"
],
"*.ts": [
"prettier -w",
"eslint --fix"
]
},
"devDependencies": {
"@babel/core": "7.23.2",
"@babel/plugin-transform-modules-commonjs": "^7.23.0",
"@babel/plugin-transform-typescript": "7.22.15",
"@babel/preset-env": "7.23.2",
"@babel/preset-typescript": "7.23.2",
"@babel/types": "^7.23.0",
"@types/jest": "^29.5.5",
"@types/node": "^20.8.4",
"@typescript-eslint/eslint-plugin": "6.7.5",
"@typescript-eslint/parser": "6.7.5",
"babel-jest": "29.7.0",
"babel-plugin-module-resolver": "5.0.0",
"eslint": "8.51.0",
"eslint-config-google": "0.14.0",
"eslint-config-prettier": "9.0.0",
"eslint-plugin-deprecation": "2.0.0",
"eslint-plugin-jest": "27.4.2",
"eslint-plugin-jest-extended": "2.0.0",
"eslint-plugin-jest-formatting": "3.1.0",
"eslint-plugin-prettier": "5.0.1",
"husky": "^8.0.3",
"is-ci": "3.0.1",
"jest": "^29.7.0",
"lerna": "^7.3.1",
"lerna-changelog": "^2.2.0",
"lint-staged": "14.0.1",
"nock": "^13.3.4",
"prettier": "3.0.3",
"prettier-eslint": "15.0.1",
"ts-node-dev": "^2.0.0",
"typescript": "^5.2.2"
}
"*.ts": [
"prettier -w",
"eslint --fix"
]
},
"devDependencies": {
"@babel/core": "7.22.5",
"@babel/plugin-transform-modules-commonjs": "^7.22.5",
"@babel/plugin-transform-typescript": "7.22.15",
"@babel/preset-env": "7.22.5",
"@babel/preset-typescript": "7.22.5",
"@babel/types": "^7.22.5",
"@tsconfig/node16": "16.1.1",
"@types/jest": "^29.5.5",
"@types/node": "^20.8.4",
"@typescript-eslint/eslint-plugin": "6.7.5",
"@typescript-eslint/parser": "6.7.5",
"babel-jest": "29.7.0",
"babel-plugin-module-resolver": "5.0.0",
"eslint": "8.51.0",
"eslint-config-google": "0.14.0",
"eslint-config-prettier": "9.0.0",
"eslint-plugin-deprecation": "2.0.0",
"eslint-plugin-jest": "27.4.2",
"eslint-plugin-jest-extended": "2.0.0",
"eslint-plugin-jest-formatting": "3.1.0",
"eslint-plugin-prettier": "5.0.1",
"husky": "^8.0.3",
"is-ci": "3.0.1",
"jest": "^29.7.0",
"lerna": "^7.3.1",
"lerna-changelog": "^2.2.0",
"lint-staged": "14.0.1",
"nock": "^13.3.4",
"prettier": "3.0.3",
"prettier-eslint": "15.0.1",
"ts-node-dev": "^2.0.0",
"typedoc": "0.25.2",
"typedoc-plugin-merge-modules": "5.1.0",
"typescript": "^5.1.3"
},
"dependencies": {
"@droppedcode/typedoc-plugin-copy-assets": "1.0.10"
}
}
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}`)
.digest('hex');
break;

Expand Down
Loading

0 comments on commit adc9545

Please sign in to comment.