Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replaced shims for atob and btoa with native implementations #1049

Open
wants to merge 1 commit into
base: feature/expose-File-globally
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ unreleased:
- GH-1032 Enhanced performance when operating on buffers in Node environment
- GH-1035 Added missing buffer APIs to expose a uniform interface across environments
- GH-1052 Added support URL, Encoding, File, Cryptography, and Stream globals
- GH-1049 Replaced shims for atob and btoa with native implementations
fixed bugs:
- GH-1036 Fixed `uncaughtException` event listener not being removed
- GH-1034 Fixed an issue where sandbox crashes for large response body
Expand Down
7 changes: 6 additions & 1 deletion lib/bundle/bundling-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,10 @@ module.exports = {
browserField: false,
bare: true,
builtins: false,
commondir: true
commondir: true,

// This is to prevent bundling errors for modules that
// are not in node_modules but are instead imported from a
// vendor and should be exposed via `require` inside the bundle.
ignoreMissing: true
};
4 changes: 2 additions & 2 deletions lib/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ module.exports = {
os: { preferBuiltin: true },
'liquid-json': { expose: 'json', glob: true },
'crypto-js': { glob: true },
atob: { glob: true },
btoa: { glob: true },
atob: { resolve: '../vendor/atob.js', expose: 'atob', glob: true },
btoa: { resolve: '../vendor/btoa.js', expose: 'btoa', glob: true },
ajv: { glob: true },
tv4: { glob: true },
xml2js: { glob: true },
Expand Down
6 changes: 1 addition & 5 deletions lib/sandbox/postman-legacy-interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ const _ = require('lodash'),
JSON: require('liquid-json'),
_: require('lodash3').noConflict(),
CryptoJS: require('crypto-js'),
atob: require('atob'),
btoa: require('btoa'),
tv4: require('tv4'),
xml2Json: require('./xml2Json'),
Backbone: require('backbone'),
Expand All @@ -17,7 +15,7 @@ const _ = require('lodash'),
'tests', 'globals', 'environment', 'data', 'request', 'responseCookies', 'responseHeaders', 'responseTime',
'responseCode', 'responseBody', 'iteration', 'postman',
// scope libraries
'_', 'CryptoJS', 'atob', 'btoa', 'tv4', 'xml2Json', 'Backbone', 'cheerio'
'_', 'CryptoJS', 'tv4', 'xml2Json', 'Backbone', 'cheerio'
// 'JSON', // removing JSON from the list since it is a standard JS object
],

Expand All @@ -35,8 +33,6 @@ const _ = require('lodash'),
iteration: 'pm.info.iteration',
_: 'require(\'lodash\')',
CryptoJS: 'require(\'crypto-js\')',
atob: 'require(\'atob\')',
btoa: 'require(\'btoa\')',
tv4: 'require(\'ajv\')',
xml2Json: 'require(\'xml2js\')',
Backbone: 'require(\'backbone\')',
Expand Down
1 change: 1 addition & 0 deletions lib/vendor/atob.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('buffer').atob;
1 change: 1 addition & 0 deletions lib/vendor/btoa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('buffer').btoa;
2 changes: 2 additions & 0 deletions lib/vendor/buffer/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ function getBufferModule (buffer) {
constants: buffer.constants,
File: buffer.File,
Blob: buffer.Blob,
atob: buffer.atob,
btoa: buffer.btoa,
isAscii: NOT_IMPLEMENTED,
isUtf8: NOT_IMPLEMENTED,
resolveObjectURL: NOT_IMPLEMENTED,
Expand Down
4 changes: 3 additions & 1 deletion lib/vendor/buffer/index.browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ module.exports = getBufferModule({
MAX_STRING_LENGTH: K_STRING_MAX_LENGTH
},
File: File,
Blob: Blob
Blob: Blob,
atob: atob,
btoa: btoa
});
38 changes: 0 additions & 38 deletions package-lock.json

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

2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,8 @@
"ajv": "6.12.5",
"assert": "2.0.0",
"async": "^3.2.6",
"atob": "2.1.2",
"backbone": "1.6.0",
"browserify": "^16.5.2",
"btoa": "1.2.1",
"buffer": "6.0.3",
"chai": "4.4.1",
"chai-postman": "2.0.1",
Expand Down
4 changes: 0 additions & 4 deletions test/system/bootcode-dependencies.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ const expect = require('chai').expect,
'array-filter',
'assert',
'assertion-error',
'atob',
'available-typed-arrays',
'backbone',
'base64-js',
'boolbase',
'browserify',
'btoa',
'buffer',
'call-bind',
'chai',
Expand Down Expand Up @@ -127,12 +125,10 @@ const expect = require('chai').expect,
'array-filter',
'assert',
'assertion-error',
'atob',
'available-typed-arrays',
'backbone',
'boolbase',
'browserify',
'btoa',
'call-bind',
'chai',
'chai-postman',
Expand Down
2 changes: 1 addition & 1 deletion test/system/repository.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ describe('project repository', function () {

it('should point to specific package version for bundled packages; (*, ^, ~) not expected', function () {
[
'ajv', 'assert', 'atob', 'backbone', 'btoa', 'buffer', 'chai',
'ajv', 'assert', 'backbone', 'buffer', 'chai',
'chai-postman', 'cheerio', 'crypto-js', 'csv-parse', 'liquid-json',
'lodash3', 'moment', '@postman/tough-cookie', 'tv4',
'uniscope', 'xml2js'
Expand Down
4 changes: 2 additions & 2 deletions test/unit/sandbox-libraries/legacy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('sandbox library - legacy', function () {

context.on('console', consoleSpy);
context.execute(`
atob('a');
CryptoJS.AES.encrypt('my message', 'secret key 123')
`, function (err) {
if (err) {
return done(err);
Expand All @@ -64,7 +64,7 @@ describe('sandbox library - legacy', function () {
expect(consoleSpy).to.be.calledOnce;
expect(consoleSpy.firstCall.args[1]).to.equal('warn');
expect(consoleSpy.firstCall.args[2])
.to.equal('Using "atob" is deprecated. Use "require(\'atob\')" instead.');
.to.equal('Using "CryptoJS" is deprecated. Use "require(\'crypto-js\')" instead.');
done();
});
});
Expand Down
2 changes: 0 additions & 2 deletions test/unit/sandbox-libraries/pm-require.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@
});

// TODO: fixit
it.skip('should not have access to __module_obj', function (done) {

Check warning on line 308 in test/unit/sandbox-libraries/pm-require.test.js

View workflow job for this annotation

GitHub Actions / Lint

Unexpected skipped mocha test
context.execute(`
var assert = require('assert');
try {
Expand Down Expand Up @@ -536,8 +536,6 @@
// scope libraries
'_',
'CryptoJS',
'atob',
'btoa',
'tv4',
'xml2Json',
'Backbone',
Expand Down
50 changes: 50 additions & 0 deletions test/unit/vendors/atob.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
describe('sandbox vendor - atob', function () {
this.timeout(1000 * 60);
var Sandbox = require('../../../'),
context;

beforeEach(function (done) {
Sandbox.createContext({ debug: true }, function (err, ctx) {
context = ctx;
done(err);
});
});

afterEach(function () {
context.dispose();
context = null;
});

it('should exist in global', function (done) {
context.execute(`
const assert = require('assert');
assert.strictEqual(typeof atob, 'function', 'typeof atob must be function');
`, done);
});

it('should be exposed via require', function (done) {
context.execute(`
const assert = require('assert');
const atob = require('atob');
assert.strictEqual(typeof atob, 'function', 'typeof atob must be function');
`, done);
});

it('should have same implementation exposed via global, require and buffer', function (done) {
context.execute(`
const assert = require('assert');
const requiredAtob = require('atob');
const bufferAtob = require('buffer').atob;
assert.strictEqual(atob === requiredAtob, true);
assert.strictEqual(atob === bufferAtob, true);
`, done);
});

it('should decode base64 encoded string', function (done) {
context.execute(`
const assert = require('assert');
const decoded = atob('cG9zdG1hbi1zYW5kYm94');
assert.strictEqual(decoded, 'postman-sandbox');
`, done);
});
});
50 changes: 50 additions & 0 deletions test/unit/vendors/btoa.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
describe('sandbox vendor - btoa', function () {
this.timeout(1000 * 60);
var Sandbox = require('../../../'),
context;

beforeEach(function (done) {
Sandbox.createContext({ debug: true }, function (err, ctx) {
context = ctx;
done(err);
});
});

afterEach(function () {
context.dispose();
context = null;
});

it('should exist in global', function (done) {
context.execute(`
const assert = require('assert');
assert.strictEqual(typeof btoa, 'function', 'typeof btoa must be function');
`, done);
});

it('should be exposed via require', function (done) {
context.execute(`
const assert = require('assert');
const btoa = require('btoa');
assert.strictEqual(typeof btoa, 'function', 'typeof btoa must be function');
`, done);
});

it('should have same implementation exposed via global, require and buffer', function (done) {
context.execute(`
const assert = require('assert');
const requiredBtoa = require('btoa');
const bufferBtoa = require('buffer').btoa;
assert.strictEqual(btoa === requiredBtoa, true);
assert.strictEqual(btoa === bufferBtoa, true);
`, done);
});

it('should encode a string to base64', function (done) {
context.execute(`
const assert = require('assert');
const decoded = btoa('postman-sandbox');
assert.strictEqual(decoded, 'cG9zdG1hbi1zYW5kYm94');
`, done);
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
describe('sandbox library - buffer', function () {
const isNode = typeof window === 'undefined';

describe('sandbox vendor - buffer', function () {
this.timeout(1000 * 60);
var Sandbox = require('../../../'),
context;
Expand Down Expand Up @@ -157,7 +159,7 @@ describe('sandbox library - buffer', function () {
it('should be able to convert large buffer to string', function (done) {
// For native buffer, the max string length is ~512MB
// For browser buffer, the max string length is ~100MB
const SIZE = (typeof window === 'undefined' ? 511 : 100) * 1024 * 1024;
const SIZE = (isNode ? 511 : 100) * 1024 * 1024;

context.execute(`
const assert = require('assert'),
Expand Down Expand Up @@ -286,4 +288,33 @@ describe('sandbox library - buffer', function () {
assert.strictEqual(Blob === bufferBlob, true);
`, done);
});

(isNode ? it : it.skip)('should be in sync with latest available `buffer` module', function (done) {
const buffer = require('buffer'),
expectedProps = Object.getOwnPropertyNames(buffer).sort();

context.execute(`
const assert = require('assert');
const buffer = require('buffer');
const actualProps = Object.getOwnPropertyNames(buffer).sort();

assert.deepStrictEqual(actualProps, ${JSON.stringify(expectedProps)});
`, done);
});

(isNode ? it : it.skip)('should be in sync with latest available `Buffer` class', function (done) {
const fnProps = Object.getOwnPropertyNames(function () { return 0; }).sort(),
expectedProps = Object.getOwnPropertyNames(Buffer).sort().filter((prop) => {
return !fnProps.includes(prop);
});

context.execute(`
const assert = require('assert');
const actualProps = Object.getOwnPropertyNames(Buffer).sort().filter((prop) => {
return !${JSON.stringify(fnProps)}.includes(prop);
});

assert.deepStrictEqual(actualProps, ${JSON.stringify(expectedProps)});
`, done);
});
});
Loading