Access nonce value inside your index.html - node.js

I'm having prod.js module like this which I'm using to set content security policy
const helmet = require('helmet');
const compression = require('compression');
module.exports = function (app) {
app.use((req, res, next) => {
res.locals.cspNonce = crypto.randomBytes(16).toString("hex");
next();
});
app.use(
helmet.contentSecurityPolicy({
useDefaults: true,
directives: {
scriptSrc: [ "'self'", 'js.stripe.com', 'https://checkout.stripe.com', 'js.stripe.com', 'https://billing.stripe.com', ( request, response ) => `'nonce-${res.locals.cspNonce}'` ],
styleSrc: ["'unsafe-inline'"],
connectSrc:[" * 'self' https://checkout.stripe.com https://billing.stripe.com"],
frameSrc: ["'self' https://checkout.stripe.com https://billing.stripe.com https://js.stripe.com ;"],
imgSrc: [" 'self' blob: https://api.company.com/ data:"],
},
})
);
app.use(compression());
};
I want to access this nonce value created in index.html inside my react app. So that I can pass it to script tags like this
React app index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script
nonce={.........//Get the nonce value here............}
>
</script>
<title>Some title</title>
But I'm not able to figure out how to access nonce inside my Index.html.
P.S: I'm new to programming. Please let me know if you need any other info to help me with this case.
Adding additional info ----------
I'm invoking prod.js in my Index.js file inside my node project.
My Index.js looks like this
const express = require('express');
const https = require('https');
const path = require('path');
const app = express();
require('./startup/routes')(app);
require('./startup/db')();
require('./startup/config')();
require('./startup/validation')();
require('./startup/prod')(app);

Your nonce value will be resolved after you fetch it from your API.
Here is a simplistic example of implementation:
class MyApp {
constructor() {
this.nonce = "";
this.app_ready = false;
this.fetchNonce();
}
setNonce(value) {
this.nonce = value;
this.app_ready = true;
// Do what you have to do when your app is ready, mount your components, etc...
}
fetchNonce() {
fetch("https://url/to/your/api")
.then(response => {
this.setNonce(response.headers.key.to.your.value)
})
.catch(error => {/*Handle you app state in case of error...*/})
}
}

Related

Node js, i can't get my browser button to get a list of teams in the json file

I'm new to Node js, and i'm cuurently writing a program to fetch data from a local json file and display in the browser, but nothing happens when i click the button. Not getting errors either. The program runs as follows: 1). node app.js 2.) opens index.html on the server (127.0.0.1:3000) 3.) click the button "Get list of the team". the button has an action = "teams" and the Controller should invoke the action to fetch the teams from the json file. The Controller invokes the Model, then renders the data in the index.htm property called "teamList". Then i expect to see the teams displayed in the browser. Here is my code:
app.js:
const path = require("path");
const express = require('express');
const cors = require('cors');
const fetch = require('node-fetch');
const bodyParser = require('body-parser');
const router = require('./routes/router');
const app = express();
app.use(express.urlencoded({extended: false}));
app.use(express.json());
app.use(express.static("public"));
app.set("views" , "views");
app.set("view engine", "hbs");
const host = "127.0.0.1"
const port = 3000
app.use(cors());
app.use(bodyParser.json());
//app.use('/', router);
app.get('/', (req, res) =>{
res.render("index", {
teamsList: ""
})
})
app.get('/add', (req, res) =>{
res.render("post-tal", {
Sum: ""
})
})
app.listen(port, host, () => {
console.log(`The server is running at: http://${host}:${port}`);
});
index.html:
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>WebApp</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.min.css">
<style>
.eNavAction {cursor:pointer}
.buttons {margin-top: 20px}
</style>
<script src="js/simple-helper.js"></script>
<script src="../controller/MainController.js"></script>
<script src="apiServer/controller.js"></script>
<script src="apiServer/model/apiServer-model.js"></script>
<script src="apiServer/routes/router.js"></script>
<script>
var Current = {};
const Model = new TeamsModel();
const View = new TeamView();
const ViewTal = new TalView();
const Controller = new MainController();
document.addEventListener('DOMContentLoaded', function() {
// Controller.init();
Helper.onClassClick('eNavAction', Controller.navAction);
});
</script>
</head>
<body>
<nav class="navbar is-link" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<span style="font-weight:bold; font-size:20px">My Web App</span>
</a>
</div>
<div id="navbar" class="navbar-menu">
<div class="navbar-start">
<a class="eNavAction navbar-item" action ="teams">Teams</a>
<a class="navbar-item" action= "tal" href="http://127.0.0.1:3000/add">Sum</a>
</div>
</div>
</nav>
<div class="section">
<div id="main-container">
<button class="eNavAction navbar-item" action ="teams">Get list of the team</button>
<div id="listContainer">
{{teamsList}}
</div>
</div>
</div>
</body>
</html>
MainController.js:
class MainContainer {
teamList = (req, res) => {
Model.loadTeams()
.then(function (data) {
res.json(data);
//res.send(data);
res.render("index", {
teamList: {data} // A property called teamList to be displayed on the browser
})
})
.catch(error => console.log(error));
}
navAction() {
let action = this.getAttribute('action');
if (action == "teams") {
Controller.teamList();
}else if(action == "tal")
Controller.calculateSum();
}
}
Model.js
class TeamsModel {
async loadTeams() {
try {
const json = await fetch('./json/prov-nodes.json', 'utf8')
.then(function(response){
return response.json();
})
.then(function(data){
console.log(data);
});
}catch (error) {
console.log(error)
}
}
}
I tried to reconstruct your problem. First of all I show that I fixed code and get result:
that code in controller.js (Model.js)
class TeamsModel {
async loadTeams() {
try {
const json = await fetch('/data/prov-nodes.json')
return json.json(); // Important! return must be in loadTeams!
}catch (error) {
console.log(error) // it'll never been shown!
}
}
}
As you can see I used '/data/prov-nodes.json' as path. Yes now I can access to file that I had not before by './json/prov-nodes.json'.
I just add two strings in app.js:
app.use('/js', express.static(__dirname + '/controllers')); // allows an access
app.use('/data', express.static(__dirname + '/json')); // allows an access
so import of scripts looks like:
<script src="/js/MainController.js"></script>
<script src="/js/controller.js"></script>
in index.hbs file I just do:
const Model = new TeamsModel();
const Controller = new MainController();
Controller.teamList()
I renamed MainContainer class to MainController class (just for test)
...
teamList = (req, res) => {
Model.loadTeams()
.then(function (data) {
console.log('DATA', data); // just output to console if success
})
.catch(error => console.log(error));
}
...
I believe that this helps you continue coding!
I'm not sure that I reconstruct your code right (models/controllers), but I have showed you how to read json file in express.
├── app.js
├── controllers - just modules not real controllers :)
│ ├── MainController.js
│ └── controller.js - I think this would be a model, sorry :)
├── json
│ └── prov-nodes.json
├── package-lock.json
├── package.json
└── views
└── index.hbs

NodeJS app works locally but not when deployed on firebase

I am trying to deploy a nodeJS app on firebase using this tutorial "https://www.youtube.com/watch?v=LOeioOKUKI8&t=437s", I followed exactly what was told and the app worked as intended locally using "firebase serve" but when I deployed it, POST and GET request stopped working i.e. client side code is unable to reach server side.
for example, on loading "appURL/temp" I'm getting "Content Security Policy: The page’s settings blocked the loading of a resource" error.
What I'm actually trying to do : to send JSON data from Client to server, process the data and return some result as response
What currently app does: takes input, sends it to the server on click and receive it back as response to the POST request
on Client Side (public/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script defer src="/__/firebase/7.14.6/firebase-app.js"></script>
<script defer src="/__/firebase/init.js"></script>
</head>
<body>
<h1>Home</h1>
<input type="text" id="ip">
<button onclick="send()">send</button>
<div id="text"></div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
let textDiv = document.getElementById("text")
function send(){
let ip = document.getElementById("ip").value;
axios.post('/home',ip)
.then( resp => {
textDiv.innerHTML = JSON.stringify(resp.data);
})
}
</script>
</body>
on Server Side (functions/index.js
const func = require('./add'); //this is just to wrap the string with brackets
const functions = require('firebase-functions');
const express = require('express');
const multer = require('multer');
const upload = multer();
const app = express();
app.get('/temp', (req, resp) => {
resp.send("GET Works");
console.log("GET");
})
app.post('/home', upload.single("data"), (req, res) => {
console.log(func.add(JSON.stringify(req.body)))
res.send(func.add(JSON.stringify(req.body)))
});
exports.app = functions.https.onRequest(app);
firebase.json
{
"hosting": {
"public": "public",
"rewrites":[{
"source": "**",
"function": "app"
}],
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}
Directory Structure
Versions
node : 13.6.0
express : 6.13.4
mutler : 6.13.4

Why is app.use() not serving up the 'public' directory when I save even though the path is appears to be correct?

I'm following a slightly outdated tutorial on node and express, and my code is identical to the tutorial, but app.use is not serving up the public directory as I wish. When I go to the root localhost:3000 I still see Weather like in the tags on line 19. When I delete it, I don't see anything, including the public directory's index.html file.
Here is my index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge"> -->
<title>Document</title>
</head>
<body>
<h1>From a static file.</h1>
</body>
</html>
Here is my app.js script:
/* nodejs script that will create, configure, and start the server.
run script: node src/app.js
keep server running: nodemon src/app.js
*/
const path = require('path');
const express = require('express');
const app = express();
const publicDirectoryPath = path.join(__dirname, '../public'); // abs path to serve
// STACKOVERFLOW - WHY ISN'T THIS SERVING UP PUBLIC DIRECTORY?
app.use(express.static(publicDirectoryPath)); // serve 'public' directory
// create root route
app.get('/', (req, res) => {
res.send('<h1>Weather</h1>');
});
// create a help route
app.get('/help', (req, res) => {
res.send([
{name: 'Barack H. Obama'},
{name: 'George W. Bush'},
{name: 'William J. Clinton'}
]);
});
// create an about route
app.get('/about', (req, res) => {
res.send('<h1>About</h1>');
});
// create a weather route
app.get('/weather', (req, res) => {
res.send({
forecast: 'rain',
location: 'Los Angeles'
});
});
// port 3000 is common development port, starts server
app.listen(3000, () => {
console.log('Server is up on port 3000'); // never displays in browser
});
it should be public instead ..public like this
const publicDirectoryPath = path.join(__dirname, 'public')
As app.js and public share the same parent directory at the same level. So ..public will point out to dir public outside src which is not available.

Serve pre-made gzip files

I use compression-webpack-plugin to make gzip files durring my bundle process, so when bundling is done I have files like this in my dist folder.
bundle.eefaef91f71795847e74.js
bundle.eefaef91f71795847e74.js.gz
vendor.jduu4f4lj71759dj7e74.js
vendor.jduu4f4lj71759dj7e74.js.gz
stylesLocal.b7ac53d721aca93e4e65099cf74dc90f.css
stylesLocal.b7ac53d721aca93e4e65099cf74dc90f.css.gz
Inside server I use express-static-gzip to serve my gzip files. Why isn't this working. My page doesnt even wanna load? If I put Express.static instead of expressStaticGzip it works normally.
import Express from 'express'
import path from 'path'
import conf from './conf'
import appRenderer from './appRenderer'
import webpackUtils from './webpackUtils'
var expressStaticGzip = require('express-static-gzip')
const APP_PORT: number = conf.APP_PORT
const PORT: any = process.env.PORT || APP_PORT
const app: Express = new Express()
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
app.use(expressStaticGzip(path.join(__dirname, '../', 'dist')))
/* check with the server before using the cached resource */
app.use((req: Object, res: Object, next: () => void): void => {
res.set('Cache-Control', 'no-cache')
return next()
})
/* Use server side rendering for first load */
app.use(appRenderer)
/* Use CommonChunks and long term caching */
app.use(webpackUtils)
// Routes
app.get('*', (req: Object, res: Object) => {
res.render('index', {app: req.body})
})
app.listen(PORT, () => {
console.log(`
Express server is up on port ${PORT}
Production environment
`)
})
And I refernce them in my index.ejs file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>D</title>
<link rel='stylesheet' type='text/css' href="stylesLocal.b7ac53d721aca93e4e65099cf74dc90f.css">
</head>
<body>
<div id="app"><%- app %></div>
<script src="vendor.jduu4f4lj71759dj7e74.js"></script>
<script src="bundle.eefaef91f71795847e74.js"></script>
</body>
</html>
As explained in the readme of express-static-gzip, the syntax is slightly different from express.static.
Instead of
app.use(expressStaticGzip(path.join(__dirname, '../', 'dist')))
try
app.use('/', expressStaticGzip(path.join(__dirname, '../', 'dist')))

"Invariant Violation" Using React Server renderToString on Server-Side

I'm trying to set up an isomorphic server-side rendering React app using Webpack, but am getting this error when I try turning my React code into a string using renderToString:
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
I stop getting this error when I comment out the line with the renderToString function (of course, the app still doesn't work - I just no longer get an error message).
I've tried passing renderToString <RootApp /> and React.createElement(RoutingContext instead of making a factory, and neither of those has worked. Using React.createElement resulted in the same error, and using <RootApp /> threw an unexpected token < error.
And ideas on what could be going on?
My app looks like:
app.js
"use strict"
require("babel-register");
const Express = require('express');
const BodyParser = require('body-parser');
const Path = require('path');
const Fs = require('fs');
const Url = require('url');
const ReactRouter = require('react-router');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const app = Express();
app.set('view engine', 'ejs');
app.get('*', (req, res) => {
let RootApp = require('./components/app.jsx');
let rootAppFactory = React.createFactory(RootApp);
let reactHtml = ReactDOMServer.renderToString(rootAppFactory({}));
res.render('index', {reactOutput: reactHtml});
})
if (process.env.NODE_ENV !== 'test') {
let port = process.env.port || 4000;
app.listen(port);
console.log('Listening on port', port);
} else {
module.exports = app;
}
app.jsx
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
class App extends Component {
render() {
return (
<div>
{this.props.children}
</div>
)
}
}
export default App;
index.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Vjeverica</title>
</head>
<body>
<div id="root">
<%- reactOutput %>
</div>
<script src="bundle.js"></script>
</body>
</html>
Ended up getting this working. The issue was in how I was requiring app.jsx in app.js - because I'm using require instead of import, I needed to change require('./components/app.jsx') to require('./components/app.jsx').default to get the default export.

Resources