javascript-opentimestamps
Version:
JS Porting of OpenTimestamps
409 lines (354 loc) • 14.3 kB
JavaScript
const test = require('tape')
const rp = require('request-promise')
const Utils = require('../src/utils.js')
const OpenTimestamps = require('../src/open-timestamps.js')
const DetachedTimestampFile = require('../src/detached-timestamp-file.js')
const Context = require('../src/context.js')
const Ops = require('../src/ops.js')
const Notary = require('../src/notary.js')
// const Timestamp = require('../timestamp.js');
const baseUrl = 'https://raw.githubusercontent.com/opentimestamps/javascript-opentimestamps/master'
let incompleteOtsInfo
let incompleteOts
let incomplete
let helloworldOts
let helloworld
let merkle2Ots
let merkle2OtsInfo
let unknown
let unknownOts
let knownUnknown
let knownUnknownOts
let merkle3
let merkle3Ots
let badStamp
let badStampOts
let osdsp
let osdspOts
test('setup', assert => {
const incompleteOtsInfoPromise = rp({ url: baseUrl + '/examples/incomplete.txt.ots.info', encoding: null })
const incompleteOtsPromise = rp({ url: baseUrl + '/examples/incomplete.txt.ots', encoding: null })
const incompletePromise = rp({ url: baseUrl + '/examples/incomplete.txt', encoding: null })
const helloworldOtsPromise = rp({ url: baseUrl + '/examples/hello-world.txt.ots', encoding: null })
const helloworldPromise = rp({ url: baseUrl + '/examples/hello-world.txt', encoding: null })
const merkle2OtsPromise = rp({ url: baseUrl + '/examples/merkle2.txt.ots', encoding: null })
const merkle2OtsInfoPromise = rp({ url: baseUrl + '/examples/merkle2.txt.ots.info', encoding: null })
const unknownPromise = rp({ url: baseUrl + '/examples/unknown-notary.txt', encoding: null })
const unknownOtsPromise = rp({ url: baseUrl + '/examples/unknown-notary.txt.ots', encoding: null })
const knownUnknownPromise = rp({ url: baseUrl + '/examples/known-and-unknown-notary.txt', encoding: null })
const knownUnknownOtsPromise = rp({ url: baseUrl + '/examples/known-and-unknown-notary.txt.ots', encoding: null })
const merkle3Promise = rp({ url: baseUrl + '/examples/merkle3.txt', encoding: null })
const merkle3OtsPromise = rp({ url: baseUrl + '/examples/merkle3.txt.ots', encoding: null })
const badStampPromise = rp({ url: baseUrl + '/examples/bad-stamp.txt', encoding: null })
const badStampOtsPromise = rp({ url: baseUrl + '/examples/bad-stamp.txt.ots', encoding: null })
const osdspPromise = rp({ url: baseUrl + '/examples/osdsp.txt', encoding: null })
const osdspOtsPromise = rp({ url: baseUrl + '/examples/osdsp.txt.ots', encoding: null })
Promise.all([
incompleteOtsInfoPromise, incompleteOtsPromise, incompletePromise,
helloworldOtsPromise, helloworldPromise,
merkle2OtsPromise, merkle2OtsInfoPromise,
unknownPromise, unknownOtsPromise,
knownUnknownPromise, knownUnknownOtsPromise,
merkle3Promise, merkle3OtsPromise,
badStampPromise, badStampOtsPromise,
osdspPromise, osdspOtsPromise
]).then(values => {
incompleteOtsInfo = values[0]
incompleteOts = values[1]
incomplete = values[2]
helloworldOts = values[3]
helloworld = values[4]
merkle2Ots = values[5]
merkle2OtsInfo = values[6]
unknown = values[7]
unknownOts = values[8]
knownUnknown = values[9]
knownUnknownOts = values[10]
merkle3 = values[11]
merkle3Ots = values[12]
badStamp = values[13]
badStampOts = values[14]
osdsp = values[15]
osdspOts = values[16]
assert.end()
}).catch(err => {
assert.fail('err=' + err)
})
})
// INFO TESTS
test('OpenTimestamps.info()', assert => {
const detachedOts = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(incompleteOts))
const otsInfoCalc = OpenTimestamps.info(detachedOts)
assert.false(otsInfoCalc === undefined)
assert.false(incompleteOts === undefined)
assert.true(incompleteOtsInfo.equals(Buffer.from(otsInfoCalc)))
assert.end()
})
test('OpenTimestamps.info()', assert => {
const detachedOts = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(merkle2Ots))
const merkle2OtsInfoCalc = OpenTimestamps.info(detachedOts)
assert.false(merkle2OtsInfoCalc === undefined)
assert.false(merkle2Ots === undefined)
assert.true(merkle2OtsInfo.equals(Buffer.from(merkle2OtsInfoCalc)))
assert.end()
})
test('OpenTimestamps.info()', assert => {
const detachedOts = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(unknownOts))
const unknownInfoCalc = OpenTimestamps.info(detachedOts)
assert.false(unknownInfoCalc === undefined)
assert.false(unknownOts === undefined)
assert.end()
})
test('OpenTimestamps.info()', assert => {
const detachedOts = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(knownUnknownOts))
const knownUnknownInfoCalc = OpenTimestamps.info(detachedOts)
assert.false(knownUnknownInfoCalc === undefined)
assert.false(knownUnknownOts === undefined)
assert.end()
})
test('OpenTimestamps.info()', assert => {
const detachedOts = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(merkle3Ots))
const merkle3InfoCalc = OpenTimestamps.info(detachedOts)
assert.false(merkle3InfoCalc === undefined)
assert.false(merkle3Ots === undefined)
assert.end()
})
test('OpenTimestamps.info()', assert => {
const detachedOts = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(badStampOts))
const badStampInfoCalc = OpenTimestamps.info(detachedOts)
assert.false(badStampInfoCalc === undefined)
assert.false(badStampOts === undefined)
assert.end()
})
test('OpenTimestamps.DetachedTimestampFile()', assert => {
const detached1 = DetachedTimestampFile.fromBytes(new Ops.OpSHA256(), incomplete)
const ctx = new Context.StreamDeserialization(incomplete)
const detached2 = DetachedTimestampFile.fromBytes(new Ops.OpSHA256(), ctx)
const ctx1 = new Context.StreamDeserialization(incomplete)
const fdHash = new Ops.OpSHA256().hashFd(ctx1)
const detached3 = DetachedTimestampFile.fromHash(new Ops.OpSHA256(), fdHash)
const bufferHash = Buffer.from(fdHash)
const detached4 = DetachedTimestampFile.fromHash(new Ops.OpSHA256(), bufferHash)
assert.true(detached1.equals(detached2))
assert.true(detached2.equals(detached3))
assert.true(detached3.equals(detached4))
assert.end()
})
// STAMP TESTS FILE
test('OpenTimestamps.stamp()', assert => {
const sha256 = Utils.hexToBytes('05c4f616a8e5310d19d938cfd769864d7f4ccdc2ca8b479b10af83564b097af9')
const detached = DetachedTimestampFile.fromBytes(new Ops.OpSHA256(), incomplete)
OpenTimestamps.stamp(detached).then(() => {
assert.false(detached === undefined)
assert.true(Utils.arrEq(sha256, detached.fileDigest()))
assert.end()
}).catch(err => {
assert.fail('err=' + err)
})
})
// STAMP TESTS HASH
test('OpenTimestamps.stamp()', assert => {
// Pass single input file
const sha256 = Utils.hexToBytes('05c4f616a8e5310d19d938cfd769864d7f4ccdc2ca8b479b10af83564b097af9')
const detached = DetachedTimestampFile.fromHash(new Ops.OpSHA256(), sha256)
OpenTimestamps.stamp(detached).then(() => {
assert.false(detached === undefined)
assert.true(Utils.arrEq(sha256, detached.fileDigest()))
assert.end()
}).catch(err => {
assert.fail('err=' + err)
})
})
// MULTISTAMP TESTS HASH
test('OpenTimestamps.stamp()', assert => {
const files = [
incomplete,
helloworld
]
const sha256 = [
Utils.hexToBytes('05c4f616a8e5310d19d938cfd769864d7f4ccdc2ca8b479b10af83564b097af9'),
Utils.hexToBytes('03ba204e50d126e4674c005e04d82e84c21366780af1f43bd54a37816b6ab340')
]
const detaches = []
files.forEach(file => {
const detached = DetachedTimestampFile.fromBytes(new Ops.OpSHA256(), new Context.StreamDeserialization(file))
detaches.push(detached)
})
files.forEach((files, i) => {
assert.true(Utils.arrEq(sha256[i], detaches[i].fileDigest()))
})
OpenTimestamps.stamp(detaches).then(() => {
assert.equals(detaches.length, files.length)
detaches.forEach((timestamp, i) => {
assert.false(timestamp === undefined)
assert.true(Utils.arrEq(sha256[i], timestamp.fileDigest()))
})
assert.end()
}).catch(err => {
assert.fail('err=' + err)
})
})
// UPGRADE TESTS
test('OpenTimestamps.upgrade()', assert => {
const detached = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(incompleteOts))
const detachedBefore = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(incompleteOts))
OpenTimestamps.upgrade(detached).then(changed => {
assert.true(detached !== null)
assert.true(changed)
assert.false(detached.equals(detachedBefore))
assert.end()
}).catch(err => {
assert.fail('err=' + err)
assert.end()
})
})
test('OpenTimestamps.upgrade()', assert => {
const detached = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(helloworldOts))
const detachedBefore = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(helloworldOts))
OpenTimestamps.upgrade(detached).then(changed => {
assert.true(detached !== null)
assert.false(changed)
assert.true(detached.equals(detachedBefore))
assert.end()
}).catch(err => {
assert.fail('err=' + err)
assert.end()
})
})
test('OpenTimestamps.upgrade()', assert => {
const detached = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(unknownOts))
const detachedBefore = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(unknownOts))
OpenTimestamps.upgrade(detached).then(changed => {
assert.true(detached !== null)
assert.false(changed)
assert.true(detached.equals(detachedBefore))
assert.end()
}).catch(err => {
assert.fail('err=' + err)
assert.end()
})
})
test('OpenTimestamps.upgrade()', assert => {
const detached = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(knownUnknownOts))
const detachedBefore = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(knownUnknownOts))
OpenTimestamps.upgrade(detached).then(changed => {
assert.true(detached !== null)
assert.true(changed)
assert.false(detached.equals(detachedBefore))
assert.end()
}).catch(err => {
assert.fail('err=' + err)
assert.end()
})
})
test('OpenTimestamps.upgrade()', assert => {
const detached = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(merkle3Ots))
const detachedBefore = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(merkle3Ots))
OpenTimestamps.upgrade(detached).then(changed => {
assert.true(detached !== null)
assert.true(changed)
assert.false(detached.equals(detachedBefore))
assert.end()
}).catch(err => {
assert.fail('err=' + err)
assert.end()
})
})
test('OpenTimestamps.upgrade()', assert => {
const detached = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(badStampOts))
const detachedBefore = DetachedTimestampFile.deserialize(new Context.StreamDeserialization(badStampOts))
OpenTimestamps.upgrade(detached).then(changed => {
assert.true(detached !== null)
assert.false(changed)
assert.true(detached.equals(detachedBefore))
assert.end()
}).catch(err => {
assert.fail('err=' + err)
assert.end()
})
})
test('OpenTimestamps.stamp&upgrade()', assert => {
const sha256 = Utils.hexToBytes('05c4f616a8e5310d19d938cfd769864d7f4ccdc2ca8b479b10af83564b097af9')
const detached = DetachedTimestampFile.fromBytes(new Ops.OpSHA256(), incomplete)
OpenTimestamps.stamp(detached).then(() => {
assert.false(detached === undefined)
assert.true(Utils.arrEq(sha256, detached.fileDigest()))
return OpenTimestamps.upgrade(detached)
}).then(changed => {
assert.true(detached !== null)
assert.false(changed)
assert.end()
}).catch(err => {
assert.fail('err=' + err)
assert.end()
})
})
test('OpenTimestamps.emptyTimestamp()', assert => {
const info = 'File sha256 hash: 05c4f616a8e5310d19d938cfd769864d7f4ccdc2ca8b479b10af83564b097af9\nTimestamp:\n'
const detached = DetachedTimestampFile.fromBytes(new Ops.OpSHA256(), incomplete)
const detachedInfo = OpenTimestamps.info(detached)
assert.equal(detachedInfo, info)
// serialize & deserialize
const ctx = new Context.StreamSerialization()
detached.serialize(ctx)
const buffer = Buffer.from(ctx.getOutput())
// error to deserialize an ots with empty timestamp
try {
DetachedTimestampFile.deserialize(new Context.StreamDeserialization(buffer))
assert.true(false)
} catch (err) {
assert.true(true)
}
assert.end()
})
test('OpenTimestamps.serialize()', assert => {
// from bytes: serialize to buffer
const det = DetachedTimestampFile.fromBytes(new Ops.OpSHA256(), helloworld)
const ots = det.serializeToBytes()
// from bytes: serialize with context
try {
const detached = DetachedTimestampFile.fromBytes(new Ops.OpSHA256(), helloworld)
const ctx = new Context.StreamSerialization()
detached.serialize(ctx)
assert.true(Utils.arrEq(ots, ctx.getOutput()))
} catch (err) {
assert.fail(err)
}
// from hash: serialize to buffer
try {
const hash = (new Ops.OpSHA256()).call(helloworld)
const detached = DetachedTimestampFile.fromHash(new Ops.OpSHA256(), hash)
const bytes = Utils.arrayToBytes(detached.serializeToBytes())
assert.true(Utils.arrEq(ots, bytes))
} catch (err) {
assert.fail(err)
}
// from hash: serialize with context
try {
const hash = (new Ops.OpSHA256()).call(helloworld)
const detached = DetachedTimestampFile.fromHash(new Ops.OpSHA256(), hash)
const ctx = new Context.StreamSerialization()
detached.serialize(ctx)
assert.true(Utils.arrEq(ots, ctx.getOutput()))
} catch (err) {
assert.fail(err)
}
// from ots: serialize to buffer
try {
const detached = DetachedTimestampFile.deserialize(helloworldOts)
const bytes = Utils.arrayToBytes(detached.serializeToBytes())
assert.true(Utils.arrEq(helloworldOts, bytes))
} catch (err) {
assert.fail(err)
}
// from ots: serialize with context
try {
const detached = DetachedTimestampFile.deserialize(helloworldOts)
const ctx = new Context.StreamSerialization()
detached.serialize(ctx)
assert.true(Utils.arrEq(helloworldOts, ctx.getOutput()))
} catch (err) {
assert.fail()
}
assert.end()
})