Securing XMLHttpRequest/AJAX from iterating through given parameters - javascript

Hello:) I am working on a project that requires to authenticate the user, not just via a normal login. I have certain information in my database (let's say projectnames) and I only want to show certain projects to certain users. The whole thing is already written in PHP, what I wanted to do now is to use AJAX/XMLHTTPREQUESTS from JS. The PHP file is taking the value of uid and returns then a json, that contains the information (in this case, projectnames of projects the user is working on). Yet I have it written like this:
var req = new XMLHttpRequest();
var uid = 1 //for testing
req.onreadystatechange = function () {
if (req.readyState == 4 && req.status == 200) {
var json = JSON.parse(req.responseText);
}
};
req.open("GET", "getprojects.php?uid=" + uid);
req.send();
Basically this works great, and the PHP is also working. The problem I have now, is that someone could simply bruteforce it's way into my system by iterating through the UserIDs. My question now is how I could secure my code, so that not everyone can easily iterate through all the uid's.
If you need more info, just tell.
Thanks already :)

Related

Return an object from an array of objects for a specific URL in JavaScript

I have a somewhat complicated issue. I'm working for a client that has an array of objects available for every lead on their website (e.g. contact form submission, newsletter signup etc.).
I'm currently working in Google Tag Manager to solve this issue. In order to let my client create their own events, I'm setting up a Tag Manager template where he can create these objects themselves.
However, I want to tie a specific object to a specific action. So if he creates the following object:
var obj1 = {name: 'test', page = 'example.com/test'}
I want this object to only work on that specific page. I know how to create this in JavaScript with a number of if/else statements. But I don't want to adjust the code every time he comes with a new action.
These actions use specific 'thank-you' or 'confirmation' pages to trigger an event on. I'm currently working on a way to push one of these objects whenever someone signs up. For example:
var obj1 = {name: 'newsletter', page = 'example.com/thank-you-newsletter'}
var obj2 = {name: 'contact_form', page = 'example.com/sign-up-contact'}
At the moment, there is no way of restructuring this. So, I was thinking the following:
var page = 'example.com/thank-you-newsletter'; //current page
var userSubmittedURL = 'example.com/thank-you-newsletter'; //given by me
list = [];
if (page === userSubmittedURL) {
list.push(obj1)
}
This userSubmittedURL changes all the time, is there a way to create a specifc object for a specifc page without adjusting the code all the time?
The way to do it is to store the page information in another source (like a text file) and then load it dynamically using ajax. Here is an example from w3Schools (https://www.w3schools.com/js/tryit.asp?filename=tryjs_ajax_first)
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
document.getElementById("demo").innerHTML =
this.responseText;
}
xhttp.open("GET", "ajax_info.txt");
xhttp.send();
In onload, rather than setting an elements innerHTML, you can use this.responseText to get your url

Can I access elements from a web page with JavaScript?

I'm making a Discord bot in JavaScript and implementing a feature where when you ask a coding question it gives you a snippet. I'm using Grepper and returning the url with the search results. For example:
Hello World in JavaScript Search Results. I would like to access the div containing the snippet. Is this possible? And how would I do it?
Here's my code:
if (message.startsWith('programming')) {
// Command = programming
message = message.replace('programming ', ''); // Remove programming from the string
message = encodeURIComponent(message) // Encode the string for a url
msg.channel.send(`https://www.codegrepper.com/search.php?answer_removed=1&q=${message}`); // Place formatted string into url and send it to the discord server
// Here the program should access the element containing the snippet instead of sending the url:
}
I'm new to JavaScript so sorry if this is a stupid question.
As far as I know the API you are using returns HTML/Text data, not JSON, Grepper has a lot more APIs if you just look into them, you can instead use this API that returns JSON data. If you need more information you can check this Unofficial List of Grepper APIs
https://www.codegrepper.com/api/get_answers_1.php?v=2&s=${SearchQuery}&u=98467
How Do I Access the div containing the snippet?
To access the div you might need to use python web scraping to scrape the innerHTML of the div but I think it's easier to use the other API.
Or
You can put /api/ in the url like:
https://www.codegrepper.com/api/search.php?answer_removed=1&q=js%20loop
The easiest way for this is to send a GET request to the underlying API
https://www.codegrepper.com/api/search.php?q=hello%20world%20javascript&search_options=search_titles
This will return the answers in JSON format. Obviously you'd have to adjust the parameters.
How did I find out about this?
Simply look at the network tab of your browser's dev tools while loading the page. You'll see a GET request being sent out to the endpoint, returning mentioned answers as JSON.
The best way is to use the grepper api.
Install node-fetch
npm i node-fetch, You need this package for making requestes to the api.
To import It in the code just type:
const fetch = require('node-fetch');
Write this code
Modify your code like this:
if (message.startsWith('programming')) {
message = message.replace('programming ', '');
message = encodeURIComponent(message)
// Making the request
fetch(`https://www.codegrepper.com/api/search.php?answer_removed=1&q=${message}`)
.then(res => res.json())
.then(response => {
// response is a json object containing all the data You need
// now You need to parse this data
const answers = response.answers; // this is an array of objects
const answers_limit = 3; // set a limit for the answers
// cheking if there is any answer
if(answers.length == 0) {
return msg.channel.send("No answers were found!");
}
// creating the embed
const embed = new Discord.MessageEmbed()
.setTitle("Here the answers to your question!")
.setDescription("")
// parsing
for(let i = 0; i < answers_limit; i++) {
if(answers[i]) {
embed.description += `**${i+1}° answer**:\n\`\`\`js\n${answers[i].answer}\`\`\`\n`;
}
}
console.log(embed)
msg.channel.send(embed);
});
}

JS: Node.js and Socket.io - globals and architecture

Dear all,
Im working with JS for some weeks and now I need a bit of clarification. I have read a lot of sources and a lot of Q&A also in here and this is what I learned so far.
Everything below is in connection with Node.js and Socket.io
Use of globals in Node.js "can" be done, but is not best practice, terms: DONT DO IT!
With Sockets, everything is treated per socket call, meaning there is hardly a memory of previous call. Call gets in, and gets served, so no "kept" variables.
Ok I build up some chat example, multiple users - all get served with broadcast but no private messages for example.
Fairly simple and fairly ok. But now I am stuck in my mind and cant wrap my head around.
Lets say:
I need to act on the request
Like a request: "To all users whose name is BRIAN"
In my head I imagined:
1.
Custom object USER - defined globally on Node.js
function User(socket) {
this.Name;
this.socket = socket; }
2.
Than hold an ARRAY of these globally
users = [];
and on newConnection, create a new User, pass on its socket and store in the array for further action with
users.push(new User(socket));
3.
And on a Socket.io request that wants to contact all BRIANs do something like
for (var i = 0; i < users.length; i++) {
if(user[i].Name == "BRIAN") {
// Emit to user[i].socket
}}
But after trying and erroring, debugging, googling and reading apparently this is NOT how something like this should be done and somehow I cant find the right way to do it, or at least see / understand it. can you please help me, point me into a good direction or propose a best practice here? That would be awesome :-)
Note:
I dont want to store the data in a DB (that is next step) I want to work on the fly.
Thank you very much for your inputs
Oliver
first of all, please don't put users in a global variable, better put it in a module and require it elsewhere whenever needed. you can do it like this:
users.js
var users = {
_list : {}
};
users.create = function(data){
this._list[data.id] = data;
}
users.get = function(user_id){
return this._list[user_id];
};
users.getAll = function(){
return this._list;
};
module.exports = users;
and somewhere where in your implementation
var users = require('users');
For your problem where you want to send to all users with name "BRIAN",
i can see that you can do this good in 2 ways.
First.
When user is connected to socketio server, let the user join a socketio room using his/her name.
so it will look like this:
var custom_namespace = io.of('/custom_namespace');
custom_namespace.on('connection', function(client_socket){
//assuming here is where you send data from frontend to server
client_socket.on('user_data', function(data){
//assuming you have sent a valid object with a parameter "name", let the client socket join the room
if(data != undefined){
client_socket.join(data.name); //here is the trick
}
});
});
now, if you want to send to all people with name "BRIAN", you can achieve it by doing this
io.of('/custom_namespace').broadcast.to('BRIAN').emit('some_event',some_data);
Second.
By saving the data on the module users and filter it using lodash library
sample code
var _lodash = require('lodash');
var Users = require('users');
var all_users = Users.getAll();
var socket_ids = [];
var users_with_name_brian = _lodash.filter(all_users, { name : "BRIAN" });
users_with_name_brian.forEach(function(user){
socket_ids.push(user.name);
});
now instead of emitting it one by one per iteration, you can do it like this in socketio
io.of('/custom_namespace').broadcast.to(socket_ids).emit('some_event',some_data);
Here is the link for lodash documentation
I hope this helps.

Instagram API URL to return all images with a certain tag

I'm using this URL to return a count for all images tagged with yolo:
https://api.instagram.com/v1/tags/yolo?access_token=
Is there anyway to return the image URLs and their metadata as well? I can only seem to get hold of the image URLs from the user related to the access token.
I can retrive the data I need by scraping Instagram with the following call. How can I extract the .window._sharedData as a json object?
var xhr = new XMLHttpRequest();
xhr.open('GET', "https://www.instagram.com/explore/tags/yolo/");
xhr.onload = function() {
if (xhr.status === 200) {
var result = xhr.responseText;
// .window._sharedData;
console.log(result);
// ('request successful ' + xhr.responseText.);
}
else {
console.log('request failed: ' + xhr.status);
}
};
xhr.send();
To get all the media and the related metadata, you need to use the GET /tags/tag-name/media/recent function, like so: https://api.instagram.com/v1/tags/yolo/media/recent?access_token=
First you'll get a list of 20 (if I remember correctly, can't check right now) most recent medias (images and/or videos) and then you have to check the id of the last media item you got. Then you just create a new request with MIN_TAG_ID set to that value.
Repeat until you have all the medias from that tag.
Basically all functions in the Instagram API that return a list of items, will have some sort of paging enabled. You just need to request the results page by page to get the full collection.
If you're testing your application on the sandbox, you'll get a different set of results than what the live application would get. Here's the explanation from Instagram's API documentation:
As another example, let's consider an endpoint that returns a list of media: /tags/{tag-name}/media/recent. The response returned by this endpoint will contain only media with the given tag, as expected. But instead of returning media from any public Instagram user, it will return only media that belongs to your sandbox users, restricted to the last 20 for each user.

API Request Loop Node.js and LiveChat API

As a side project at work, I am currently working on implementing a LiveChat Report web app. Basically, it will download all of our LiveChat data to .csv files for analysis, etc.
I have the entire thing working quite well; however, I am having a hard time wrapping my head around how to loop though requests based on pages of results returned. For example, I want certain information from each chat. LiveChat API only returns 25 chats on each page. Unfortunately, I cannot call each page at a time and depending on the date range parameters, the number of pages varies each time. I want to get all of these pages on 1 csv, if possible.
My request looks like:
function chatListReport() {
document.getElementById('chat_list_submit').addEventListener('click', function(event) {
var req = new XMLHttpRequest();
var params = {date_from:null,date_to:null, page:null};
params.date_from = document.getElementById('date_from').value;
params.date_to = document.getElementById('date_to').value;
params.page = document.getElementById('page').value;
req.onreadystatechange = function() { //when response received
if (req.readyState == 4 && req.status == 200) {
var response = (req.responseText);
var final = "data:text/csv;charset=utf-8," + encodeURI(response);
var link = document.createElement('a');
link.setAttribute('href', final);
link.setAttribute('download', 'ChatListSurveyReport.csv');
link.click();
}}
req.open('POST', '/chat_list_report', true); //submit update via POST to server
req.setRequestHeader('Content-Type', 'application/json'); //set request header
req.send(JSON.stringify(params));
event.preventDefault();
});
My server side looks like this (using NPM liveChatAPI):
app.post('/chat_list_report', function(req, res){
var params = req.body;
api.chats.list(params, function(data){
var headers = 'Chat Date,Agent,PostChat Survey Rating,Comments';
var result = (data.chats || [])
.filter(function(chat) {return chat.type === "chat"})
.map(function(chat) {
var postSurvey = chat.postchat_survey || [];
return [
chat.ended.replace(",", ""),
chat.agents[0].display_name,
(postSurvey[0] || {}).value || "",
(postSurvey[1] || {}).value || "",
].join(',');
});
result.unshift(headers);
res.send(result.join('\n'));
});
});
I am able to return the number of pages. That is included in the returned JSON. So in short, is there a way to return that page number response back to the request and loop through the request X amount of times and then create 1 csv with all of the information? Right now I am limited to only 25 chats per single request.
Thanks! Any help is greatly appreciated.
We see two possible solutions:
1:
A. Front-end sends a request to the backend, and then the backend returns ID of a job, which the front-end must store on it’s side, for example in the localStorage.
B. At this time, back-end works on the jobs on its own, and tries to finish it, as a complete task.
C. Front-end sends a request to the back-end every few seconds about the task, giving it’s ID. While the task is not complete, back-end replies with 'in-progress',
and front-end continues to enquire about the task until its finished.
D. If the front-end enquires about the task, and on this time receive notification
that the task is completed, then back-end returns a message like finished' with
further completed information.
E.
GUI should notify:
o Waiting for response
o Response successful, link to download a file.
---------OR----------
2:
A. Front-end sends request to back-end, back-end registers the task and after
completing the task sends an e-mail with the completed data.
B. Front-end informs that the task has been added to the ‘queue’ and only when it is
completed will an email be sent with the results of the task.
C. Requires adding additional input on the front end side : e-mail and handling some sort of API for e-mails e.g e,g,:https://postmarkapp.com/
Let me know how it works,
Cheers,
Adam

Categories

Resources