javascript: how to detect environment on server side pages - javascript

I've inherited a react/javascript app and I'd like to make a small change to export different mailchimp account variables for prod vs test environments, in mailchimp-configuration.js. (These values get imported from src/server/index.js)
I updated mailchimp-configuration.js to check whether process.env.NODE_ENV == 'production'. This works, but it isn't quite right since I can run my local sandbox (or staging) server 'as production', in which case the production account gets used instead of the test one. I need to use something more conclusive that'll know whether we're running in the production environment vs staging or localhost.
An easy solution on the browser pages is to check the url via window.location.href, but unfortunately from mailchimp-configuration.js, window is not defined.
I suppose I could set a global variable somewhere, but that's last-resort stuff. What's a good way to check my environment from the server side?
thanks!

I need to use something more conclusive that'll know whether we're running in the production environment vs staging or localhost.
There is technically no difference between "a nodejs instance running on a computer" and "a nodejs instance running on a computer". The only way to distinguish "your localhost" and "a production server" is to tell the nodejs instance where it runs in, and thats done by process.ENV.
I updated mailchimp-configuration.js to check whether process.env.NODE_ENV == 'production'. This works, but it isn't quite right since I can run my local sandbox (or staging) server 'as production', in which case the production account gets used instead of the test one.
Actually this is the way to go, if you fear that your secret email account gets used by a test server, then that secret should actually go into a secret manager, such as Vault

You could use one of node's native os functions and determine according to a certain value if you are running node locally in dev -> Link
Standard practice is to set an environmental variable to the according environment you're in (production or development).
process.env.NODE_ENV
perform a check:
if (process.env.NODE_ENV === 'development') {
// do dev stuff
}
if (process.env.NODE_ENV === 'production') {
//do production stuff
}

Related

How to secure API Keys in Environment Variables in a Vue CLI 4 and Electron project

I'm trying to develop a desktop app which would need to make a few private API calls, authenticated using some secret keys.
The keys are created for me by external IT service providers outside of my organisation - they are responsible for the security so there are a few constraints:
They said even though they have already taken steps on their end to secure the API and there are mitigation strategies in place even if a breach happens, but still they would like to make sure that I treat the keys with a security-conscious mindset and take whatever steps possible on my end as well to make sure they remain secured.
I'm not allowed to just create random middleware / gateway on a private server or serverless platform to perform the API calls on my app's behalf as these calls may contain business data.
I have done some research and from what I can find, the general recommendation is to set up a ".env" file in the project folder and use environment variables in that file to store the API keys.
But upon reading the Vue CLI documentation I found the following:
WARNING
Do not store any secrets (such as private API keys) in your app!
Environment variables are embedded into the build, meaning anyone can
view them by inspecting your app's files.
So, given the constraints, is there a way to store these keys securely in a Vue CLI 4 + Electron Desktop app project?
Thanks.
In general, especially if you have a lot of environment variables, it would be better practice to store environment variables in a dot env file (.env), however, it's possible that this file could be leaked when you package your electron app. So, in this case it would be better to store your environment variables from the terminal/command line. To do so follow this guide (https://www.electronjs.org/docs/api/environment-variables).
Keep in mind anything that requires the API key/private information try to keep it on the backend, i.e., the electron process and send the results to the Vue front end.
Here's an example of how you could implement this:
On windows from CMD:
set SOME_SECRET="a cool secret"
On POSIX:
$ export SOME_SECRET="a cool secret"
Main process:
// Other electron logic
const { ipcMain } = require("electron");
// Listen for an event sent from the client to do something with the secret
ipcMain.on("doSomethingOnTheBackend", (event, data) => {
API.post("https://example.com/some/api/endpoint", {token: process.env.SOME_SECRET, data});
});
Client side:
const { ipcRenderer } = require("electron");
ipcRenderer.send("doSomethingOnTheBackend", {username: "test", password: "some password"});
Also note, to use the ipcRenderer on the client side nodeIntegration needs to be enabled.
Here are some more resources to help you get started:
https://www.electronjs.org/docs/api/ipc-renderer
https://www.electronjs.org/docs/api/ipc-main

Storing IP addresses in JavaScript variable

I have a total of 7 machines in a test setup that run test scripts between any two combinations of those machines. These scripts require the IP address of the machines involved in the test run. I'd like to store each machine's IP address in a variable to not only make it easier to reference and call in our JavaScript test scripts, but also design the variables so that they'll be set by pinging the machine to get an up to date version of said address. I don't expect them to change, but you never know what might happen and this would allow to completely ignore them for the most part.
We're using Squish as our IDE for running JavaScript test scripts and Squish has an in house function OS.system that lets you run the command prompt.
It's probably obvious that I can't just use something like const pc1 = OS.system("ping pc-name") since ping gives a return far more than just the IP address.
I was wondering if there was a simpler way to pass a machine's ip address to a JavaScript variable.
I don't know which OS you are using but you can do something like that in Linux bash:
ping -c 1 google.de | grep PING | awk '{print $3}'
But I would recommend you to use a library for that.
You can take a look at this: (node.js)
https://nodejs.org/api/dns.html

How to customise email transports

As I understood Meteor internally uses nodemailer to send emails and creates the corresponding transport based on the defined MAIL_URL environment property.
We have implemented an EmailSenderService which creates several different nodemailer transports. It uses the account settings defined as settings for production mode and a hardcoded ethereal account for development mode.
I wonder if and how it is possible to change the internal Meteor email handling to use our application specific EmailSenderService to send all kind of emails especially the ones send via the account-password package (e.g. enrollment- and forgot-password-emails). My idea is to redirect the calls to the central Email.send function to our EmailSenderService instead of calling the Meteor internal logic.
Thank you for thinking along and any upcoming ideas and hints...
You've got a few options:
1. Monkeypatch Email.send
As #iiro says, you can just monkey patch the Email module by replacing the send method with your own.
Email.send = function (options) {
return EmailSenderService.send(options);
}
2. Replace the email package with a local version
If Meteor finds a package of the same name in the packages/ directory of your project, it will use that one over it's own implementation. Documentation
3. Use undocumented features to hook into Email.send
EDIT: I didn't see that EmailTest isn't exported. So this only works by making a local copy like in option 2.
Looking at the source of the email package, there's a hook which is run at the start of Email.send and allows you to prevent the default execution by returning false. You could use this like so:
EmailTest.hookSend(function (options) {
EmailSenderService.send(options)
return false; // To stop default sending behaviour
});

Is it possible to change the Express Session to a different store after creation

I am using memcached as a backing store for an ExpressJS session - chosen via an app configuration setting. I would like to fall back from memcached to memory if the memcached host cannot be contacted. (This isn't necessarily a production strategy as memcached is very reliable - it's more for when I forget to boot the Docker instance in dev, but could still be a production fail-safe.)
I first thought I could "app.use" a new session instance, and try to remove the first one, but I have read that it's difficult (if possible) to "un-use" Express middleware i.e. to swap the middleware in-place in the chain, or generally tinker with the chain once it's been setup.
The problem there is after the connection timeout period, the app middleware has been setup with many further services installed after the session middleware.
My second thought was can I re-configure the Express Session instance itself and change the store after it's been created? I could not see any way in the documentation.
My third idea was to wrap the express-session in a new "swappable store" class, but I'm wary of the scope of wrapping the entire interface.
For example in my app setup:
app.use(services.session.middleware());
// then a lot of other middleware...
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(rootPath, 'public')));
...etc
And in the session service, which selects and configures the session instance:
function middleware() {
// default / Memory Store options
const opts = {
resave: false,
saveUninitialized: false,
...etc
}
};
// Install any configured backing store
if(config.session.storage === "memcached"){
const MemcachedStore = require('connect-memcached')(session);
opts.proxy = 'true';
opts.store = new MemcachedStore({
hosts: ...,
secret: ...
});
const errorHandler = (type, details)=> {
/* HERE I WOULD LIKE TO RE-MAKE THE SESSION USING MEMORY
* AND DISCARD THE MEMCACHED ONE
* (THIS HAPPENS AFTER APP BOOT HAS FINISHED)
*/
console.error( String.format("Memcached {3} with host:{0} details:{1}.", details.server, details.messages.join( '' ), type));
}
opts.store.client.on('failure', details => errorHandler('failure', details));
opts.store.client.on('issue', details => errorHandler('issue', details));
}
return session(opts);
}
I think there are several approaches you can try for this. The first is to configure a storage system based on which configuration you have supplied on startup (probably via a module like config or nconf). The second is to run a quick check when booting up the app to make sure it can access the memcache service, and if it can't then fallback to memory with an error.
I would be fairly weary of doing either of these, since you're using docker and it should be easy to boot memcache. This is because you'll be introducing code which might trigger in production should there be some connection issue, and then you might find yourself accidentally serving sessions out of memory rather than something like memcache potentially without realising.
I'll expand on both strategies here and provide a third possibly better option.
1. Choose the cache system based on a config
This should be fairly straight forward, simply extract your configuration into some sort of config manager / environment variables (checkout config or nconf). When starting the application and connecting your session middleware, you can pull out all the possibly configurations, see which exist and attach one based on that. This is similar to how your if (config.session.storage === 'memcache") looks at the moment. Just use a fallback of not configuring one and the express-session middleware will fall back to memory. This way you can leave out the configuration completely and just always use memory for development.
2. Run a test before connecting to the desired service
In combination with the above, if memcache details are provided you could run a quick test by attempting to store something in memcache on startup. Perhaps new Date(); to signal when the application booted up? If this throws an error, then just don't attach the MemcachedStore to the express-session options and you can safely destroy the MemcachedStore.
3. Throw an error if you cannot connect to Memcached
This is in further combination to #2. If you identify that memcache configurations are provided, then I would personally do a check to see if you can contact the serivce and if not then throw an error and stop the application. This would mean that in development you immedietely know the issue, and in production you would as well and can trigger automatic alerts for yourself based on the fact that the application failed to start.
This is probably the best and most robust solution, generally doing a silent fallback is not a great idea when talking about connected services as things can go wrong and you have no idea. I appreciate that this is for development purposes and you need to be pragmatic, but if it saves you accidentally serving all sessions from your servers memory then this would be super beneficial.

Singe Page Application External Configurations (Not On NodeJS)

I'm looking for either a reference or an answer to what I think is a very common problem that people who are current implementing JavaScript MVC frameworks (such as Angular, Ember or Backbone) would come across.
I am looking for a way or common pattern to externalize application properties that are accessible in the JS realm. Something that would allow the javascript to load server side properties such as endpoints, salts, etc. that are external to the application root. The issue that I'm coming across is that browsers do not typically have access to the file systems because it is a security concerns.
Therefore, what is the recommended approach for loading properties that are configurable outside of a deployable artifact if such a thing exists?
If not, what is currently being used or is in practice that is considered the recommended approach for this types of problem?
I am looking for a cross compatible answer (Google Chrome is awesome, I agree).
Data Driven Local Storage Pattern
Just came up with that!!
The idea is to load the configuration properties based on a naming over convention configuration where all properties are derived from the targeted hostname. That is, the hostname will derive a trusted endpoint and that endpoint will load the corresponding properties to the application. These application properties will contain information that is relative at runtime. The runtime information will be supplied to the integration parts which then communicate via property iteration on the bootstrapping start up.
To keep it simple, we'll just use two properties here:
This implementation is Ember JS specific but the general idea should be portable
I am currently narrowing the scope of this question to a specific technological perspective, that is Ember JS with the following remedy that is working properly for me and hope it will help any of you out there dealing with the same issue.
Ember.Application.initializer implementation in start up
initialize: function (container, application) {
var origin = window.location.origin;
var host = window.location.hostname;
var port = window.location.port;
var configurationEndPoint = '';
//local mode
if(host === 'localhost'){
//standalone using api stub on NODEJS
if(port === '8000'){
configurationEndPoint = '/api/local';
}//standalone UI app integrating with back end application on same machine, different port
else{
configurationEndPoint = '/services/env';
}
origin += configurationEndPoint;
}else{
throw Error('Unsupported Environment!!');
}
//load the configuration from a trusted resource and store it in local storage on start up
$.get(origin,
function( data ) {
//load all configurations as key value pairs and store in localStorage for access.
configuration = data.configuration;
for(var config in configuration){
debugger;
var objectProperty = localStorage + '.' + config.toString()
objectProperty = configuration[config];
}
}
);
}
Configurable Adapter
export default DS.RESTAdapter.extend({
host: localStorage.host,
namespace: localStorage.namespace
});
No later than yesterday morning i was tackling the same issue.
Basically, you have two options:
Use localStorage/indexedDB or any other client-side persistent storage. (But you have to put config there somehow).
Render your main template (the one that gets rendered always) with a hidden where you put config JSON.
Then in your app init code you get this config and use it. Plain and simple in theory, but lets get down to nasty practice (for second option).
First, client should get config before application loads. It is not easy sometimes. e.g. user should be logged in to see config. In my case i check if i can provide config on the first request, and if not redirect user to login page. This leads us to second limitation. Once you are ready to provide config, you have to reboot app completely so that configuration code run again (at least in Angular it is necessary, as you cannot access providers after the app bootstraps).
Another constraint, the second option is useless if you use static html and cannot change it somehow on server before sending to the client.
May be a better option would be to combine both variants. This should solve some problems for returning users, but first interaction will not be very pleasant anyway. I have not tried this yet.

Categories

Resources