Updated openpgp module to 4.6.2

This commit is contained in:
Dominique Da Silva 2019-11-10 01:22:11 +00:00
parent 1af65868d5
commit d9edce1ea7
4 changed files with 117 additions and 74 deletions

View file

@ -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",

View file

@ -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 }));
});
});
});

View file

@ -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();
});
});
});

View file

@ -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}} &#39;-----BEGIN PGP PUBLIC KEY BLOCK-----&#39;">{{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>