How to use greenlock module in node without express - node.js

I've been trying to use the greenlock.js module for Node to try and obtain ssl certificates for a domain registered in cloudflare.
I have seen some examples on greenlock-express, however, I would like to use this module without needing to use express.
The issue is that I obtain the following error when creating the greenlock object:
internal/validators.js:120
throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
at validateString (internal/validators.js:120:11)
at Object.resolve (path.js:980:7)
at Object.Init._init (/git_reps/greenlock_test/node_modules/#root/greenlock/lib/init.js:128:14)
at Object.greenlock._create (/git_reps/greenlock_test/node_modules/#root/greenlock/greenlock.js:58:22)
at Object.G.create (/git_reps/greenlock_test/node_modules/#root/greenlock/greenlock.js:482:15)
at Object.<anonymous> (/git_reps/greenlock_test/greenlock-test.js:13:27)
at Module._compile (internal/modules/cjs/loader.js:1138:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14) {
code: 'ERR_INVALID_ARG_TYPE'
}
My code is as follows, I have not even implemented any other function yet because it breaks here:
1 'use strict'
2
3 const pkg = require ('./package.json');
4 const Greenlock = require('greenlock');
5 const acmeDnsCloudflare = require('acme-dns-01-cloudflare');
6
7 const cloudflareDns01 = new acmeDnsCloudflare({
8 token: 'dummyToken',
9 verifyPropagation: true,
10 verbose: true
11 });
13 let greenlock = Greenlock.create({
14 configDir: './greenlock.d/config.json',
15 packageAgent: pkg.name + '/' + pkg.version,
16 maintainerEmail: 'maintaner#example.com',
17 staging: true,
18 notify: function(event, details){
19 if('error'=== event){
20 console.error(details);
21 }
22 }
23 });

I don't know wich version you're using, using current 4.0.5 the challenge module has to be defined as a string and is instanciate internally by GreenLock
"use strict";
var config_ovh = require('./my_modules/config_ovh');
var pkg = require("./package.json");
var Greenlock = require("#root/greenlock");
var greenlock = Greenlock.create({
packageRoot: __dirname,
configDir: "./greenlock.d/",
packageAgent: pkg.name + "/" + pkg.version,
maintainerEmail: "me#domain.fr",
staging: true,
notify: function (event, details) {
if ("error" === event) {
console.error('greenlock notify :' + event, details);
}
},
});
greenlock.manager
.defaults({
agreeToTerms: true,
subscriberEmail: "me#domain.fr",
store: {
module: "greenlock-store-fs",
basePath: "./certs",
},
challenges: {
"dns-01": {
module: "acme-dns-01-ovh",
appKey: config_ovh.appKey,
appSecret: config_ovh.appSecret,
consumerKey: config_ovh.consumerKey,
region: "ovh-eu",
propagationDelay: 5000,
},
},
})
.then(function (fullConfig) {
//...
});
var altnames = [
"sub1.domain.fr",
"sub2.domain.fr",
];
greenlock
.add({
subject: altnames[0],
altnames: altnames,
})
.then(function () {
// saved config to db (or file system)
console.log('greenlock then', arguments);
});
This code successfully generates the certificates (acme-dns-01-ovh being my own implementation for the OVH DNS challenge), but the process terminates and I currently don't see how the auto-renewal works...

Related

Unexpected token '.' while trying to use Nodemailer SES transport sdk

I need to extend the functionality of my SMTP feature to handle bulk emails. It works fine, however when a big amount of emails presented it sends them very slowly (about 2-3 per second). Our current AWS plan allows up to 15 emails per second. I read NodeMailer documentation and tried to implement the SES SDK, however it crashes my app right away.
Here is an error:
/home/node/app/node_modules/#aws-sdk/client-ses/dist-cjs/protocols/Aws_query.js:3734
if (input.ReplacementTags?.length === 0) {
^
SyntaxError: Unexpected token '.'
at wrapSafe (internal/modules/cjs/loader.js:915:16)
at Module._compile (internal/modules/cjs/loader.js:963:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
at Module.load (internal/modules/cjs/loader.js:863:32)
at Function.Module._load (internal/modules/cjs/loader.js:708:14)
at Module.require (internal/modules/cjs/loader.js:887:19)
at require (internal/modules/cjs/helpers.js:74:18)
at Object.<anonymous> (/home/node/app/node_modules/#aws-sdk/client-ses/dist-cjs/commands/CloneReceiptRuleSetCommand.js:8:21)
at Module._compile (internal/modules/cjs/loader.js:999:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
[nodemon] app crashed - waiting for file changes before starting...
Here is my dependency list:
"#aws-sdk/client-ses": "^3.204.0",
"#aws-sdk/credential-provider-node": "^3.204.0",
"nodemailer": "^6.4.16"
And here is my nodeMailer code:
require('dotenv').config()
const nodemailer = require('nodemailer')
const Settings = require('./agentLogic/settings')
const Util = require('./util')
let aws = require('#aws-sdk/client-ses') // new feature I'm trying to implement
let {defaultProvider} = require('#aws-sdk/credential-provider-node') // new feature I'm trying to implement
const ses = new aws.SES({
apiVersion: '2010-12-01',
region: 'us-west-2',
defaultProvider,
}) // new feature I'm trying to implement
let currentSMTP = {}
async function emailService() {
currentSMTP = await Settings.getSMTP()
const decryptedPassword = Util.decrypt(
currentSMTP.dataValues.value.auth.pass,
currentSMTP.dataValues.value.IV,
)
const transporter = nodemailer.createTransport({
host: currentSMTP.dataValues.value.host,
// Defaults to 587 if "secure" is false or no value provided or 465 if true
port:
currentSMTP.dataValues.value.encryption === false
? 587
: !currentSMTP.dataValues.value.encryption
? 587
: currentSMTP.dataValues.value.encryption,
// False for STARTTLS (must use port 587), true for TLS (must use port 465)
secure: !currentSMTP.dataValues.value.encryption
? false
: currentSMTP.dataValues.value.encryption,
auth: {
user: currentSMTP.dataValues.value.auth.mailUsername
? currentSMTP.dataValues.value.auth.mailUsername
: currentSMTP.dataValues.value.auth.email,
pass: decryptedPassword,
},
tls: {
// Change to "false" to not fail on invalid certs
rejectUnauthorized: true,
},
SES: {ses, aws}, // new feature I'm trying to implement
sendingRate: 15, // new feature I'm trying to implement (I need this to match our current AWS SMTP plan of 15 emails/second)
})
return transporter
}
const sendMail = async (message) => {
const transporter = await emailService()
return new Promise((resolve, reject) => {
transporter.sendMail(message, (error, info) => {
if (error) {
console.log('Error occurred')
console.log(error.message)
reject('error')
} else {
console.log('Message sent successfully!')
console.log(nodemailer.getTestMessageUrl(info))
resolve(true)
}
// Only needed when using pooled connections
transporter.close()
})
})
}
Please, note that by default all the SMTP settings are not set. The user may or may not set the SMTP on demand. But the app comes without some SMTP preset values (such as host, username, email etc)
Can anyone help me understand why I'm getting and how to fix it?

Running NodeJS App with Socket IO on Shared CPanel server Unexpected token

I created a very simple socket IO app which receives a message and posts it back in a socket group.
The app is running successfully on my Windows machine with Node.js v12.14.0. But I want to get rid of my port forwarding so asked my hoster if it was possible to run the Node.js app on Cpanel. They were not a fan, but opened it up.
I had to install the dependencies manually but finally got no more dependency error while starting the app, but ended up with the error below. After doing some google-ing it probably has to do with the Node.js version on the server which is v6.16.0 . The hoster says they can't get this updated as it comes with cpanel. Now I was hoping there is a way to get my app.js running on this version.
Error:
enter code here[username#server app]$ node /home/username/domains/website.nl/app/app.js
/home/username/domains/website.nl/app/node_modules/ws/lib/websocket.js:347
...options
^^^
SyntaxError: Unexpected token ...
at createScript (vm.js:56:10)
at Object.runInThisContext (vm.js:97:10)
at Module._compile (module.js:549:28)
at Object.Module._extensions..js (module.js:586:10)
at Module.load (module.js:494:32)
at tryModuleLoad (module.js:453:12)
at Function.Module._load (module.js:445:3)
at Module.require (module.js:504:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (/home/username/domains/website.nl/app/node_modules/ws/index.js:3:19)
[username#server app]$ node -v
v6.16.0
The app:
var fs = require('fs');
var https = require('https');
var prvKey = fs.readFileSync('/home/username/ssl/keys/1.key').toString();
var prvCert = fs.readFileSync('/home/username/ssl/certs/1.crt').toString();
var server = https.createServer({key:prvKey,cert:prvCert});
var serverPort = 3000;
// var server = https.createServer();
var io = require('socket.io')(server);
server.listen(serverPort, function() {
console.log('server up and running at %s port', serverPort);
});
io.on("connection", function(socket) {
console.log("user connected: " + socket.id + " - " + socket.request.connection.remoteAddress);
var activequizid = null;
socket.on('jsondata', function(data){
if(data.join.join == "true"){
console.log(socket.id + " join group " + data.join.quizid)
socket.join(data.join.quizid)
}
})
socket.on('jsondataupdate', function(data){
console.log(data.update)
if(data.update.status){
socket.to(data.update.quizid).emit('update', data.update);
}
})
socket.on("disconnect", function(socketd) {
console.log(socketd)
console.log(this.id)
});
socket.on('connection', function () {
console.log('connection!')
})
socket.on('reconnecting', function () {
console.log('reconnecting!')
})
socket.on('reconnect', function () {
console.log('reconnect!')
})
socket.on('disconnect', function () {
console.log('disconnect!')
})
});
console.log("sever online")
websocket.js (partly function with error (look for "...options")) :
send(data, options, cb) {
if (this.readyState === WebSocket.CONNECTING) {
throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
}
if (typeof options === 'function') {
cb = options;
options = {};
}
if (typeof data === 'number') data = data.toString();
if (this.readyState !== WebSocket.OPEN) {
sendAfterClose(this, data, cb);
return;
}
const opts = {
binary: typeof data !== 'string',
mask: !this._isServer,
compress: true,
fin: true,
...options
};
if (!this._extensions[PerMessageDeflate.extensionName]) {
opts.compress = false;
}
this._sender.send(data || EMPTY_BUFFER, opts, cb);
}

What is causing the error "Cannot set uncompiled validation rules without configuring a validator" in NodeJS?

Here's what I have so far.
'use strict';
const Hapi = require("#hapi/hapi");
const Joi = require("#hapi/joi")
const server = new Hapi.Server({ host: "0.0.0.0", port: 80 });
server.route({
method: "POST",
path: "/board",
options: {
validate: {
payload: {
name: Joi.object({
name: Joi.string().min(1).max(15)
})
}
}
},
handler: async (request, h) => {
// do stuff
}
});
server.start();
This produces the error
Error: Cannot set uncompiled validation rules without configuring a validator
at new module.exports (C:\Users\Fukatsumu\Desktop\projects\Textboard\node_modules\#hapi\hoek\lib\error.js:23:19)
at Object.module.exports [as assert] (C:\Users\Fukatsumu\Desktop\projects\Textboard\node_modules\#hapi\hoek\lib\assert.js:20:11)
at Object.exports.compile (C:\Users\Fukatsumu\Desktop\projects\Textboard\node_modules\#hapi\hapi\lib\validation.js:48:10)
at module.exports.internals.Route._setupValidation (C:\Users\Fukatsumu\Desktop\projects\Textboard\node_modules\#hapi\hapi\lib\route.js:197:43)
at new module.exports.internals.Route (C:\Users\Fukatsumu\Desktop\projects\Textboard\node_modules\#hapi\hapi\lib\route.js:122:14)
at internals.Server._addRoute (C:\Users\Fukatsumu\Desktop\projects\Textboard\node_modules\#hapi\hapi\lib\server.js:498:23)
at internals.Server.route (C:\Users\Fukatsumu\Desktop\projects\Textboard\node_modules\#hapi\hapi\lib\server.js:491:22)
at Object.<anonymous> (C:\Users\Fukatsumu\Desktop\projects\Textboard\index.js:37:8)
at Module._compile (internal/modules/cjs/loader.js:956:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
at Module.load (internal/modules/cjs/loader.js:812:32)
at Function.Module._load (internal/modules/cjs/loader.js:724:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)
at internal/main/run_main_module.js:17:11
I expected this to validate the request, but instead it's producing an error message that there are very few details on how to fix.
It should be
'use strict';
const Hapi = require("#hapi/hapi");
const Joi = require("#hapi/joi")
const server = new Hapi.Server({ host: "0.0.0.0", port: 80 });
server.route({
method: "POST",
path: "/board",
options: {
validate: {
payload: Joi.object({
name: Joi.string().min(1).max(15)
})
}
},
handler: async (request, h) => {
// do stuff
}
});
server.start();
payload: Joi.object({
name: Joi.string().min(1).max(15)
})
On upgrading to Latest hapi, check your code for route validate and response.schema settings and if you are passing values that must be compiled (see above for the lack of Joi.object() as a typical case), either wrap your schema with Joi.object() or call server.validator(Joi)

Webpacking a NodeJS Express API with MySQL throws connection error in mode '-p', not in '-d'

I have a simple Express API where I use MySQL to retrieve my data. I use Webpack 4 to bundle it with a very simple configuration:
'use strict';
const path = require('path');
module.exports = {
entry: './src/main.js',
target: 'node',
output: {
filename: 'gept_api.js',
path: path.resolve(__dirname, 'dist'),
},
node: {
__dirname: true,
},
};
When I use webpack --config webpack.config.js -d for development everything works just fine.
However, when I run webpack --config webpack.config.js -p for production it suddenly doesn't work anymore, and throws an error when it's getting a connection from the pool.
TypeError: Cannot read property 'query' of undefined
at Object.getItem (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:154359)
at t.db_pool.getConnection (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:154841)
at c._callback (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:68269)
at c.end (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:8397)
at C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:322509
at Array.forEach (<anonymous>)
at C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:322487
at process._tickCallback (internal/process/next_tick.js:112:11)
So somehow this is broken by using the production mode in webpack 4. The connection object undefined somehow, while it isn't in development mode.
I have no idea how to fix this, since I'm a noob in using Webpack. I tried searching on google, but couldn't find anything relevant.
How I create my pool:
'use strict';
var mysql = require('mysql');
var secret = require('./db-secret');
module.exports = {
name: 'gept_api',
hostname: 'https://api.toxsickproductions.com/gept',
version: '1.3.0',
port: process.env.PORT || 1910,
db_pool: mysql.createPool({
host: secret.host,
port: secret.port,
user: secret.user,
password: secret.password,
database: secret.database,
ca: secret.ca,
}),
};
How I consume the connection:
pool.getConnection((err, connection) => {
PlayerRepository.getPlayer(req.params.username, connection, (statusCode, player) => {
connection.release();
res.status(statusCode);
res.send(player);
return next();
});
});
and
/** Get the player, and logs to HiscoreSearch if exists.
*
* Has callback with statusCode and player. Status code can be 200, 404 or 500.
* #param {string} username The player's username.
* #param {connection} connection The mysql connection object.
* #param {(statusCode: number, player: { username: string, playerType: string }) => void} callback Callback with statusCode and the player if found.
*/
function getPlayer(username, connection, callback) {
const query = 'SELECT p.*, pt.type FROM Player p JOIN PlayerType pt ON p.playerType = pt.id WHERE username = ?';
connection.query(query, [username.toLowerCase()], (outerError, results, fields) => {
if (outerError) callback(500);
else if (results && results.length > 0) {
logHiscoreSearch(results[0].id, connection, innerError => {
if (innerError) callback(500);
else callback(200, {
username: results[0].username,
playerType: results[0].type,
deIroned: results[0].deIroned,
dead: results[0].dead,
lastChecked: results[0].lastChecked,
});
});
} else callback(404);
});
}
I found what was causing the issue. Apparantly the mysql package relies on Function.prototype.name because setting keep_fnames: true fixed the production build. (https://github.com/mishoo/UglifyJS2/tree/harmony#mangle-options)
I disabled the Webpack 4 standard minification and used custom UglifyJSPlugin settings:
'use strict';
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: './src/main.js',
target: 'node',
output: {
filename: 'gept_api.js',
path: path.resolve(__dirname, 'dist'),
},
node: {
__dirname: true,
},
optimization: {
minimize: false,
},
plugins: [
new UglifyJsPlugin({
parallel: true,
uglifyOptions: {
ecma: 6,
mangle: {
keep_fnames: true,
},
},
}),
],
};

NodeMailer - Transport option must be a transport instance or configuration object

I am trying to create a email verification mailer following the example from here. I added both email-template and nodemailer packages. I made the transporter available as an adapter throughout my application. Below is the code for mailer.ts:
import * as mailer from 'nodemailer';
import * as dotenv from 'dotenv';
dotenv.load({ path: '.env' });
var mailConfig = {
host: process.env.MAIL_HOST,
port: process.env.MAIL_PORT,
auth: {
user: process.env.MAIL_USERNAME,
pass: process.env.MAIL_PASSWORD
}
};
var transporter = mailer.createTransport(mailConfig);
module.exports = transporter;
I am trying to build a wrapper around email-template like below signup.ts:
const EmailTemplate = require('email-templates');
var mailer = require('../mailer');
var sendEmailVerficationLink = mailer.templateSender(
new EmailTemplate({
views: { root: './verify' }
}), {
from: process.env.MAIL_FROM,
});
exports.sendVerficationLink = function (obj) {
sendEmailVerficationLink({
to: obj.email,
subject: 'Verify your Email'
}, {
name: obj.username,
token: obj.otp
}, function (err, info) {
if (err) {
console.log(err)
} else {
console.log('Sign up mail sent to ' + obj.email + ' for verification.');
}
});
};
In my actual controller, I try to send the mail as below user.ts:
var verify = require('../utils/mailer-templates/signup');
signup = (req, res) => {
..
verify.sendVerficationLink(obj); // send the actual user object
..
}
But I keep getting this error:
Error: Transport option must be a transport instance or configuration object
[1] at new Email (C:\Users\User\Documents\Vivavii-REST\node_modules\email-templates\lib\index.js:82:83)
[1] at Object.<anonymous> (C:\Users\User\Documents\Vivavii-REST\dist\utils\mailer-templates\signup.js:3:54)
[1] at Module._compile (module.js:641:30)
[1] at Object.Module._extensions..js (module.js:652:10)
[1] at Module.load (module.js:560:32)
[1] at tryModuleLoad (module.js:503:12)
[1] at Function.Module._load (module.js:495:3)
[1] at Module.require (module.js:585:17)
[1] at require (internal/module.js:11:18)
[1] at Object.<anonymous> (C:\Users\User\Documents\Vivavii-REST\dist\controllers\user.js:14:14)
[1] at Module._compile (module.js:641:30)
[1] at Object.Module._extensions..js (module.js:652:10)
[1] at Module.load (module.js:560:32)
[1] at tryModuleLoad (module.js:503:12)
[1] at Function.Module._load (module.js:495:3)
[1] at Module.require (module.js:585:17)
Main issue You used outdated example. In the example nodemailer has 2.7.2 version and unknown email-templates. Current nodemailer version is 4.4.1.
In the latest email-templates version you don't need directly work with nodemailer. You can pass configuration in transport params. Here is fixed version of your code:
const EmailTemplate = require('email-templates');
const dotenv = require('dotenv');
dotenv.load({ path: '.env' });
const emailTemplate = new EmailTemplate({
message: {
from: process.env.MAIL_FROM
},
transport: {
host: process.env.MAIL_HOST,
port: process.env.MAIL_PORT,
auth: {
user: process.env.MAIL_USERNAME,
pass: process.env.MAIL_PASSWORD
}
}
});
function sendVerficationLink(obj) {
return emailTemplate.send({
template: 'verify',
message: {
to: obj.email
},
locals: {
name: obj.username,
token: obj.otp
}
});
};
exports.sendVerficationLink = sendVerficationLink;
Some details:
mailer.ts is redundant
in project there is folder emails with templates. More infomation

Resources