Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Change Log

v5.7.0
---
* **New option:** `advertisement` allows to control the display of the JavaScript Obfuscator Pro advertisement message in the console. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1448

v5.6.0
---
* Pro API: `obfuscatePro` now fall back to the basic local obfuscation API when no Pro feature (`vmObfuscation` or `parseHtml`) is enabled, instead of throwing an `ApiError`
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ Following options are available for the JS Obfuscator:

```javascript
{
advertisement: true,
compact: true,
controlFlowFlattening: false,
controlFlowFlatteningThreshold: 0.75,
Expand Down Expand Up @@ -618,6 +619,7 @@ Following options are available for the JS Obfuscator:

-o, --output

--advertisement <boolean>
--compact <boolean>
--config <string>
--control-flow-flattening <boolean>
Expand Down Expand Up @@ -715,6 +717,13 @@ Following options are available for the JS Obfuscator:

<!-- ##options-start## -->

### `advertisement`
Type: `boolean` Default: `true`

Allows to control the display of the JavaScript Obfuscator Pro advertisement message in the console.

The message is only shown when using the Node.js CLI in an interactive (TTY) terminal, is never shown in CI environments or in the browser, and is limited to a few displays. Set this option to `false` to disable the advertisement message completely.

### `compact`
Type: `boolean` Default: `true`

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "javascript-obfuscator",
"version": "5.6.0",
"version": "5.7.0",
"description": "JavaScript obfuscator",
"keywords": [
"obfuscator",
Expand Down
2 changes: 1 addition & 1 deletion src/JavaScriptObfuscator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
* @returns {IObfuscationResult}
*/
public obfuscate(sourceCode: string): IObfuscationResult {
if (AdvertisementUtils.shouldShowAdvertisement()) {
if (AdvertisementUtils.shouldShowAdvertisement(this.options.advertisement)) {
this.logger.advertise(LoggingMessage.JavaScriptObfuscatorProAdFirstPart);
this.logger.advertise(LoggingMessage.JavaScriptObfuscatorProAdSecondPart);
}
Expand Down
5 changes: 5 additions & 0 deletions src/cli/JavaScriptObfuscatorCLI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
.usage('<inputPath> [options]')
.version(Utils.buildVersionMessage(process.env.VERSION, process.env.BUILD_TIMESTAMP), '-v, --version')
.option('-o, --output <path>', 'Output path for obfuscated code')
.option(
'--advertisement <boolean>',
'Allows to control the JavaScript Obfuscator Pro advertisement message shown in the console',
BooleanSanitizer
)
.option('--compact <boolean>', 'Disable one line output code compacting', BooleanSanitizer)
.option('--config <boolean>', 'Name of js / json config file')
.option('--control-flow-flattening <boolean>', 'Enables control flow flattening', BooleanSanitizer)
Expand Down
3 changes: 2 additions & 1 deletion src/custom-code-helpers/CustomCodeHelperObfuscator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export class CustomCodeHelperObfuscator implements ICustomCodeHelperObfuscator {
numbersToExpressions: this.options.numbersToExpressions,
simplify: this.options.simplify,
seed: this.randomGenerator.getRawSeed(),
...additionalOptions
...additionalOptions,
advertisement: false
}).getObfuscatedCode();
}
}
1 change: 1 addition & 0 deletions src/interfaces/options/IOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SourceMapMode } from '../../enums/source-map/SourceMapMode';
import { SourceMapSourcesMode } from '../../enums/source-map/SourceMapSourcesMode';

export interface IOptions {
readonly advertisement: boolean;
readonly compact: boolean;
readonly controlFlowFlattening: boolean;
readonly controlFlowFlatteningThreshold: number;
Expand Down
6 changes: 6 additions & 0 deletions src/options/Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ export class Options implements IOptions {
}
};

/**
* @type {boolean}
*/
@IsBoolean()
public readonly advertisement!: boolean;

/**
* @type {boolean}
*/
Expand Down
1 change: 1 addition & 0 deletions src/options/presets/Default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { StringArrayEncoding } from '../../enums/node-transformers/string-array-
import { StringArrayWrappersType } from '../../enums/node-transformers/string-array-transformers/StringArrayWrappersType';

export const DEFAULT_PRESET: TInputOptions = Object.freeze({
advertisement: true,
compact: true,
config: '',
controlFlowFlattening: false,
Expand Down
1 change: 1 addition & 0 deletions src/options/presets/NoCustomNodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { StringArrayWrappersType } from '../../enums/node-transformers/string-ar
import { StringArrayIndexesType } from '../../enums/node-transformers/string-array-transformers/StringArrayIndexesType';

export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
advertisement: true,
compact: true,
controlFlowFlattening: false,
controlFlowFlatteningThreshold: 0,
Expand Down
8 changes: 7 additions & 1 deletion src/utils/AdvertisementUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,14 @@ export class AdvertisementUtils {
* Also increments the display count if returning true
*
* In browser environments, always returns false
*
* @param {boolean} advertisement value of the `advertisement` option
*/
public static shouldShowAdvertisement(): boolean {
public static shouldShowAdvertisement(advertisement: boolean): boolean {
if (!advertisement) {
return false;
}

// Don't show in browser - only Node.js CLI
if (!this.isNodeEnvironment()) {
return false;
Expand Down
92 changes: 92 additions & 0 deletions test/functional-tests/cli/JavaScriptObfuscatorCLI.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ISourceMap } from '../../../src/interfaces/source-code/ISourceMap';

import { StdoutWriteMock } from '../../mocks/StdoutWriteMock';

import { AdvertisementUtils } from '../../../src/utils/AdvertisementUtils';
import { JavaScriptObfuscatorCLI } from '../../../src/JavaScriptObfuscatorCLIFacade';
import { ProApiClient } from '../../../src/pro-api/ProApiClient';
import { parseSourceMapFromObfuscatedCode } from '../../helpers/parseSourceMapFromObfuscatedCode';
Expand Down Expand Up @@ -1356,6 +1357,97 @@ describe('JavaScriptObfuscatorCLI', function (): void {
});
});

describe('`--advertisement` option', () => {
const advertisementText: string = 'JavaScript Obfuscator Pro';

let shouldShowAdvertisementStub: sinon.SinonStub,
consoleLogStub: sinon.SinonStub;

const isAdvertisementLogged = (): boolean =>
consoleLogStub
.getCalls()
.some((call) =>
call.args.some((arg) => typeof arg === 'string' && arg.includes(advertisementText))
);

beforeEach(() => {
shouldShowAdvertisementStub = sinon
.stub(AdvertisementUtils, 'shouldShowAdvertisement')
.callsFake((advertisement: boolean): boolean => advertisement);
consoleLogStub = sinon.stub(console, 'log');
});

afterEach(() => {
shouldShowAdvertisementStub.restore();
consoleLogStub.restore();
rimraf.sync(outputFilePath);
});

describe('Variant #1: `--advertisement` option is not set (enabled by default)', () => {
let isAdvertisementShown: boolean;

beforeEach(async () => {
await JavaScriptObfuscatorCLI.obfuscate([
'node',
'javascript-obfuscator',
fixtureFilePath,
'--output',
outputFilePath
]);

isAdvertisementShown = isAdvertisementLogged();
});

it('should show the advertisement message', () => {
assert.isTrue(isAdvertisementShown);
});
});

describe('Variant #2: `--advertisement` option is set to `true`', () => {
let isAdvertisementShown: boolean;

beforeEach(async () => {
await JavaScriptObfuscatorCLI.obfuscate([
'node',
'javascript-obfuscator',
fixtureFilePath,
'--output',
outputFilePath,
'--advertisement',
'true'
]);

isAdvertisementShown = isAdvertisementLogged();
});

it('should show the advertisement message', () => {
assert.isTrue(isAdvertisementShown);
});
});

describe('Variant #3: `--advertisement` option is set to `false`', () => {
let isAdvertisementShown: boolean;

beforeEach(async () => {
await JavaScriptObfuscatorCLI.obfuscate([
'node',
'javascript-obfuscator',
fixtureFilePath,
'--output',
outputFilePath,
'--advertisement',
'false'
]);

isAdvertisementShown = isAdvertisementLogged();
});

it('should not show the advertisement message', () => {
assert.isFalse(isAdvertisementShown);
});
});
});

describe('`--pro-api-token` option', () => {
let fetchStub: sinon.SinonStub;
let proApiFilePath: string;
Expand Down
123 changes: 123 additions & 0 deletions test/functional-tests/issues/issue1448.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import * as sinon from 'sinon';

import { assert } from 'chai';

import { AdvertisementUtils } from '../../../src/utils/AdvertisementUtils';

import { JavaScriptObfuscator } from '../../../src/JavaScriptObfuscatorFacade';

//
// https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1448
//
describe('Issue #1448', () => {
const code: string = 'var foo = 1;';

describe('`advertisement` option', () => {
let shouldShowAdvertisementStub: sinon.SinonStub,
consoleLogStub: sinon.SinonStub;

beforeEach(() => {
shouldShowAdvertisementStub = sinon
.stub(AdvertisementUtils, 'shouldShowAdvertisement')
.callsFake((advertisement: boolean): boolean => advertisement);
consoleLogStub = sinon.stub(console, 'log');
});

afterEach(() => {
shouldShowAdvertisementStub.restore();
consoleLogStub.restore();
});

describe('Variant #1: `advertisement` option is enabled by default', () => {
let isAdvertisementShown: boolean, loggedMessage: string;

beforeEach(() => {
JavaScriptObfuscator.obfuscate(code);

isAdvertisementShown = consoleLogStub.called;
loggedMessage = isAdvertisementShown ? String(consoleLogStub.firstCall.args[0]) : '';
});

it('should show the advertisement message', () => {
assert.isTrue(isAdvertisementShown);
});

it('should log the JavaScript Obfuscator Pro advertisement message', () => {
assert.include(loggedMessage, 'JavaScript Obfuscator Pro');
});
});

describe('Variant #2: `advertisement` option is set to `true`', () => {
let isAdvertisementShown: boolean;

beforeEach(() => {
JavaScriptObfuscator.obfuscate(code, { advertisement: true });

isAdvertisementShown = consoleLogStub.called;
});

it('should show the advertisement message', () => {
assert.isTrue(isAdvertisementShown);
});
});

describe('Variant #3: `advertisement` option is set to `false`', () => {
let isAdvertisementShown: boolean;

beforeEach(() => {
JavaScriptObfuscator.obfuscate(code, { advertisement: false });

isAdvertisementShown = consoleLogStub.called;
});

it('should not show the advertisement message', () => {
assert.isFalse(isAdvertisementShown);
});

it('should pass the disabled `advertisement` flag to the display check', () => {
assert.isTrue(shouldShowAdvertisementStub.calledWith(false));
});
});

describe('Variant #4: `advertisement` option is enabled but display conditions are not met', () => {
let isAdvertisementShown: boolean;

beforeEach(() => {
shouldShowAdvertisementStub.returns(false);

JavaScriptObfuscator.obfuscate(code, { advertisement: true });

isAdvertisementShown = consoleLogStub.called;
});

it('should not show the advertisement message', () => {
assert.isFalse(isAdvertisementShown);
});
});

describe('Variant #5: obfuscation of code that produces custom code helpers', () => {
const stringHeavyCode: string = 'var foo = \'long string value for the array\'; console.log(foo);';

let advertisementDisplayCount: number;

beforeEach(() => {
JavaScriptObfuscator.obfuscate(stringHeavyCode, {
stringArray: true,
stringArrayThreshold: 1,
stringArrayWrappersCount: 1
});

advertisementDisplayCount = consoleLogStub
.getCalls()
.filter((call) =>
typeof call.args[0] === 'string' &&
call.args[0].includes('JavaScript Obfuscator Pro is now available')
).length;
});

it('should show the advertisement message exactly once', () => {
assert.strictEqual(advertisementDisplayCount, 1);
});
});
});
});
1 change: 1 addition & 0 deletions test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ import './functional-tests/issues/issue424.spec';
import './functional-tests/issues/issue437.spec';
import './functional-tests/issues/issue1419.spec';
import './functional-tests/issues/issue1437.spec';
import './functional-tests/issues/issue1448.spec';
import './functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec';
import './functional-tests/node-transformers/control-flow-transformers/block-statement-control-flow-transformer/BlockStatementControlFlowTransformer.spec';
import './functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/BinaryExpressionControlFlowReplacer.spec';
Expand Down
Loading
Loading