ahorek / terser-ruby

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Trouble with params to achieve sufficient obfuscation in rails

optimusmoose opened this issue · comments

Hello and thanks for the gem. I had quite a time finding out the syntax for modifying parameters in rails, and struggled to get the provided parameters to pass without errors. I bet I'm doing something wrong.

Here's what I've got in production.rb:

config.assets.js_compressor = Terser.new( mangle: true, keep_fnames: false, toplevel: true )

The only change in the resulting code seems to be the replacement of variable names with single letters.

Question 1: Am I specifying "keep_fnames" incorrectly? I tried false and true, and in both cases the function names remain unmodified. If I can get the function names to mangle, it will go a long way towards what I'm trying to achieve.

Question 2: How do you set the parameter to modify property names? I tried properties: true and mangle_properties: true to no avail.

Suggestion: It might help others to add a rails example of setting parameters in production.rb as above. It took me a while to figure out something that worked.

Many thanks!

Q1: modifying function names works fine, do you have a small example?
(function() {
function plus(a, b) { return a + b; };
plus(1, 2);
})();

mangle: true, keep_fnames: false, toplevel: true
!function(){function n(n,t){return n+t}n(1,2)}();
mangle: true, keep_fnames: true, toplevel: true
!function(){function plus(n,u){return n+u}plus(1,2)}();

Q2: you probably hit a bug. mangle_properties is unfortunately broken for a long time
https://github.com/ahorek/terser-ruby/blob/1e0293e90ebe7dfd5900d059cd95704f10d4c60d/spec/terser_spec.rb#L49C16-L49C16
the API is probably different and it has to be updated according to https://github.com/terser/terser#minify-options-structure

if anyone's interested in fixing this, contributions are welcome :)

Thank you for the reply, the heads up on properties, and the proof that change function names works.

I can't find a single instance in my project of any function whose name was changed. Here are some properties of my project, in case something here is relevant:
We are using Rails 7.
We are using JS controllers / stimulus.
We are not using function() syntax.

Example:
const checkIfShapeIsOnChart = (chart, shape) => {
const { chartArea, scales } = chart;
const xValues = shape.map((point) => scales.x.getPixelForValue(point[0]));
const yValues = shape.map((point) => scales.y.getPixelForValue(point[1]));

if (Math.min(xValues) > chartArea.right || Math.max(xValues) < chartArea.left || Math.min(yValues) > chartArea.bottom || Math.max(yValues) < chartArea.top) {
return false;
}
return true;
}

const setPointInsideChart = (chart, point) => {
const { chartArea, scales } = chart;

let xPixel = scales.x.getPixelForValue(point[0]);
if (xPixel < chartArea.left) xPixel = chartArea.left;
if (xPixel > chartArea.right) xPixel = chartArea.right;

let yPixel = scales.y.getPixelForValue(point[1]);
if (yPixel < chartArea.top) yPixel = chartArea.top;
if (yPixel > chartArea.bottom) yPixel = chartArea.bottom;

return [xPixel, yPixel];
}

(...)
export {
checkIfShapeIsOnChart,
setPointInsideChart
}

Is mangled into:
const checkIfShapeIsOnChart = (e,t)=>{ const {chartArea: o, scales: a} = e , r = t.map((e=>a.x.getPixelForValue(e[0]))) , l = t.map((e=>a.y.getPixelForValue(e[1]))); return !(Math.min(r) > o.right || Math.max(r) < o.left || Math.min(l) > o.bottom || Math.max(l) < o.top) }
(space inserted for readability)
, setPointInsideChart = (e,t)=>{ const {chartArea: o, scales: a} = e; let r = a.x.getPixelForValue(t[0]); r < o.left && (r = o.left), r > o.right && (r = o.right); let l = a.y.getPixelForValue(t[1]); return l < o.top && (l = o.top), l > o.bottom && (l = o.bottom), [r, l] } export {checkIfShapeIsOnChart, setPointInsideChart}

The gem is obviously doing some things to this code (note the abbreviated variable names), but the function names are not changed. Perhaps only functions that are declared using function() are picked up by the parser for name changing?

If so, I suppose I could re-declare all my functions. But I'm not sure how else to declare class methods.

For example, here are some class methods from the project:
`replaceGraphWithMessage(a) {
const t = document.getElementById("stacked_chromatogram_graph_message");
t.style.display = "block",
t.innerText = a
}

replaceMessageWithGraph() {
const a = document.getElementById("stacked_chromatogram_graph_message");
a.style.display = "none",
a.innerText = ""
}`

Hmmm... I changed a few function declarations to use function(), but the function names still didn't change.

I suspect that this has something to do with how I am exporting functions, the way Rails 7 JS controllers work, or how I've got things configured. Any clues as to what I should look into?

could you try it with Terser.new( mangle: { keep_fnames: false, toplevel: true } ) ?

btw you can experiment with different settings here https://try.terser.org/ just note that the ruby wrapper has different defaults, so results may vary...

That worked. Thank you very much!

I hate to trouble you more, and I know this is outside the scope of the gem per se: Do you happen to know a method for rendering the separate file into one large one? The hope here is to achieve even more obfuscation through getting rid of lines like this:

export {l as checkIfShapeIsOnChart, r as setPointInsideChart, a as drawShape, i as drawVerticalLines, n as drawOvalIfTooSmall, s as drawCircle, h as drawX, c as roundShapePoints, g as combineShapes, m as getShapeDifference, x as getShapeOverlap, u as setShapeWithHoles};

Exports are like a public API, they cannot be (safely) removed or renamed and Terser doesn't know all dependencies. Theoretically, a bundler like Webpack could do that (still unsafe), but I wouldn't recommend it. It won't give you any security if that's what you're after...

Many thanks!