@smartledger/bsv 7.10.1 → 7.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,104 @@
1
+ 'use strict'
2
+
3
+ /* global describe, it, before */
4
+
5
+ // The browser `crypto` polyfill is our own three-function shim, not crypto-browserify.
6
+ //
7
+ // Two things have to hold, and neither is visible to a test that stays inside lib/.
8
+ //
9
+ // 1. `elliptic` must not re-enter the bundles. It carries an advisory with no patched
10
+ // version, and it is reachable from crypto-browserify via browserify-sign and
11
+ // create-ecdh. build/esbuild.js used to keep it out with a hand-written onResolve
12
+ // stub; removing crypto-browserify removed the need for the stub, and this file
13
+ // replaces it. A stub is silent when it stops matching — an assertion is not.
14
+ //
15
+ // 2. The shim must keep implementing what the bundles actually call. If someone adds a
16
+ // `crypto.pbkdf2` call to a bundled module, resolution still succeeds and the member
17
+ // is simply `undefined`, so the failure surfaces far from its cause.
18
+ //
19
+ // The known-answer test exists because "the bundle builds" and "the bundle hashes
20
+ // correctly" are different claims, and only the second one matters to a caller.
21
+
22
+ require('chai').should()
23
+ var crypto = require('crypto')
24
+ var esbuild = require('../../build/esbuild.js')
25
+ var shim = require('../../build/esbuild/crypto-shim.js')
26
+
27
+ // Reachable from crypto-browserify; `elliptic` is the one with no fix available.
28
+ var BANNED = ['elliptic', 'browserify-sign', 'create-ecdh', 'crypto-browserify']
29
+
30
+ describe('browser crypto shim', function () {
31
+ this.timeout(300000)
32
+
33
+ var pkgsByBundle = {}
34
+
35
+ before(function () {
36
+ return Promise.all(esbuild.BUNDLES.map(function (cfg) {
37
+ return esbuild.buildOne(cfg, { metafile: true, write: false, logLevel: 'silent' })
38
+ .then(function (result) {
39
+ pkgsByBundle[cfg.file] = Object.keys(result.metafile.inputs)
40
+ .map(function (p) {
41
+ var m = /node_modules\/((?:@[^/]+\/)?[^/]+)\//.exec(p)
42
+ return m && m[1]
43
+ })
44
+ .filter(Boolean)
45
+ })
46
+ }))
47
+ })
48
+
49
+ it('built every bundle', function () {
50
+ esbuild.BUNDLES.length.should.be.above(0)
51
+ Object.keys(pkgsByBundle).length.should.equal(esbuild.BUNDLES.length)
52
+ })
53
+
54
+ // Guard against the graph being empty for an unrelated reason, which would make the
55
+ // "no banned packages" assertion below pass without checking anything.
56
+ it('resolved a non-trivial dependency graph', function () {
57
+ Object.keys(pkgsByBundle).forEach(function (file) {
58
+ pkgsByBundle[file].length.should.be.above(0, file + ' has no node_modules inputs')
59
+ })
60
+ })
61
+
62
+ it('pulls no part of the elliptic chain into any bundle', function () {
63
+ var offenders = []
64
+ Object.keys(pkgsByBundle).forEach(function (file) {
65
+ BANNED.forEach(function (pkg) {
66
+ if (pkgsByBundle[file].indexOf(pkg) !== -1) offenders.push(file + ' → ' + pkg)
67
+ })
68
+ })
69
+ offenders.should.deep.equal([])
70
+ })
71
+
72
+ it('exports exactly the members the bundles call', function () {
73
+ Object.keys(shim).sort().should.deep.equal(['createHash', 'createHmac', 'randomBytes'])
74
+ })
75
+
76
+ // Deliberately absent: secrets.js-grempe prefers getRandomValues over randomBytes when
77
+ // it is present, so exporting it would silently move the Shamir CSPRNG to another code
78
+ // path. crypto-browserify did not expose it either.
79
+ it('does not expose getRandomValues', function () {
80
+ ;(shim.getRandomValues === undefined).should.equal(true)
81
+ })
82
+
83
+ it('hashes identically to node crypto', function () {
84
+ ['', 'abc', 'The quick brown fox jumps over the lazy dog'].forEach(function (input) {
85
+ ;['sha1', 'sha256', 'sha512', 'ripemd160'].forEach(function (alg) {
86
+ shim.createHash(alg).update(input).digest('hex')
87
+ .should.equal(crypto.createHash(alg).update(input).digest('hex'), alg + ' of ' + JSON.stringify(input))
88
+ })
89
+ })
90
+ })
91
+
92
+ it('hmacs identically to node crypto', function () {
93
+ shim.createHmac('sha512', Buffer.from('key')).update('message').digest('hex')
94
+ .should.equal(crypto.createHmac('sha512', Buffer.from('key')).update('message').digest('hex'))
95
+ })
96
+
97
+ it('draws distinct random bytes of the requested length', function () {
98
+ var a = shim.randomBytes(32)
99
+ var b = shim.randomBytes(32)
100
+ a.length.should.equal(32)
101
+ b.length.should.equal(32)
102
+ a.toString('hex').should.not.equal(b.toString('hex'))
103
+ })
104
+ })
@@ -68,9 +68,18 @@ describe('feature bundles externalise the shared primitives', function () {
68
68
  // from an externalised entry would bundle a second copy silently, with every existing
69
69
  // test green.
70
70
  it('contains only its own feature code, pinned per bundle', function () {
71
- // Accepted in any bundle: a tiny lodash subset with no library state, deliberately
72
- // duplicated rather than routed through the global.
73
- var SHARED = ['lib/util/']
71
+ // Accepted in any bundle: stateless helpers, deliberately duplicated rather than
72
+ // routed through the global.
73
+ //
74
+ // Named FILES, not the directory. `lib/util/` as a prefix exempts anything added
75
+ // under it later, including something stateful — which is the property this test
76
+ // exists to prevent. Listing them means a new util file has to be considered.
77
+ //
78
+ // And listing ONLY what is actually embedded, for the same reason: naming a file
79
+ // that no bundle pulls in pre-approves it, so the consideration never happens.
80
+ // Measured — `lib/util/_.js` is the only one today. If a bundle starts needing
81
+ // another, this line should change in the same commit that causes it.
82
+ var SHARED = ['lib/util/_.js']
74
83
  var EXPECTED = {
75
84
  'bsv-ecies.min.js': ['lib/ecies/'],
76
85
  'bsv-message.min.js': ['lib/message/'],
@@ -35,7 +35,10 @@ function run (build, opts) {
35
35
  return {
36
36
  verified: verified,
37
37
  errstr: interp.errstr || '',
38
- stack: (interp.stack || []).map(function (b) { return BN.fromScriptNumBuffer(b).toString() })
38
+ stack: (interp.stack || []).map(function (b) { return BN.fromScriptNumBuffer(b).toString() }),
39
+ // The raw bytes as well: several Chronicle behaviours are about WIDTH, not
40
+ // value, and a script-number reading collapses that distinction.
41
+ raw: (interp.stack || []).map(function (b) { return Buffer.from(b) })
39
42
  }
40
43
  }
41
44
 
@@ -53,8 +56,37 @@ describe('Chronicle script surface', function () {
53
56
  })
54
57
  })
55
58
 
56
- it('is off by default, so none of this changes existing evaluation', function () {
57
- (Interpreter.DEFAULT_FLAGS & CHRONICLE).should.equal(0)
59
+ // This assertion used to read `(Interpreter.DEFAULT_FLAGS & CHRONICLE).should.equal(0)`
60
+ // — and Interpreter.DEFAULT_FLAGS does not exist, so it evaluated `undefined & n`,
61
+ // which is 0 for every n. A tautology, written by me, in the same change that added
62
+ // the flag. What it MEANT to assert is that verify() enables nothing on its own.
63
+ it('is not enabled unless the caller asks: verify() defaults to no flags', function () {
64
+ // Deliberately NOT via run(): that helper defaults to CHRONICLE, so it would
65
+ // measure the helper rather than the library. Omit the argument entirely.
66
+ var script = new Script().add(Opcode.OP_VER)
67
+ var interp = new Interpreter()
68
+ var verified = interp.verify(new Script(), script, new bsv.Transaction(), 0)
69
+ verified.should.equal(false)
70
+ interp.errstr.should.match(/BAD_OPCODE/)
71
+ })
72
+
73
+ it('mainnetFlags() opts in, and can opt out for a pre-activation UTXO', function () {
74
+ // Chronicle gates PER UTXO in the node (`utxo_after_chronicle`), so the library
75
+ // cannot decide this globally — it can only make both answers easy to express.
76
+ (Interpreter.mainnetFlags() & CHRONICLE).should.not.equal(0)
77
+ ;(Interpreter.mainnetFlags({ afterChronicle: false }) & CHRONICLE).should.equal(0)
78
+ Interpreter.CHRONICLE_ACTIVATION_HEIGHT.should.equal(943816)
79
+ })
80
+
81
+ it('mainnetFlags() actually evaluates a Chronicle script', function () {
82
+ var r = run(function (s) { s.add(Opcode.OP_VER) },
83
+ { flags: Interpreter.mainnetFlags(), version: 7 })
84
+ r.stack[r.stack.length - 1].should.equal('7')
85
+
86
+ var pre = run(function (s) { s.add(Opcode.OP_VER) },
87
+ { flags: Interpreter.mainnetFlags({ afterChronicle: false }), version: 7 })
88
+ pre.verified.should.equal(false)
89
+ pre.errstr.should.match(/BAD_OPCODE/)
58
90
  })
59
91
  })
60
92
 
@@ -109,6 +141,11 @@ describe('Chronicle script surface', function () {
109
141
  ;[1, 2, 10].forEach(function (v) {
110
142
  var r = run(function (s) { s.add(Opcode.OP_VER) }, { version: v })
111
143
  r.stack[r.stack.length - 1].should.equal(String(v))
144
+ // LENGTH too, not just the numeric reading. `01000000` and `01` both read
145
+ // as 1, so the value check alone passes whether OP_VER pushes four
146
+ // little-endian bytes or a minimally-encoded script number — and pushing
147
+ // the script number was the bug fixed in #95.
148
+ r.raw[r.raw.length - 1].length.should.equal(4)
112
149
  })
113
150
  })
114
151
  })
package/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  'use strict'
2
2
  // GENERATED by scripts/sync-version.js on `npm version` — do not edit.
3
- module.exports = '7.10.1'
3
+ module.exports = '7.12.0'