mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Add import attributes support (#1388)
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
Change Log
|
||||
|
||||
v5.4.0
|
||||
---
|
||||
* Add support for `import attributes`. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1256
|
||||
* Replaced `mkdirp` dependency with native `fs.mkdirSync({ recursive: true })`. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1275. Thank you https://github.com/roli-lpci!
|
||||
|
||||
v5.3.1
|
||||
---
|
||||
* Fixed class expression name references inside class body being incorrectly resolved to an import binding with the same name, causing broken code at runtime. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1386
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "javascript-obfuscator",
|
||||
"version": "5.3.1",
|
||||
"version": "5.4.0",
|
||||
"description": "JavaScript obfuscator",
|
||||
"keywords": [
|
||||
"obfuscator",
|
||||
@@ -21,10 +21,11 @@
|
||||
},
|
||||
"types": "typings/index.d.ts",
|
||||
"dependencies": {
|
||||
"@javascript-obfuscator/escodegen": "2.3.1",
|
||||
"@javascript-obfuscator/escodegen": "2.4.0",
|
||||
"@javascript-obfuscator/estraverse": "5.4.0",
|
||||
"@vercel/blob": ">=0.23.0",
|
||||
"acorn": "8.15.0",
|
||||
"acorn-import-attributes": "^1.9.5",
|
||||
"assert": "2.1.0",
|
||||
"chalk": "4.1.2",
|
||||
"chance": "1.1.13",
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import * as acorn from 'acorn';
|
||||
import * as ESTree from 'estree';
|
||||
import chalk, { Chalk } from 'chalk';
|
||||
import { importAttributesOrAssertions } from 'acorn-import-attributes';
|
||||
|
||||
const AcornParser = acorn.Parser.extend(importAttributesOrAssertions);
|
||||
|
||||
/**
|
||||
* Facade over AST parser `acorn`
|
||||
@@ -67,7 +70,7 @@ export class ASTParserFacade {
|
||||
sourceType
|
||||
};
|
||||
|
||||
const program: acorn.Node & ESTree.Program = <acorn.Node & ESTree.Program>acorn.parse(sourceCode, config);
|
||||
const program: acorn.Node & ESTree.Program = <acorn.Node & ESTree.Program>AcornParser.parse(sourceCode, config);
|
||||
|
||||
if (comments.length) {
|
||||
program.comments = comments;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
declare module 'acorn-import-attributes' {
|
||||
import { Parser } from 'acorn';
|
||||
|
||||
type TParserExtension = (BaseParser: typeof Parser) => typeof Parser;
|
||||
|
||||
export const importAttributes: TParserExtension;
|
||||
export const importAssertions: TParserExtension;
|
||||
export const importAttributesOrAssertions: TParserExtension;
|
||||
}
|
||||
@@ -1478,6 +1478,116 @@ describe('JavaScriptObfuscator', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Import attributes', () => {
|
||||
describe('Variant #1: import with "with" syntax', () => {
|
||||
const importAttributesRegExp: RegExp = /from\s*'\.\/config\.json'\s*with\s*\{\s*type\s*:\s*'json'\s*\}/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = `import config from './config.json' with { type: 'json' };\nconsole.log(config);`;
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(code, {
|
||||
...NO_ADDITIONAL_NODES_PRESET
|
||||
}).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should preserve import attributes in obfuscated code', () => {
|
||||
assert.match(obfuscatedCode, importAttributesRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: import with multiple attributes', () => {
|
||||
const importAttributesRegExp: RegExp = /from\s*'\.\/data\.json'\s*with\s*\{\s*type\s*:\s*'json'\s*,\s*integrity\s*:\s*'sha384-abc'\s*\}/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = `import data from './data.json' with { type: 'json', integrity: 'sha384-abc' };\nconsole.log(data);`;
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(code, {
|
||||
...NO_ADDITIONAL_NODES_PRESET
|
||||
}).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should preserve multiple import attributes in obfuscated code', () => {
|
||||
assert.match(obfuscatedCode, importAttributesRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: import with "assert" syntax (deprecated)', () => {
|
||||
const importAssertionsRegExp: RegExp = /from\s*'\.\/config\.json'\s*assert\s*\{\s*type\s*:\s*'json'\s*\}/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = `import config from './config.json' assert { type: 'json' };\nconsole.log(config);`;
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(code, {
|
||||
...NO_ADDITIONAL_NODES_PRESET
|
||||
}).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should preserve import assertions in obfuscated code', () => {
|
||||
assert.match(obfuscatedCode, importAssertionsRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #4: export with "with" syntax', () => {
|
||||
const exportAttributesRegExp: RegExp = /from\s*'\.\/config\.json'\s*with\s*\{\s*type\s*:\s*'json'\s*\}/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = `export { default as config } from './config.json' with { type: 'json' };`;
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(code, {
|
||||
...NO_ADDITIONAL_NODES_PRESET
|
||||
}).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should preserve export attributes in obfuscated code', () => {
|
||||
assert.match(obfuscatedCode, exportAttributesRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #5: export all with "with" syntax', () => {
|
||||
const exportAllAttributesRegExp: RegExp = /export\s*\*\s*from\s*'\.\/utils\.js'\s*with\s*\{\s*type\s*:\s*'javascript'\s*\}/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = `export * from './utils.js' with { type: 'javascript' };`;
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(code, {
|
||||
...NO_ADDITIONAL_NODES_PRESET
|
||||
}).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should preserve export all attributes in obfuscated code', () => {
|
||||
assert.match(obfuscatedCode, exportAllAttributesRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #6: side-effect import with "with" syntax', () => {
|
||||
const sideEffectImportRegExp: RegExp = /import\s*'\.\/styles\.css'\s*with\s*\{\s*type\s*:\s*'css'\s*\}/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = `import './styles.css' with { type: 'css' };`;
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(code, {
|
||||
...NO_ADDITIONAL_NODES_PRESET
|
||||
}).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should preserve side-effect import attributes in obfuscated code', () => {
|
||||
assert.match(obfuscatedCode, sideEffectImportRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOptionsByPreset', () => {
|
||||
describe('Variant #1: base behaviour', () => {
|
||||
const optionsPresetName: TOptionsPreset = OptionsPreset.HighObfuscation;
|
||||
|
||||
@@ -87,5 +87,79 @@ describe('ASTParserFacade', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Import attributes', () => {
|
||||
describe('Variant #1: import with "with" syntax', () => {
|
||||
const sourceCode: string = `import config from "./config.json" with { type: "json" };`;
|
||||
|
||||
let astTree: any;
|
||||
|
||||
before(() => {
|
||||
astTree = ASTParserFacade.parse(sourceCode, { ecmaVersion });
|
||||
});
|
||||
|
||||
it('should parse import with "with" syntax without error', () => {
|
||||
assert.exists(astTree);
|
||||
assert.equal(astTree.type, 'Program');
|
||||
assert.equal(astTree.body[0].type, 'ImportDeclaration');
|
||||
});
|
||||
|
||||
it('should preserve import attributes in AST', () => {
|
||||
const importDecl = astTree.body[0];
|
||||
assert.exists(importDecl.attributes);
|
||||
assert.isArray(importDecl.attributes);
|
||||
assert.equal(importDecl.attributes.length, 1);
|
||||
assert.equal(importDecl.attributes[0].key.name, 'type');
|
||||
assert.equal(importDecl.attributes[0].value.value, 'json');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: import with "assert" syntax (deprecated)', () => {
|
||||
const sourceCode: string = `import config from "./config.json" assert { type: "json" };`;
|
||||
|
||||
let astTree: any;
|
||||
|
||||
before(() => {
|
||||
astTree = ASTParserFacade.parse(sourceCode, { ecmaVersion });
|
||||
});
|
||||
|
||||
it('should parse import with "assert" syntax without error', () => {
|
||||
assert.exists(astTree);
|
||||
assert.equal(astTree.type, 'Program');
|
||||
assert.equal(astTree.body[0].type, 'ImportDeclaration');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: export with "with" syntax', () => {
|
||||
const sourceCode: string = `export { default as config } from "./config.json" with { type: "json" };`;
|
||||
|
||||
let astTree: any;
|
||||
|
||||
before(() => {
|
||||
astTree = ASTParserFacade.parse(sourceCode, { ecmaVersion });
|
||||
});
|
||||
|
||||
it('should parse export with "with" syntax without error', () => {
|
||||
assert.exists(astTree);
|
||||
assert.equal(astTree.type, 'Program');
|
||||
assert.equal(astTree.body[0].type, 'ExportNamedDeclaration');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #4: dynamic import with "with" syntax', () => {
|
||||
const sourceCode: string = `const config = await import("./config.json", { with: { type: "json" } });`;
|
||||
|
||||
let astTree: any;
|
||||
|
||||
before(() => {
|
||||
astTree = ASTParserFacade.parse(sourceCode, { ecmaVersion });
|
||||
});
|
||||
|
||||
it('should parse dynamic import with "with" syntax without error', () => {
|
||||
assert.exists(astTree);
|
||||
assert.equal(astTree.type, 'Program');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -329,10 +329,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98"
|
||||
integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
|
||||
|
||||
"@javascript-obfuscator/escodegen@2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@javascript-obfuscator/escodegen/-/escodegen-2.3.1.tgz#a534e73740830d6c7546ca686773b40b09a6b9d1"
|
||||
integrity sha512-Z0HEAVwwafOume+6LFXirAVZeuEMKWuPzpFbQhCEU9++BMz0IwEa9bmedJ+rMn/IlXRBID9j3gQ0XYAa6jM10g==
|
||||
"@javascript-obfuscator/escodegen@2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@javascript-obfuscator/escodegen/-/escodegen-2.4.0.tgz#9d2b19b94793106cafa5cd5041c4e40d42943fb7"
|
||||
integrity sha512-h9cJ/qb3Y3c1jMQPWypt2CGTFgP34V5OtWLqoOCjV6CT/DUXMZFpoTAfDHpuUrRP0oxNd0UwnVAsPtPuYsoXxQ==
|
||||
dependencies:
|
||||
"@javascript-obfuscator/estraverse" "^5.3.0"
|
||||
esprima "^4.0.1"
|
||||
@@ -1017,6 +1017,11 @@ abbrev@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf"
|
||||
integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==
|
||||
|
||||
acorn-import-attributes@^1.9.5:
|
||||
version "1.9.5"
|
||||
resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef"
|
||||
integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==
|
||||
|
||||
acorn-import-phases@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz#16eb850ba99a056cb7cbfe872ffb8972e18c8bd7"
|
||||
|
||||
Reference in New Issue
Block a user