I have a very small Django app, mostly just for learning purposes. I am using the inbuilt User model provided by Django. To learn the functionality, I've created pages which allow me to create and edit users without having to go to the admin panel.
The register page allows me to very easily check for things like password and email validity, as when I POST to a View, I simply use user_form.is_valid() to check the fields are correct (username is less than 30 characters, password less than 128, other conditions...).
For my edit page, I wanted to make the content more responsive so I have made use of AJAX requests via JQuery, allowing me to perform actions without reloading the page. This works great, but it does leave me with the problem of checking validity, as I am not sending the form, I am just using Javascript to pick out the queries and send them in an AJAX request as such:
$.get('/dms/edit_user_changeuser/', {inputNameSend : $("#inputname").val(), usernameToSend : $("#usernameID").val(), emailToSend : $("#emailID").val(),passwordToSend : $("#passwordID").val(), disabledToSend : checkedVal}, function(data){
if(data != "success"){
$("#errorDisplay").show();
}else{
$("#savedDisplay").show();
$("#user_form").hide();
}
});
And this is how the associated View handles it:
#login_required
def user_edit_changeuser(request):
# Like before, get the request's context.
context = RequestContext(request)
inputname = request.GET['inputNameSend']
newUsername = request.GET['usernameToSend']
newEmail = request.GET['emailToSend']
newPassword = request.GET['passwordToSend']
if(request.GET['disabledToSend'] == "true"):
disabledBool = False
else:
disabledBool = True
try:
user_obj = User.objects.get(username=inputname)
print("retUser")
user_obj.username = newUsername
user_obj.email = newEmail
user_obj.is_active = disabledBool
user_obj.set_password(newPassword)
user_obj.save()
print(str(disabledBool))
return HttpResponse("success")
except Exception, e:
return HttpResponse(str(e))
This all works assuming input is valid, but is there something like User.checkValidPassword(newPassword) to manually check validity?
User instances have a method check_password which does exactly what you want it to do
user = User.object.get(username=inputname)
user.checK_password('a_password')
The above checks to see if the current users password matches what is saved in the db. If you were instead asking about validating to make sure the newPassword is valid ie. is the proper length, contains numbers, etc. There is no reason you cannot use a form to validate the user input, just as you would if it were not an AJAX based view
as a side note, it is not necessarly the best thing to catch all exceptions in python. It can mask all sorts of errors that you want to see fail!
if you are expecting that a user might not exist do it explicitly.
try:
user = User.object.get(username=inputname)
except User.DoesNotExist:
# all other expections will not be caught!
Related
I have purchased a booking plugin (wordpress) to add to a site.
https://wpamelia.com/
I cannot show the site I am working on, but here a demo from plugin developers
https://sports.wpamelia.com/#book
Once you have chosen your date and time, you end up on a form with input fields.
I was able to pre-fill this form with data that I could pass via the URL.
My URL would look something like this: https://sports.wpamelia.com/?first=Jim&last=Tester&email=something%40something.com&phone=0222222222#book
But here is the problem:
Even though I managed to use jQuery to pre-fill the input fields of the form, as soon as I click confirm the fields' content is erased and the error "Please enter... " appears for each of them.
So again:
STEP 1: I open the booking page with an URL containing data in the query string
STEP 2: Using jQuery, I manage to pre-fill the form that appears after having chosen date and time (first name, last name ...)
STEP 3: I click "Confirm"
RESULT: all the fields are empty and for each one the error message "Please enter first name" (etc..) appears
I've messaged the plugin developers. Only answer was that there is indeed no functionality to take the data from the Query String into the form fields yet.
MY QUESTIONS:
1) How could I find out, with chrome inspector or other tools, why exactly the content I pre-fill into the form is ignored?
---> I've tried things like getEventListeners in the chrome inpector's console, but I don't really see how to get information out of that
2) Would anyone know what the issue is and/or how I could bypass it?
---> there is a lot of javascript from the plugin developers behind that and something is expecting manual entering of the data into the fields...
---> but even when trying to fake manual entering with things like $(this).trigger("change").val(function(i,val){return 'aaaa';}); this didn't solve the problem....
(If anyone is interested, I can post later my javascript/jQuery functionality to get the form fields pre-filled with data from Query String... interesting code as you have to wait until the fields appear for jQuery to recognise them..)
Thanks so much for any help!
cheers
Admino
#Admino - this may not be the best solution and I know this is an old question so you may not need it now but after not finding a better one it at least worked for me.
function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
});
return vars;
}
function valueOutput(element) {
element.dispatchEvent(new Event('input'));
}
jQuery(function() {
jQuery(document).on('change', 'input', function(e) {
valueOutput(e.target);
});
// you may want to perform more validations here if needed
// just checking here if email is present (but not checking for valid email address)
var fname = getUrlVars()["first"];
var lname = getUrlVars()["last"];
var email = getUrlVars()["email"];
var phone = getUrlVars()["phone"];
var custom1 = getUrlVars()["custom1"]; // you know this field label is Order Number
if (email.length > 0) {
// run an interval until the elements are present on the page (form displayed)
var checkInputs = setInterval(function() {
if (jQuery('.amelia-app-booking label[for="customer.email"]').length > 0) {
var em = jQuery('.amelia-app-booking label[for="customer.email"]').closest('.el-form-item').find('.el-input__inner');
// this checks to see if an Amelia customer is already present
if (em.val() == '') {
em.prop('value', email).val(email).trigger('change');
jQuery('.amelia-app-booking label[for="customer.firstName"]').closest('.el-form-item').find('.el-input__inner').prop('value', fname).val(fname).trigger('change');
jQuery('.amelia-app-booking label[for="customer.lastName"]').closest('.el-form-item').find('.el-input__inner').prop('value', lame).val(lame).trigger('change');
jQuery('.amelia-app-booking label[for="customer.phone"]').closest('.el-form-item').find('.el-input-group__prepend').siblings('.el-input__inner').prop('value', phone).val(phone).trigger('change');
}
// for custom fields I check the label text to find the correct input
if (custom1 != '') {
jQuery('.amelia-app-booking label:contains("Order Number")').closest('.el-form-item').find('.el-input__inner').prop('value', custom1).val(custom1).trigger('change');
}
// form info is updated so clear the interval
clearInterval(checkInputs);
}
}, 500);
}
});
You may want to try a different method than url params to sync this info so it's not so public in the url string. This code may not need both the prop and val jquery setters but I just left them for you to try. Hope it helps (and to others I'm open to a better solution)!
I have created a form where a user gets to type in data that is saved in variables when the data is submitted. I am requesting a solution that will both save the user's data whilst also redirecting the user to a new .html-page when the button is pressed.
<button type="button" onclick="getInfo()">Submit</button>
As you can see above, the button is activating a function, that will save the info like this:
function getInfo(){
var firstname = document.getElementById("firstname").value
var lastname = document.getElementById("lastname").value
var adress = document.getElementById("adress").value
var password1 = document.getElementById("password1").value
var password2 = document.getElementById("password2").value
}
How can I make this possible? Sincerely, Decentralized.
Hi You can use form action with multiform attribute just like this
<form id="form_name" action="yourhtmlname.html" method="post" class="pure-form" enctype="multipart/form-data">
Maybe you are searching for something like that :
function getInfo(){
var firstname = document.getElementById("firstname").value
var lastname = document.getElementById("lastname").value
var adress = document.getElementById("adress").value
var password1 = document.getElementById("password1").value
var password2 = document.getElementById("password2").value
localStorage['firstname'] = firstname; // store data into browser's storage
window.location = 'http://overpage.html'; // change the browser's page
}
Note :
you can access data one the ther page using
var firstnameNewPage = localStorage['firstname'];
take a look at sessionStorage if you want to keep data available only for session usage
First of all, this is not how you should handle credentias and authentication, but for the sake of this question, I'll ignore that.
Since your question is very broad and can have many possible answers.
So my answer is going to be general
Here are some of the ways you can store this data and display it in another page are:
Send the data to a server, so it can be stored in the server's session or database to be retrieved latter (via an ajax call, or html forms).
Make your app a single page application so all your 'pages' share a state that can be used to move data around.
Some examples of javascript frameworks from Wikipedia that are implemented as SPA:
AngularJS, Ember.js, Meteor.js, ExtJS and React
Use a browser APIs called sessionStorage or localStorage.
They can be used to store key-value pairs of strings to be accessed latter for.
You could also store JSON data in them using the JSON.parse and JSON.stringify functions.
My suggestion:
From these possibilities I would say option 3 (localStorage) would be the easiest to implement with something like:
localStorage.setItem('first name', fname);
and
var fname = localStorage.getItem('first name');
Which would save these values in the browser.
And you can do location.replace('/path/to/other/page.html') right after that and load these values in the other page as long as you use it in the same domain.
Is there a way to redirect the user to a certain URL on the basis of what comes out of an XMLHttpRequest()? Here's what I am trying to achieve:
User hits submit, form gets submitted, XMLHttpRequest() fired
Response received from the server, stored in var hr
If hr = abc, show contents of hr
If hr = xyz, redirect user to http://www.something.com
What I am looking for is if there's any predesigned method in either JS or JQ to handle such redirects. I understand redirects can be specified in the <meta> tags in the <header> section of the page but if I did that, how will I be able to add conditions to it? I would have posted a copy of the script I have attempted but can't because right now, I have no idea where to even begin!
In case someone is curious about the scenario, this is a Web-based dictionary/conjugation service. So, on the verb conjugation page, if the user enters a valid verb, the response (i.e. the conjugation tables) is displayed. However, if the user enters a word that's valid but not a verb so it can't be conjugated, I want the user to be automatically redirected to the dictionary page where the entered word's dictionary entry will be displayed. Not sure if I have explained it well enough but please feel free to ask should you have any questions.
Try testing with switch(request.responseText) and call window.location.assign("http://your-url.com"); in the preferred case "xyz"! Alternatively window.open("http://anotherxxxwebsite.com") opens the link in a new browser window.
There's no "predesigned" method, but you can write that logic yourself. Depending on your current API you could either check if the returned value is an URI (or some other designated value instead) an redirect accordingly. Assuming a deferred object returned from jQuery.ajax:
defer.done(function(data, textStatus, jqXHR) {
// assuming a string, but this could really be anthing, e.g.
// an object containing an appropriate attribute, etc.
if (data.indexOf('http') === 0) {
window.open(data);
} else {
// render your stuff
}
});
I am posting a form to the controller and making it asynchronous. I am storing values in input form hidden. When a button is clicked, a javascript function is called. It both fetches the value from an input field, as well as a value from input form hidden. It then sends a json string to the controller to handle this request.
Controller:
[HttpPost, Authorize]
public ActionResult DoSomeStuff (string leagueName, string doSomething) {
var service = new Service(_db);
var league = service.GetLeague(leagueName);
if (league != null) {
// validate doSomething
league.Action = doSomething;
_db.SaveChanges();
}
return new EmptyResult();
}
Javascript:
$(document).on("click", "#submitForm", function () {
var json = {
"leagueName": $("input[name=leagueName]").val(),
"doSomething": $("input[name=doSomething]").val()
};
$.post("/Home/DoSomeStuff/", json, function () {
// async display something
});
}
Html:
<input type="text" name="doSomething">
<button type="submit" id="submitForm"</button>
<input type="hidden" name="leagueName" value="#item.League.LeagueName" />
What is the best way to let javascript fetch a stored value (more secure way then input type hidden)?
How can I prevent some user from altering the value from the input type
hidden field?
How can I prevent some user from altering the value from the input
type hidden field?
You cannot!
What is the best way to let javascript fetch a stored value (more
secure way then input type hidden)?
The general rule is, do not trust data coming from client. You should always validate it on server before doing anything.
If you are worried about a user update the league name field value in the form to some other users league name and post it, What you should be doing is, explicitly checking whether the user has proper permission to do something on the posted league in your server code.
[HttpPost, Authorize]
public ActionResult DoSomeStuff (string leagueName, string doSomething) {
var service = new Service(_db);
var league = service.GetLeague(leagueName);
// Now check whether the current user has access/permission
// to perform some operation on this league.
// Ex : if(!service.IsUserAuthorizedToDoSomething(league))
// {
// return View("NotAuthorized");
// }
//to do: Return something
}
If the value needs to come from the client (and be part of the HTTP request) then there's absolutely nothing you could do to prevent the client from modifying its contents. If the client is not supposed to modify the contents of some fields then those fields have nothing to do in your markup and be part of the postback HTTP requests (be it as hidden fields or whatever markup element comes to your mind). They should safely reside on your server (database?) and be retrieved using some identifier coming from the client. Obviously whether the client can access the information related to this identifier is subject to something called authorization. Basically you should first know who your client is (authentication) and then verify in your data model if this client has access to the corresponding records. It's as simple as that.
[HttpPost]
[Authorize]
public ActionResult DoSomeStuff (string id, string doSomething)
{
var service = new Service(_db);
var league = service.GetLeagueById(id);
if (!HasAccessToLeague(User.Identity.Name, league))
{
// you are not suppose to modify the contents of this league
// throw him a 404 or something
}
else
{
if (league != null)
{
// validate doSomething
league.Action = doSomething;
_db.SaveChanges();
}
}
return new EmptyResult();
}
obviously the implementation of the HasAccessToLeague(string username, string leagueId) method will greatly depend on your data model and how your authorization logic.
Also you used XSS in your question title but here your problem is not about XSS or javascript but rather designing authorization layer in your web application.
of course its possible to do this! After all, your server app manages to track who the currently logged on user is using insecure client storage.
When a user logs on, the server will generate a secret message and store it in an encrypted token that's passed to the client and bak in a cookie (which is just another piece of unsecured client data storage). When you send requests to the server, it gets the cookie, decrypts it, and checks the data inside to tell who the user is.
You can do the same - for the hidden fields, encrypt them, put them in a hidden input (or a cookie if you prefer) and send them back to the server. However, you can only use them in your client javascript if you send them plain text as well, which means you need to still perform some checking on the server, but that checking can be as simple as comparing the encrypted values with the hidden form values, if any do not match, reject the request.
things to bear in mind though, encrypion is slow. It can be quicker to fetch the values from a DB instead, though you might use a cache for these. YMMV.
An alternative option is to generate a javascript file with the values in and ensure that the client browser cannot edit them using security features such as content-security-policy. The disadvantage is an inability to use these values in html (as obviously the user can edit them there) so you'll have to pass data back to the server via js calls.
I am having trouble finding an efficient asynchronous method to test whether an email that a user enters is unique. I don't want to use validates within my controller because I want to present a popup before the user submits the form.
I'm basically trying to do User.find(:all, :conditions => ["email == ?", current_user.email]) but from within the javascript on my html page.
You would need something like this:
A method in your controller that checks email uniqueness, like unique = (User.find(:all, :conditions => ["email == ?", current_user.email])).length == 0. Let it just return JSON like this: render json: unique. No need for a view.
A route to that method.
A function in JavaScript that sends an email to the above route and gets a JSON document in return.
Here's an untested example using jQuery:
function isEmailUnique(email) {
jQuery.get('/my-controller/test-email-uniqueness', email, function(json) {
if (json.unique) {
// Tell the user the email is in use.
}
});
}
That should do it. You'll need to work a little on the structure of the JSON document returned by the controller. Do no return the entire user record since this can give evil people access to stuff they shouldn't have access to. Preferably return something like { 'email': 'user#example.com', 'unique': true }
Hope it helps.