Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Managing configs for different environments is kind of a pain.
In short I wanted it to:
NODE_ENV
environment variable to grab appropriate configconst config = require('getconfig')
from anywhere in the app and have it Just Work™npm install getconfig
config/default.json
(or config/default.js
, anything you can require()
will work) file in the same folder as the main entry point (usually project root)const Config = require('getconfig');
Getconfig looks for a config directory in the same folder as the main entry point of your app. Your configuration files should be contained within that directory.
The configuration files attempted by require, in order, are:
config/default
config/all
config/{{NODE_ENV}}
config/local
Note that we don't list extensions, that's because the files are loaded via node's require
mechanism, so anything node can require will work.
In the event that NODE_ENV
is not set, getconfig will attempt to load dev
, devel
, develop
, and development
in its place.
In a lot of situations it's simpler to pass configuration via environment variables, rather than hardcoding it into a config file.
Fortunately, getconfig
can fill those in for you. Just set the value of a key to reference the environment variable and it will be expanded inline. For example:
{
"envVariable": "$ENV_VAR"
}
Note that this will only work for environment variables whose names are within the character set of A-Z, 0-9, and _ (underscore). This is to prevent collisions with things like complex strings that may start with a $
.
Environment variables can be made optional by specifying a second $
in the value's name, such as:
{
"envVariable": "$$ENV_VAR"
}
When an optional environment variable is unspecified, it is removed from that layer of configuration. This allows you to specify a default in config/default
and an optional value in config/dev
, and if the optional value in config/dev
is unset the value from config/default
will be used.
Required environment variables may be used in string interpolation like so:
{
"envVariable": "some ${ENV_VAR}"
}
However when used in interpolation like the above, no type conversions will be applied.
Additionally, since all environment variables are strings, getconfig can also perform type coercion for you by specifying a ::type
suffix. The following types are supported out of the box:
{
"stringArray": "$STRING_ARRAY_VALUE::array",
"boolean": "$BOOL_VALUE::boolean",
"booleanArray": "$BOOLEAN_ARRAY_VALUE::array:boolean",
"date": "$DATE_VALUE::date",
"dateArray": "$DATE_ARRAY_VALUE::array:date",
"number": "$NUMBER_VALUE::number",
"numberArray": "$NUMBER_ARRAY_VALUE::array:number",
"object": "$OBJECT_VALUE::object",
"objectArray": "$OBJECT_ARRAY_VALUE::array:object",
"regex": "$REGEX_VALUE::regex",
"regexArray": "$REGEX_ARRAY_VALUE::array:regex"
}
The array
type is special in that it accepts an optional argument specified by an additional :type
suffix, that allows creating an array of a typed value.
In addition to the built in types, it is possible to add your own types like so:
const Errors = require('getconfig/errors');
const Types = require('getconfig/types');
Types.custom = function (val, arg1, arg2) {
// do some conversion here
return val;
// throw new Errors.ConversionError(); // if something failed
};
const Config = require('getconfig');
You can then use ::custom
as a suffix in your config and environment variables will be processed through your custom function. If your custom function accepts arguments (in the example above arg1
and arg2
) they can be passed like so $$ENV_VAR::custom:arg:arg
. Note that every argument will be passed as a string and it is up to your custom function to handle them appropriately.
Your configuration can also reference variables within itself as part of string interpolation, so a config file like the following is valid:
{
"port": "$PORT::number",
"host": "$HOSTNAME",
"url": "http://${self.host}:${self.port}
}
This allows you to define a variable once and reuse it in multiple places. This has the same limitations as string interpolation with environment variables however, it will not apply type conversions, and the value referenced must exist. You can refer to deeper keys by using a dot as a path separator like so:
{
"some": {
"deep": {
"value": "here"
}
},
"top": "${self.some.deep.value}"
}
Note that if the contents of a self referencing key is only the reference (i.e. ${self.value}
vs http://${self.value}
) the reference will be copied not interpolated. This allows you to reference objects in multiple places like so:
{
"postgres": {
"user": "pg",
"database": "test"
},
"clientOne": {
"database": "${self.postgres}"
},
"clientTwo": {
"database": "${self.postgres}"
}
}
In the above example, the database
key under both clientOne
and clientTwo
will be a reference to the top level postgres
object, simplifying configuration reuse.
In certain circumstances, when your app isn't run directly (e.g. test runners) getconfig may not be able to lookup your config file properly. In this case, you can set a GETCONFIG_ROOT
environment variable to the directory where your config files are located.
In addition to the above behaviors, getconfig
will attempt to load a .env
file located in either the config
directory or the project root (i.e. one level above the config
directory). These .env
files are parsed as close to the dotenv package as possible for compatibility's sake.
When used in a Google Cloud Function or an AWS Lambda function, getconfig will use the CODE_LOCATION
or LAMBDA_TASK_ROOT
environment variable, respectively, to automatically locate the appropriate root. This means that you can include your config
directory in your function deployment and things should work as you would expect them to.
Note: Google Cloud Functions automatically set NODE_ENV
to "production"
when deployed, however Lambda leaves NODE_ENV
unset by default.
getconfig will always fill in the getconfig.env
value in your resulting config object with the current environment name so you can programatically determine the environment if you'd like. If no NODE_ENV
is set it will also set getconfig.isDev
to true
.
getconfig also includes a small helper tool for debugging and inserting values from your config into shell scripts and the like, it can be used like:
getconfig [path] config.value
The path
parameter is optional and allows you to define the root of your project, the default is the current working directory. The second parameter is the path within the config to print.
4.4.0
all
layer, which loads before the NODE_ENV
layer but after default
and can help eliminate the need for multiple files with the same contents.4.3.0
4.2.0
4.1.0
4.0.0
3.1.0
3.0.0
2.0.0
1.0.0
0.x.x
range per semver conventions.dev
enviroments now look for related config files. So if you've set your $NODE_ENV
to development
and it will still find a file called dev_config.json
.0.3.0
- Switching from JSON.parse to ALCE to allow single quotes and comments. Better readme.MIT
if you dig it follow @HenrikJoreteg and/or @quitlahok on twitter.
FAQs
Environment aware config reader
We found that getconfig demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.