From 28b074571311a626ec49e385588d219101db8660 Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Thu, 25 Apr 2024 16:01:59 +0530 Subject: [PATCH 1/7] changed token for git publish --- .github/workflows/npm-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 900f449c..c3dccf3c 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -31,4 +31,4 @@ jobs: - run: npm ci - run: npm publish --tag latest env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.PKG_TOKEN }} From 3e2716f1e1d3ce522b48a6ed7ac5d33ed50fa014 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Fri, 10 May 2024 16:03:18 +0530 Subject: [PATCH 2/7] fixed sre issue related to beta v4 of JS --- src/lib/query.ts | 144 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 133 insertions(+), 11 deletions(-) diff --git a/src/lib/query.ts b/src/lib/query.ts index 591d741b..7de09cb5 100644 --- a/src/lib/query.ts +++ b/src/lib/query.ts @@ -18,6 +18,24 @@ export class Query extends BaseQuery { this._parameters = { ...this._parameters, ...queryObj }; } } + // Validate if input is alphanumeric + private isValidAlphanumeric(input: string): boolean { + const alphanumericRegex = /^[a-zA-Z0-9_.-]+$/; + return alphanumericRegex.test(input); + } + // Validate if input is a valid regex pattern + private isValidRegexPattern(input: string): boolean { + try { + new RegExp(input); + return true; + } catch (error) { + return false; + } + } + // Validate if value is an array of strings, numbers, or booleans + private isValidValue(value: any[]): boolean { + return Array.isArray(value) && value.every(item => typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean'); + } /** * @method where @@ -40,18 +58,22 @@ export class Query extends BaseQuery { * @returns {Query} */ where( - fieldUid: string, - queryOperation: QueryOperation | TaxonomyQueryOperation, + fieldUid: string, + queryOperation: QueryOperation | TaxonomyQueryOperation, fields: string | string[] | number | number[] | object | boolean, additionalData?: object ): Query { + if (!this.isValidAlphanumeric(fieldUid)) { + console.error("Invalid fieldUid:", fieldUid); + return this; + } if (queryOperation == QueryOperation.EQUALS) { this._parameters[fieldUid] = fields; - } else { + } + else { const parameterValue: { [key in QueryOperation]?: string | string[] } = { [queryOperation]: fields, ...additionalData }; this._parameters[fieldUid] = parameterValue; } - return this; } @@ -70,11 +92,18 @@ export class Query extends BaseQuery { * @returns {Query} */ regex(fieldUid: string, regexPattern: string, options?: string): Query { - this._parameters[fieldUid] = { $regex: regexPattern }; - - if (options) this._parameters[fieldUid].$options = options; - - return this; + if (!this.isValidAlphanumeric(fieldUid)) { + console.error("Invalid fieldUid:", fieldUid); + return this; + } + if (!this.isValidRegexPattern(regexPattern)) { + throw new Error("Invalid regexPattern: Must be a valid regular expression"); + } + else { + this._parameters[fieldUid] = { $regex: regexPattern }; + if (options) this._parameters[fieldUid].$options = options; + return this; + } } /** @@ -95,8 +124,10 @@ export class Query extends BaseQuery { */ whereIn(referenceUid: string, queryInstance: Query): Query { // eslint-disable-next-line @typescript-eslint/naming-convention, prettier/prettier + if (!this.isValidAlphanumeric(referenceUid)) { + throw new Error("Invalid referenceUid: Must be alphanumeric."); + } this._parameters[referenceUid] = { '$in_query': queryInstance._parameters }; - return this; } @@ -118,8 +149,10 @@ export class Query extends BaseQuery { */ whereNotIn(referenceUid: string, queryInstance: Query): Query { // eslint-disable-next-line @typescript-eslint/naming-convention, prettier/prettier + if (!this.isValidAlphanumeric(referenceUid)) { + throw new Error("Invalid referenceUid: Must be alphanumeric."); + } this._parameters[referenceUid] = { '$nin_query': queryInstance._parameters }; - return this; } @@ -183,6 +216,14 @@ export class Query extends BaseQuery { * @returns {Query} */ containedIn(key: string, value: (string | number | boolean)[]): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } + if (!this.isValidValue(value)) { + console.error("Invalid value:", value); + return this; + } this._parameters[key] = { '$in': value }; return this; } @@ -201,6 +242,14 @@ export class Query extends BaseQuery { * @returns {Query} */ notContainedIn(key: string, value: (string | number | boolean)[]): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } + if (!this.isValidValue(value)) { + console.error("Invalid value:", value); + return this; + } this._parameters[key] = { '$nin': value }; return this; } @@ -219,6 +268,10 @@ export class Query extends BaseQuery { * @returns {Query} */ exists(key: string): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } this._parameters[key] = { '$exists': true }; return this; } @@ -237,6 +290,10 @@ export class Query extends BaseQuery { * @returns {Query} */ notExists(key: string): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } this._parameters[key] = { '$exists': false }; return this; } @@ -300,6 +357,14 @@ export class Query extends BaseQuery { * @returns {Query} */ equalTo(key: string, value: string | number | boolean): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } + if (typeof value !== 'string' && typeof value !== 'number') { + console.error("Invalid value (expected string or number):", value); + return this; + } this._parameters[key] = value; return this; } @@ -317,6 +382,14 @@ export class Query extends BaseQuery { * @returns {Query} */ notEqualTo(key: string, value: string | number | boolean): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } + if (typeof value !== 'string' && typeof value !== 'number') { + console.error("Invalid value (expected string or number):", value); + return this; + } this._parameters[key] = { '$ne': value }; return this;; } @@ -335,6 +408,10 @@ export class Query extends BaseQuery { * @returns {Query} */ referenceIn(key: string, query: Query): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } this._parameters[key] = { '$in_query': query._parameters } return this; } @@ -353,6 +430,10 @@ export class Query extends BaseQuery { * @returns {Query} */ referenceNotIn(key: string, query: Query): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } this._parameters[key] = { '$nin_query': query._parameters } return this; } @@ -371,6 +452,10 @@ export class Query extends BaseQuery { * @returns {Query} */ tags(values: (string | number | boolean)[]): Query { + if (!this.isValidValue(values)) { + console.error("Invalid value:", values); + return this; + } this._parameters['tags'] = values; return this; } @@ -389,6 +474,10 @@ export class Query extends BaseQuery { * @returns {Query} */ search(key: string): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } this._queryParams['typeahead'] = key return this } @@ -407,6 +496,15 @@ export class Query extends BaseQuery { * @returns {Query} */ lessThan(key: string, value: (string | number)): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } + if (typeof value !== 'string' && typeof value !== 'number') { + console.error("Invalid value (expected string or number):", value); + return this; + } + this._parameters[key] = { '$lt': value }; return this; } @@ -425,6 +523,14 @@ export class Query extends BaseQuery { * @returns {Query} */ lessThanOrEqualTo(key: string, value: (string | number)): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } + if (typeof value !== 'string' && typeof value !== 'number') { + console.error("Invalid value (expected string or number):", value); + return this; + } this._parameters[key] = { '$lte': value }; return this; } @@ -443,6 +549,14 @@ export class Query extends BaseQuery { * @returns {Query} */ greaterThan(key: string, value: (string | number)): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } + if (typeof value !== 'string' && typeof value !== 'number') { + console.error("Invalid value (expected string or number):", value); + return this; + } this._parameters[key] = { '$gt': value }; return this; } @@ -461,6 +575,14 @@ export class Query extends BaseQuery { * @returns {Query} */ greaterThanOrEqualTo(key: string, value: (string | number)): Query { + if (!this.isValidAlphanumeric(key)) { + console.error("Invalid key:", key); + return this; + } + if (typeof value !== 'string' && typeof value !== 'number') { + console.error("Invalid value (expected string or number):", value); + return this; + } this._parameters[key] = { '$gte': value }; return this; } From 2493df6db976981e7b006812361c0e2441933825 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Fri, 10 May 2024 16:12:03 +0530 Subject: [PATCH 3/7] version bump --- CHANGELOG.md | 3 +++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89120515..f14e3e32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## Change log +### Version: 4.0.1 +#### Date: May-20-2024 +Fixed SRE vulnerabilities ### Version: 4.0.0 #### Date: April-23-2024 diff --git a/package-lock.json b/package-lock.json index 4fee30b3..b0b49f52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@contentstack/delivery-sdk", - "version": "4.0.0", + "version": "4.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@contentstack/delivery-sdk", - "version": "4.0.0", + "version": "4.0.1", "dependencies": { "@contentstack/core": "^1.0.1", "@contentstack/utils": "^1.3.3", diff --git a/package.json b/package.json index 0bb08b10..f1898d10 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/delivery-sdk", - "version": "4.0.0", + "version": "4.0.1", "type": "commonjs", "main": "./dist/cjs/src/index.js", "types": "./dist/types/src/index.d.ts", From c2c6681a04fdf1e92205c5d685cf0fb75a88a8c5 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Fri, 10 May 2024 16:43:23 +0530 Subject: [PATCH 4/7] Minor changes done --- src/lib/query.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/lib/query.ts b/src/lib/query.ts index 7de09cb5..b2cebe53 100644 --- a/src/lib/query.ts +++ b/src/lib/query.ts @@ -25,13 +25,10 @@ export class Query extends BaseQuery { } // Validate if input is a valid regex pattern private isValidRegexPattern(input: string): boolean { - try { - new RegExp(input); - return true; - } catch (error) { - return false; + RegExp(input); + return true; } - } + // Validate if value is an array of strings, numbers, or booleans private isValidValue(value: any[]): boolean { return Array.isArray(value) && value.every(item => typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean'); From 0b546ed08c60f88e011813cb53478a57c8b4eb9d Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Fri, 10 May 2024 16:49:28 +0530 Subject: [PATCH 5/7] changes done --- src/lib/query.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/lib/query.ts b/src/lib/query.ts index b2cebe53..7753b8e0 100644 --- a/src/lib/query.ts +++ b/src/lib/query.ts @@ -25,10 +25,16 @@ export class Query extends BaseQuery { } // Validate if input is a valid regex pattern private isValidRegexPattern(input: string): boolean { - RegExp(input); - return true; + try { + RegExp(input) + return true; } - + catch { + return false; + } + + } + // Validate if value is an array of strings, numbers, or booleans private isValidValue(value: any[]): boolean { return Array.isArray(value) && value.every(item => typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean'); From 410d31ab5cb9f947b4f703c6e13eba9d82e2bb58 Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Fri, 17 May 2024 12:39:02 +0530 Subject: [PATCH 6/7] feat: added x-user-agent in headers --- src/lib/contentstack.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/contentstack.ts b/src/lib/contentstack.ts index d69b57c0..43f54973 100644 --- a/src/lib/contentstack.ts +++ b/src/lib/contentstack.ts @@ -6,6 +6,8 @@ import { Policy, StackConfig } from './types'; import { getHost } from './utils'; export * as Utils from '@contentstack/utils'; +let version = '{{VERSION}}'; + /** * @method stack * @memberof Contentstack @@ -71,6 +73,8 @@ export function stack(config: StackConfig): StackClass { defaultConfig.headers['x-header-ea'] = config.early_access.join(','); } + defaultConfig.headers['X-User-Agent'] = 'contentstack-delivery-typescript-{{PLATFORM}}/' + version; + // return new Stack(httpClient(defaultConfig), config); const client = httpClient(defaultConfig as any); From 9b5db44bb76ee96c78ebcd7362a186947e3279b2 Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Thu, 23 May 2024 11:48:02 +0530 Subject: [PATCH 7/7] feat: branch property in stack config --- src/lib/contentstack.ts | 4 ++++ src/lib/types.ts | 1 + test/api/live-preview.spec.ts | 3 +++ test/unit/contentstack.spec.ts | 2 ++ 4 files changed, 10 insertions(+) diff --git a/src/lib/contentstack.ts b/src/lib/contentstack.ts index 43f54973..57931fb2 100644 --- a/src/lib/contentstack.ts +++ b/src/lib/contentstack.ts @@ -69,6 +69,10 @@ export function stack(config: StackConfig): StackClass { throw new Error('Environment for Stack is required'); } + if (config.branch) { + defaultConfig.headers.branch = config.branch; + } + if (config.early_access) { defaultConfig.headers['x-header-ea'] = config.early_access.join(','); } diff --git a/src/lib/types.ts b/src/lib/types.ts index 5edbd766..c6bf6400 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -14,6 +14,7 @@ export interface StackConfig extends HttpClientParams { apiKey: string; deliveryToken: string; environment: string; + branch?: string; early_access?: string[]; region?: Region; locale?: string; diff --git a/test/api/live-preview.spec.ts b/test/api/live-preview.spec.ts index c45e0cc2..d50835ad 100644 --- a/test/api/live-preview.spec.ts +++ b/test/api/live-preview.spec.ts @@ -7,6 +7,7 @@ dotenv.config(); const apiKey = process.env.API_KEY as string const deliveryToken = process.env.DELIVERY_TOKEN as string const environment = process.env.ENVIRONMENT as string +const branch = process.env.BRANCH as string describe('Live preview tests', () => { test('should check for values initialized', () => { @@ -14,10 +15,12 @@ describe('Live preview tests', () => { apiKey: apiKey, deliveryToken: deliveryToken, environment: environment, + branch: branch, }); const livePreviewObject = stack.config.live_preview; expect(livePreviewObject).toBeUndefined(); expect(stack.config.host).toBe('cdn.contentstack.io'); + expect(stack.config.branch).toBe(branch); }); test('should check host when live preview is enabled and management token is provided', () => { diff --git a/test/unit/contentstack.spec.ts b/test/unit/contentstack.spec.ts index ee8a79c3..9ca04522 100644 --- a/test/unit/contentstack.spec.ts +++ b/test/unit/contentstack.spec.ts @@ -97,12 +97,14 @@ describe('Contentstack', () => { apiKey: 'apiKey', deliveryToken: 'delivery', environment: 'env', + branch: 'branch', }; const stackInstance = createStackInstance(config); expect(stackInstance).toBeInstanceOf(Stack); expect(stackInstance.config.apiKey).toEqual(config.apiKey); expect(stackInstance.config.deliveryToken).toEqual(config.deliveryToken); expect(stackInstance.config.environment).toEqual(config.environment); + expect(stackInstance.config.branch).toEqual(config.branch); done(); });