Updated openpgp module to 4.6.2
This commit is contained in:
parent
1af65868d5
commit
d9edce1ea7
4 changed files with 117 additions and 74 deletions
22
package.json
22
package.json
|
@ -37,7 +37,7 @@
|
|||
"eslint-config-nodemailer": "^1.2.0",
|
||||
"grunt": "^1.0.1",
|
||||
"grunt-cli": "^1.2.0",
|
||||
"grunt-contrib-nodeunit": "^1.0.0",
|
||||
"grunt-contrib-nodeunit": "^2.0.0",
|
||||
"grunt-eslint": "^20.1.0",
|
||||
"jsxgettext-andris": "^0.9.0-patch.1",
|
||||
"lodash": "^4.17.4",
|
||||
|
@ -61,10 +61,11 @@
|
|||
"connect-redis": "^3.3.0",
|
||||
"cookie-parser": "^1.4.3",
|
||||
"cors": "^2.8.4",
|
||||
"country-list": "^2.2.0",
|
||||
"csurf": "^1.9.0",
|
||||
"csv-parse": "^1.2.3",
|
||||
"csv-parse": "^4.6.5",
|
||||
"device": "^0.3.8",
|
||||
"dompurify": "^1.0.2",
|
||||
"dompurify": "^2.0.7",
|
||||
"escape-html": "^1.0.3",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"express": "^4.15.5",
|
||||
|
@ -72,11 +73,11 @@
|
|||
"faker": "^4.1.0",
|
||||
"feedparser": "^2.2.1",
|
||||
"fs-extra": "^4.0.2",
|
||||
"geoip-ultralight": "^0.1.5",
|
||||
"geoip-country": "^3.2.6",
|
||||
"gettext-parser": "^1.3.0",
|
||||
"gm": "^1.23.0",
|
||||
"handlebars": "^4.0.10",
|
||||
"hbs": "^4.0.1",
|
||||
"handlebars": "^4.4.5",
|
||||
"hbs": "^4.0.6",
|
||||
"he": "^1.1.1",
|
||||
"html-to-text": "^3.3.0",
|
||||
"humanize": "0.0.9",
|
||||
|
@ -88,7 +89,7 @@
|
|||
"juice": "^4.1.1",
|
||||
"libmime": "^3.1.0",
|
||||
"mailparser": "^2.0.5",
|
||||
"marked": "^0.3.6",
|
||||
"marked": "^0.7.0",
|
||||
"memory-cache": "^0.2.0",
|
||||
"mjml": "4.5.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
|
@ -100,13 +101,14 @@
|
|||
"node-gettext": "^2.0.0",
|
||||
"node-mocks-http": "^1.6.5",
|
||||
"nodemailer": "^4.1.1",
|
||||
"nodemailer-openpgp": "^1.1.0",
|
||||
"nodemailer-openpgp": "^1.2.0",
|
||||
"npmlog": "^4.1.2",
|
||||
"object-hash": "^1.1.8",
|
||||
"openpgp": "^2.5.11",
|
||||
"openpgp": "^4.6.2",
|
||||
"passport": "^0.4.0",
|
||||
"passport-ldapauth": "^2.1.3",
|
||||
"passport-ldapjs": "^1.0.3",
|
||||
"passport-local": "^1.0.0",
|
||||
"passport-ldapauth": "^2.0.0",
|
||||
"premailer-api": "^1.0.4",
|
||||
"redfour": "^1.0.2",
|
||||
"redis": "^2.8.0",
|
||||
|
|
118
routes/lists.js
118
routes/lists.js
|
@ -206,57 +206,85 @@ router.post('/ajax/:id', (req, res) => {
|
|||
|
||||
let statuses = [_('Unknown'), _('Subscribed'), _('Unsubscribed'), _('Bounced'), _('Complained')];
|
||||
|
||||
res.json({
|
||||
draw: req.body.draw,
|
||||
recordsTotal: total,
|
||||
recordsFiltered: filteredTotal,
|
||||
data: data.map((row, i) => [
|
||||
let dataPromise = Promise.all(data.map((row, i) => Promise.all([
|
||||
Promise.resolve([
|
||||
(Number(req.body.start) || 0) + 1 + i,
|
||||
htmlescape(row.email || ''),
|
||||
htmlescape(row.firstName || ''),
|
||||
htmlescape(row.lastName || '')
|
||||
].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) {
|
||||
|
||||
let keys = value.keys;
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let key = keys[i];
|
||||
switch (key.verifyPrimaryKey()) {
|
||||
case 0:
|
||||
return _('Invalid key');
|
||||
case 1:
|
||||
return _('Expired key');
|
||||
case 2:
|
||||
return _('Revoked key');
|
||||
htmlescape(row.lastName || ''),
|
||||
]),
|
||||
new Promise((resolve) => {
|
||||
let fieldsPromise = Promise.all(fields.getRow(fieldList, row).map( async (cRow) => {
|
||||
switch (cRow.type) {
|
||||
case 'number':
|
||||
return Promise.resolve(htmlescape(cRow.value && humanize.numberFormat(cRow.value, 0) || ''));
|
||||
case 'longtext':
|
||||
let value = (cRow.value || '');
|
||||
if (value.length > 50) {
|
||||
value = value.substr(0, 47).trim() + '…';
|
||||
}
|
||||
return Promise.resolve(htmlescape(value));
|
||||
case 'gpg':
|
||||
return new Promise((resolve) => {
|
||||
let value = (cRow.value || '').trim();
|
||||
if (!value.length) {
|
||||
resolve(''); // no key
|
||||
}
|
||||
}
|
||||
openpgp.key.readArmored(value).
|
||||
then((value) => {
|
||||
const noResultsError = new Error('No armored keys returned');
|
||||
|
||||
value = value.keys && value.keys[0] && value.keys[0].primaryKey.fingerprint;
|
||||
if (value) {
|
||||
value = '0x' + value.substr(-16).toUpperCase();
|
||||
}
|
||||
}
|
||||
} catch (E) {
|
||||
value = 'parse error';
|
||||
if (!(typeof value === 'object') || !('keys' in value)) { throw noResultsError }
|
||||
if (value.err && value.err.length) { throw value.err[0] }
|
||||
if (!value.keys.length) { throw noResultsError }
|
||||
|
||||
let keysVerification = Promise.race(value.keys.map((key) => key.verifyPrimaryKey()));
|
||||
|
||||
keysVerification.then((verifiedKey) => {
|
||||
switch (verifiedKey) {
|
||||
case 0:
|
||||
return resolve(_('Invalid key'));
|
||||
case 1:
|
||||
return resolve(_('Expired key'));
|
||||
case 2:
|
||||
return resolve(_('Revoked key'));
|
||||
}
|
||||
value = value.keys[0].primaryKey.fingerprint.join('');
|
||||
if (value) {
|
||||
value = '0x' + value.substr(-16).toUpperCase();
|
||||
}
|
||||
return resolve(htmlescape(value || ''));
|
||||
});
|
||||
}).
|
||||
catch((error) => {
|
||||
const message = error.message || error || _('Unexpected error');
|
||||
resolve('<span title="' + message + '" class="subscriber-status-4">' + _('Parse error') + ' <a class="glyphicon glyphicon-info-sign" style="text-decoration:none" title="' + message + '"> </a></span>');
|
||||
});
|
||||
}).catch((error) => log.error('GPG', error));
|
||||
default:
|
||||
return Promise.resolve(htmlescape(cRow.value || ''));
|
||||
}
|
||||
return htmlescape(value || '');
|
||||
} else {
|
||||
return htmlescape(cRow.value || '');
|
||||
}
|
||||
})).concat(config.views.lists.statuscolored ? '<span class="subscriber-status-' + row.status + '">' + statuses[row.status] + '</span>' : statuses[row.status]).concat(row.created && row.created.toISOString ? '<span class="datestring" data-date="' + row.created.toISOString() + '" title="' + row.created.toISOString() + '">' + row.created.toISOString() + '</span>' : 'N/A').concat('<a href="/lists/subscription/' + list.id + '/edit/' + row.cid + '">' + _('Edit') + '</a>'))
|
||||
});
|
||||
}));
|
||||
|
||||
fieldsPromise.then(fieldsResults => {
|
||||
resolve(fieldsResults);
|
||||
}).catch((error) => log.error('Lists', error));
|
||||
}),
|
||||
Promise.resolve(config.views.lists.statuscolored ? '<span class="subscriber-status-' + row.status + '">' + statuses[row.status] + '</span>' : statuses[row.status] ),
|
||||
Promise.resolve(row.created && row.created.toISOString ? '<span class="datestring" data-date="' + row.created.toISOString() + '" title="' + row.created.toISOString() + '">' + row.created.toISOString() + '</span>' : 'N/A' ),
|
||||
Promise.resolve('<a href="/lists/subscription/' + list.id + '/edit/' + row.cid + '">' + _('Edit') + '</a>' )
|
||||
])));
|
||||
|
||||
dataPromise.then(data => {
|
||||
data = data.map(row => row.reduce((acc, val) => acc.concat(val), [])); // flatten results
|
||||
res.json({
|
||||
draw: req.body.draw,
|
||||
recordsTotal: total,
|
||||
recordsFiltered: filteredTotal,
|
||||
data: data
|
||||
})
|
||||
}).catch((error) => res.json({ draw: req.body.draw, recordsTotal: 0, recordsFiltered: 0, data:[], error: error.message }));
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -864,30 +864,43 @@ router.post('/publickey', passport.parseForm, (req, res, next) => {
|
|||
return next(err);
|
||||
}
|
||||
|
||||
let privKey;
|
||||
try {
|
||||
privKey = openpgp.key.readArmored(configItems.pgpPrivateKey).keys[0];
|
||||
if (configItems.pgpPassphrase && !privKey.decrypt(configItems.pgpPassphrase)) {
|
||||
privKey = false;
|
||||
}
|
||||
} catch (E) {
|
||||
// just ignore if failed
|
||||
}
|
||||
|
||||
if (!privKey) {
|
||||
const sendError = () => {
|
||||
err = new Error(_('Public key is not set'));
|
||||
err.status = 404;
|
||||
return next(err);
|
||||
}
|
||||
|
||||
let pubkey = privKey.toPublic().armor();
|
||||
const sendResult = (privKey) => {
|
||||
let pubkey = privKey.toPublic().armor();
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Content-Disposition': 'attachment; filename=public.asc'
|
||||
});
|
||||
res.end(pubkey);
|
||||
}
|
||||
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Content-Disposition': 'attachment; filename=public.asc'
|
||||
});
|
||||
|
||||
res.end(pubkey);
|
||||
openpgp.key.readArmored(configItems.pgpPrivateKey).
|
||||
then((armored) => {
|
||||
let privKey = armored.keys[0];
|
||||
if (configItems.pgpPassphrase) {
|
||||
privKey.decrypt(configItems.pgpPassphrase).
|
||||
then((success) => {
|
||||
if (success) {
|
||||
sendResult(privKey);
|
||||
}
|
||||
}).
|
||||
catch((error) => {
|
||||
log.error('GPG', error);
|
||||
sendError();
|
||||
})
|
||||
} else {
|
||||
sendResult(privKey);
|
||||
}
|
||||
}).
|
||||
catch((error) => {
|
||||
log.error('GPG', error);
|
||||
sendError();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
<button class="btn-download-pubkey" type="submit" form="download-pubkey">{{#translate}}Download signature verification key{{/translate}}</button>
|
||||
{{/if}}
|
||||
<textarea class="form-control gpg-text" rows="4" name="{{column}}" placeholder="{{#translate}}Begins with{{/translate}} '-----BEGIN PGP PUBLIC KEY BLOCK-----'">{{value}}</textarea>
|
||||
<span class="help-block">
|
||||
<span class="help-block" style="padding:10px 0;">
|
||||
{{#translate}}Insert your GPG public key here to encrypt messages sent to your address{{/translate}} <em>({{#translate}}optional{{/translate}})</em>
|
||||
</span>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue