Skip to content

Commit e7aa248

Browse files
author
Andrei
committed
Merge pull request #335 from solid/email-support
using node mailer as email service
2 parents 90d0c71 + b94b36e commit e7aa248

10 files changed

Lines changed: 172 additions & 4 deletions

File tree

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
sudo: false
22
language: node_js
33
node_js:
4-
- "4.0"
5-
- "5.0"
4+
- "6.0"
5+
66
cache:
77
directories:
88
- node_modules

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ $ solid --allow-signup --port 8443 --cert /path/to/cert --key /path/to/key --roo
9191

9292
Your users will have a dedicated folder under `./accounts`. Also, your root domain's website will be in `./accounts/yourdomain.tld`. New users can create accounts on `/accounts/new` and create new certificates on `/accounts/cert`. An easy-to-use sign-up tool is found on `/accounts`.
9393

94+
##### How can send emails to my users with my Gmail?
95+
96+
> To use Gmail you may need to configure ["Allow Less Secure Apps"](https://www.google.com/settings/security/lesssecureapps) in your Gmail account unless you are using 2FA in which case you would have to create an [Application Specific](https://security.google.com/settings/security/apppasswords) password. You also may need to unlock your account with ["Allow access to your Google account"](https://accounts.google.com/DisplayUnlockCaptcha) to use SMTP.
97+
9498
### Run the Linked Data Platform (intermediate)
9599
If you don't want WebID Authentication and Web Access Control, you can run a simple Linked Data Platform.
96100

bin/lib/init.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,23 @@ module.exports = function (program) {
3131
// Prompt to the user
3232
inquirer.prompt(questions)
3333
.then((answers) => {
34+
// setting email
35+
if (answers.useEmail) {
36+
answers.email = {
37+
host: answers['email-host'],
38+
port: answers['email-port'],
39+
secure: true,
40+
auth: {
41+
user: answers['email-auth-user'],
42+
pass: answers['email-auth-pass']
43+
}
44+
}
45+
delete answers['email-host']
46+
delete answers['email-port']
47+
delete answers['email-auth-user']
48+
delete answers['email-auth-pass']
49+
}
50+
3451
// clean answers
3552
Object.keys(answers).forEach((answer) => {
3653
if (answer.startsWith('use')) {

bin/lib/options.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const fs = require('fs')
2+
const path = require('path')
23

34
module.exports = [
45
// {
@@ -11,7 +12,8 @@ module.exports = [
1112
help: 'Root folder to serve (defaut: \'./\')',
1213
question: 'Path to the folder you want to serve. Default is',
1314
default: './',
14-
prompt: true
15+
prompt: true,
16+
filter: (value) => path.resolve(value)
1517
},
1618
{
1719
name: 'port',
@@ -162,6 +164,54 @@ module.exports = [
162164
help: 'Enforce same origin policy in the ACL',
163165
flag: true,
164166
prompt: true
167+
},
168+
{
169+
name: 'useEmail',
170+
help: 'Do you want to set up an email service?',
171+
flag: true,
172+
prompt: true,
173+
default: true
174+
},
175+
{
176+
name: 'email-host',
177+
help: 'Host of your email service',
178+
prompt: true,
179+
default: 'smtp.gmail.com',
180+
when: (answers) => {
181+
return answers.useEmail
182+
}
183+
},
184+
{
185+
name: 'email-port',
186+
help: 'Port of your email service',
187+
prompt: true,
188+
default: '465',
189+
when: (answers) => {
190+
return answers.useEmail
191+
}
192+
},
193+
{
194+
name: 'email-auth-user',
195+
help: 'User of your email service',
196+
prompt: true,
197+
when: (answers) => {
198+
return answers.useEmail
199+
},
200+
validate: (value) => {
201+
if (!value || value === '') {
202+
return 'You must enter this information'
203+
}
204+
return true
205+
}
206+
},
207+
{
208+
name: 'email-auth-pass',
209+
help: 'Password of your email service',
210+
type: 'password',
211+
prompt: true,
212+
when: (answers) => {
213+
return answers.useEmail
214+
}
165215
}
166216
]
167217

bin/lib/start.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,22 @@ module.exports = function (program) {
4444
}
4545

4646
function bin (argv) {
47+
if (!argv.email) {
48+
argv.email = {
49+
host: argv['emailHost'],
50+
port: argv['emailPort'],
51+
secure: true,
52+
auth: {
53+
user: argv['emailAuthUser'],
54+
pass: argv['emailAuthPass']
55+
}
56+
}
57+
delete argv['emailHost']
58+
delete argv['emailPort']
59+
delete argv['emailAuthUser']
60+
delete argv['emailAuthPass']
61+
}
62+
4763
// Set up --no-*
4864
argv.live = !argv.noLive
4965

lib/create-app.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ var proxy = require('./handlers/proxy')
1010
var IdentityProvider = require('./identity-provider')
1111
var vhost = require('vhost')
1212
var path = require('path')
13+
var EmailService = require('./email-service')
14+
1315
var corsSettings = cors({
1416
methods: [
1517
'OPTIONS', 'HEAD', 'GET', 'PATCH', 'POST', 'PUT', 'DELETE'
@@ -20,7 +22,7 @@ var corsSettings = cors({
2022
origin: true
2123
})
2224

23-
function createApp (argv) {
25+
function createApp (argv = {}) {
2426
var ldp = new LDP(argv)
2527
var app = express()
2628

@@ -42,6 +44,10 @@ function createApp (argv) {
4244
// Setting options as local variable
4345
app.locals.ldp = ldp
4446

47+
if (argv.email && argv.email.host) {
48+
app.locals.email = new EmailService(argv.email)
49+
}
50+
4551
var sessionSettings = {
4652
secret: ldp.secret || uuid.v1(),
4753
saveUninitialized: false,

lib/email-service.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict'
2+
3+
const nodemailer = require('nodemailer')
4+
const extend = require('extend')
5+
6+
class EmailService {
7+
constructor (settings = {}) {
8+
// This reflects nodemailer string option, we allow it
9+
if (typeof settings !== 'string') {
10+
settings = extend(settings, {secure: true})
11+
}
12+
this.mailer = nodemailer.createTransport(settings)
13+
14+
if (settings.sender) {
15+
this.sender = settings.sender
16+
} else if (settings.host) {
17+
this.sender = `no-reply@${settings.host}`
18+
}
19+
}
20+
sendMail (email, callback) {
21+
this.mailer.sendMail(email, callback)
22+
}
23+
}
24+
25+
module.exports = EmailService

lib/identity-provider.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ IdentityProvider.prototype.post = function (req, res, next) {
508508
}
509509

510510
var self = this
511+
var email = req.app.locals.email
511512
var options = req.body
512513
options.host = req.get('host')
513514
options.firstUser = res.locals.firstUser
@@ -531,6 +532,22 @@ IdentityProvider.prototype.post = function (req, res, next) {
531532
function (newCert, callback) {
532533
cert = newCert
533534
self.create(options, cert, callback)
535+
},
536+
function (callback) {
537+
if (email && options.email) {
538+
email.sendMail({
539+
from: `"no-reply" <${email.sender}>`, // sender address
540+
to: options.email,
541+
subject: 'Account created',
542+
text: 'Your account has been created',
543+
html: '<b>Your account has been created</b>'
544+
}, (err) => {
545+
if (err) debug('Error sending email', err)
546+
callback()
547+
})
548+
} else {
549+
callback()
550+
}
534551
}
535552
], function (err) {
536553
if (err) {

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"negotiator": "^0.6.0",
4646
"node-forge": "^0.6.38",
4747
"node-uuid": "^1.4.3",
48+
"nodemailer": "^2.3.2",
4849
"nomnom": "^1.8.1",
4950
"rdflib": "^0.6.1",
5051
"request": "^2.72.0",
@@ -60,6 +61,7 @@
6061
"mocha": "^2.2.5",
6162
"nock": "^7.0.2",
6263
"rsvp": "^3.1.0",
64+
"sinon": "^1.17.4",
6365
"standard": "^6.0.4",
6466
"supertest": "^1.0.1"
6567
},

test/email-service.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const EmailService = require('../lib/email-service')
2+
const sinon = require('sinon')
3+
const expect = require('chai').expect
4+
5+
describe('Email Service', function () {
6+
let email, transport
7+
8+
beforeEach(() => {
9+
transport = {
10+
name: 'testsend',
11+
version: '1',
12+
send: function (data, callback) {
13+
callback()
14+
},
15+
logger: false
16+
}
17+
email = new EmailService(transport)
18+
})
19+
20+
it('should send emails', (done) => {
21+
sinon.stub(transport, 'send').yields(null, 'bep bop')
22+
23+
email.sendMail({
24+
subject: 'test'
25+
}, function (err, info) {
26+
expect(err).to.not.exist
27+
expect(info).to.equal('bep bop')
28+
done()
29+
})
30+
})
31+
})

0 commit comments

Comments
 (0)