undersign
Version:
Create eIDAS compatible XAdES digital signatures with certificate OCSP responses and timestamps. Works with the Estonian Id-card and Mobile-Id to create BDOCs, but isn't limited to Estonia.
148 lines (122 loc) • 4.72 kB
JavaScript
var Asic = require("../../lib/asic")
var Yauzl = require("yauzl")
var ManifestXml = require("../../lib/manifest_xml")
var slurp = require("../../lib/stream").slurp
var ASICE_TYPE = "application/vnd.etsi.asic-e+zip"
describe("Asic", function() {
describe("new", function() {
it("must return a new Asic instance", function() {
new Asic().must.be.an.instanceof(Asic)
})
it("must have type set to the ASIC-E MIME type", function() {
new Asic().type.must.equal(ASICE_TYPE)
})
it("must zip a mimetype file first", function*() {
var zip = yield parseZip(yield new Asic().toBuffer())
var entries = yield parseZipEntries(zip)
entries.mimetype.isCompressed().must.be.false()
yield readZipEntry(zip, entries.mimetype).must.then.equal(ASICE_TYPE)
})
it("must zip a manifest file even if empty", function*() {
var zip = yield parseZip(yield new Asic().toBuffer())
var entries = yield parseZipEntries(zip)
Object.keys(entries).length.must.equal(2)
var entry = entries["META-INF/manifest.xml"]
var manifest = ManifestXml.parse(yield readZipEntry(zip, entry))
var file = manifest.m$manifest["m$file-entry"]
file["m$media-type"].must.equal(ASICE_TYPE)
file["m$full-path"].must.equal("/")
})
})
describe(".prototype.add", function() {
it("must support non-ASCII characters", function*() {
var asic = new Asic
asic.add("Ööpääsuke 🐦.txt", "Hello, 🌍!", "text/plain")
var zip = yield parseZip(yield asic.toBuffer())
var entries = yield parseZipEntries(zip)
Object.keys(entries).length.must.equal(3)
var manifestEntry = entries["META-INF/manifest.xml"]
var manifest = ManifestXml.parse(yield readZipEntry(zip, manifestEntry))
var files = manifest.m$manifest["m$file-entry"]
files.length.must.equal(2)
files[0]["m$media-type"].must.equal(ASICE_TYPE)
files[0]["m$full-path"].must.equal("/")
files[1]["m$media-type"].must.equal("text/plain")
files[1]["m$full-path"].must.equal("Ööpääsuke 🐦.txt")
var document = yield readZipEntry(zip, entries["Ööpääsuke 🐦.txt"])
document.must.equal("Hello, 🌍!")
})
})
describe(".prototype.addSignature", function() {
it("must add signature files with incrementing ids", function*() {
var asic = new Asic
asic.addSignature("signature-xml-1")
asic.addSignature("signature-xml-2")
asic.addSignature("signature-xml-3")
asic.add("document.txt", "Hello, world!", "text/plain")
var zip = yield parseZip(yield asic.toBuffer())
var entries = yield parseZipEntries(zip)
Object.keys(entries).length.must.equal(6)
yield Promise.all([
readZipEntry(zip, entries["META-INF/signatures-1.xml"]),
readZipEntry(zip, entries["META-INF/signatures-2.xml"]),
readZipEntry(zip, entries["META-INF/signatures-3.xml"])
]).must.then.eql([
"signature-xml-1",
"signature-xml-2",
"signature-xml-3"
])
// Signatures are not in the manifest.
var manifestEntry = entries["META-INF/manifest.xml"]
var manifest = ManifestXml.parse(yield readZipEntry(zip, manifestEntry))
var files = manifest.m$manifest["m$file-entry"]
files.length.must.equal(2)
files[0]["m$media-type"].must.equal(ASICE_TYPE)
files[0]["m$full-path"].must.equal("/")
files[1]["m$media-type"].must.equal("text/plain")
files[1]["m$full-path"].must.equal("document.txt")
})
})
describe(".prototype.toStream", function() {
it("must return a ZIP file", function*() {
var asic = new Asic
asic.end()
var stream = asic.toStream()
var zip = yield parseZip(yield slurp(stream))
zip.must.be.an.instanceof(Yauzl.ZipFile)
})
})
describe(".prototype.toBuffer", function() {
it("must return a ZIP file", function*() {
var zip = yield parseZip(yield new Asic().toBuffer())
zip.must.be.an.instanceof(Yauzl.ZipFile)
})
})
describe(".prototype.end", function() {
it("must permit calling Asic.prototype.end multiple times", function*() {
var asic = new Asic
asic.add("document.txt", "Hello, world!", "text/plain")
asic.end()
asic.end()
var zip = yield parseZip(yield asic.toBuffer())
var entries = yield parseZipEntries(zip)
Object.keys(entries).length.must.equal(3)
})
})
})
function parseZipEntries(zip) {
var entries = {}
zip.on("entry", (entry) => (entries[entry.fileName] = entry))
return new Promise(function(resolve, reject) {
zip.on("error", reject)
zip.on("end", resolve.bind(null, entries))
})
}
function readZipEntry(zip, entry) {
return new Promise(function(resolve, reject) {
zip.openReadStream(entry, (err, stream) => (
err ? reject(err) : resolve(slurp(stream, "utf8"))
))
})
}
function* parseZip(buffer) { return yield Yauzl.fromBuffer.bind(null, buffer) }