Reset Password Page Not Rendering Correctly When Accessing from Reset Email Link - node.js

Ok, so first off, this is my first post. I've searched high and low for a solution, but have found none. I have posted this first on Udemy, for the course I've taken, but no one has answered, so I'm reposting it here.
I have been trying very hard to figure out why the new-password page will not display correctly for me. The reset link works fine, and I can even reset the password on my new password page when I am sent there from the email link.
However, no matter what I do, I can't get it to display any styling. It only gives me basic html. The logic works fine, it's just the page that doesn't display correctly.
I know it isn't a path issue to the css folder either. If I simply render as another basic page without any token logic, such as replacing my index page with the new-password page, then it displays normally. I just don't know what I'm missing, or if there was some updates that I need to take into consideration.
I'm hoping someone sees this and can help me out. It's the only thing that doesn't work right, and it's very frustrating.
Just to be a little more clear, if I do something like below, and just replace or create a route, the page shows up correctly. It's the token logic I believe that is breaking the rendering, I just don't know how, since I don't get any errors.
Please let me know what code you may need to see, as I'm not sure what sections would be helpful, there are a lot of moving parts here. I will be happy to post whatever is needed.
exports.getNewPassword = (req, res, next) => {
res.render("auth/new-password", {
path: "/new-password",
pageTitle: "Update Password",
});
};
With the logic built-in and following the email reset link, the below will not render any styling, only the html.
exports.getNewPassword = (req, res) => {
const token = req.params.token;
User.findOne({
resetToken: token,
resetTokenExpiration: { $gt: Date.now() },
})
.then((user) => {
if (!user) {
req.flash(
"error",
"That reset password link has already been used."
);
return res.redirect("/");
}
let message = req.flash("error");
message.length > 0 ? (message = message[0]) : (message = null);
res.render("auth/new-password", {
path: "/new-password",
pageTitle: "New Password",
errorMessage: message,
userId: user._id.toString(),
passwordToken: token,
});
})
.catch((err) => console.log(err));
};
I am using ejs for templating as well. As I said above, if I remove all token logic and just render the page as a normal view, it works fine.
<main>
<% if (errorMessage) { %>
<div class="user-message user-message--error"><%= errorMessage %></div>
<% } %>
<form class="login-form" action="/new-password" method="POST">
<div class="form-control">
<label for="password">Password</label>
<input type="password" name="password" id="password">
</div>
<input type="hidden" name="userId" value="<%= userId %>">
<input type="hidden" name="passwordToken" value="<%= passwordToken %>">
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button class="btn" type="submit">Update Password</button>
</form>
</main>

Well, in case anyone stumbles across this, the answer was pretty simple, though I'm not sure why in this one instance is was a problem. However, the solution was to add a forward slash in front of my path to the css location for the update password page.
Again, not sure why it needed it, seeing as all my other css and view pages were in the same folder structures and worked fine, but it apparently solved the issue. SMDH.
<link rel="stylesheet" href="/css/login.css" />

Related

Getting "Cannot POST" with registration page using Sequelize

I'm sure there's a sound reason as to why I can't get this to work but I've been staring at the code for a long time and I'm brutally stuck. I'm trying to build out a very basic registration form that should store the data in my PostgreSQL database. I'm using bcrypt to hash out the password, but even without still having issues.
My HTML has the following:
<form action="/register/new" method="post">
<label for="username">Username</label>
<input type="text" name="username">
<label for="password">Password</label>
<input type="password" name="password">
<label for="confirm">Confirm Password</label>
<input type="password" name="confirm">
<button type="submit">Submit</button>
</form>
Then for the code I have:
app.get("/register", function(req,res){
res.render("register");
})
app.post('register', function(req,res){
let newUser = {
username: req.body.username,
passwordHash: bcrypt.hashSynce(req.body.password, 8)
}
models.Users.create(newUser).then(function(){
res.redirect('/login');
})
});
The plan for the registration data to be stored and the user redirected to the login page, login stores them in session, and so on. I thought for a bit that the issue was the action on the form but regardless I'm getting Cannot POST /register/new. I've also played around with doing a findOrCreate and do a comparison but I wanted to start with actually just creating before I make it more complex. The same issue occurs with cannot post.
Any thoughts on what I need to change?
Probably would've worked better if I did a app.post("/register"...
Simple miss of an "/"
try this modified code...
app.post('/register', function(req,res) {
let newUser = {
username: req.body.username,
passwordHash: bcrypt.hashSync(req.body.password, 8)
}
// if it does not connect/save try using models.User instead of models.Users below.
models.Users.create(newUser).then(function(){
res.location('/login');
res.redirect('/login');
})
});

Cannot delete mongodb entry with node and handlebars

I tried various ways to delete a entry but no luck. I know I'm close. I did use "post" instead of "delete" with no luck. I did the action request on the html, no luck. Im in a pickle :(
My routers:
router.delete('/:id',function(req, res){
Docket.findById(req.params.id, function(err, docket){
docket.remove(function(err){
res.redirect('/dockets');
});
});
});
Handlebars:
<form name="create-docket-form" id="create-docket-form" method="post">
<div class="form-submit">
<input type="submit" name="delete" value="Delete my docket" />
</div>
</form>
In your form, you are using method method="post", but your route is listening for DELETE requests: router.delete('/:id',function(req, res){ So this router is never triggered because the app can't found the route.
I wonder, how do you send your requests, but in if you are using no JavaScript code, you can work around this by applying approach from this answer.
I did solve this problem, first, you have to change the "delete" to "get" in the "router.get()", after that, you go to HandleBars file and put a tag 'button' inside the tag '', put the 'href: '/adress/{{variable to delete}}', go to your node.js and prepare the route, now I'll show you my code:
NODE.EXPRESS / .JS:
app.get(`/del-comander/:comand`,express.json() ,(req,res)=>{
let comanderDel = req.params.comand
Comander.deleteOne({comander: comanderDel}).then(()=>{
console.log(`deleted: ${comanderDel}`)
res.redirect('back')
}).catch((err)=>{
res.send(err)
})
}),
HANDLEBARS:
{{#each comanders}}
<strong> comander: </strong>{{comander}} <br>
<strong> skill: </strong>{{skill}} <br>
<strong>season: </strong>{{season}} <br>
<a href='/del-comander/{{comander}}'><button>delete</button></a>
<br>
<hr>
{{/each}}
OBS: the args inside '{{}}' was connected with the DataBase, I also did more than just delete the data and printed it to the screen, so each data could be deleted separately, I do not know if my answer was good, but somebody else could have this same problem if you want more code just ask.

Angularjs + Laravel Stripe integration - Response goes to server and other details missing

i have an Angular Storefront app set up. I have a shopping cart functionality in place and a stripe "pay with card" button etc. pretty much looks like this:
<form action="/#/order" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{{ stripeApiKey }}"
data-billingAddress=true
data-shippingAddres=true
data-amount="{{ amount }}"
data-name="StoreFront Name"
data-description="Custom-Made Jewellery"
data-image="../images/www/logo.png"
data-locale="auto">
</script>
</form>
Evrything up to this point is working fine. I submit the form and stripe returns the token but the form goes to the server following the route localhost/order (without the # symbol) instead of angular's localhost/#/order.
Why is stripe forcing this redirect? In other words why isn't angular capturing this return call?
Anyways. Then I create a route with Laravel to capture this and dump to inspect the returned data like so:
Route::post('/order', function($request){
dd($request);
});
Yep, data captured by stripe-generated form is returned except amount is missing... I mean everything including stripeToken, buyer's details such as: Name, Email, Billing and Shipping address are returned BUT detail regarding the amount is missing.
Is this normal or I'm I missing something?
Lastly currency is still showing the default: Where can I change currency from say USD to GBP?
Thanks in advance
1/ I don't think Checkout is forcing the redirect, but I don't know enough about Angular to explain what's going on, sorry.
2/ Yes, this is normal. The amount passed to Checkout in the data-amount configuration option is used for display purposes only. The actual amount that is charged is the one you pass in the amount parameter in the charge creation request in your server-side code.
If you need the amount to be user-specified (for instance, if you're taking donations), you'll need to add the amount to the form. Here is a simple JSFiddle to illustrate this case: https://jsfiddle.net/ywain/g2ufa8xr/
3/ You can use the data-currency parameter to change the currency displayed in the Checkout form. Just like data-amount, this is for display purposes only and the actual currency used for the charge is specified by the currency parameter in the charge creation.
This is what i managed to do.
I went with the custom form approach. I had a form template to capture both customer and card inputs in billing.template.html like so:
<form method="POST" id="payment-form">
<span class="payment-errors"></span>
<div>
<label>Name</label>
<input type="text" name="name" data-stripe="name">
</div>
<div>
<label>Email</label>
<input type="text" name="email" data-stripe="address_email">
</div>
<div>
<label>Address Line 1</label>
<input type="text" name="street" data-stripe="address_line1">
</div>
<div>
<label>Postcode</label>
<input type="text" name="postcode" data-stripe="address_zip">
</div>
<div>
<label for="country">Country</label>
<select ng-include="'../templates/_partials/_countrylist.html'"
id="countries" name="country" class="form-control"
name="country" ng-model="country" id="country" size="2"
data-stripe="address_country" required></select>
</div>
<div class="form-row">
<label>
<span>Card Number</span>
<input type="text" name="cardNumber" size="20" data-stripe="number"/>
</label>
</div>
<div class="form-row">
<label>
<span>CVC</span>
<input type="text" name="cvc" size="4" data-stripe="cvc"/>
</label>
</div>
<div class="form-row">
<label>
<span>Expiration (MM/YYYY)</span>
<input type="text" name="expMonth" size="2" data-stripe="exp-month"/>
</label>
<span> / </span>
<input type="text" name="expYear" size="4" data-stripe="exp-year"/>
</div>
<button id="customButton">Pay with Card</button>
</form>
I know we are not supposed to use name attribute in those form inputs but i left them so i could use angular validation, but i remove them using jquery before submitting to server.
Now i created a controller to handle the form: BillingController.js. In there i had an "on click" handler which kick started things by getting a hold of the form and doing some preparatory work: disabling button to prevent further clicks and removing those 'dreaded' name attributes, comme ca:
$('#customButton').on('click',function(event) {
var $form = $('#payment-form');
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
//NOW REMOVE THOSE NAME ATTRIBUTES
$form.find('input').removeAttr('name');
// call Stripe object and send form data to get back the token.
// NOTE first argument is $form
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
Now let me quote the documentation here as this is very important to understand: https://stripe.com/docs/tutorials/forms
The important code to notice is the call to Stripe.card.createToken.
The first argument is the form element containing credit card data
entered by the user. The relevant values are fetched from their
associated inputs using the data-stripe attribute specified in the
form.
Next we create stripeResponseHandler(). Remember it was the second argument in Stripe.card.createToken($form, stripeResponseHandler); above which gets called when Stripe returns the token.
function stripeResponseHandler(status, response) {
var $form = $('#payment-form');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false);
} else {
// response contains id and card, which contains additional card details
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// and submit
$form.get(0).submit();
}
};
This is copy and paste stuff from stripe's own documentation: https://stripe.com/docs/tutorials/forms. Now, I want to say that, this is where a lot of us were tripping over the fact that form was performing a redirect etc. - notice final line $form.get(0).submit(); . Thats what caused the auto submit, redirecting to what ever action was on form, if u had any (in my case action attribute wasn't necessary as i was doing redirects in my controller).
So i decided to remove $form.get(0).submit() and implemented my own redirect after i was done sending data to the server.
NOTE: Stripe's response will have included data from the $form - try console.log(response); to have an idea of what's being posted back.
FINALLY:
We check if there were any errors returned and if so display them. Otherwise its all good, send data to the server.
The final code looks like:
function stripeResponseHandler(status, response) {
var $form = $('payment-form');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
} else {
// response contains id and card, which contains additional card details
var token = response.id;
// prepare data
var data = {
stripeToken: token,
fullName: response.card.name,
street: response.card.address_line1,
postcode: response.card.address_zip,
town: response.card.address_city,
country: response.card.address_country,
last4: response.card.last4
};
// send to server
$http.post('/checkout', data).then(function(result){
// here you can redirect yourself.
window.location.href = "/#/order-complete";
});
}
};
Angular really playing well with stripe here. Check out this link also: https://gist.github.com/boucher/1750368 - learn a lot from it.
I hope it helps someone today. Happy coding!
Stripe doesn't get involved with your form aside from preventing the default action on form submit event and stopping event propagation. Once the checkout process completes, it appends the relevant data to your form and then triggers a form submit event that is handled by HTML / Javascript natively.
I recommend using something like https://github.com/tobyn/angular-stripe-checkout to get your Stripe response handled correctly by Angular.
Otherwise you could add ng-submit="handleStripeCheckout($event)" to your form instead of action="/#/form". When Stripe's checkout process completes, your $scope.handleStripeCheckout method will be run and you can analyze the new form data inside that method.
Edit: Stripe checkout.js actually triggers form.submit(). That's a pretty bad bug on their part considering that almost no browsers handle that correctly. (Form submitted using submit() from a link cannot be caught by onsubmit handler)

Organizing view files in Node.js app

I finished this walkthrough for creating a very basic Reddit clone using the MEAN stack. The app included a few different views, such as a view for all posts, a single post, the login form, and the register form, and all of these views were included in a single file: views/index.ejs.
Is putting all the views together like this common practice, or was it merely for brevity in the tutorial? I was hoping to be able to separate at least the login and register forms from the rest of the views in index.ejs for the sake of organization, but placing them in a login.ejs file in views causes a 404.
Login portion of views/index.ejs
<script type="text/ng-template" id="/login.html">
<div class="page-header">
<h1>Flapper News</h1>
</div>
<div ng-show="error" class="alert alert-danger row">
<span>{{ error.message }}</span>
</div>
<form ng-submit="logIn()"style="margin-top:30px;">
<h3>Log In</h3>
<div class="form-group">
<input type="text" class="form-control" placeholder="Username" ng-model="user.username"></input>
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="Password" ng-model="user.password"></input>
</div>
<button type="submit" class="btn btn-primary">Log In</button>
</form>
</script>
Login portion of routes/index.js
router.post('/login', function(req, res, next){
if(!req.body.username || !req.body.password){
return res.status(400).json({message: 'Please fill out all fields'});
}
passport.authenticate('local', function(err, user, info){
if(err){ return next(err); }
if(user){
return res.json({token: user.generateJWT()});
} else {
return res.status(401).json(info);
}
})(req, res, next);
});
Login portion of controller
.state('login', {
url: '/login',
templateUrl: '/login.html',
controller: 'AuthCtrl',
onEnter: ['$state', 'auth', function($state, auth){
if(auth.isLoggedIn()){
$state.go('home');
}
}]
})
I don't understand how the views fit together in this app. What is telling the app to find the login template in index.ejs, and how can I redirect the app to look in a different file?
The way they did this is a little strange, but it was most likely for the sake of brevity.
The reason why it's 404'ing is because of how the routes are set up. There's a single route to serve index.ejs, and the rest of the routing is handled client-side through Angular. In fact, the only reason they used ejs is because they wanted to send it using Express' res.render() method most likely. (Although, since it's just HTML from what I saw, instead of actually using any EJS, they could likely just as easily used Express' res.sendFile() method, or prior to 4.8.0, res.send() in conjunction with Node's builtin fs.readFile to send the plain HTML file.
If you wanted to split out the views you'd have to set up server-side routes, but I guess they were dead set on a single-page app. More commonly, views that are rendered on the server-side are split out into individual files, with a main "layout", in which other views are included into.

PHP secure mail executing even when recaptcha verification fails

When entering the security words in recaptcha and clicking the Submit button, the PHP secure e-mail function is executed - even when the recaptcha verification fails and returns the error message. The basic code follows. What can I do to NOT execute the e-mail function? Thank you.
<form name="contactform" method="POST" onSubmit="return validateCaptcha()"
action="send_form_email.php">
</form>
<script type="text/javascript">
jQuery(document).ready(function (){
Recaptcha.create(" --- my key ---_",
"recpatcha_show",
{
theme: "red",
callback: Recaptcha.focus_response_field
}
);
});
</script>
<div id="recpatcha_show"></div>
<div id="captchaStatus" style="color:red;font:16px;"></div>
<br />
<input type="submit" value="Submit">
I don't know exactly how recaptcha works, but I'm guessing you'll have to prevent the form from submitting when the chaptcha characters don't match.
With jQuery its:
if(characters dont match){
event.preventDefault();
} else {
submit form
}
Also, you might want to read this:
https://developers.google.com/recaptcha/docs/php?hl=nl
You can make recaptcha completely back-end, that way you can completly validate the user imput before sending the e-mail.

Resources