Skip to content

Commit

Permalink
SK-1621: increase code coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
“amith-skyflow” committed Oct 22, 2024
1 parent ac27df1 commit 5d032f1
Show file tree
Hide file tree
Showing 13 changed files with 634 additions and 317 deletions.
29 changes: 13 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"name": "skyflow-node",
"version": "1.14.0",
"description": "Skyflow SDK for Node.js",
"main": "./lib/index.js",
"module": "./lib/index.js",
"main": "./lib/src/index.js",
"module": "./lib/src/index.js",
"scripts": {
"test": "jest --coverage",
"build": "tsc",
Expand Down Expand Up @@ -35,7 +35,7 @@
"axios": "^1.6.1",
"dotenv": "^16.4.5",
"jsonwebtoken": "^9.0.2",
"jwt-decode": "^4.0.0"
"jwt-decode": "^2.2.0"
},
"devDependencies": {
"@babel/plugin-proposal-decorators": "^7.25.7",
Expand Down
10 changes: 10 additions & 0 deletions src/error/codes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ const SKYFLOW_ERROR_CODE = {
EMPTY_CLUSTER_ID: { http_code: 400, message: errorMessages.EMPTY_CLUSTER_ID },
INVALID_CLUSTER_ID: { http_code: 400, message: errorMessages.INVALID_CLUSTER_ID },

INVALID_BEARER_TOKEN: { http_code: 400, message: errorMessages.INVALID_BEARER_TOKEN },
INVALID_PARSED_CREDENTIALS_STRING: { http_code: 400, message: errorMessages.INVALID_PARSED_CREDENTIALS_STRING },
INVALID_API_KEY: { http_code: 400, message: errorMessages.INVALID_API_KEY },
INVALID_FILE_PATH: { http_code: 400, message: errorMessages.INVALID_FILE_PATH },

INVALID_BEARER_TOKEN_WITH_ID: { http_code: 400, message: errorMessages.INVALID_BEARER_TOKEN_WITH_ID },
INVALID_PARSED_CREDENTIALS_STRING_WITH_ID: { http_code: 400, message: errorMessages.INVALID_PARSED_CREDENTIALS_STRING_WITH_ID },
INVALID_API_KEY_WITH_ID: { http_code: 400, message: errorMessages.INVALID_API_KEY_WITH_ID },
INVALID_FILE_PATH_WITH_ID: { http_code: 400, message: errorMessages.INVALID_FILE_PATH_WITH_ID },

INVALID_TOKEN: { http_code: 400, message: errorMessages.INVALID_TOKEN },
TOKEN_EXPIRED: { http_code: 400, message: errorMessages.TOKEN_EXPIRED },
INVALID_ENV: { http_code: 400, message: errorMessages.INVALID_ENV },
Expand Down
12 changes: 12 additions & 0 deletions src/error/messages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ const errorMessages = {
INVALID_LOG_LEVEL: `${errorPrefix} Initialization failed. Invalid log level. Specify a valid log level.`,
EMPTY_CREDENTIAL_FILE_PATH: `${errorPrefix} Initialization failed. Invalid credentials. Specify a valid file path.`,
INVALID_CREDENTIAL_FILE_PATH: `${errorPrefix} Initialization failed. Invalid credentials. Expected file path to be a string.`,

INVALID_FILE_PATH: `${errorPrefix} Initialization failed. Invalid skyflow credentials. Expected file path to exists.`,
INVALID_API_KEY: `${errorPrefix} Initialization failed. Invalid skyflow credentials. Specify a valid api key.`,
INVALID_PARSED_CREDENTIALS_STRING: `${errorPrefix} Initialization failed. Invalid skyflow credentials. Specify a valid credentials string.`,
INVALID_BEARER_TOKEN: `${errorPrefix} Initialization failed. Invalid skyflow credentials. Specify a valid token.`,

INVALID_FILE_PATH_WITH_ID: `${errorPrefix} Initialization failed. Invalid credentials. Expected file path to exists for %s1 with %s2 %s3.`,
INVALID_API_KEY_WITH_ID: `${errorPrefix} Initialization failed. Invalid credentials. Specify a valid api key for %s1 with %s2 %s3.`,
INVALID_PARSED_CREDENTIALS_STRING_WITH_ID: `${errorPrefix} Initialization failed. Invalid credentials. Specify a valid credentials string for %s1 with %s2 %s3.`,
INVALID_BEARER_TOKEN_WITH_ID: `${errorPrefix} Initialization failed. Invalid credentials. Specify a valid token for %s1 with %s2 %s3.`,

EMPTY_CONNECTION_ID: `${errorPrefix} Initialization failed. Invalid connection ID. Specify a valid connection Id.`,
INVALID_CONNECTION_ID: `${errorPrefix} Initialization failed. Invalid connection ID. Specify connection Id as a string.`,
Expand Down Expand Up @@ -162,6 +172,8 @@ const errorMessages = {

INVALID_ORDER_BY: `${errorPrefix} Validation error. The orderBy key has a value of type %s1. Specify orderBy as string.`,
INVALID_FIELDS: `${errorPrefix} Validation error. The fields key has a value of type %s1. Specify fields as array of strings.`,

INVAILD_JSON_RESPONSE: `${errorPrefix} Validation error. The invalid json response. Please reach out to skyflow using requestId - %s1.`,
};

export default errorMessages;
6 changes: 3 additions & 3 deletions src/utils/jwt-utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { JwtPayload, jwtDecode } from 'jwt-decode';
import jwt_decode, { JwtPayload } from 'jwt-decode';
import { MessageType, printLog } from '..';
import logs from '../logs';

Expand All @@ -13,7 +13,7 @@ function isExpired(token: string) {
return true
}
let isJwtExpired = false;
const decoded: JwtPayload = jwtDecode(token);
const decoded: JwtPayload = jwt_decode(token);
const currentTime = (new Date().getTime() / 1000);
const expiryTime = decoded.exp;
if (expiryTime && currentTime > expiryTime) {
Expand All @@ -26,7 +26,7 @@ function isExpired(token: string) {
function isTokenValid(token: string) {
if (token === "") return false
let isJwtExpired = false;
const decoded: JwtPayload = jwtDecode(token);
const decoded: JwtPayload = jwt_decode(token);
const currentTime = (new Date().getTime() / 1000);
const expiryTime = decoded.exp;
if (expiryTime && currentTime > expiryTime) {
Expand Down
113 changes: 113 additions & 0 deletions src/utils/validations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import QueryRequest from "../../vault/model/request/query";
import TokenizeRequest from "../../vault/model/request/tokenize";
import UpdateRequest from "../../vault/model/request/update";
import { SkyflowConfig, StringKeyValueMapType } from "../../vault/types";
import { isValid } from "../jwt-utils";
import * as fs from 'fs';

export function isEnv(value?: string): boolean {
return value !== undefined && Object.values(Env).includes(value as Env);
Expand All @@ -41,6 +43,45 @@ export function isLogLevel(value?: string): boolean {
return value !== undefined && Object.values(LogLevel).includes(value as LogLevel);
}

function isValidAPIKey(apiKey: string) {
if(!apiKey || apiKey===null || apiKey===undefined){
return false;
}
if(apiKey && typeof apiKey === 'string' && apiKey.startsWith("sky-")){
return true;
}
return false;
};

function isValidCredentialsString(credentialsString: string) {
if(!credentialsString || credentialsString===null || credentialsString===undefined){
return false;
}
if(credentialsString && typeof credentialsString === 'string'){
try {
let credentialsObj = JSON.parse("{}")
credentialsObj = JSON.parse(credentialsString);
if ( credentialsObj?.clientID === null || credentialsObj?.keyID === null || credentialsObj?.clientID === null) {
return false;
}
return true;
} catch(err) {
return false;
}
}
return false;
};

function isValidPath(path: string) {
if(!path || path===null || path===undefined){
return false;
}
if(path && typeof path === 'string' && fs.existsSync(path)){
return true;
}
return false;
};

export const validateSkyflowConfig = (config: SkyflowConfig) => {
if (config) {
if (!Object.prototype.hasOwnProperty.call(config, 'vaultConfigs')) {
Expand Down Expand Up @@ -82,6 +123,22 @@ export const validateCredentialsWithId = (credentials: Credentials, type: string
throw new SkyflowError(SKYFLOW_ERROR_CODE.MULTIPLE_CREDENTIALS_PASSED_WITH_ID, [type, typeId, id]);
}

if (credentials?.token && typeof credentials?.token !== 'string' && !isValid(credentials?.token)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_BEARER_TOKEN_WITH_ID, [type, typeId, id]);
}

if (credentials?.credentialsString && typeof credentials?.credentialsString !== 'string' && !isValidCredentialsString(credentials?.credentialsString)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_PARSED_CREDENTIALS_STRING_WITH_ID, [type, typeId, id]);
}

if (credentials?.apiKey && typeof credentials?.apiKey !== 'string' && !isValidAPIKey(credentials?.apiKey)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_API_KEY_WITH_ID, [type, typeId, id]);
}

if (credentials?.path && typeof credentials?.path !== 'string' && !isValidPath(credentials?.path)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_FILE_PATH_WITH_ID, [type, typeId, id]);
}

};

export const validateVaultConfig = (vaultConfig: VaultConfig) => {
Expand All @@ -105,6 +162,24 @@ export const validateVaultConfig = (vaultConfig: VaultConfig) => {
}
};

export const validateUpdateVaultConfig = (vaultConfig: VaultConfig) => {
if (!Object.prototype.hasOwnProperty.call(vaultConfig, 'vaultId')) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_VAULT_ID);
}
if (!vaultConfig?.vaultId || typeof vaultConfig?.vaultId !== 'string') {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_VAULT_ID);
}
if (vaultConfig?.clusterId && typeof vaultConfig.clusterId !== 'string') {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_CLUSTER_ID, [vaultConfig?.vaultId]);
}
if (vaultConfig?.env && !isEnv(vaultConfig.env)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_ENV, [vaultConfig?.vaultId]);
}
if (vaultConfig?.credentials) {
validateCredentialsWithId(vaultConfig.credentials, VAULT, VAULT_ID, vaultConfig.vaultId);
}
};

export const validateSkyflowCredentials = (credentials: Credentials) => {
const { token, path, credentialsString, apiKey } = credentials;

Expand All @@ -121,6 +196,22 @@ export const validateSkyflowCredentials = (credentials: Credentials) => {
throw new SkyflowError(SKYFLOW_ERROR_CODE.MULTIPLE_CREDENTIALS_PASSED);
}

if (credentials?.token && typeof credentials?.token !== 'string' && !isValid(credentials?.token)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_BEARER_TOKEN);
}

if (credentials?.credentialsString && typeof credentials?.credentialsString !== 'string' && !isValidCredentialsString(credentials?.credentialsString)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_PARSED_CREDENTIALS_STRING);
}

if (credentials?.apiKey && typeof credentials?.apiKey !== 'string' && !isValidAPIKey(credentials?.apiKey)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_API_KEY);
}

if (credentials?.path && typeof credentials?.path !== 'string' && !isValidPath(credentials?.path)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_FILE_PATH);
}

};

export const validateConnectionConfig = (connectionConfig: ConnectionConfig) => {
Expand Down Expand Up @@ -149,6 +240,28 @@ export const validateConnectionConfig = (connectionConfig: ConnectionConfig) =>
}
};

export const validateUpdateConnectionConfig = (connectionConfig: ConnectionConfig) => {
if (!Object.prototype.hasOwnProperty.call(connectionConfig, 'connectionId')) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_CONNECTION_ID);
}

if (typeof connectionConfig?.connectionId !== 'string' || connectionConfig?.connectionId.trim().length === 0) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_CONNECTION_ID);
}

if (connectionConfig?.connectionUrl && (typeof connectionConfig?.connectionUrl !== 'string' || connectionConfig?.connectionUrl.trim().length === 0)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_CONNECTION_URL);
}

if (connectionConfig?.connectionUrl && !isValidURL(connectionConfig.connectionUrl)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_CONNECTION_URL);
}

if (connectionConfig?.credentials) {
validateCredentialsWithId(connectionConfig.credentials, CONNECTION, CONNECTION_ID, connectionConfig.connectionId);
}
};

function validateInsertInput(input: unknown): void {
try {
const inputObject = input as { [key: string]: unknown };
Expand Down
19 changes: 11 additions & 8 deletions src/vault/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,17 @@ class VaultClient {
});

private handleJsonError(err: any, data: any, requestId: string, reject: Function) {
//handle parsing
let description = JSON.parse(JSON.stringify(data));
const statusCode = description?.error?.http_status;
const grpcCode = description?.error?.grpc_code;
const details = description?.error?.details;

description = description?.error?.message || description;
this.logAndRejectError(description, err, requestId, reject, statusCode, grpcCode, details);
try {
let description = JSON.parse(JSON.stringify(data));
const statusCode = description?.error?.http_status;
const grpcCode = description?.error?.grpc_code;
const details = description?.error?.details;

description = description?.error?.message || description;
this.logAndRejectError(description, err, requestId, reject, statusCode, grpcCode, details);
} catch (err) {
this.logAndRejectError(errorMessages.INVAILD_JSON_RESPONSE, err, requestId, reject, 500, undefined, undefined);
}
}

private handleTextError(err: any, data: any, requestId: string, reject: Function) {
Expand Down
Loading

0 comments on commit 5d032f1

Please sign in to comment.