JSON environnement variable is seen as a string - json

I'm trying to help a friend about his nodejs application.
He use NodeMailer to send emails automatically. We both use ubuntu.
To avoid any leaks, the credential for NodeMailer are set as an environnement variable called EMAIL_CREDENTIALS.
In the app, EMAIL_CREDENTIAL is called as follow:
var emailCredentials = process.env.EMAIL_CREDENTIALS;
if (emailCredentials === 'undefined') {
throw Error('Email credentials are not present');
}
// create reusable transporter object using the default SMTP transport
var transporter = nodemailer.createTransport(emailCredentials);
To set email credential I added a line in src/environnement :
EMAIL_CREDENTIALS={host:"smtp.gmail.com", port: 587, secure: false, auth: {user: "**user**", pass: "**pass**"}}
When I run some test, NodeMailer return the following error
Error: Unsupported configuration, downgrade Nodemailer to v0.7.1 to use it
at Nodemailer.sendMail (/home/**path**/node_modules/nodemailer/lib/nodemailer.js:274:18)
This error happen because type of param === 'string' in nodemailer.createTransport(param) .
My friend has been using this code for a pretty long time with no problem.
Somehow, I understand where the error come from but I would like to know how is it possible that the environnement variable of my friends setup isn't a string and mine is ? And how should I set my variable to be able to run his code without modifying it ?
EDIT: To use JSON.parse() would be a solution but I would prefer not to modifie the app code and as I said this configuration seems to work for my friend so I would like to understand where's the difference.

It is better not to use environment variables for other than simple values. I would suggest you to use a plain JS or JSON file with those variables, that you can simple require(). You can ignore this file via .gitignore, if you do not want it to be included in a git repository.
You can take a look at my configuration module here: https://www.npmjs.com/package/mikro-config
It is designed to be used this way.
Using it, your general configuration will be stored in /config/default.js file, and your environment specific configuration will be stored in /config/env/$NODE_ENV.js file (or in /config/env/$NODE_ENV.local.js, which should be ignored by git, as I described above).

Related

ChainableTemporaryCredentials getPromise and Missing credentials in config, if using AWS_CONFIG_FILE

I have an node application deployed in GCP.
The application includes code to access ressources in AWS-cloud.
For this purpose it uses the aws-SDK with ChainableTemporaryCredentials.
The relevant code lines are...
const credentials = new ChainableTemporaryCredentials({
params: {
RoleArn: `arn:aws:iam::${this.accountId}:role/${this.targetRoleName}`,
RoleSessionName: this.targetRoleName,
},
masterCredentials: new WebIdentityCredentials({
RoleArn: `arn:aws:iam::${this.proxyAccountId}:role/${this.proxyRoleName}`,
RoleSessionName: this.proxyRoleName,
WebIdentityToken: token,
}),
})
await credentials.getPromise()
The WebIdentityToken was received from google and looks good.
At AWS-side I created an proxy-role (the line from masterCredentials RoleArn).
However at runtime I get the error:
Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1
I do not understand this error. Because my application runs in GCP and I use temporary credentials I do not understand why I should use aws-credentials in form of an credentials file or environment variables like AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY. I thought the idea to use ChainableTemporaryCredentials is NOT to have direct aws-credentials. Right?
You can see the public code at:
https://github.com/cloud-carbon-footprint/cloud-carbon-footprint/blob/trunk/packages/aws/src/application/GCPCredentials.ts
and documentation regarding env-variables at:
https://www.cloudcarbonfootprint.org/docs/configurations-glossary/
Any help which leads to understanding of this error message is welcome.
Thomas
Solved it. "Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1 was totally misleading." In reality it was a problem with the field-names in the GCP-JWT-token und the policy in aws. See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html#ck_aud

Parsoid test page fail during VisualEditor installation

I'm trying to install VisualEditor in my MediaWiki wiki but I get stuck when I test Parsoid.
This is the result of the test page:
error: No API URI available for prefix: enwiki; domain: undefined path: /_rt/mediawikiwiki/Parsoid
Error: No API URI available for prefix: enwiki; domain: undefined
at /usr/lib/parsoid/src/lib/config/MWParserEnvironment.js:295:10
at /usr/lib/parsoid/node_modules/prfun/lib/index.js:532:26
at tryCatch2 (/usr/lib/parsoid/node_modules/babybird/lib/promise.js:48:12)
at PrFunPromise.Promise (/usr/lib/parsoid/node_modules/babybird/lib/promise.js:458:15)
at new PrFunPromise (/usr/lib/parsoid/node_modules/prfun/lib/index.js:57:21)
at /usr/lib/parsoid/node_modules/prfun/lib/index.js:530:18
at tryCatch1 (/usr/lib/parsoid/node_modules/babybird/lib/promise.js:40:12)
at promiseReactionJob (/usr/lib/parsoid/node_modules/babybird/lib/promise.js:269:19)
at PromiseReactionJobTask.call (/usr/lib/parsoid/node_modules/babybird/lib/promise.js:284:3)
at flush (/usr/lib/parsoid/node_modules/babybird/node_modules/asap/raw.js:50:29)
I set the API in the settings.js file end to make sure it is correct I tested using the curl command. And it works.
But I still have the problem.
Any suggestion?
You would've put something like this in Parsoid's localsettings.js:
parsoidConfig.setInterwiki( 'localhost', 'http://mediawiki.krenair.dev/mediawiki_dev/w/api.php' );
(example from my dev wiki setup)
That first string (in my case, 'localhost') should be identical to the value VE is set to use by $wgVisualEditorParsoidPrefix in your wiki's LocalSettings.php (unless you're using some other system to configure that stuff like VirtualRestConfig, in which case I can probably help in the comments). I believe you currently have it set to 'enwiki' for some reason, or else something is going wrong leading parsoid to default to 'enwiki' (I really don't know why they consider that a sane default).

Node settings file vs mysql store

i've build my first Node app in which i need to use 5-10 global variables a lot. The thing is i would like to be able to change those values without restarting the server.
So what i though was setup an interval and update those files either from a ( JSON ? ) file or through a couple of queries to the database.
Now what would be my better option here ? Both mysql and read file modules are used in the app.
Security based wouldn't it be best to place the json file behind the public folder and read from that ? Although without sql injection being possible i think in the DB should be pretty safe too.
What do you guys think ?? Still a newbie in Node JS.
Thanks
With yamljs, the overhead is that you will need to install it. From your question, it seems you are already using a bunch of 3rd party modules in your app.
Why not use something that is a part of node.js itself?
Use the fs module.
Example:
var fs = require('fs');
var obj;
fs.readFile('myData.json', 'utf8', function (err, data) {
if (err) throw err;
obj = JSON.parse(data);
});
Docs: https://nodejs.org/api/fs.html#fs_fs_readfile_file_options_callback
A common technique for passing configuration variables to a server is via a YAML file. Normally this file is read once when the server starts but you could periodically query they file to see when it was last updated and if the file was changed update the configuration variables currently in use.
yamljs
YAML = require('yamljs');
config = YAML.load('myfile.yml');
then you can periodically check the last time a file was modified using the mtime property of fs.stat
fs.stat(path, [callback])
If you find that the last modified time has changed then you can re-read the YAML file and update your config with the new values. ( you will probably want to do a sanity check to make sure the file wasn't corrupted etc. )
If you don't want to write the file watching logic yourself I recommend checking out chokidar
// Initialize watcher.
var watcher = chokidar.watch('myfile.yml', {
ignored: /[\/\\]\./,
persistent: true
});
// Add event listeners.
watcher.on('change', function(path) {
// Update config
})

Meteor: reading simple JSON file

I am trying to read a JSON file with Meteor. I've seen various answers on stackoverflow but cannot seem to get them to work. I have tried this one which basically says:
Create a file called private/test.json with the following contents:
[{"id":1,"text":"foo"},{"id":2,"text":"bar"}]
Read the file contents when the server starts (server/start.js):
Meteor.startup(function() {
console.log(JSON.parse(Assets.getText('test.json')));
});
However this seemingly very simple example does not log anything to the console. If I trye to store it in a variable instead on console.logging it and then displaying it client side I get
Uncaught ReferenceError: myjson is not defined
where myjson was the variable I stored it in. I have tried reading the JSON client side
Template.hello.events({
'click input': function () {
myjson = JSON.parse(Assets.getText("myfile.json"));
console.log("myjson")
});
}
Which results in:
Uncaught ReferenceError: Assets is not defined
If have tried all of the options described here: Importing a JSON file in Meteor with more or less the same outcome.
Hope someone can help me out
As per the docs, Assets.getText is only available on the server as it's designed to read data in the private directory, to which clients should not have access (thus the name).
If you want to deliver this information to the client, you have two options:
Use Assets.getText exactly as you have done, but inside a method on the server, and call this method from the client to return the results. This seems like the best option to me as you're rationing access to your data via the method, rather than making it completely public.
Put it in the public folder instead and use something like jQuery.getJSON() to read it. This isn't something I've ever done, so I can't provide any further advice, but it looks pretty straightforward.
The server method is OK, just remove the extra semi-colon(;). You need a little more in the client call. The JSON data comes from the callback.
Use this in your click event:
if (typeof console !== 'undefined'){
console.log("You're calling readit");
Meteor.call('readit',function(err,response){
console.log(response);
});
}
Meteor!

How can I let users register my product online?

I've a MySql database hosted in my web site, with a table named UsrLic
Where any one wants to buy my software must register and enter his/her Generated Machine Key (+ username, email ...etc).
So my question is:
I want to automate this process from my software, how this Process will be?
Should I connect and update my database directly from my software ( and this means I must save all my database connection parameters in it * my database username , password , server * and then use ADO or MyDac to connect to this database ? and if yes how secure is this process ?
or any other suggestions .
I recommend creating an API on your web site in PHP and calling the API from Delphi.
That way, the database is only available to your web server and not to the client application, ever. In fact, you should run your database on localhost or with a private IP so that only machines on the same physical network can reach it.
I have implemented this and am implementing it again as we speak.
PHP
Create a new file named register_config.php. In this file, setup your MySQL connection information.
Create a file named register.php. In this file, put your registration functions. From this file, include 'register_config.php'. You will pass parameters to the functions you create here, and they will do the reading and writing to your database.
Create a file named register_api.php. From this file, include 'register.php'. Here, you will process POST or GET variables that are sent from your client application, call functions in register.php, and return results back to the client, all via HTTP.
You will have to research connecting to and querying a MySQL database. The W3Schools tutorials will have you doing this very quickly.
For example:
Your Delphi program calls https://mysite/register_api.php with Post() and sends the following values:
name=Marcus
email=marcus#gmail.com
Here's how the beginning of register_api.php might look:
// Our actual database and registration functions are in this library
include 'register.php';
// These are the name value pairs sent via POST from the client
$name = $_POST['name'];
$email = $_POST['email'];
// Sanitize and validate the input here...
// Register them in the DB by calling my function in register.php
if registerBuyer($name, $email) {
// Let them know we succeeded
echo "OK";
} else {
// Let them know we failed
echo "ERROR";
}
Delphi
Use Indy's TIdHTTP component and its Post() or Get() method to post data to register_api.php on the website.
You will get the response back in text from your API.
Keep it simple.
Security
All validation should be done on the server (API). The server must be the gatekeeper.
Sanitize all input to the API from the user (the client) before you call any functions, especially queries.
If you are using shared web hosting, make sure that register.php and register_config.php are not world readable.
If you are passing sensitive information, and it sounds like you are, you should call the registration API function from Delphi over HTTPS. HTTPS provides end to end protection so that nobody can sniff the data being sent off the wire.
Simply hookup a TIdSSLIOHandlerSocketOpenSSL component to your TIdHTTP component, and you're good to go, minus any certificate verification.
Use the SSL component's OnVerifyPeer event to write your own certificate verification method. This is important. If you don't verify the server side certificate, other sites can impersonate you with DNS poisoning and collect the data from your users instead of you. Though this is important, don't let this hold you up since it requires a bit more understanding. Add this in a future version.
Why don't you use e.g. share*it? They also handle the buying process (i don't see how you would do this for yourself..) and let you create a reg key through a delphi app.