Python-requests module, post two "values" to renew&scrape website - javascript

The first part was already answered, however, EDIT isn't.
I am using python and the requests module to scrape a website. Therefore I have to “click” a Renew-Button, which is a link(href) wrapped in an image “pat_renewmark.gif”.
html
<form name="checkout_form" method="POST" id="checkout_form">
<input type="HIDDEN" id="checkoutpagecmd">
<a href="#" onclick="return submitCheckout( 'sortByCheckoutDate', 'bycheckoutdate' )">
<img src="/screens/pat_sortbychkout.gif" alt="SORT BY DATE CHECKED OUT" border="0">
</a>
<input type="HIDDEN" name="currentsortorder" value="current_duedate">
<a href="#" onclick="return submitCheckout( 'requestRenewSome', 'requestRenewSome' )">
<img src="/screens/pat_renewmark.gif" alt="RENEW SELECTED ITEMS" border="0">
</a>
</form>
javascript (submitCheckout)
function submitCheckout(buttonname, buttonvalue)
{
var oHiddenID;
oHiddenID = document.getElementById("checkoutpagecmd");
oHiddenID.name = buttonname;
oHiddenID.value = buttonvalue;
//c29364j/c1365070 - prevent the patron from submitting twice
var oButtonSpan;
oButtonSpan = document.getElementById("checkoutbuttons0");
if (oButtonSpan) oButtonSpan.style.display = "none";
oButtonSpan = document.getElementById("checkoutbuttons1");
if (oButtonSpan) oButtonSpan.style.display = "none";
document.getElementById("checkout_form").submit();
return true;
}
Apparently submitCheckout passes .name and value, which are both assigned to ”requestRenewSome”’, to the hidden input with theid=“checkoutpagecmd”`.
I’ve worked with the requests module before and I am able to handle a simple username&password input , for example:
html
<div class="formEntryArea">
<label for="extpatid">
<span class="formLabel">
Your username:
</span>
</label>
<input name="extpatid" id="extpatid" value="" size="20" maxlength="40">
<label for="extpatpw">
<span class="formLabel">
Your password:
</span>
</label>
<input name="extpatpw" id="extpatpw" type="PASSWORD" value="" size="20" maxlength="40">
</div>
python
import requests
with requests.Session() as c:
LOGIN_URL = "https://example.com"
USERNAME = “XXXXX”
PASSWORD = “YYYYY”
source = c.get(LOGIN_URL)
data_load = dict(extpatid=USERNAME,extpatpw=PASSWORD)
head_load = dict(referer=LOGIN_URL)
c.post(LOGIN_URL, data=data_load, headers=head_load)
However, here c.post is handling only one “value” per input (either USERNAME or PASSWORD) and no javascript code is included.
As it seems, for the problem above I somehow have to post the two attributes/strings
.name = 'requestRenewSome'
.value = 'requestRenewSome'
? Or is the approach completely different to the example I attached?
EDIT
The answer from matino (or the comment from t.m.adam) solves the problem! Unfortunately the User then has to approve that he is sure he wants to renew by clicking a YES button.
html
<form name="checkout_form" method="POST" id="checkout_form">
<input type="HIDDEN" id="checkoutpagecmd">
<input type="HIDDEN" name="currentsortorder" value="current_duedate">
<span id="checkoutbuttons0">
<input type="SUBMIT" name="renewsome" value="YES">
<input type="SUBMIT" name="donothing" value="NO">
</span>
</form>
I therefore added 'renewsome': 'YES'to the data_load dictionary, but thats not enough. I don't know the value for the hidden input/s? id=checkoutpagecmd and/or? name=currentsortorder but couldn't find any answer on how to proceed.
P.S. I know it's actually a knew question, and I'm going to separate it, if it's getting answered.

What the javascript code actually does is dynamically assigning name and value to the hidden input. So in the end there can be 2 cases:
<input type="hidden" id="checkoutpagecmd" name="sortByCheckoutDate" value= "bycheckoutdate">
or
<input type="hidden" id="checkoutpagecmd" name="requestRenewSome" value= "requestRenewSome">
Knowing that, you can send http request like this:
requests.post(url, data={'sortByCheckoutDate': 'bycheckoutdate'}) # 1st case
requests.post(url, data={'requestRenewSome': 'requestRenewSome'}) # 2nd case

Related

compare two fields in Flask Jinja2

I am trying to compare two fields generated with Jinja, however, without the need of pressing the submit button.
I have used the included validators, standard if cases, etc. None of them work as expected, so I tried Javascript.
In general, I want to:
Compare two fields (domain/server). If their IP addresses are not exactly a 'Confirm' button should be shown.
In order to do that, I need to reload the server-side HTML.
Additionally, I am unable to figure out how to compare the two fields' IP addresses via Javascript.
Here is a sample code:
<div id="home" class="text-center">
Hello, {{ username }}
</div>
<body>
<input type="text" id="domain" size="30">
<input type="text" id="server" size="30">
{% if not compareArecords %}
<button type="button" class="btn btn-danger">Danger</button><br>
{%endif %}
</body>
<script>
document.getElementById("domain").addEventListener("keyup", compareArecords);
document.getElementById("server").addEventListener("keyup", compareArecords);
function compareArecords() {
var text1 = document.getElementById("domain");
var text2 = document.getElementById("server");
if (text1.value === text2.value)
return true;
else
return false;
}
</script>
What's typically done in order not to have to reload the html is to have the element hidden with css until you need to display it. In your example would be something like
<body>
<input type="text" id="domain" size="30">
<input type="text" id="server" size="30">
<button type="button" class="btn btn-danger hidden" id="btn-danger">Danger</button><br>
</body>
<script>
document.getElementById("domain").addEventListener("keyup", compareArecords);
document.getElementById("server").addEventListener("keyup", compareArecords);
function compareArecords() {
var text1 = document.getElementById("domain");
var text2 = document.getElementById("server");
if (text1.value === text2.value)
// Nothing to do here!
else {
var danger_btn = document.getElementById("btn-danger");
danger_btn.classList.toggle("hidden");
}
}
</script>
Css:
.hidden { display: none; }
It should be noted that you can also generate the Danger button entirely with javascript, and that's not overly complicated either, should you want to do that, but it has some drawbacks like separation of concerns.

JavaScript only changes text of first iteration with thymeleaf

I hope you are all well.
I have a school assignment, and I want to dynamically be able to change the name of a 'project'. This assignment is about projects. The way I've done it right now works with the first 'project' from a list of 'projects' iterated through with thymeleaf. I'm aware that what I've done right now is absolutely bad code behavior, but we have had no teaching in JS yet. But I really wanted this feature.
I don't know how to make this work for each project preview, right now it works for the first preview, but for the rest it just erases the project name from database. (see picture)
<div class="projects" th:each="projectNames : ${listOfProjects}">
<form action="deleteProjectPost" method="post">
<input type="hidden" th:value="${projectNames.projectID}" name="deleteID">
<input type="image" src="delete.png" alt="Submit" align="right" class="deleteProject" onclick="return confirm('Are you sure that you want to delete this project?')">
</form>
<form action="/editProjName" method="post">
<input type="hidden" name="projectID" th:value="${projectNames.projectID}">
<input type="hidden" id="oldName" th:value="${projectNames.projectName}">
<input type="hidden" id="newName" name="projectName">
<input type="image" src="edit.png" alt="Submit" onclick="change_text()" align="right" class="editProject">
</form>
<form action="/projectPost" method="post">
<input class="projectInfo" name="projectID" type="text" th:value="'Project No.: ' + ${projectNames.projectID}" readonly="readonly">
<input class="projectInfo" type="text" th:value="'Project name: ' + ${projectNames.projectName}" readonly="readonly">
<input class="projectInfo" type="text" th:value="${projectNames.projectStartDate} + ' - ' + ${projectNames.projectEndDate}" readonly="readonly">
<input type="submit" value="OPEN" class="openProject">
</form>
</div>
<script>
function change_text() {
var changedText;
var projectName = prompt("Please enter name of project:");
var oldName = document.getElementById("oldName").value;
if (projectName === null || projectName === "") {
changedText = oldName;
} else {
changedText = projectName;
}
document.getElementById("newName").value = changedText;
}
</script>
First form in HTML is the red cross to delete an entire 'project'. Second form is what is intended to change the name displayed on the 'project preview', but only works on first preview and deletes project name from the rest. Last form is the actual preview. I couldn't find another way to have multiple forms and do different POSTS while working with Java Spring and Thymeleaf.
My wish is to make the change_text() function work for each 'project preview'
Best regards!
function change_text(imageInput) {
var changedText;
var projectName = prompt("Please enter name of project:");
var oldName = imageInput.parentNode.querySelector('.old-name').value;
if (projectName === null || projectName === "") {
changedText = oldName;
} else {
changedText = projectName;
}
imageInput.parentNode.querySelector('.new-name').value = changedText;
}
<form action="/editProjName" method="post">
<input type="hidden" name="projectID" th:value="${projectNames.projectID}">
<input type="hidden" class="old-name" id="oldName" th:value="${projectNames.projectName}">
<input type="hidden" class="new-name" id="newName" name="projectName">
<input type="image" src="edit.png" alt="Submit" onclick="change_text(this)" align="right" class="editProject">
</form>
Ok so I made a few changes. First, notice the inputs with oldName and newName now have classes on them. These can be repeated. If you are not using the ids for anything other than the script, you should remove them. Otherwise if you have styling rules for them you should consider changing those CSS rules to use the class instead so you can remove the invalid repeating ids.
Secondly, the onlick of the image now passes in this. What that does is it passes in the actual input that the user clicked, so you have some context into which form element the user is interacting with.
Then looking at the logic, the method now accepts in imageInput which is the this from the onclick.
Using imageInput.parentNode we go up the DOM Tree to the parent element of the input, which is the form in this case. We can then turn around and use querySelector to find the other element in the form we want to manipulate. And it will only find the element in our particular form because that is what we are selecting off of.

how to prevent a user from maliciously alter a query (laravel)

i have a form which sends the following data to the server:
<!-- This form pulls, using JS event handlers, data from the table record selected -->
<form id="edit_form" action="" method="POST" role="form">
{{ csrf_field() }}
{{ method_field('PATCH') }}
<div class="form-group">
<label>ID do Cartão</label>
<input type="text" class="form-control" name="idcartao_edit" placeholder="ID do Cartão" value="" />
</div>
<div class="form-group">
<label>Nome do aluno</label>
<input type="text" class="form-control"
name="nome_aluno_edit" placeholder="Nome do Aluno" value="" />
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" name="email_edit" placeholder="E-mail" value="" />
</div>
<div class="form-group">
<label>Curso</label>
<select id="curso_edit" class="form-control" name="curso_edit">
<option>Seleccionar curso...</option>
#foreach($curso_list as $curso)
<option value="{{$curso->encrypted_id}}">{{$curso->curso}}</option>
#endforeach
</select>
</div>
<div class="form-group">
<label>Triénio</label>
<!-- Trigerred by a JS event handler when a curso_edit option is selected -->
<select id="trienio_edit" class="form-control" name="trienio_edit">
<option>Seleccionar triénio...</option>
</select>
</div>
<!-- Triggered when user opens a bootstrap modal. Pulls the value from the table record selected -->
<input type="hidden" id="idcartao_original" name="idcartao_original" value="" />
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Editar aluno</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Fechar</button>
</div>
</form>
on the server side, the data inputed by the user is processed like this:
public function update(Request $request, Aluno $aluno)
{
$id_aluno = $aluno->where('id_cartao', '=', $request->input('idcartao_original'))->first()->id;
$aluno = $aluno->find($id_aluno);
$aluno->id_cartao = $request->input('idcartao_edit');
$aluno->nome = $request->input('nome_aluno_edit');
$aluno->email = $request->input('email_edit');
$aluno->trienio_id = decrypt($request->input('trienio_edit'));
$aluno->save();
return redirect()->route('alunos');
}
the problem with this form is that the user can change the id to a different one, and the query will load an entirely non-intended different user. like changing the value from 1 to 2, for example, on this input field:
<input type="hidden" id="idcartao_original" name="idcartao_original" value="" />
so instead of loading a model like this:
ID: 1
ID Cartão: 1011000
Nome: Joseph Wilson
E-mail: joseph.67#gmail.com
it will load a model like this:
ID: 2
ID Cartão: 1011001
Nome: John Black
E-mail: johnblackwilliams#gmail.com
and proceed to change the data of a, like i said, an entirely non-intentional different model.
i've already tried to send encrypted ids using an ajax call to the server but considering the inputs can end up like this:
curso_edit option (the encrypted values are the encrypted ids of the "TAI" option, for example)
<option value="eyJpdiI6ImJqZGJKOGVBOFMyQ0huUXdKVHhFMXc9PSIsInZhbHVlIjoidWpROWRrSUFYREszbTF2Q24zTkVoZz09IiwibWFjIjoiM2QxYWViNzU0NWIyN2M2ZGQzMmMwYWJjYWUxZTAyYzBkOGNlNWQ0MDAzMjIyNzA1YWExNzg5ODA2MmNhYjBiMCJ9">TAI</option>
<option value="eyJpdiI6IjRVMWowT0cwYWxVeWpOXC9YaW0yRlJnPT0iLCJ2YWx1ZSI6IkF1VmZoTGdPT3BsTnR3MWV0bXhGdkE9PSIsIm1hYyI6ImY2ZDRiOGIyZDFmMjdmNjhkYzA4ZDMzNGVmNzY2NWZkYzhiMzA1ODljMmM1Njk3ODA1ZGFkZjQ4MWI5ZGM4MzcifQ==">TAL</option>
and so on...
trienio_edit option
<option value="eyJpdiI6ImpmTjBHSk8zTzQ0NmFLR0t1SkxhVXc9PSIsInZhbHVlIjoiOTFYOEluYXFWQk4xMVYxYk1JUHZ0Zz09IiwibWFjIjoiMWZhZDU0NmE2MWQwODliYzg3ZDEzM2Q5NTM3NWJiYTUxMzM5ZTQyMjMwMDBjZDI2OGE4ODEyZjAzNjk3MTVlYyJ9">2015-2018</option>
<option value="eyJpdiI6IjhvUTNGbnNZbG1Ja0d0NktFZFRNaGc9PSIsInZhbHVlIjoicGdKeWtZa1VEeHpDTzQ5QVFhRHcrdz09IiwibWFjIjoiM2EwM2IzZDY3Y2VmZWI4N2QzNTUyZGVlMTUxNjVkZjFiOWUzNGViYjdiNTFiMGZmMDEwMjBhY2JlYTg3ZDg3MiJ9">2014-2017</option>
and so on...
even if the user doesn't have access to the ids in their raw state, he can still inspect the element using chrome or other browser and pull the encrypted id corresponding to the curso/trienio they want to maliciously change (those present in the options)
so even if i send an ajax call to the server in order to pull an encrypted id corresponding to the item being altered in the form like this:
query by corresponding encrypted curso_edit id/value, encrypted trienio_edit id/value, unique email
the user can inspect the javascript code, replace the encrypted curso_edit, trienio_edit value, and e-mail by another one present in the options above.
how can i fix this ?
p.s - dont be too harsh on me. this problem is somewhat difficult to explain and i've tried my best to explain it, if you need more details say
by the way: i've organized the model by id, id cartao, nome, email and by using relationships, trienio and curso. this is somewhat a school management system, and by virtue of that, anybody that knows this info: course (curso), year (trienio), card id (id cartao, those are school cards with an id on it) ,name (nome) and email of a student will easily guess the columns values. i need something stronger and unguessable. and considering a school environment, those informations are very easily obtainable

On submit, remote call php - why aren't $_POST values being posted?

So, I'm a bit in unfamiliar territory with json and remote calls but the url and datatype is correct and... it is clearly arriving at target. BUT.!
It's a very simple form with 3 visible and 2 hidden fields.
<form id="subChange" action="#" method="POST">
<div style="clear:both;">first name</div>
<div>
<input id="fart" type="text" style="margin:4px;width:90%;" name="newFirst" value="" data-validetta="required,characters,remote[check_update]">
</div> last name<BR>
<div>
<input type="text" style="margin:4px;width:90%;" name="newLast" value="" data-validetta="required,characters,remote[check_update]">
</div> eMail<BR>
<div>
<input type="hidden" name="oldName" value="Conor" data-validetta="remote[check_update]">
</div>
<div>
<input type="hidden" name="oldEmail" value="cburkeg#gmail.com" data-validetta="remote[check_update]">
</div>
<div>
<input type="text" style="margin:4px;width:90%;" name="newEmail" value="" data-validetta="required,email,remote[check_update]">
</div>
<div style="margin-top:12px">
<input type="submit" name="sub_change" value="change it" data-validetta="remote[check_update]">
</div>
</form>
Here is the js
<script type="text/javascript">
$(function(){
$("#subChange").validetta({
realTime : true,
bubbleLoc:"right",
onValid : function( event ){
event.preventDefault();
$("#changeDIV").html("thanks Conor <P>Your subscription has been updated");
},
remote : { check_update : { type : "POST", url : "checkNewsUpdate.php", datatype : "json" }}
});
})
</script>
With fields filled we test Submit; name='sub_change' value='change it'
if (isset($_POST['sub_change'])) {
$count = count($_POST);
$postdata = file_get_contents("php://input"); //... write to file, etc.
}
output -
$count: 1
$postdata: sub_change=change+it
What happened to the other fields?
My only current working solution is to set each field with the remote call and set a $_POST validation (done auto., in real time) for each input which writes to a remote file. On submit we then call the contents of that file. Only trouble is it misses the 2 hidden files - there is no auto trigger :(
This is a clumsy work-around (that doesn't even work).
I thought about setting the hidden fields as an ID but getting the value with PHP is a trial. There must be something real simple I am missing here.

get name of hidden form

What i want to do is get the name of the hidden form which in this case is named:6ca3787zz7n149b2d286qs777dd8357b, the problem is, that form name always changes, the only thing that is the same is its value, which is 1, well 99% of the time, the only thing that is 100% the same that i guess could be somehow used to retrieve the form name is:L2ZvcnVtcy8 which is just above it. I am also attempting to do this via running javascript manually on the browser (chrome), so having that in mind where the javascript code is run through the url bar like this javascript:codegoeshere, how can i get the form name, -->(6ca3787zz7n149b2d286qs777dd8357b)?
<form action="index.php?feature=xxxxxx" method="post" name="login">
<input type="submit" name="submit" class="button" value="Logout" />
<input type="hidden" name="option" value="username" />
<input type="hidden" name="task" value="logout" />
<input type="hidden" name="return" value="L2ZvcnVtcy8=" />
<input type="hidden" name="6ca3787zz7n149b2d286qs777dd8357b" value="1" /> </form>
</li>
Check all the solutions below in this fiddle.
Some possibilities:
Assuming there is only one element with the name login and that element is the <form>, you can use:
document.getElementsByName('login')[0].getElementsByTagName('input')[4].name
If the return <input> has a fixed name attribute, then this should work (the additional .nextSibling is because there is a text node between them):
document.getElementsByName('return')[0].nextSibling.nextSibling.name
If any other of of those <input>s has a fixed name, you can use (in the example I take the <input> with name=task):
document.getElementsByName('task')[0].parentNode.getElementsByTagName('input')[4].name);
If all you really have is that fixed value, you'll have to use a for loop through all the <input>s:
var lastResortName = (function () { for(var i=0, ipts = document.getElementsByTagName('input'), n = ipts.length; i < n; i++) { if (ipts[i].value === "L2ZvcnVtcy8=") return ipts[i+1].name; } })();
Note: If there are duplicated values for the mentioned name attributes, test with the index ([0], [1], [2] and so on) until you find the expected elements.
That's really easy if you use JQuery:
$('input[type="hidden"]:eq(3)').attr('name')
Here your code running:
http://jsfiddle.net/7CHYa/

Categories