Last active
November 22, 2022 13:14
-
-
Save abernardobr/93f08c2a751225afe2c27a60adba1f47 to your computer and use it in GitHub Desktop.
Example XML Crypto, using A3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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