Getting a variable from a Server script to a Client script - javascript

Here's the current issue i'm struggling with. I'm on a webapp project, in which I have 2 scripts :
A script called start.js in which I initialize the server and initialize a variable, token. This script is ran when I start the webapp.
A script called viewer.js which initialize a viewer. That viewer requires the previous token to work.
I can't generate the token from the client side, because it requires NodeJS, and as far as I understood NodeJS doesn't work on Client side.
I've tried to use global variables, global methods, or HTTP requests, but none of these methods seems to work so far. Any tip on how to do it ?
Here is what I tried:
// start.js
const ForgeSDK = require('forge-apis');
const express = require('express');
const path = require('path');
var app = express();
app.use('/static', express.static(__dirname + '/static'));
/**
* Token generation
*/
oAuth2TwoLegged.authenticate().then(function(credentials){
setToken(credentials.access_token)
}, function(err){
console.error(err);
});
function setToken(newToken) {
console.log("Definition du nouveau token")
token = newToken;
console.log(token)
};
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.listen(3000, function () {
console.log('Token provider listening on port 3000')
});
// viewer.js
var token = '';
/**
* Viewer initialization
*/

You can pass a callback to your config options to obtain the token (usually via ajax) to requests:
var options = {
env: 'AutodeskProduction',
getAccessToken: function(onGetAccessToken) {
//
// TODO: Replace static access token string below with call to fetch new token from your backend
// Both values are provided by Forge's Authentication (OAuth) API.
//
// Example Forge's Authentication (OAuth) API return value:
// {
// "access_token": "<YOUR_APPLICATION_TOKEN>",
// "token_type": "Bearer",
// "expires_in": 86400
// }
//
var accessToken = '<YOUR_APPLICATION_TOKEN>';
var expireTimeSeconds = 86400;
onGetAccessToken(accessToken, expireTimeSeconds);
}
}
Autodesk.Viewing.Initializer(options, function onInitialized(){
...
See here for details.
And see here and here to create an endpoint to generate access tokens in your Node backend.

Related

Connecting to parse server from https://example.com fails

I'm trying to connect to the Parse server that is implemented in a VPS, from a website that served with apache.
The website is https://example.com, At first, when I tried to connect to parse server in Javascript codes, I did :
Parse.initialize("myAppId");
Parse.serverURL = 'http://ipOfVPS:1337/parse'
But I get mixed content: the page at '' was loaded over HTTPS .. error.
then I changed parse server Url in javascript to https://ipOfVPS:1337/parse and in the backend of parse server, I run the server with HTTPS. and now when I want to load the website of https://example.com, I get this error in chrome:
net::ERR_CERT_AUTHORITY_INVALID and this error in Firefox:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at.
I will be thankful if anybody helps me with this issue.
Here below I pasted my index.js:
// Example express application adding the parse-server module to expose Parse
// compatible API routes.
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var path = require('path');
var databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'XXXX',
masterKey: process.env.MASTER_KEY || 'XXXX', //Add your master key here. Keep it secret!
serverURL: process.env.SERVER_URL || 'https://localhost:1337/parse', // Don't forget to change to https if needed
liveQuery: {
classNames: ["Message","Chats"] // List of classes to support for query subscriptions
},
push: {
android: {
apiKey: 'XXX'
}
}
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey
var options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem'),
requestCert: true,
//ca: fs.readFileSync('/etc/ssl/certs/ca.crt'),
rejectUnauthorized: false
};
var app = express();
// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));
// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);
// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
res.status(200).send('I dream of being a website. Please star the parse-server repo on GitHub!');
});
// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function(req, res) {
res.sendFile(path.join(__dirname, '/public/test.html'));
});
var port = process.env.PORT || 1337;
var httpsServer = require('https').createServer(options,app);
httpsServer.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
// This will enable the Live Query real-time server
ParseServer.createLiveQueryServer(httpsServer);

Using redis in an Express route

I want to simply be able to store a value in a key in one route
/api/foo?redisKey="1" (set value for id=1)
then I want to get the value in another route.
/api/bar?redisKey="1" (get value for id=1)
However, redis is async so you have to wait for it to connect
client.on('connect', function() {
//perform redis operations
});
I'm not sure how to synchronize this in my router.
I am going to assume you're using redis for your client library.
In your express route file, you do not want to create the connection during each request. Instead you will instantiate your redis client outside of the express middleware function, and use it during requests.
Here's a sample app:
var redis = require("redis");
var client = redis.createClient();
var express = require('express')
var app = express()
// GET request
// example: curl "localhost:3000/api/foo?redisKey=1"
app.get('/api/foo', function (req, res) {
var redisKey = req.query.redisKey
client.get(redisKey, function (err, reply) {
if(err){ res.status(400).send(err.getMessage()); return; }
res.status(200).send(reply.toString())
});
})
// for setting, use POST request
// example: curl -X POST "localhost:3000/api/foo?redisKey=1&redisValue=helloWorld"
app.post('/api/foo', function(req, res){
var redisKey = req.query.redisKey,
redisValue = req.query.redisValue
// assuming value is also a string in URL query string
client.set(redisKey, redisValue, function (err, reply){
res.status(200).send(reply.toString())
});
})
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})

Make http request within node js routes

I am building a slideshow that pulls pictures with a certain tag on instagram. The Instagram API requires me to make a call to their auth URL to receive an access token. Using node js and express I built out the backend like so:
var express = require('express');
var app = express();
app.use(express.static('public'));
app.listen(4000,function(){
console.log("Listening to app on localhost 4000");
})
app.get('/',function(req,res){
1. make call to Instagram authorization URL:
https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=http://localhost:4000&response_type=code
2. URL will be redirected with access code parameter
3. Use access code to make POST request to receive access token to be able to make GET requests.
})
My question is how do I make a request to visit that url within NodeJS/Express? Is it just a normal http.request()?
I don't want to user to go through the redirect process so that's why I want to put it in Node. I'm following these instructions https://www.instagram.com/developer/authentication/
You can do a redirect or use a npm library like instagram-node-lib
var express = require('express');
var request = require('request');
var app = express();
app.use(express.static('public'));
app.listen(4000, function () {
console.log("Listening to app on localhost 4000");
})
app.get('/', function (req, res) {
res.redirect('https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=http://localhost:4000/mycallback&response_type=code')
})
app.get('/mycallback', function (req, res) {
//handle token retrieval here
//do a get request as per the instagram documentation using the code sent back
var code = req.query.code
var url = 'https://api.instagram.com/oauth/access_token'
var options = {
method: 'post',
body: {
client_secret: 'CLIENT_SECRET',
grant_type: 'authorization_code',
redirect_uri: 'AUTHORIZATION_REDIRECT_URI',
code: code
},
json: true,
url: url
}
request(options, function (err, res, body) {
//body should look something like this
// {
// "access_token": "fb2e77d.47a0479900504cb3ab4a1f626d174d2d",
// "user": {
// "id": "1574083",
// "username": "snoopdogg",
// "full_name": "Snoop Dogg",
// "profile_picture": "..."
// }
// }
})
})
You will always require the redirect as that is how oAuth works. The user enters a password on the Instagram site. A code is sent back to your server via a callback url (redirect). You then use that code to retrieve the user token. You can then use the authorization token for subsequent calls.

Securing Loopback with third party OpenID Connect

I'm trying to secure my loopback service with my third party OpenID Connect service (Keycloak) but it doesn't seem to be validating requests have accesstokens at all.
My server.js:
var loopback = require('loopback');
var boot = require('loopback-boot');
var app = module.exports = loopback();
// Passport configurators..
var loopbackPassport = require('loopback-component-passport');
var PassportConfigurator = loopbackPassport.PassportConfigurator;
var passportConfigurator = new PassportConfigurator(app);
var cont = function(req, res){
next();
};
/**
* Flash messages for passport
*
* Setting the failureFlash option to true instructs Passport to flash an
* error message using the message given by the strategy's verify callback,
* if any. This is often the best approach, because the verify callback
* can make the most accurate determination of why authentication failed.
*/
var flash = require('express-flash');
// attempt to build the providers/passport config
var config = {};
try {
config = require('../providers.json');
} catch (err) {
console.trace(err);
process.exit(1); // fatal
}
// -- Add your pre-processing middleware here --
// boot scripts mount components like REST API
boot(app, __dirname);
// The access token is only available after boot
app.middleware('auth', loopback.token({
model: app.models.accessToken
}));
app.middleware('session:before', loopback.cookieParser(app.get('cookieSecret')));
app.middleware('session', loopback.session({
secret: 'kitty',
saveUninitialized: true,
resave: true
}));
passportConfigurator.init();
// We need flash messages to see passport errors
app.use(flash());
passportConfigurator.setupModels({
userModel: app.models.user,
userIdentityModel: app.models.userIdentity,
userCredentialModel: app.models.userCredential
});
for (var s in config) {
var c = config[s];
c.session = c.session !== false;
passportConfigurator.configureProvider(s, c);
}
var ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn;
app.start = function () {
// start the web server
return app.listen(function () {
app.emit('started');
var baseUrl = app.get('url').replace(/\/$/, '');
console.log('Web server listening at: %s', baseUrl);
if (app.get('loopback-component-explorer')) {
var explorerPath = app.get('loopback-component-explorer').mountPath;
console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
}
});
};
// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, function (err) {
if (err) throw err;
// start the server if `$ node server.js`
if (require.main === module)
app.start();
});
provider.json
{
"oAuth2": {
"provider": "keycloak",
"module": "passport-openidconnect",
"authorizationURL": "https://xxx",
"tokenURL": "https://xxxx",
"clientID": "xxx",
"clientSecret": "-",
"failureFlash": true
}
}
I've been trying to follow this example:
https://github.com/strongloop/loopback-example-passport
But that doesn't explain how to connect to an OpenID Connect service and secure my APIs.
I've also tried this for specific APIs:
app.get('/api/Clients', ensureLoggedIn('/login'), cont);
I want to really lock down all APIs and check if a valid token is presented in the query which should be validated by my third party authentication service.
Thanks in advance!

Socket.io is not working with my node/express application

I am using openshift with express and no matter what configuration I change socket.io to it breaks my application. What am I missing?
I have commented out the sections that use socket.io and the app runs fine.
When I uncomment socket.io everything goes wrong. I have tried changing the position of the code to accept the standard io.listen(app), but it still breaks. I have also tried numerous examples from the internet.
Is this possible? //self.io.listen(self.app); if not what should I have socket.io listen to in the context of my app? I cannot call io.listen(server)..
var express = require('express');
//etc
// configuration
mongoose.connect(configDB.url); // connect to our database
require('./config/passport')(passport);
var App = function(){
// Scope
var self = this;
// Setup
self.dbServer = new mongodb.Server(process.env.OPENSHIFT_MONGODB_DB_HOST,parseInt(process.env.O PENSHIFT_MONGODB_DB_PORT));
self.db = new mongodb.Db(process.env.OPENSHIFT_APP_NAME, self.dbServer, {auto_reconnect: true});
self.dbUser = process.env.OPENSHIFT_MONGODB_DB_USERNAME;
self.dbPass = process.env.OPENSHIFT_MONGODB_DB_PASSWORD;
self.ipaddr = process.env.OPENSHIFT_NODEJS_IP;
self.port = parseInt(process.env.OPENSHIFT_NODEJS_PORT) || 8080;
if (typeof self.ipaddr === "undefined") {
console.warn('No OPENSHIFT_NODEJS_IP environment variable');
};
// Web app urls
self.app = express();
//self.io = require('socket.io');
//self.clients = [];
/*self.io.sockets.on('connection', function (socket) {
self.clients.push(socket);
socket.emit('welcome', { message: 'Welcome!' });
// When socket disconnects, remove it from the list:
socket.on('disconnect', function() {
var index = self.clients.indexOf(socket);
if (index != -1) {
self.clients.splice(index, 1);
}
});
});*/
// set up our express application
self.app.use(morgan('dev')); // log every request to the console
self.app.use(cookieParser()); // read cookies (needed for auth)
self.app.use(bodyParser.json()); // get information from html forms
self.app.use(bodyParser.urlencoded({ extended: true }));
self.app.use(bodyParser());
self.app.use(multer({ dest: process.env.OPENSHIFT_DATA_DIR}));
self.app.use(compression());
self.app.use(express.static(__dirname + '/public'));
self.app.use("/public2", express.static(process.env.OPENSHIFT_DATA_DIR));
self.app.set('view engine', 'ejs'); // set up ejs for templating
self.app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', 'true');
next();
}
);
// required for passport
self.app.use(session({
secret:'example',
maxAge: 6 * 3 * 60 * 1000,
store: new MongoStore({ url: process.env.OPENSHIFT_MONGODB_DB_URL,
clear_interval: 6 * 3 * 60 * 1000 })
}));
self.app.use(passport.initialize());
self.app.use(passport.session()); // persistent login sessions
self.app.use(flash()); // use connect-flash for flash messages stored in session
require('./app/routes.js')(self.app, passport); // load our routes and pass in our app and fully configured passport
self.connectDb = function(callback){
self.db.open(function(err, db){
if(err){ throw err };
self.db.authenticate(self.dbUser, self.dbPass, {authdb: "admin"}, function(err, res){
if(err){ throw err };
callback();
});
});
};
//starting the nodejs server with express
self.startServer = function(){
self.app.listen(self.port, self.ipaddr, function(){
console.log('%s: Node server started on %s:%d ...', Date(Date.now()), self.ipaddr, self.port);
});
//websockets
//self.io.listen(self.app);
};
// Destructors
self.terminator = function(sig) {
if (typeof sig === "string") {
console.log('%s: Received %s - terminating Node server ...', Date(Date.now()), sig);
process.exit(1);
};
console.log('%s: Node server stopped.', Date(Date.now()) );
};
process.on('exit', function() { self.terminator(); });
self.terminatorSetup = function(element, index, array) {
process.on(element, function() { self.terminator(element); });
};
['SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT', 'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2', 'SIGPIPE', 'SIGTERM'].forEach(self.terminatorSetup);
};
//make a new express app
var app = new App();
//call the connectDb function and pass in the start server command
app.connectDb(app.startServer);
Thank you for your comments. The solution was to create a self.server variable to pass the express server into socket.io. I have tested the connection and it is working fine now; with all of the other server dependencies.
//starting the nodejs server with express
self.startServer = function(){
self.server = self.app.listen(self.port, self.ipaddr, function(){
console.log('%s: Node server started on %s:%d ...', Date(Date.now()), self.ipaddr, self.port);
});
//websockets
self.io = require('socket.io').listen(self.server);
};

Categories