Skip to content

Commit

Permalink
added support of secret variable
Browse files Browse the repository at this point in the history
  • Loading branch information
dev-sharma-08 committed Oct 3, 2023
1 parent bd8a1f1 commit 8167475
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 15 deletions.
2 changes: 1 addition & 1 deletion lib/collection/mutation-tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var _ = require('../util').lodash,
* @returns {Boolean}
*/
isPrimitiveMutation = function (mutation) {
return mutation && mutation.length <= 2;
return mutation && mutation.length <= 3;
},

/**
Expand Down
6 changes: 3 additions & 3 deletions lib/collection/property.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ var _ = require('../util').lodash,
*
* @private
* @param {*} value Any JS variable within which we are trying to discover {{variables}}
* @param {[Object]} seen Set of objects traversed before to avoid infinite recursion
* @param {[Object]} result Set of variables to accumulate result in the recursive call
* @returns {Object} Set of variables
* @param {Object[]} seen Set of objects traversed before to avoid infinite recursion
* @param {Object[]} result Set of variables to accumulate result in the recursive call
* @returns {Object[]} Set of variables
*/
function _findSubstitutions (value, seen = new Set(), result = new Set()) {
if (!value || seen.has(value)) {
Expand Down
57 changes: 51 additions & 6 deletions lib/collection/variable-scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ var _ = require('../util').lodash,
SET: 'set',
UNSET: 'unset'
},

SECRET = 'secret',
DEFAULT = 'default',
VariableScope;

/**
Expand Down Expand Up @@ -219,7 +220,7 @@ _.assign(VariableScope.prototype, /** @lends VariableScope.prototype */ {
*
* @param {String} key - The name of the variable to set.
* @param {*} value - The value of the variable to be set.
* @param {Variable.types} [type] - Optionally, the value of the variable can be set to a type
* @param {'secret' | 'default'} [type] - Optionally, the value of the variable can be set to a type
*/
set: function (key, value, type) {
var variable = this.values.oneNormalizedVariable(key),
Expand All @@ -239,7 +240,15 @@ _.assign(VariableScope.prototype, /** @lends VariableScope.prototype */ {
}

// track the change if mutation tracking is enabled
this._postman_enableTracking && this.mutations.track(MUTATIONS.SET, key, value);
if (this._postman_enableTracking) {
// eslint-disable-next-line security/detect-possible-timing-attacks
if (type === SECRET || type === DEFAULT) {
this.mutations.track(MUTATIONS.SET, key, value, type);
}
else {
this.mutations.track(MUTATIONS.SET, key, value);
}
}
},

/**
Expand Down Expand Up @@ -359,13 +368,14 @@ _.assign(VariableScope.prototype, /** @lends VariableScope.prototype */ {
* @param {String} instruction Instruction identifying the type of the mutation, e.g. `set`, `unset`
* @param {String} key -
* @param {*} value -
* @param {String} type -
*/
applyMutation: function (instruction, key, value) {
applyMutation: function (instruction, key, value, type) {
// we know that `set` and `unset` are the only supported instructions
// and we know the parameter signature of both is the same as the items in a mutation
/* istanbul ignore else */
if (this[instruction]) {
this[instruction](key, value);
this[instruction](key, value, type);
}
},

Expand Down Expand Up @@ -463,6 +473,41 @@ _.assign(VariableScope, /** @lends VariableScope */ {
}
});

/**
* CollectionVariableScope are the variable scope that are defined at the collection level.
*/
class CollectionVariableScope extends VariableScope {
/**
* Creates a new variable, or updates an existing one.
*
* @param {String} key - The name of the variable to set.
* @param {*} value - The value of the variable to be set.
*/
set (key, value) {
var variable = this.values.oneNormalizedVariable(key),

// create an object that will be used as setter
update = { key, value };


// If a variable by the name key exists, update it's value and return.
// @note adds new variable if existing is disabled. Disabled variables are not updated.
if (variable && !variable.disabled) {
variable.update(update);
}
else {
this.values.add(update);
}

// track the change if mutation tracking is enabled
if (this._postman_enableTracking) {
// eslint-disable-next-line security/detect-possible-timing-attacks
this.mutations.track(MUTATIONS.SET, key, value);
}
}
}

module.exports = {
VariableScope
VariableScope,
CollectionVariableScope
};
21 changes: 21 additions & 0 deletions lib/collection/variable.js
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,27 @@ _.assign(Variable, /** @lends Variable */ {
return val; // pass through
},

/**
* @param {*} val -
* @returns {*}
*/
out (val) {
return val; // pass through
}
},

/**
* A "secret" type value stores data as postman secret variables
*/
secret: {
/**
* @param {*} val -
* @returns {*}
*/
in (val) {
return val; // pass through
},

/**
* @param {*} val -
* @returns {*}
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ module.exports = {
Variable: require('./collection/variable').Variable,
VariableList: require('./collection/variable-list').VariableList,
VariableScope: require('./collection/variable-scope').VariableScope,
CollectionVariableScope: require('./collection/variable-scope').CollectionVariableScope,
ProxyConfig: require('./collection/proxy-config').ProxyConfig,
ProxyConfigList: require('./collection/proxy-config-list').ProxyConfigList,
Version: require('./collection/version').Version
Expand Down
4 changes: 2 additions & 2 deletions test/unit/mutation-tracker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ describe('MutationTracker', function () {
it('should not track invalid mutation format', function () {
var tracker = new MutationTracker();

// expected signature is two parameters
tracker.track('set', 'foo', 'bar', 'baz');
// expected signature is three parameters
tracker.track('set', 'foo', 'bar', 'secret', 'baz');

expect(tracker.count()).to.eql(0);
});
Expand Down
52 changes: 52 additions & 0 deletions test/unit/variable-scope.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,30 @@ describe('VariableScope', function () {
expect(scope.mutations.count()).to.equal(1);
});

it('should track set operations with datatype when datatype is secret', function () {
var scope = new VariableScope();

scope.enableTracking();

scope.set('foo', 'bar', 'secret');

expect(scope).to.have.property('mutations');
expect(scope.mutations.count()).to.equal(1);
expect(scope.mutations.stream[0].length).to.equal(3);
});

it('should track set operations without datatype when datatype other than secret', function () {
var scope = new VariableScope();

scope.enableTracking();

scope.set('foo', 'bar', 'string');

expect(scope).to.have.property('mutations');
expect(scope.mutations.count()).to.equal(1);
expect(scope.mutations.stream[0].length).to.equal(2);
});

it('should track unset operations', function () {
var scope = new VariableScope({
values: [{
Expand Down Expand Up @@ -1379,6 +1403,34 @@ describe('VariableScope', function () {
expect(scope1.values).to.eql(scope2.values);
});

it('should be capable of being replayed with secret datatype', function () {
var initialState = {
values: [{
key: 'foo',
value: 'foo'
}, {
key: 'bar',
value: 'bar'
}]
},
scope1 = new VariableScope(initialState),
scope2 = new VariableScope(initialState);

scope1.enableTracking();

// add a new key
scope1.set('baz', 'baz', 'secret');
// update a key
scope1.set('foo', 'foo updated', 'secret');
// remove a key
scope1.unset('bar');

// replay mutations on a different object
scope1.mutations.applyOn(scope2);

expect(scope1.values).to.eql(scope2.values);
});

it('should be serialized', function () {
var scope = new VariableScope(),
serialized,
Expand Down
26 changes: 26 additions & 0 deletions test/unit/variable.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ describe('Variable', function () {
});
});

it('should prepopulate value and type when passed to the constructor (secret)', function () {
let v = new Variable({
value: 'Picard',
type: 'secret'
});

expect(v).to.deep.include({
value: 'Picard',
type: 'secret'
});
});

it('should typecast value during construction when type is provided (number)', function () {
var v = new Variable({
value: '108',
Expand Down Expand Up @@ -227,6 +239,20 @@ describe('Variable', function () {
expect(v.get()).to.equal(jsonValue);
});

it('should support any data type if type is set to `secret`', function () {
var v = new Variable({ type: 'secret' }),
jsonValue = { iam: 'json' };

v.set('Picard');
expect(v.get()).to.equal('Picard');

v.set(3.142);
expect(v.get()).to.equal(3.142);

v.set(jsonValue);
expect(v.get()).to.equal(jsonValue);
});

it('should type cast values to the specific type set', function () {
var v = new Variable({
type: 'string'
Expand Down
22 changes: 19 additions & 3 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Type definitions for postman-collection 4.0.2
// Type definitions for postman-collection 4.2.1
// Project: https://github.com/postmanlabs/postman-collection
// Definitions by: PostmanLabs
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
Expand Down Expand Up @@ -2365,7 +2365,7 @@ declare module "postman-collection" {
* @param value - The value of the variable to be set.
* @param [type] - Optionally, the value of the variable can be set to a type
*/
set(key: string, value: any, type?: Variable.types): void;
set(key: string, value: any, type?: 'secret' | 'default'): void;
/**
* Removes the variable with the specified name.
* @param key - -
Expand Down Expand Up @@ -2402,6 +2402,18 @@ declare module "postman-collection" {
static isVariableScope(obj: any): boolean;
}

/**
* CollectionVariableScope are the variable scope that are defined at the collection level.
*/
export class CollectionVariableScope {
/**
* Creates a new variable, or updates an existing one.
* @param key - The name of the variable to set.
* @param value - The value of the variable to be set.
*/
set(key: string, value: any): void;
}

export namespace Variable {
/**
* The object representation of a Variable consists the variable value and type. It also optionally includes the `id`
Expand Down Expand Up @@ -2456,7 +2468,11 @@ declare module "postman-collection" {
* Free-form type of a value. This is the default for any variable, unless specified otherwise. It ensures that
* the variable can store data in any type and no conversion is done while using Variable.get.
*/
any = "{\"in\":\"\",\"out\":\"\"}"
any = "{\"in\":\"\",\"out\":\"\"}",
/**
* A "secret" type value stores data as postman secret variables
*/
secret = "{\"in\":\"\",\"out\":\"\"}"
}
}

Expand Down

0 comments on commit 8167475

Please sign in to comment.