Meteor SMTP Credentials viewable in source code on deployed application - javascript

I have built an application and added my SMTP credentials like this (in the server code block):
Meteor.startup(function () {
smtp = {
username: 'username#emails.com',
password: 'lkajflkadjakdlfj',
server: 'smtp.emails.com',
port: 587
}
process.env.MAIL_URL = 'smtp://' + encodeURIComponent(smtp.username) + ':' + encodeURIComponent(smtp.password) + '#' + encodeURIComponent(smtp.server) + ':' + smtp.port;
});
This works, and is sending just fine. But my credentials are available to anyone just be reading the source code of my deployed application.
Is there somewhere else I should be storing these credentials? Or another method entirely of setting this up?

Try to avoid hardcoding environment variables in your code in general, there are several other options available to you.
You could use Meteor.settings to store your private credentials :
private/settings.json
{
"MAIL_URL": "smtp://smtp://postmaster%40mg.domain.com:password#smtp.mailgun.org:587"
}
server/config.js
process.env.MAIL_URL = Meteor.settings.MAIL_URL;
Don't forget to feed your app with meteor settings :
Local development workflow :
meteor --settings private/settings.json
Deploying to Meteor servers :
meteor deploy myapp.meteor.com --settings private/settings.json
Another option is to use mup (Meteor Up) which provides a config file named mup.json where you can store your credentials as env variable, which is very handy.
mup.json
"env": {
"MAIL_URL": "..."
}
Last but not least, if you're using version control, don't forget to .gitignore your settings !
.gitignore
private/settings.json
mup.json

From the Meteor documentation (http://docs.meteor.com/#/full/structuringyourapp):
Any directory named server is not loaded on the client. Similar to
wrapping your code in if (Meteor.isServer) { ... }, except the client
never even receives the code. Any sensitive code that you don't want
served to the client, such as code containing passwords or
authentication mechanisms, should be kept in the server directory.

Related

Autodesk Forge web application - from visual studio code to close .exe file

I have a working forge application ( bim360 hub sidebar with forge viewer and some charts).
It is currently running from Visual Studio Code IDE only. I want to build the app into an .exe file in order to be able to send it to a user, upload it to a server with IIS, etc..
General details:
I used Petr Broz tutorial to set up the backend of the viewer and hub
(Forge online training - view your models https://www.youtube.com/watch?v=-O1e3gXCOEQ&t=8986s )
The app is running on Node.js
I tried to use 'nexe' module and build executable file. With this method, I need to specify index.js file ("an entry point") and define a 'nexe.config.js' file. I used the entry point start.js.
Eventually, I managed to create an exe file - and when I run it from the command line, I get an error
Missing FORGE_CLIENT_ID or FORGE_CLIENT_SECRET env. variables.
although I have them in the config.js
Main questions:
Is there another way to build a close exe file from visual studio code - for a forge web application?
Am i doing something wrong with the processes I mention above?
Is it even possible to deploy a web application to IIS using an exe file?? all of the documentation points toward Azur, AWS and heroku..
Relevant files:
1) start.js:
const path = require('path');//bringing in built in node js modeules ( to resulve file system path )
const express = require('express');//module to create the express server
const cookieSession = require('cookie-session');
//any piece of code would have an opportunity to handle the request
const PORT = process.env.PORT || 3000;
const config = require('./config.js');
if (config.credentials.client_id == null || config.credentials.client_secret == null) {
console.error('Missing FORGE_CLIENT_ID or FORGE_CLIENT_SECRET env. variables.');
return;
}
let app = express();
//static middlewere to check for the front end files (html,js,css)
app.use(express.static(path.join(__dirname, 'public')));//method inside express module: a middlewere for serving static files this line will check in 'public' folder if the request
//that is sent (specific file) is in there. if so - it will ignore the rest of the stack(the rest of the code)
app.use(cookieSession({
// create 2 cookies that stores the name and encripted key
name: 'forge_session',
keys: ['forge_secure_key'],//takes cater of decipher the encription for the forge key for us
maxAge: 14 * 24 * 60 * 60 * 1000 // 14 days, same as refresh token
}));
app.use(express.json({ limit: '50mb' }));//middlewere that looks at the title of the request - and if its .json it will look at the body of the request and parese it to javascript object
app.use('/api/forge', require('./routes/oauth.js'));//adding our custom express routers that will handle the different endpoints.
app.use('/api/forge', require('./routes/datamanagement.js'));
app.use('/api/forge', require('./routes/user.js'));
app.use((err, req, res, next) => {
console.error(err);
res.status(err.statusCode).json(err);
});
app.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); });
2) config.js:
// Autodesk Forge configuration
module.exports = {
// Set environment variables or hard-code here
credentials: {
client_id: process.env.FORGE_CLIENT_ID,
client_secret: process.env.FORGE_CLIENT_SECRET,
callback_url: process.env.FORGE_CALLBACK_URL
},
scopes: {
// Required scopes for the server-side application-->privliges for our internal opperation in the server side ("back end")
internal: ['bucket:create', 'bucket:read', 'data:read', 'data:create', 'data:write'],
// Required scope for the client-side viewer-->priveliges for the client ("front end")
public: ['viewables:read']
}
};
Author of the tutorial here :)
I'm not sure how nexe works exactly but please note that the sample app expects input parameters such as FORGE_CLIENT_ID or FORGE_CLIENT_SECRET to be provided as environment variables.
As a first step, try running your *.exe file after setting the env. variables in your command prompt.
If that doesn't work, try hard-coding the input parameters directly into the config.js file (replacing any of the process.env.* references), and then bundle everything into an *.exe file. This is just for debugging purposes, though! You shouldn't share your credentials with anyone, not even inside an *.exe file. So as an alternative I'd suggest that you update the sample app to read the input parameters from somewhere else, perhaps from a local file.
after trying a lot of solutions, i got to the conclusion that the reason that nothing happened was that the oathantication files ( with the clint_id and clint_password) was not embedded in the .exe file.
the way to include those files with the nexe module is to use the flag -r "Foldername/subfoldername/filename.js".
first, crate a nexe.config.js file that would contain the entry point file name to the app. ( in my case, the file name is " start.js")
second, write the following commands in the command line:
cd C:\Projects\MyAppFolder
npm install -g nexe
// specify all the files you want to include inside the exe file
nexe start.js -r "config.js" -r "nexe.config.js" -r "routes/common/oauth.js" -r "routes/*.js" -r "public//." -r ".vscode/**/." -r "package-lock.json" -r "package.json" --build --output "AppName.exe"

How to run code depending on whether its running on live website or localhost?

I'm new to coding. I have a node.js application which I have deployed using "Heroku.com". I want to use a custom domain for the application as well as having SSL active using the custom domain. When the application uses the default domain given by Heroku, SSL is automatically in place, however if I want SSL to work when I use a custom domain, I have to include the following code in my app.js file in order for SSL to work:
app.use((req, res, next) => {
if (req.header('x-forwarded-proto') !== 'https')
res.redirect(`https://${req.header('host')}${req.url}`)
else
next()
});
This works fine, however when I am maintaining my app locally (in VS Code) and use localhost:3000 for testing purposes I have to comment out the code above in order to be able to view the app using locahost because of something to do with localhost not working with HTTPS.
So my question is, is there a code (if statement or something of the like) that will run that code if its being used in a live environment or to not run if its being used in localhost. This is mainly so I don't have to continue to comment out the code before and after deployment and testing.
If you have any other advice or better solutions for this kind of thing I would appreciate it.
Cheers,
Sam
You can use the concept of environment variables to differentiate between the production enviroment (live website on heroku) and the development environment (localhost). Specifically, you can set an environment variable NODE_ENV (just a popular naming convention, nothing in-built) to a value that can be used inside your code logic to perform actions based on the environment.
You can access the value by writing
const env = process.env.NODE_ENV;
Note: You have to set the environment variable first, otherwise process.env.NODE_ENV is just going to be undefined.
How to set the environment variables?
There are a couple of ways, like having a .env file, passing through CLI, etc. I'll show you a quick way. While running your server on localhost, write this,
NODE_ENV=development node server.js
Now, inside your server.js, you can do something like
// If NODE_ENV is undefined, assume production
const env = process.env.NODE_ENV || 'production';
app.use((req, res, next) => {
if (env === 'production' && req.header('x-forwarded-proto') !== 'https') {
res.redirect(`https://${req.header('host')}${req.url}`)
}
else {
next()
}
})
You can have as many environments as you like (development, testing, production, staging, etc.) Also check out dotenv module
[Edit]
Create folder called config inside add settings.js
package.json
app.js
--config // Will hold your configuration settings
----settings.js // Your settings
In settings.js
const settings = {
development: {
// Developpment configuration settings
email: 'development#gmail.com'
},
staging: {
// staging settings
email: 'staging#gmail.com'
},
production: {
// Production configuration settings
email: 'production#gmail.com'
},
}
const getSettings = () => {
if (!process.env.NODE_ENV) return settings.development
if (process.env.NODE_ENV === 'staging') return settings.staging
return settings.production
}
module.exports = getSettings()
what is proccess.env.NODE_ENV? It's an enviroment variable which if you didn't declare will return undefined and you can make it's variable different by setting it from the terminal
When you go to development try to run this command in the hoster terminal
export NODE_ENV=production
DON'T RUN THIS IN YOUR LOCAL TERMINAL, try to ask your web hosters how to run a command in their command line to store environment variable
for heroku: heroku run export process.env.NODE_ENV
DON'T WRITE ANY SENSITIVE DATA THERE! store them in environment variables too
Also for the port you would want to do something like this in your app.js
const port = process.env.PORT || 3000

Running Meteor Up how to choose settings file

I am using Meteor Up to deploy my app to production server.
For now I am configuring Meteor.settings through settings-dev.json and settings-prod.json for development and production environments.
I have two main doubts:
How can I run 'mup deploy' command from my machine and choose settings-prod.json?
Is this the best practice to configure my server and resource values using settings-[env].json to deploy my app?
Thanks
Just use the default name /settings.json. It will work. When you execute mup init it will automatically create 2 files.
mup.json - Meteor Up configuration file
settings.json - Settings for Meteor's settings API
And yes it is a good idea to use settings.json. Just be careful to not insert any secret information inside "public": {}
For example:
{
"public": {
"publicKey": 'xxx' // available to the client
},
"oauthSecretKey": "xxx" // available to server only
}

Node.js sensitive information in javascript file?

Is it safe to contain sensitive information such as database connection details on a JavaScript file running on a Node.js server ?
For instance:
var mysql = require('db-mysql');
new mysql.Database({
hostname: 'localhost',
user: 'user',
password: 'password',
database: 'test'
}).on('error', function(error) {
console.log('ERROR: ' + error);
}).on('ready', function(server) {
console.log('Connected to ' + server.hostname + ' (' + server.version + ')');
}).connect();
Since JavaScript file is a client-side file, is this information can't be seen through the client on a typical browser using the developer tool ?
Since you're executing the script server-side, this same code is not viewable on the client-side. Think of it along the same lines as a PHP script or similar. However as already pointed out, if you place your script inside a publicly accessible directory, then people could see the code.
A couple of alternatives to placing your credentials directly inside your script could be to move your credentials securely (e.g. with appropriate file/user permissions) to a file in some other directory that your script reads from or get your credentials from the environment like:
# DB_USER=foo DB_PASS=bar node myscript.js
Then inside your script:
new mysql.Database({
hostname: 'localhost',
user: process.env.DB_USER,
password: process.env.DB_PASS,
database: 'test'
// ...
Yes, it's safe to do that. Client will have only access to what you will send to him from your application. This is not client-side file, it's node.js and your application server-side file. Remember to NOT include this file with other JS files like jquery etc which you will send to your clients.
Although it is safe, but what If directory browsing is enabled on server ?

Meteor environment variables invalid in production

I am using Meteor UP for deployment and have set the environment variable both in the mup.json file and a file server/lib/env.js which contains them.
Here is where its being accessed:
Meteor.startup(function() {
// Remove configuration entries in case service is already configured
Accounts.loginServiceConfiguration.remove({
service: "facebook"
});
// Add Facebook configuration entry
Accounts.loginServiceConfiguration.insert({
"service": "facebook",
"appId": process.env.FACEBOOK_1,
"secret": process.env.FACEBOOK_2
});
});
However in the browser I'm getting "Invalid app id: null", but it works in development, any ideas?
Use Meteor.settings.
Development
Define settings in .config/development/settings.json.
Create shell script (dev.sh) in root of your meteor project:
#!/bin/bash
meteor --settings .config/development/settings.json
Instead using command meteor run ./dev.sh
Production (deploy using mup)
mup init creates 'deployment directory' with generated files mup.json and settings.json.
It is important to execute mup init outside of your meteor app directory, so deployment configuration will not be stored on app server.
Usage
Example of settings.json:
{
"service_id":"...",
"service_secret":"...",
"public":{
"service_name":"..."
}
}
If the settings object contains a key named public, then
Meteor.settings.public will be available on the client as well as the
server. All other properties of Meteor.settings are only defined on
the server.
server only:
Meteor.settings.service_id
Meteor.settings.service_secret
server and client :
Meteor.settings.public.service_name
Update:
Changed paths accordingly to Hubert OG's comment

Categories

Resources