Skip to content

Instantly share code, notes, and snippets.

@bennotti
Forked from abernardobr/crypto_xml_a3.txt
Created November 22, 2022 13:14
Show Gist options
  • Save bennotti/ad4764ec565aed2d5cc7260710a06479 to your computer and use it in GitHub Desktop.
Save bennotti/ad4764ec565aed2d5cc7260710a06479 to your computer and use it in GitHub Desktop.

Revisions

  1. @abernardobr abernardobr renamed this gist Apr 28, 2016. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. @abernardobr abernardobr created this gist Apr 14, 2016.
    255 changes: 255 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,255 @@
    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 });
    });
    }