How can I obfuscate AngularJS codes? - angularjs

How can I obfuscate AngularJS codes?
We have tried gulp-obfuscate, but it does not work. Anyone can help us? Thanks a lot!
We have done like this
someModule.controller('MyController',[ '$scope', function($scope) {",
but after success to get the obfuscated codes like this
function H͇̬͔̳̖̅̒ͥͧẸ̖͇͈͍̱̭̌͂͆͊_C͈OM̱̈́͛̈ͩ͐͊ͦEͨ̓̐S̬̘͍͕͔͊̆̑̈́̅4() {
var H͇̬͔̳̖̅̒ͥͧẸ̖͇͈͍̱̭̌͂͆͊_C͈OM̱̈́͛̈ͩ͐͊ͦEͨ̓̐S̬̘͍͕͔͊̆̑̈́̅1, H͇̬͔̳̖̅̒ͥͧẸ̖͇͈͍̱̭̌͂͆͊_C͈OM̱̈́͛̈ͩ͐͊ͦEͨ̓̐S̬̘͍͕͔͊̆̑̈́̅2, H͇̬͔̳̖̅̒ͥͧẸ̖͇͈͍̱̭̌͂͆͊_C͈OM̱̈́͛̈ͩ͐͊ͦEͨ̓̐S̬̘͍͕͔͊̆̑̈́̅3;
...
H͇̬͔̳̖̅̒ͥͧẸ̖͇͈͍̱̭̌͂͆͊_C͈OM̱̈́͛̈ͩ͐͊ͦEͨ̓̐S̬̘͍͕͔͊̆̑̈́̅3 = H͇̬͔̳̖̅̒ͥͧẸ̖͇͈͍̱̭̌͂͆͊_C͈OM̱̈́͛̈ͩ͐͊ͦEͨ̓̐S̬̘͍͕͔͊̆̑̈́̅1 + H͇̬͔̳̖̅̒ͥͧẸ̖͇͈͍̱̭̌͂͆͊_C͈OM̱̈́͛̈ͩ͐͊ͦEͨ̓̐S̬̘͍͕͔͊̆̑̈́̅2;
return H͇̬͔̳̖̅̒ͥͧẸ̖͇͈͍̱̭̌͂͆͊_C͈OM̱̈́͛̈ͩ͐͊ͦEͨ̓̐S̬̘͍͕͔͊̆̑̈́̅3;
}
all angularjs codes in app-52143d391a.js not worked, it return
Uncaught Error: [$injector:nomod] Module 'client' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
After run
gulp.task('obfuscate', function () {
return gulp.src('../webapp/scripts/app-*.js')
.pipe(ngAnnotate())
.pipe(obfuscate())
.pipe(gulp.dest('dist'));
});
all are ok, and get below codes:
http://pan.baidu.com/s/1ntXuGbB
then run with below error:
Uncaught TypeError:  _ 206. _ 252 is not a function(anonymous function) # app-6c38d9a2fc.js:2
generated.js:9279Uncaught Error: [$injector:modulerr] Failed to instantiate module client due to:
Error: [$injector:nomod] Module 'client' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.4.7/$injector/nomod?p0=client

From the ngDocs:
Careful: If you plan to minify your code, your service names will get
renamed and break your app.
To make your code work after minification you have to use the inject property, every-time you use dependancy injection, to annotate your components. So even if the variable names change angular will know how to map the mangled variables with the proper service.
e.g:
Here we pass the $scope with dependency injection:
someModule.controller('MyController', function($scope) {
For this line to work you have to change to this:
someModule.controller('MyController',[ '$scope', function($scope) {
Or:
MyController.$inject = ['$scope'];
someModule.controller('MyController', function($scope) {
Or even better.
Use gulp-ng-annotate before the obsfucate task which does all that work for you.
UPDATE
After Obsfucation you should see the $inject string as they where, instead this plugin obsufucates them also. Meaning:
['$http', function($http) {
becomes:
[ "ಠ_ಠ727", function( ಠ_ಠ727 )
instead of:
[ "$http", function( ಠ_ಠ727 )
There is a relevant issue on github
I would suggest you use another plugin. With gulp-uglify I didn't have any issue.

Related

Mock an AngularJS module to pass to another

I'm having some trouble mocking a factory belonging to one of my modules. The factory I would like to mock has 2 dependencies:
Factory class:
angular.module('serviceapp')
.factory('claims.service', ['applicationSettings', 'localStorageService', function (applicationSettings, localStorageService) {
//Factory code here
}]);
Test class:
//Instantiate some values
var mockAppSettings = {};
var mockStorageService = {};
var $factory; //Will hold my factory
//Targeting my module for mocking
beforeEach(angular.mock.module('serviceapp'));
//Providing some values for the dependencies of my module
beforeEach(module('serviceapp', function ($provide) {
$provide.value('applicationSettings', mockAppSettings);
$provide.value('localStorageService', mockStorageService);
}));
//Problems start here
beforeEach(inject(function ($injector) {
$factory = $injector.get('claims.service');
}));
I get an error message
Failed to instantiate module serviceapp due to:
Failed to instantiate module accountModule due to:
Module 'accountModule' is not available!
When investigating I see that accountModule is listed as a dependency for the serviceApp module.
App.module class:
angular.module('serviceapp', [accountModule])
However I'm having some trouble mocking this module to pass to serviceapp. I have tried to mock the accountModule in the same way I have mocked the serviceapp in the beginning however this is still bring up the same error message. How can I mock and pass one module to another?
angular.mock.module('serviceapp') shouldn't be read literally. It doesn't mock a module. It is the same thing as module('serviceapp') and is used in modular environments where module is reserved.
So, all that
beforeEach(angular.mock.module('serviceapp'));
beforeEach(module('serviceapp', ...));
does is loading serviceapp twice (doesn't hurt but doesn't help either).
To avoid Module 'accountModule' is not available!, it should be (re)defined:
beforeAll(() => {
angular.module('accountModule', [])
});
The problem with this approach is that even if it was defined, it will be overridden to the end of test run. If real accountModule needs to be used in other tests, this won't be possible.
The appropriate solution for similar design issues (this also applies to dependencies that aren't desirable in tests, e.g. router modules) is
angular.module('serviceapp', ['accountModule']);
angular.module('serviceapp.internal', [])
.factory('claims.service',...);
Here serviceapp serves as a shallow wrapper for serviceapp.internal, while the latter can be safely tested. If serviceapp is top-level module that is used for bootstrapping, this indicates that the application wasn't modularized enough, this hurts testing.

Gulp Task Breaking on Angular Files

I have the gulp task set up and running to create an Angular app, and it runs without error and creates the files correctly, but when I load the page on a browser, I get following error messages.
Is there some step or some plugin I'm missing to get the Angular files to all "work"? I've used the angularFilesort() and ngAnnotate() plugins already.
var bower = gulp.src(bower_files)
.pipe(concat("bower-expanded.js"))
.pipe(gulp.dest(paths.prod))
.pipe(rename("bower.js"))
.pipe(uglify())
.pipe(gulp.dest(paths.prod + paths.js));
// gather and compress the app's js files
var app = gulp.src(paths.source + "app/**/*.js")
.pipe(angularFilesort())
.pipe(concat("app-expanded.js"))
.pipe(ngAnnotate({
add: true,
single_quotes: true
}))
.pipe(gulp.dest(paths.prod))
.pipe(rename("app.js"))
.pipe(uglify())
.pipe(gulp.dest(paths.prod + paths.js));
The errors are
TypeError: (intermediate value)(...) is not a function
(function(angular) {
which points to these lines of code
(function(angular) {
'use strict';
/**
* Called with an array this acts like map, otherwise it acts like _.mapValues
* in lodash.
* #return {Array|Object} The same type as the input argument.
*/
var mapValues = function(obj, callback) {
if (angular.isArray(obj))
The other error is
Error: [$injector:modulerr] Failed to instantiate module app due to:
[$injector:modulerr] Failed to instantiate module angularSpinner due to:
[$injector:nomod] Module 'angularSpinner' is not available!
You either misspelled the module name or forgot to load it.
If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.4.4/$injector/nomod?p0=angularSpinner
I notice you're not running ngAnnotate on your bower components, but you are running uglify on them. This could be causing your problem.
Try:
var bower = gulp.src(bower_files)
.pipe(concat("bower-expanded.js"))
.pipe(ngAnnotate({
add: true,
single_quotes: true
}))
.pipe(gulp.dest(paths.prod))
.pipe(rename("bower.js"))
.pipe(uglify())
.pipe(gulp.dest(paths.prod + paths.js));
As an aside, it's not an awesome idea to concatenate all of your dependencies into a single file. The browser can handle asynchronously loading multiple JS files and will do so much faster than loading a single, massive JS file.
After reading through various answers in SO the first error usually refers to a forgotten ; in the lines prior to the error.
You can configure the concat task to use ; as a seperator for js files to avoid this.
On the second I agree with #ShaunScovil, also using the .min files provided from each bower package is safer.
You can make use of this main-bower-files package to set this up depending of the env and automate the process of building one or more files of all bower dependencies.
This same thing happens with GruntJS and I recently learned how to fix it. Make sure all of your angular js controllers, directive and filters have proper includes on them.
Example wont work:
angular.module('uniApp').directive('autoFocus', function ($timeout) {
return function (scope, element, attrs) {
scope.$watch(attrs.autoFocus,
function (newValue) {
$timeout(function () {
element.focus();
});
}, true);
};
});
Notice on the above how the $timeout is not properly included?
Example will work:
angular.module('uniApp').directive('autoFocus',['$timeout', function ($timeout) {
return function (scope, element, attrs) {
scope.$watch(attrs.autoFocus,
function (newValue) {
$timeout(function () {
element.focus();
});
}, true);
};
}]);
Now the $timeout is properly included. Make sure to check this little detail on all controllers, filters, and directives.

AngularJs can't inject $provide and $injector services in module.run

I'm trying to define services dynamically in angularjs, as the docs says, $provide and $injector are services, thus they should be injectable in module.run..
I need to make the dynamic services available from app bootstrap, that's why i'm trying to define them in module.run
angular.module('remote.interface',[])
.run(['$provide', '$injector', function(provide, injector){
// provide dynamically
}]);
but this ends up in an Error : [$injector:unpr] Unknown provider: $provideProvider <- $provide, and same eror for $injector if i try to remove $provide injection.
Where's the bug?
[EDIT]
after some research i tried something like this:
var module = angular.module('remote.interface',[])
.run([function(){
var provide = module.provider(),
injector = angular.injector();
provide.value('my.val',{i:'am a value'});
injector.get('my.val'); // this throws [$injector:unpr] Unknown provider: my.valProvider <- my.val
}]);
even if i remove the injector.get call, if i try to inject my.val, for example, in another-module's controller, angular throws the same error.
Have a look at the documentation for module and have a read at the comments in the example setup, particularly these comments.
config
You can only inject Providers (not instances) into config blocks
run
You can only inject instances (not Providers) into run blocks
Here is an example setup on JSFiddle injecting $provide and $injector correctly.
https://docs.angularjs.org/guide/module
angular.module('myModule', []).
config(function(injectables) { // provider-injector
// This is an example of config block.
// You can have as many of these as you want.
// You can only inject Providers (not instances)
// into config blocks.
}).
run(function(injectables) { // instance-injector
// This is an example of a run block.
// You can have as many of these as you want.
// You can only inject instances (not Providers)
// into run blocks
});

Getting error when trying to use $provide in jasmine unit test

I'm using AngularJS and trying to test a controller that calls a factory to get some data.
This is the controller code:
'use strict'
angular.module('AngularApp')
.controller 'IndexCtrl', ($scope, session, navigation) ->
session.find().then (response) ->
$scope.session = response.data
$scope.someOtherVariable = {}
Naturally, I'd like to swap the factory with a mock to prevent calling a real API. I'm trying to use $provide.factory to inject the mock copy:
'use strict'
describe 'Controller: IndexCtrl', ->
# load the controller's module
beforeEach module 'mosaicAdminWebClientApp'
beforeEach module ($provide) ->
$provide.factory 'session', ->
true
IndexCtrl = {}
scope = {}
# Initialize the controller and a mock scope
beforeEach inject ($controller, $rootScope) ->
scope = $rootScope.$new()
IndexCtrl = $controller 'IndexCtrl', {
$scope: scope
}
it 'should attach a list of awesomeThings to the scope', ->
expect(true).toBe true
When running this test with Karma, I guess this error:
Chrome 32.0.1700 (Mac OS X 10.9.1) Controller: IndexCtrl should attach a list of awesomeThings to the scope FAILED
Error: [ng:areq] Argument 'fn' is not a function, got Object
http://errors.angularjs.org/1.2.10-build.2176+sha.e020916/ng/areq?p0=fn&p1=not%20a%20function%2C%20got%20Object
at /Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:78:12
at assertArg (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:1363:11)
at assertArgFn (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:1373:3)
at annotate (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:3019:5)
at Object.invoke (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:3685:21)
at /Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:3554:71
at Array.forEach (native)
at forEach (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:303:11)
at Object.createInjector [as injector] (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular/angular.js:3554:3)
at workFn (/Users/blaiz/Documents/some_angular_app/app/bower_components/angular-mocks/angular-mocks.js:2144:52)
Chrome 32.0.1700 (Mac OS X 10.9.1): Executed 10 of 10 (1 FAILED) (0.26 secs / 0.068 secs)
Warning: Task "karma:unit" failed. Use --force to continue.
Aborted due to warnings.
I've tried many different permutation, such as removing the label, passing an object or simple value instead of a function and none of them worked.
The documentation (http://docs.angularjs.org/api/AUTO.$provide) shows that I should call the factory() method with as factory(name, $getFn) where name is a string and $getFn is a function. That's what I'm doing but it's not working.
Anything I've missed? Does anyone know how to properly use $provide in Jasmine unit tests?
Thanks
Update:
I found a plunkr similar that solved an issue similar to this one here: stackoverflow.com/questions/19297258/why-is-provide-only-available-in-the-angular-mock-module-function-and-q-onl
I created my own plunkr with this code, but with the test code in JS instead of Coffee and got it to work: plnkr.co/edit/gfBzMXpKdJgPKnoyJy5A?p=preview
Now I manually converted the JS code into Coffee: plnkr.co/edit/qGGMayFjJoeYZyFKPjuR?p=preview
The error is back so the coffee code is wrong but the js code works.
Found the answer to my question.
Since CoffeeScript always returns the result from the last statement, in this case, CoffeeScript returns $provide inside of module(), which is wrong. An easy way to fix that is to just manually add a return statement after $provide, like this:
beforeEach module 'mosaicAdminWebClientApp', ($provide) ->
$provide.service 'session', ()->
return
Hope that will help someone else.

Getting "Unknown provider: $qProvider <- $q" when fetching the defer/promise from my AngularJS injector

I am trying to create a simple example where I get the promise/defer object from AngularJS's service solution:
var $q;
function init() {
var $injector = window.angular.injector();
console.log($injector);
$injector.invoke(["$q", function (_$q) {
console.log($q);
$q = _$q;
}]);
}
init();
But it results in:
Error: Unknown provider: $qProvider <- $q
[Break On This Error]
throw Error("Unknown provider: " + path.join(' <- '));
What could I have missed?
You have to add which module the provider resides in like this:
var $injector = window.angular.injector(['ng']);
Then it will work!
Edit: Regarding the 'ng' module, the docs specifically says that it must be explicitly added. From the angular injector docs:
modules – {Array.<string|Function>} – A list of module functions or their aliases.
See angular.module. The ng module must be explicitly added.
Use https://github.com/kriskowal/q if you're outside a angular.js module lifecycle, I've go down that road and it will not work well, $q is not meant to be used outside of a bootstraped module (require a $rootScope).

Resources