commit
4d56287583
16 changed files with 131 additions and 6 deletions
|
@ -3,6 +3,7 @@
|
|||
let log = require('npmlog');
|
||||
|
||||
let nodemailer = require('nodemailer');
|
||||
let openpgpEncrypt = require('nodemailer-openpgp').openpgpEncrypt;
|
||||
let settings = require('./models/settings');
|
||||
let Handlebars = require('handlebars');
|
||||
let fs = require('fs');
|
||||
|
@ -82,7 +83,7 @@ function getTemplate(template, callback) {
|
|||
}
|
||||
|
||||
function createMailer(callback) {
|
||||
settings.list(['smtpHostname', 'smtpPort', 'smtpEncryption', 'smtpUser', 'smtpPass', 'smtpLog', 'smtpDisableAuth', 'smtpMaxConnections', 'smtpMaxMessages', 'smtpSelfSigned'], (err, configItems) => {
|
||||
settings.list(['smtpHostname', 'smtpPort', 'smtpEncryption', 'smtpUser', 'smtpPass', 'smtpLog', 'smtpDisableAuth', 'smtpMaxConnections', 'smtpMaxMessages', 'smtpSelfSigned', 'pgpPrivateKey', 'pgpPassphrase'], (err, configItems) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
@ -108,6 +109,10 @@ function createMailer(callback) {
|
|||
rejectUnauthorized: !configItems.smtpSelfSigned
|
||||
}
|
||||
});
|
||||
module.exports.transport.use('stream', openpgpEncrypt({
|
||||
signingKey: configItems.pgpPrivateKey,
|
||||
passphrase: configItems.pgpPassphrase
|
||||
}));
|
||||
|
||||
return callback(null, module.exports.transport);
|
||||
});
|
||||
|
|
|
@ -12,6 +12,8 @@ module.exports.grouped = ['radio', 'checkbox', 'dropdown'];
|
|||
module.exports.types = {
|
||||
text: 'Text',
|
||||
website: 'Website',
|
||||
longtext: 'Multi-line text',
|
||||
gpg: 'GPG Public Key',
|
||||
number: 'Number',
|
||||
radio: 'Radio Buttons',
|
||||
checkbox: 'Checkboxes',
|
||||
|
@ -26,6 +28,8 @@ module.exports.types = {
|
|||
module.exports.genericTypes = {
|
||||
text: 'string',
|
||||
website: 'string',
|
||||
longtext: 'textarea',
|
||||
gpg: 'textarea',
|
||||
number: 'number',
|
||||
'date-us': 'date',
|
||||
'date-eur': 'date',
|
||||
|
@ -264,7 +268,7 @@ function addCustomField(listId, name, defaultValue, type, group, visible, callba
|
|||
|
||||
let column = null;
|
||||
let key = slugify('merge ' + name, '_').toUpperCase();
|
||||
let allowedTypes = ['text', 'number', 'radio', 'checkbox', 'dropdown', 'date-us', 'date-eur', 'birthday-us', 'birthday-eur', 'website', 'option'];
|
||||
let allowedTypes = ['text', 'number', 'radio', 'checkbox', 'dropdown', 'date-us', 'date-eur', 'birthday-us', 'birthday-eur', 'website', 'option', 'gpg', 'longtext'];
|
||||
|
||||
if (allowedTypes.indexOf(type) < 0) {
|
||||
return callback(new Error('Unknown column type ' + type));
|
||||
|
@ -308,7 +312,11 @@ function addCustomField(listId, name, defaultValue, type, group, visible, callba
|
|||
switch (type) {
|
||||
case 'text':
|
||||
case 'website':
|
||||
query = 'ALTER TABLE `subscription__' + listId + '` ADD COLUMN `' + column + '` VARCHAR(255) DEFAULT NULL';
|
||||
query = 'ALTER TABLE `subscription__' + listId + '` ADD COLUMN `' + column + '` VARCHAR(255) DEFAULT NULL, ADD INDEX (' + column + ')';
|
||||
break;
|
||||
case 'gpg':
|
||||
case 'longtext':
|
||||
query = 'ALTER TABLE `subscription__' + listId + '` ADD COLUMN `' + column + '` TEXT DEFAULT NULL';
|
||||
break;
|
||||
case 'number':
|
||||
query = 'ALTER TABLE `subscription__' + listId + '` ADD COLUMN `' + column + '` INT(11) DEFAULT NULL, ADD INDEX (' + column + ')';
|
||||
|
@ -358,6 +366,8 @@ module.exports.getRow = (fieldList, values, useDate, showAll) => {
|
|||
switch (field.type) {
|
||||
case 'text':
|
||||
case 'website':
|
||||
case 'gpg':
|
||||
case 'longtext':
|
||||
{
|
||||
let item = {
|
||||
type: field.type,
|
||||
|
|
|
@ -99,6 +99,9 @@ module.exports.get = (id, callback) => {
|
|||
|
||||
segment.columns = [].concat(module.exports.defaultColumns);
|
||||
fieldList.forEach(field => {
|
||||
if (fields.genericTypes[field.type] === 'textarea') {
|
||||
return;
|
||||
}
|
||||
if (field.column) {
|
||||
segment.columns.push({
|
||||
column: field.column,
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"grunt": "^1.0.1",
|
||||
"grunt-cli": "^1.2.0",
|
||||
"grunt-contrib-nodeunit": "^1.0.0",
|
||||
"grunt-eslint": "^18.0.0"
|
||||
"grunt-eslint": "^18.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bcrypt-nodejs": "0.0.3",
|
||||
|
@ -47,7 +47,9 @@
|
|||
"multer": "^1.1.0",
|
||||
"mysql": "^2.10.2",
|
||||
"nodemailer": "^2.3.2",
|
||||
"nodemailer-openpgp": "^1.0.2",
|
||||
"npmlog": "^2.0.3",
|
||||
"openpgp": "^2.2.1",
|
||||
"passport": "^0.3.2",
|
||||
"passport-local": "^1.0.0",
|
||||
"request": "^2.71.0",
|
||||
|
|
|
@ -31,3 +31,7 @@ div.jumbotron{
|
|||
.code-editor {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.gpg-text {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
let openpgp = require('openpgp');
|
||||
let passport = require('../lib/passport');
|
||||
let express = require('express');
|
||||
let router = new express.Router();
|
||||
|
@ -156,6 +157,26 @@ router.post('/ajax/:id', (req, res) => {
|
|||
].concat(fields.getRow(fieldList, row).map(cRow => {
|
||||
if (cRow.type === 'number') {
|
||||
return htmlescape(cRow.value && humanize.numberFormat(cRow.value, 0) || '');
|
||||
} else if (cRow.type === 'longtext') {
|
||||
let value = (cRow.value || '');
|
||||
if (value.length > 50) {
|
||||
value = value.substr(0, 47).trim() + '…';
|
||||
}
|
||||
return htmlescape(value);
|
||||
} else if (cRow.type === 'gpg') {
|
||||
let value = (cRow.value || '').trim();
|
||||
try {
|
||||
value = openpgp.key.readArmored(value);
|
||||
if (value) {
|
||||
value = value.keys && value.keys[0] && value.keys[0].primaryKey.fingerprint;
|
||||
if (value) {
|
||||
value = '0x' + value.substr(-16).toUpperCase();
|
||||
}
|
||||
}
|
||||
} catch (E) {
|
||||
value = 'parse error';
|
||||
}
|
||||
return htmlescape(value || '');
|
||||
} else {
|
||||
return htmlescape(cRow.value || '');
|
||||
}
|
||||
|
|
|
@ -235,6 +235,8 @@ router.get('/:list/rules/:segment/create', passport.csrfProtection, (req, res) =
|
|||
}
|
||||
|
||||
segment.csrfToken = req.csrfToken();
|
||||
|
||||
console.log(segment);
|
||||
segment.list = list;
|
||||
|
||||
res.render('lists/segments/rule-create', segment);
|
||||
|
|
|
@ -11,7 +11,7 @@ let url = require('url');
|
|||
|
||||
let settings = require('../lib/models/settings');
|
||||
|
||||
let allowedKeys = ['service_url', 'smtp_hostname', 'smtp_port', 'smtp_encryption', 'smtp_disable_auth', 'smtp_user', 'smtp_pass', 'admin_email', 'smtp_log', 'smtp_max_connections', 'smtp_max_messages', 'smtp_self_signed', 'default_from', 'default_address', 'default_subject', 'default_homepage', 'default_postaddress', 'default_sender', 'verp_hostname', 'verp_use', 'disable_wysiwyg'];
|
||||
let allowedKeys = ['service_url', 'smtp_hostname', 'smtp_port', 'smtp_encryption', 'smtp_disable_auth', 'smtp_user', 'smtp_pass', 'admin_email', 'smtp_log', 'smtp_max_connections', 'smtp_max_messages', 'smtp_self_signed', 'default_from', 'default_address', 'default_subject', 'default_homepage', 'default_postaddress', 'default_sender', 'verp_hostname', 'verp_use', 'disable_wysiwyg', 'pgp_private_key', 'pgp_passphrase'];
|
||||
|
||||
router.all('/*', (req, res, next) => {
|
||||
if (!req.user) {
|
||||
|
|
|
@ -130,10 +130,16 @@ function formatMessage(message, callback) {
|
|||
FULL_NAME: [].concat(message.subscription.firstName || []).concat(message.subscription.lastName || []).join(' ')
|
||||
};
|
||||
|
||||
let encryptionKeys = [];
|
||||
fields.getRow(fieldList, message.subscription, true, true).forEach(field => {
|
||||
if (field.mergeTag) {
|
||||
message.subscription.mergeTags[field.mergeTag] = field.mergeValue || '';
|
||||
}
|
||||
|
||||
if (field.type === 'gpg' && field.value) {
|
||||
encryptionKeys.push(field.value.trim());
|
||||
}
|
||||
|
||||
if (field.options) {
|
||||
field.options.forEach(subField => {
|
||||
if (subField.mergeTag) {
|
||||
|
@ -206,7 +212,8 @@ function formatMessage(message, callback) {
|
|||
html: tools.formatMessage(configItems.serviceUrl, campaign, list, message.subscription, html),
|
||||
text: tools.formatMessage(configItems.serviceUrl, campaign, list, message.subscription, campaign.text),
|
||||
|
||||
attachments
|
||||
attachments,
|
||||
encryptionKeys
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
<option value="text" {{#if selectedText}} selected {{/if}}>Text</option>
|
||||
<option value="number" {{#if selectedNumber}} selected {{/if}}>Number</option>
|
||||
<option value="website" {{#if selectedWebsite}} selected {{/if}}>Website</option>
|
||||
<option value="gpg" {{#if selectedGpg}} selected {{/if}}>GPG Public Key</option>
|
||||
<option value="longtext" {{#if selectedLongtext}} selected {{/if}}>Multi-line text</option>
|
||||
<optgroup label="Date">
|
||||
<option value="date-us" {{#if selectedDateUs}} selected {{/if}}>Date (MM/DD/YYYY)</option>
|
||||
<option value="date-eur" {{#if selectedDateEur}} selected {{/if}}>Date (DD/MM/YYYY)</option>
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
<option value="text" {{#if selectedText}} selected {{/if}}>Text</option>
|
||||
<option value="number" {{#if selectedNumber}} selected {{/if}}>Number</option>
|
||||
<option value="website" {{#if selectedWebsite}} selected {{/if}}>Website</option>
|
||||
<option value="gpg" {{#if selectedGpg}} selected {{/if}}>GPG Public Key</option>
|
||||
<option value="longtext" {{#if selectedLongtext}} selected {{/if}}>Multi-line text</option>
|
||||
<optgroup label="Date">
|
||||
<option value="date-us" {{#if selectedDateUs}} selected {{/if}}>Date (MM/DD/YYYY)</option>
|
||||
<option value="date-eur" {{#if selectedDateEur}} selected {{/if}}>Date (DD/MM/YYYY)</option>
|
||||
|
|
|
@ -50,6 +50,15 @@
|
|||
<input type="url" class="form-control" name="{{column}}" value="{{value}}">
|
||||
{{/if}}
|
||||
|
||||
{{#if typeLongtext}}
|
||||
<textarea class="form-control" rows="3" name="{{column}}">{{value}}</textarea>
|
||||
{{/if}}
|
||||
|
||||
{{#if typeGpg}}
|
||||
<textarea class="form-control gpg-text" rows="3" name="{{column}}">{{value}}</textarea>
|
||||
<span class="help-block">Insert a GPG public key that will be used to encrypt messages sent this subscriber</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if typeDateUs}}
|
||||
<div class="input-group date fm-date-us">
|
||||
<input type="text" class="form-control" name="{{column}}" placeholder="MM/DD/YYYY" value="{{value}}"><span class="input-group-addon"><i class="glyphicon glyphicon-th"></i></span>
|
||||
|
|
|
@ -63,6 +63,15 @@
|
|||
<input type="url" class="form-control" name="{{column}}" value="{{value}}">
|
||||
{{/if}}
|
||||
|
||||
{{#if typeLongtext}}
|
||||
<textarea class="form-control" rows="3" name="{{column}}">{{value}}</textarea>
|
||||
{{/if}}
|
||||
|
||||
{{#if typeGpg}}
|
||||
<textarea class="form-control gpg-text" rows="3" name="{{column}}">{{value}}</textarea>
|
||||
<span class="help-block">Insert a GPG public key that will be used to encrypt messages sent this subscriber</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if typeDateUs}}
|
||||
<div class="input-group date fm-date-us">
|
||||
<input type="text" class="form-control" name="{{column}}" placeholder="MM/DD/YYYY" value="{{value}}"><span class="input-group-addon"><i class="glyphicon glyphicon-th"></i></span>
|
||||
|
|
|
@ -251,6 +251,37 @@
|
|||
{{/if}}
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>
|
||||
PGP Signing
|
||||
</legend>
|
||||
|
||||
<p>
|
||||
Only messages that are encrypted can be signed. Subsribers who have not set up a PGP public key in their profile receive normal email messages. Users with PGP key set receive encrypted messages and if you have signing key also set, the messages are signed
|
||||
with this key.
|
||||
</p>
|
||||
<p class="text-warning">
|
||||
Do not use sensitive keys here. The private key and passphrase are not encrypted in the database.
|
||||
</p>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pgp-passphrase" class="col-sm-2 control-label">Private Key Passphrase</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="pgp-passphrase" id="pgp-passphrase" placeholder="Passprase" value="{{pgpPassphrase}}">
|
||||
<span class="help-block">Only fill this if your private key is encrypted with a passphrase</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pgp-private-key" class="col-sm-2 control-label">PGP Private Key</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control gpg-text" rows="3" id="pgp-private-key" name="pgp-private-key">{{pgpPrivateKey}}</textarea>
|
||||
<span class="help-block">This value is optional. if you do not provide a private key, then PGP encrypted messages are sent without signing.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="form-group">
|
||||
|
|
|
@ -36,6 +36,15 @@
|
|||
<input type="url" class="form-control" name="{{column}}" value="{{value}}">
|
||||
{{/if}}
|
||||
|
||||
{{#if typeLongtext}}
|
||||
<textarea class="form-control" rows="3" name="{{column}}">{{value}}</textarea>
|
||||
{{/if}}
|
||||
|
||||
{{#if typeGpg}}
|
||||
<textarea class="form-control gpg-text" rows="3" name="{{column}}">{{value}}</textarea>
|
||||
<span class="help-block">Insert your GPG public key here to encrypt messages sent to your address</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if typeDateUs}}
|
||||
<div class="input-group date fm-date-us">
|
||||
<input type="text" class="form-control" name="{{column}}" placeholder="MM/DD/YYYY" value="{{value}}"><span class="input-group-addon"><i class="glyphicon glyphicon-th"></i></span>
|
||||
|
|
|
@ -33,6 +33,15 @@
|
|||
<input type="url" class="form-control" name="{{column}}" value="{{value}}">
|
||||
{{/if}}
|
||||
|
||||
{{#if typeLongtext}}
|
||||
<textarea class="form-control" rows="3" name="{{column}}">{{value}}</textarea>
|
||||
{{/if}}
|
||||
|
||||
{{#if typeGpg}}
|
||||
<textarea class="form-control gpg-text" rows="3" name="{{column}}">{{value}}</textarea>
|
||||
<span class="help-block">Insert your GPG public key here to encrypt messages sent to your address</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if typeDateUs}}
|
||||
<div class="input-group date fm-date-us">
|
||||
<input type="text" class="form-control" name="{{column}}" placeholder="MM/DD/YYYY" value="{{value}}"><span class="input-group-addon"><i class="glyphicon glyphicon-th"></i></span>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue