Skip to content

Instantly share code, notes, and snippets.

@abernardobr
Last active November 22, 2022 13:14
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save abernardobr/93f08c2a751225afe2c27a60adba1f47 to your computer and use it in GitHub Desktop.
Save abernardobr/93f08c2a751225afe2c27a60adba1f47 to your computer and use it in GitHub Desktop.
Example XML Crypto, using A3
var SignedXml = require('xml-crypto').SignedXml;
var FileKeyInfo = require('xml-crypto').FileKeyInfo;
LocalSchema.statics.sign = function(options, cb) {
var user = options.user;
if(user.orgId !== options.payload.orgId) {
return cb(HD.errors.unauthorizedAction, {});
}
if(user.pemType === 'A1') {
if(!_.isEmpty(user.pem)) {
var xml = '<document><docinfo>' +
'<name>' + options.payload.name + '</name>' +
'<type>' + options.payload.type + '</type>' +
'<content>' + options.payload.document + '</content>' +
'</docinfo></document>';
var sig = new SignedXml();
sig.signingKey = user.pem.key;
sig.addReference("//*[local-name(.)='docinfo']");
try {
sig.computeSignature(xml);
return cb(null, {documentSigned: sig.getSignedXml()});
} catch(ex) {
return cb(HD.errors.invalidSignedDocument, {});
}
} else {
return cb(HD.errors.unauthorizedAction, {});
}
} else if(user.pemType === 'A3') {
return cb(HD.errors.notImplementedYet, {});
} else {
return cb(HD.errors.notImplementedYet, {});
}
}
LocalSchema.statics.signAndSaveA1 = function(options, cb) {
var self = this;
var user = HD.getUser(options.request);
var docId = options.params.id;
var curDoc;
var docNameGuid;
var documentSigned;
var funcs = [];
var payload = {};
// get the document
funcs.push(function(next) {
model.findOne({ _id: HD.ObjectID(docId), orgId: user.orgId, userId: user._id.toString() }).lean().exec(function(err, retDoc) {
if(!err && retDoc != null) {
curDoc = retDoc;
docNameGuid = Path.basename(retDoc.document, Path.extname(retDoc.document));
next();
} else {
next(HD.errors.invalidSignedDocument);
}
});
});
// get the base64 for the document that is in s3
funcs.push(function(next) {
Domains.s3().getBase64(curDoc.document, function (err, retBase64Doc) {
if (!err && retBase64Doc !== '') {
options.payload.orgId = user.orgId;
options.payload.name = curDoc.name;
options.payload.type = curDoc.type;
options.payload.document = retBase64Doc;
}
next(err);
});
});
// sign the document
funcs.push(function(next) {
model.sign(options, function(err, retData) {
if(!err && retData != null && !_.isEmpty(retData) && retData.documentSigned && retData.documentSigned !== '') {
documentSigned = retData.documentSigned;
} else {
err = err ? err : HD.errors.invalidSignedDocument;
}
next(err);
});
});
// add to s3 the signed document
funcs.push(function(next) {
var organame = options.params.orgname;
var areaId = options.params.areaId;
var filename = organame + "/" + areaId + "/" + docNameGuid + '_signed.xml';
var buffer = new Buffer(documentSigned);
Domains.s3().addBuffer(buffer, filename, 'text/xml', function (err) {
var bytes = buffer.length;
if (!err) {
if(!_.isUndefined(bytes) || bytes === 0) {
payload.$inc = { bytes: bytes };
payload.bytesSigned = bytes;
payload.documentSigned = filename;
} else
err = HD.errors.invalidSignedDocument;
}
next(err);
});
});
// save the document
funcs.push(function(next) {
model.findByIdAndUpdate(curDoc._id, payload, function(err, retDoc) {
if(retDoc == null)
err = HD.errors.invalidSignedDocument;
next(err);
})
});
Async.series(funcs, function(err) {
cb(err, err ? { documentSigned: {} } : { documentSigned: documentSigned });
});
}
LocalSchema.statics.unsignAndSave = function(options, cb) {
var user = HD.getUser(options.request);
var docId = options.params.id;
var curDoc;
var funcs = [];
var payload = {};
// get the document
funcs.push(function(next) {
model.findOne({ _id: HD.ObjectID(docId), orgId: user.orgId, userId: user._id.toString() }).lean().exec(function(err, retDoc) {
if(!err && retDoc != null) {
curDoc = retDoc;
next();
} else {
next(HD.errors.invalidSignedDocument);
}
});
});
// remove from s3 the signed document
funcs.push(function(next) {
var _afterRemoveS3 = function() {
if (curDoc.bytesSigned > 0) {
var bytes = curDoc.bytesSigned * -1;
payload.$inc = {bytes: bytes};
payload.bytesSigned = 0;
}
payload.documentSigned = '';
next();
}
if(curDoc.documentSigned.indexOf('<document Id=') === -1 && curDoc.documentSigned !== '') {
Domains.s3().remove(curDoc.documentSigned, function (err) {
_afterRemoveS3();
});
} else {
_afterRemoveS3();
}
});
// save the document
funcs.push(function(next) {
model.findByIdAndUpdate(curDoc._id, payload, function(err, retDoc) {
if(retDoc == null)
err = HD.errors.invalidSignedDocument;
next(err);
})
});
Async.series(funcs, function(err) {
cb(err, { success: err ? false : true });
});
}
LocalSchema.statics.signAndSave = function(options, cb) {
var self = this;
var user = HD.getUser(options.request);
if(user.pemType === 'A1') {
model.signAndSaveA1(options, cb);
} else if(user.pemType === 'A3') {
return cb(HD.errors.notImplementedYet, { documentSigned: {} });
} else {
return cb(HD.errors.notImplementedYet, { documentSigned: {} });
}
}
LocalSchema.statics.verify = function(options, cb) {
var user = HD.getUser(options.request);
var docId = options.params.id;
var curDoc;
var funcs = [];
var verifyUser;
var isVerified = false;
var validationErrors;
var signedDocumentContent = '';
if(_.isUndefined(user.pem) || _.isEmpty(user.pem)) {
cb(null, { isVerified: false, validationErrors: [] });
}
// get the document
funcs.push(function(next) {
model.findOne({ _id: HD.ObjectID(docId), orgId: user.orgId, userId: user._id.toString() }).lean().exec(function(err, retDoc) {
if(!err && retDoc != null) {
curDoc = retDoc;
next();
} else {
next(HD.errors.invalidSignedDocument);
}
});
});
// get users pem
funcs.push(function(next) {
Domains.s3().getBuffer(curDoc.documentSigned, function (err, retBuffer) {
if (!err && retBuffer !== null) {
signedDocumentContent = retBuffer.toString('utf-8');
}
next(err);
});
});
// get the file content from s3
funcs.push(function(next) {
Domains.users().dcrud.findById(options.payload.userId).select({ pem: 1 }).lean().exec(function (err, retVerifyUser) {
if (!err && retVerifyUser !== '') {
verifyUser = retVerifyUser;
}
next(err);
});
});
// verify signed the document
funcs.push(function(next) {
var doc = new DOM().parseFromString(signedDocumentContent);
var signature = Select(doc, "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];
var sig = new SignedXml();
sig.keyInfoProvider = new KeyInfo(verifyUser.pem.certificate);
sig.loadSignature(signature.toString());
var res = sig.checkSignature(signedDocumentContent);
if (!res) {
validationErrors = sig.validationErrors;
isVerified = false;
} else
isVerified = true;
next();
});
Async.series(funcs, function(err) {
cb(err, { isVerified: isVerified, validationErrors: validationErrors });
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment