Facing problem while trying axios with pug template - node.js

I'm trying to use axios with pug template but facing a problem.
here is my code:
base.pug
doctype html
html
head
block head
meta(charset='UTF-8')
meta(name='viewport' content='width=device-width, initial-scale=1.0')
link(rel='stylesheet' href='/css/style.css')
link(rel='shortcut icon' type='image/png' href='/img/favicon.png')
link(rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lato:300,300i,700')
title Natours | #{title}
body
// HEADER
include _header
// CONTENT
block content
h1 This is a placeholder heading
// FOOTER
include _footer
script(src='https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js')
script(src='/js/login.js')
and in login.js
const login = async (email, password) => {
try {
const res = await axios({
method: 'POST',
url: 'http:127.0.0.1:3000/api/v1/login',
data: {
email,
password
}
});
console.log(res);
} catch (err) {
console.log(err);
}
};
document.querySelector('.form').addEventListener('submit', e => {
e.preventDefault();
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
login(email, password);
});
but everytime i'm trying to submit the form i'm getting this error in console.log
"
Refused to load the script 'https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js' because it violates the following Content Security Policy directive: "script-src 'self'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.
"

You need to add Content Security Policy headers for script-src to allow your site to load scripts from a different domain, in this case cdnjs.cloudflare.com.
You can do this either in your webserver (if you're using one) or in the Node.js application.
Content-Security-Policy: script-src <source>;
In Node/Express it would be something like:
res.setHeader('Content-Security-Policy', 'script-src cdnjs.cloudflare.com');
You can also use a library such as: https://www.npmjs.com/package/express-csp-header

Related

How to add basic authentication header to form

I'm using node server built on https://github.com/passport/express-4.x-local-example(just changed app.get('/login'... to app.post('/login' … in server.js.
In pug, I created a page with a login form based on https://www.w3schools.com/howto/howto_css_login_form.asp and when I submit form (input names changed to username and password, method="post", action "/login") everything works fine. Since I don't want to send passwords in a body without authentification, I need to add basic auth to my post request.
How do I do that?
I tried adding event listener submit to my form and stopping default action with event.preventDefault();. I then created new XMLHttpRequest(), set request header to basic auth and sent the XML request to server. When using console I can verify the request came in, did the job, but the reply from server (which should redirect) returned to my XML request, not actually redirecting the page.
When I try sending the same POST request via POSTMAN, the response is a redirect page.
If I remove event listener the form gets submitted and everything works fine (but without adding auth headers).
doctype html
head
meta(charset='UTF-8')
title Login
link(rel='stylesheet', href='stylesheets/main.css')
link(rel='icon', type="image/png", href='favicon.png')
body
form(action='/login', id='form1' method='post')
.imgcontainer
img.avatar(src='images/img_avatar2.png', alt='Avatar')
.container
label(for='username')
b Username
input(type='text', placeholder='Enter Username', name='username', autofocus, required, id='uname')
label(for='password')
b Password
input(type='password', placeholder='Enter Password', name='password', required, id='pword')
button(type='submit') Login
script.
document.getElementById("form1").addEventListener("submit", submitFunction);
function submitFunction() {
event.preventDefault();
var usr=document.getElementById('uname').value;
var pwd=document.getElementById('pword').value;
var obj = {'username' : usr, 'password' : pwd};
var request = new XMLHttpRequest();
request.open("POST", "/login", false);
request.setRequestHeader('Authorization', 'Basic Y2xpZW50SUQ6c2VjcmV0S2V5');
request.setRequestHeader('Content-Type', 'application/json');
request.send(JSON.stringify(obj));
}
Authentication is not needed and will not make your request secure as without encryption the HTTP request is still plain text.
Encryption will make your request secure, your page and API should both use HTTPS, and when using encryption you do not need the additional authentication.
I found a workaround to include headers. First of all, I was using the wrong passport strategy. I used local and should have used ('passport-http').BasicStrategy. Here is an example
https://github.com/passport/express-3.x-http-basic-example
I added a placeholder for response in my XMLHttpRequest so the script part of my pug looks now like
script.
document.getElementById("form1").addEventListener("submit", submitFunction);
function submitFunction() {
event.preventDefault();
var username = document.getElementById('uname').value;
var password = document.getElementById('pword').value;
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (this.readyState == 4) {
// Typical action to be performed when the document is ready:
// accept and redirect code in here based on the answer from the server
}
};
request.open("POST", "/login", false);
request.setRequestHeader('Authorization', "Basic " + btoa(username + ":" + password));
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.send();
}
of course, as Absor said ih his answer (thank you) it's still just plain text so maybe it will not add security to my request.

Set Default defaultSession.cookie in Node.js?

Basically, I need something that works in express and node.js With the behavior of electron (of the following function)
const { session } = require('electron').remote
const cookies = session.defaultSession.cookies;
cookies.set({
url: url,
name:'NAME',
value: cookie,
domain:'.project.auth.com',
path:'/',
httpOnly:true
}, (error, cookie) => {
// res.end(error);
});
This will set a header called Cookie: NAME = Cookie
In all the files that are requested. (From HTML, JS, CSS among others)
I need something similar but using the EJS template system or if it is not possible.
A method that allows doing this only showing the example file the .png

slim framework 3, fail to render html page

Am using twig-view to render the html, currently am unable to change the Content type returned to the browser, i can see that content type returned by slim as json instead of html content hence all codes are displayed in browser
$app->get('/',function(Request $req,Response $res,array $args) use ($app){
$container = $app->getContainer();
$container->view->render($res, 'test.html',[]);
});
enter image description here
Try to return the response like this:
return $container->view->render($res, 'test.html', []);
Addition to Zamrony P. Juhara
i have found that middleware i put was editing response to be returned as json content
->withHeader("Content-Type", "application/json")
/*
CORS
*/
$app->add(function ($req, $res, $next) {
$response = $next($req, $res);
return $response
//->withHeader("Content-Type", "application/json")
//->withHeader('Access-Control-Allow-Origin', 'http://localhost:2222/')
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,PATCH,OPTIONS');
});
so the browser was only getting json content response hence it was dumping all codes as json content instead of Content-Type: "text/html",
and that solved my problem

How to download an excel (xlsx) file using Angular 5 HttpClient get method with Node/Express backend?

I have an excel file in a directory on my nodejs server - Path to the file is - ./api/uploads/appsecuritydesign/output/appsecdesign.xlsx
On click of a button in my Angular 5 component I am just trying to download the file using FileSaver.
Below is my Angular component.
Here the template code for the button in Angular that will call the saveFile() function once clicked.
<a class="btn btn-primary" (click) = "saveFile()">Download</a>
Here is the saveFile() function.
saveFile(){
console.log("In ToolInput Component: ", this.token); //Okta token
console.log("In ToolInput Component: ", this.whatamidoing); //this variable has the server FilePath
this.fileService.getappsecdesignfile(this.token, this.whatamidoing).subscribe(res => {
let blobtool5 = new Blob([res], { type: 'application/vnd.ms-excel;charset=utf-8' });
FileSaver.saveAs(blobtool5, 'Application_Security_Design.xlsx');
},
(err: HttpErrorResponse) => {
if (err.error instanceof Error) {
console.log('An error occurred:', err.error.message);
console.log('Status', err.status);
} else {
console.log(`Backend returned code ${err.status}, body was: ${err.error}`);
console.log('Status', err.status);
}
});
}
At this point I checked the console.log in the browser. They are exactly what they are supposed to be. So I am passing the correct filepath and token to getappsecdesignfile method in my fileService.
Now Lets take a look at the getappsecdesignfile method in my fileService.
getappsecdesignfile ( token, tool5filepath ) : Observable<any>{
console.log("In Service tool5filepath: ", tool5filepath);
console.log("In Service token", token);
console.log("In Service GET url: ", this.getappsecdesignfileurl);
//Since the tool5filepath has / (slashes etc) I am encoding it below.
let encodedtool5filepath = encodeURIComponent(tool5filepath);
console.log('Encoded File Path: ', encodedtool5filepath);
let req = new HttpRequest('GET', this.getappsecdesignfileurl,{params: new HttpParams().set('path', encodedtool5filepath)},{headers: new HttpHeaders().set('Accept', 'application/vnd.ms-excel').set('Authorization', token)});
console.log(req);
return this.http.request(req);
}
That's all there is to the fileService method. Lets look at the console.logs from this method from the browser to ensure all the correct values are being set.
Now Lets take a look at the request itself before we go to the server part.
As far as I am concerned the headers are set correctly, params are set correctly. Two issues I see is that Angular's interceptors probably sets the responseType: json and adds a param op:s to my request.
Node/Express Server code.
app.get('/getappsecdesignfile', function(req, res){
console.log("In get method app security design");
accessTokenString = req.headers.authorization;
console.log("Okta Auth Token:", accessTokenString);
console.log("Tool5 File Path from received from Angular: ", req.query.path); //this is where the server console logs shows Tool5 File Path after decoding: ./undefined
oktaJwtVerifier.verifyAccessToken(accessTokenString)
.then(jwt => {
// the token is valid
console.log(jwt.claims);
res.setHeader('Content-Disposition', 'attachment; filename= + Application_Security_Design.xlsx');
res.setHeader('Content-Type', 'application/vnd.ms-excel');
let tool5filepath = './' + decodeURIComponent(req.query.path);
console.log("Tool5 File Path after decoding: ", tool5filepath);
res.download(tool5filepath);
}).catch(err => {
// a validation failed, inspect the error
res.json({success : false, message : 'Authorization error.'});
});
});
If I use Postman the api works fine. However somewhere between Angular to Node communication something happens that I don't understand.
Below is what the server logs. (Big question how does this become undefined)?
Tool5 File Path from received from Angular: undefined
Tool5 File Path after decoding: ./undefined
Error: ENOENT: no such file or directory, stat '<dirpath>/undefined'
Here is what I see in the browser log:
zone.js:2933 GET http://localhost:3000/getappsecdesignfile 404 (Not Found)
toolinput.component.ts:137 Backend returned code 404, body was: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Error: ENOENT: no such file or directory, stat '<dirpath>/undefined'</pre>
</body>
</html>
Then the browser downloads a xlsx file that is corrupt and cannot be opened.
I have checked the file resides in the directory and is ready to be downloaded.
Thanks for any tips that can help me resolve this issue.
Finally figured it out.
2 specific changes made this work.
Change # 1 - Setting responseType : 'blob' and defining the params and headers first and then using them in http.get. (http is nothing but an object of type HttpClient from angular/common/http that has been injected into the service class.
getappsecdesignfile ( token, tool5filepath ) : Observable<any>{
console.log("In Service tool5filepath: ", tool5filepath);
console.log("In Service token", token);
console.log("In Service GET url: ", this.getappsecdesignfileurl);
let encodedtool5filepath = encodeURIComponent(tool5filepath);
console.log('Encoded File Path: ', encodedtool5filepath);
let getfileparams = new HttpParams().set('filepath', encodedtool5filepath);
let getfileheaders = new HttpHeaders().set('Accept', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet').set('Authorization', token);
return this.http.get(this.getappsecdesignfileurl, {responseType: 'blob', params: getfileparams, headers: getfileheaders});
}
Change # 2 - Component code - FileSaver. For some reason type: 'application/vnd.ms-excel' did not work in FileSaver. Here the res is nothing but the response from the http.get call.
let blobtool5 = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
FileSaver.saveAs(blobtool5, 'Application_Security_Design.xlsx');

Nodejs express validate user input and redirect

I have a simple nodejs page with textbox and a button. After the user clicks the button, I want to read the user input and validate it. If the input is not OK then stay on the same page and if input is OK then redirect to another page.
I have jade file and it's corresponding js file. What's the best way to do it.
Basically I want to read the input from authcode and process it
Here is my jade code
doctype html
html(lang="en", class="no-js")
head
meta(charset="utf-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
link(rel="stylesheet", href="/foundation/css/normalize.css")
link(rel='stylesheet', href='/foundation/css/foundation.css')
link(rel='stylesheet', href='/css/style.css')
body
center
h1 Software License Expired
h3
| Please renew the contract to use the system.
h3
| Machine Code
br
input(type='text', name='machcode', value=machcode, disabled='')
br
br
h3
| Enter Auth Code
br
input(type='text', name='authcode')
br
br
button(type='button', onclick="alert('Hurray')") Renew
This is the JS page
router.get('/', function(req, res)
{
utils.dump("expiry::get - " + __filename);
res.render('expiry',
{
current_page: 'toolbar_expiry_page',
title: 'EXPIRY_PAGE',
machcode: "some code"
});
});
module.exports = router;
I took some of my own work, hope this sheds some light on the situation:
Server-side validation
router.post('/login/', function(req, res) {
var input = req.body;
// Check if both fields have been filled in
if(input.email === '' || input.password === '') {
res.render('dashboard/login', { error: 'Please enter a email / password'})
}
else {
res.render('dashboard/loggedin')
}
})
Client-side validation
form.on('submit', function(e) {
/* validate code here */
if(!valid) {
sendError(); /* generate error at real time */
return false;
}
})
Does this answer your question?

Resources