Skip to content

Commit

Permalink
feat(bundle-source): Apply evasive transforms to Endo archives (#2768)
Browse files Browse the repository at this point in the history
  • Loading branch information
kriskowal authored Apr 6, 2021
1 parent d1eb72a commit e15cee8
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 10 deletions.
1 change: 1 addition & 0 deletions packages/bundle-source/demo/comments/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** @typedef {import('./types.js').Bogus} Bogus */
5 changes: 4 additions & 1 deletion packages/bundle-source/demo/dir1/encourage.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export const message = `You're great!`;
export const encourage = nick => `Hey ${nick}! ${message}`;
export const makeError = msg => Error(msg);
// Without an evasive transform, the following comment will trip the SES censor
// for dynamic imports. */
/** @type {import('./types.js').EncourageFn} */
export const encourage = nick => `Hey ${nick}! ${message}`;
5 changes: 5 additions & 0 deletions packages/bundle-source/demo/dir1/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* @callback EncourageFn
* @param {string} nick
* @returns {string}
*/
2 changes: 1 addition & 1 deletion packages/bundle-source/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"dependencies": {
"@agoric/acorn-eventual-send": "^2.1.4",
"@agoric/babel-parser": "^7.6.4",
"@agoric/compartment-mapper": "^0.2.3",
"@agoric/compartment-mapper": "^0.2.4",
"@agoric/transform-eventual-send": "^1.4.4",
"@babel/generator": "^7.6.4",
"@babel/traverse": "^7.8.3",
Expand Down
34 changes: 28 additions & 6 deletions packages/bundle-source/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const IMPORT_RE = new RegExp('\\b(import)(\\s*(?:\\(|/[/*]))', 'sg');
const HTML_COMMENT_START_RE = new RegExp(`${'<'}!--`, 'g');
const HTML_COMMENT_END_RE = new RegExp(`--${'>'}`, 'g');

const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();
const read = async location => fs.promises.readFile(new URL(location).pathname);

export function tildotPlugin() {
Expand Down Expand Up @@ -92,15 +94,20 @@ async function makeLocationUnmapper({ sourceMap, ast }) {
function transformAst(ast, unmapLoc) {
babelTraverse(ast, {
enter(p) {
const { loc, leadingComments, trailingComments } = p.node;
if (p.node.comments) {
p.node.comments = [];
}
const {
loc,
comments,
leadingComments,
innerComments,
trailingComments,
} = p.node;
(comments || []).forEach(node => rewriteComment(node, unmapLoc));
// Rewrite all comments.
(leadingComments || []).forEach(node => rewriteComment(node, unmapLoc));
if (p.node.type.startsWith('Comment')) {
rewriteComment(p.node, unmapLoc);
}
(innerComments || []).forEach(node => rewriteComment(node, unmapLoc));
// If not a comment, and we are unmapping the source maps,
// then do it for this location.
if (unmapLoc) {
Expand All @@ -111,11 +118,15 @@ function transformAst(ast, unmapLoc) {
});
}

async function transformSource(code, { sourceMap, useLocationUnmap }) {
async function transformSource(
code,
{ sourceMap, useLocationUnmap, sourceType } = {},
) {
// Parse the rolled-up chunk with Babel.
// We are prepared for different module systems.
const ast = (babelParser.parse || babelParser)(code, {
plugins: ['bigInt'],
sourceType,
});

let unmapLoc;
Expand Down Expand Up @@ -148,7 +159,18 @@ export default async function bundleSource(
// individual package.jsons and driven by the compartment mapper.
const base = new URL(`file://${process.cwd()}`).toString();
const entry = new URL(startFilename, base).toString();
const bytes = await makeArchive(read, entry);
const bytes = await makeArchive(read, entry, {
moduleTransforms: {
async mjs(sourceBytes) {
const source = textDecoder.decode(sourceBytes);
const { code: object } = await transformSource(source, {
sourceType: 'module',
});
const objectBytes = textEncoder.encode(object);
return { bytes: objectBytes, parser: 'mjs' };
},
},
});
const endoZipBase64 = encodeBase64(bytes);
return { endoZipBase64, moduleFormat };
}
Expand Down
7 changes: 5 additions & 2 deletions packages/bundle-source/test/sanity.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function makeSanityTests(stackFiltering) {
const err = bundle.makeError('foo');
// console.log(err.stack);
t.assert(
stackContains(err.stack, 'encourage.js:3:'),
stackContains(err.stack, 'encourage.js:2:'),
'bundled source is in stack trace with correct line number',
);

Expand Down Expand Up @@ -120,7 +120,10 @@ export function makeSanityTests(stackFiltering) {
moduleFormat: mf2,
source: src2,
sourceMap: map2,
} = await bundleSource(`${__dirname}/../demo/dir1/encourage.js`);
} = await bundleSource(
`${__dirname}/../demo/dir1/encourage.js`,
'nestedEvaluate',
);
t.is(mf2, 'nestedEvaluate', 'module format 2 is nestedEvaluate');

const srcMap2 = `(${src2})\n${map2}`;
Expand Down
22 changes: 22 additions & 0 deletions packages/bundle-source/test/test-comment.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* global __dirname */
import '@agoric/install-ses';
import test from 'ava';
import { decodeBase64 } from '@endo/base64';
import { parseArchive } from '@agoric/compartment-mapper';
import bundleSource from '..';

function evaluate(src, endowments) {
Expand Down Expand Up @@ -61,3 +63,23 @@ test('comment block closer', async t => {
const srcMap1 = `(${src1})`;
nestedEvaluate(srcMap1)();
});

test('comments not associated with a code AST node', async t => {
t.plan(1);
const { endoZipBase64 } = await bundleSource(
`${__dirname}/../demo/comments/types.js`,
'endoZipBase64',
);
const endoZipBytes = decodeBase64(endoZipBase64);
const application = await parseArchive(endoZipBytes);
// If the TypeScript comment in this module does not get rewritten,
// attempting to import the module will throw a SES censorship error since
// import calls in comments are not distinguishable from containment escape
// through dynamic import.
// To verify, disable this line in src/index.js and observe that this test
// fails:
// (innerComments || []).forEach(node => rewriteComment(node, unmapLoc));
// eslint-disable-next-line dot-notation
await application['import']('./demo/comments/types.js');
t.is(1, 1);
});
7 changes: 7 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@
dependencies:
ses "^0.11.0"

"@agoric/compartment-mapper@^0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@agoric/compartment-mapper/-/compartment-mapper-0.2.4.tgz#db78b3d3c34db2204aba6eaa29155a3e0a371e73"
integrity sha512-HppJtvTQP9R/a55dX+7H4xXYlj6oPmvN9xVvWVk+BDEq0//AiS1/3qpV+R6B34raNvBPatsBzYuhZQjdHSw3+A==
dependencies:
ses "^0.12.6"

"@agoric/make-hardener@^0.1.0", "@agoric/make-hardener@^0.1.2":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@agoric/make-hardener/-/make-hardener-0.1.3.tgz#807b0072bef95d935c3370d406d9dfeb719f69ee"
Expand Down

0 comments on commit e15cee8

Please sign in to comment.