@xyo-network/boundwitness 2.21.11

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.
Files changed (178) hide show
  1. package/LICENSE +165 -0
  2. package/README.md +79 -0
  3. package/babel.config.json +5 -0
  4. package/dist/cjs/Builder/Builder.d.ts +23 -0
  5. package/dist/cjs/Builder/Builder.js +68 -0
  6. package/dist/cjs/Builder/Builder.js.map +1 -0
  7. package/dist/cjs/Builder/index.d.ts +1 -0
  8. package/dist/cjs/Builder/index.js +5 -0
  9. package/dist/cjs/Builder/index.js.map +1 -0
  10. package/dist/cjs/Test/index.d.ts +1 -0
  11. package/dist/cjs/Test/index.js +5 -0
  12. package/dist/cjs/Test/index.js.map +1 -0
  13. package/dist/cjs/Test/testBoundWitness.d.ts +3 -0
  14. package/dist/cjs/Test/testBoundWitness.js +17 -0
  15. package/dist/cjs/Test/testBoundWitness.js.map +1 -0
  16. package/dist/cjs/Validator/BodyValidator.d.ts +17 -0
  17. package/dist/cjs/Validator/BodyValidator.js +94 -0
  18. package/dist/cjs/Validator/BodyValidator.js.map +1 -0
  19. package/dist/cjs/Validator/MetaValidator.d.ts +13 -0
  20. package/dist/cjs/Validator/MetaValidator.js +67 -0
  21. package/dist/cjs/Validator/MetaValidator.js.map +1 -0
  22. package/dist/cjs/Validator/Validator.d.ts +12 -0
  23. package/dist/cjs/Validator/Validator.js +47 -0
  24. package/dist/cjs/Validator/Validator.js.map +1 -0
  25. package/dist/cjs/Validator/index.d.ts +3 -0
  26. package/dist/cjs/Validator/index.js +7 -0
  27. package/dist/cjs/Validator/index.js.map +1 -0
  28. package/dist/cjs/Validator/ip-regex.d.ts +9 -0
  29. package/dist/cjs/Validator/ip-regex.js +31 -0
  30. package/dist/cjs/Validator/ip-regex.js.map +1 -0
  31. package/dist/cjs/Validator/is-ip.d.ts +4 -0
  32. package/dist/cjs/Validator/is-ip.js +21 -0
  33. package/dist/cjs/Validator/is-ip.js.map +1 -0
  34. package/dist/cjs/Wrapper/Wrapper.d.ts +11 -0
  35. package/dist/cjs/Wrapper/Wrapper.js +27 -0
  36. package/dist/cjs/Wrapper/Wrapper.js.map +1 -0
  37. package/dist/cjs/Wrapper/index.d.ts +1 -0
  38. package/dist/cjs/Wrapper/index.js +5 -0
  39. package/dist/cjs/Wrapper/index.js.map +1 -0
  40. package/dist/cjs/index.d.ts +5 -0
  41. package/dist/cjs/index.js +9 -0
  42. package/dist/cjs/index.js.map +1 -0
  43. package/dist/cjs/isXyoPayloadOfSchemaType.d.ts +2 -0
  44. package/dist/cjs/isXyoPayloadOfSchemaType.js +6 -0
  45. package/dist/cjs/isXyoPayloadOfSchemaType.js.map +1 -0
  46. package/dist/cjs/models/Base/XyoBoundWitnessBase.d.ts +9 -0
  47. package/dist/cjs/models/Base/XyoBoundWitnessBase.js +3 -0
  48. package/dist/cjs/models/Base/XyoBoundWitnessBase.js.map +1 -0
  49. package/dist/cjs/models/Base/XyoBoundWitnessBaseSchema.d.ts +36 -0
  50. package/dist/cjs/models/Base/XyoBoundWitnessBaseSchema.js +19 -0
  51. package/dist/cjs/models/Base/XyoBoundWitnessBaseSchema.js.map +1 -0
  52. package/dist/cjs/models/Base/index.d.ts +2 -0
  53. package/dist/cjs/models/Base/index.js +6 -0
  54. package/dist/cjs/models/Base/index.js.map +1 -0
  55. package/dist/cjs/models/Meta/XyoBoundWitnessMeta.d.ts +7 -0
  56. package/dist/cjs/models/Meta/XyoBoundWitnessMeta.js +3 -0
  57. package/dist/cjs/models/Meta/XyoBoundWitnessMeta.js.map +1 -0
  58. package/dist/cjs/models/Meta/XyoBoundWitnessMetaSchema.d.ts +85 -0
  59. package/dist/cjs/models/Meta/XyoBoundWitnessMetaSchema.js +28 -0
  60. package/dist/cjs/models/Meta/XyoBoundWitnessMetaSchema.js.map +1 -0
  61. package/dist/cjs/models/Meta/index.d.ts +2 -0
  62. package/dist/cjs/models/Meta/index.js +6 -0
  63. package/dist/cjs/models/Meta/index.js.map +1 -0
  64. package/dist/cjs/models/WithXyoBoundWitnessMeta.d.ts +4 -0
  65. package/dist/cjs/models/WithXyoBoundWitnessMeta.js +3 -0
  66. package/dist/cjs/models/WithXyoBoundWitnessMeta.js.map +1 -0
  67. package/dist/cjs/models/XyoBoundWitness.d.ts +6 -0
  68. package/dist/cjs/models/XyoBoundWitness.js +3 -0
  69. package/dist/cjs/models/XyoBoundWitness.js.map +1 -0
  70. package/dist/cjs/models/XyoBoundWitnessSchema.d.ts +75 -0
  71. package/dist/cjs/models/XyoBoundWitnessSchema.js +17 -0
  72. package/dist/cjs/models/XyoBoundWitnessSchema.js.map +1 -0
  73. package/dist/cjs/models/index.d.ts +5 -0
  74. package/dist/cjs/models/index.js +9 -0
  75. package/dist/cjs/models/index.js.map +1 -0
  76. package/dist/docs.json +7 -0
  77. package/dist/esm/Builder/Builder.d.ts +23 -0
  78. package/dist/esm/Builder/Builder.js +66 -0
  79. package/dist/esm/Builder/Builder.js.map +1 -0
  80. package/dist/esm/Builder/index.d.ts +1 -0
  81. package/dist/esm/Builder/index.js +2 -0
  82. package/dist/esm/Builder/index.js.map +1 -0
  83. package/dist/esm/Test/index.d.ts +1 -0
  84. package/dist/esm/Test/index.js +2 -0
  85. package/dist/esm/Test/index.js.map +1 -0
  86. package/dist/esm/Test/testBoundWitness.d.ts +3 -0
  87. package/dist/esm/Test/testBoundWitness.js +14 -0
  88. package/dist/esm/Test/testBoundWitness.js.map +1 -0
  89. package/dist/esm/Validator/BodyValidator.d.ts +17 -0
  90. package/dist/esm/Validator/BodyValidator.js +88 -0
  91. package/dist/esm/Validator/BodyValidator.js.map +1 -0
  92. package/dist/esm/Validator/MetaValidator.d.ts +13 -0
  93. package/dist/esm/Validator/MetaValidator.js +63 -0
  94. package/dist/esm/Validator/MetaValidator.js.map +1 -0
  95. package/dist/esm/Validator/Validator.d.ts +12 -0
  96. package/dist/esm/Validator/Validator.js +42 -0
  97. package/dist/esm/Validator/Validator.js.map +1 -0
  98. package/dist/esm/Validator/index.d.ts +3 -0
  99. package/dist/esm/Validator/index.js +4 -0
  100. package/dist/esm/Validator/index.js.map +1 -0
  101. package/dist/esm/Validator/ip-regex.d.ts +9 -0
  102. package/dist/esm/Validator/ip-regex.js +27 -0
  103. package/dist/esm/Validator/ip-regex.js.map +1 -0
  104. package/dist/esm/Validator/is-ip.d.ts +4 -0
  105. package/dist/esm/Validator/is-ip.js +14 -0
  106. package/dist/esm/Validator/is-ip.js.map +1 -0
  107. package/dist/esm/Wrapper/Wrapper.d.ts +11 -0
  108. package/dist/esm/Wrapper/Wrapper.js +20 -0
  109. package/dist/esm/Wrapper/Wrapper.js.map +1 -0
  110. package/dist/esm/Wrapper/index.d.ts +1 -0
  111. package/dist/esm/Wrapper/index.js +2 -0
  112. package/dist/esm/Wrapper/index.js.map +1 -0
  113. package/dist/esm/index.d.ts +5 -0
  114. package/dist/esm/index.js +6 -0
  115. package/dist/esm/index.js.map +1 -0
  116. package/dist/esm/isXyoPayloadOfSchemaType.d.ts +2 -0
  117. package/dist/esm/isXyoPayloadOfSchemaType.js +3 -0
  118. package/dist/esm/isXyoPayloadOfSchemaType.js.map +1 -0
  119. package/dist/esm/models/Base/XyoBoundWitnessBase.d.ts +9 -0
  120. package/dist/esm/models/Base/XyoBoundWitnessBase.js +2 -0
  121. package/dist/esm/models/Base/XyoBoundWitnessBase.js.map +1 -0
  122. package/dist/esm/models/Base/XyoBoundWitnessBaseSchema.d.ts +36 -0
  123. package/dist/esm/models/Base/XyoBoundWitnessBaseSchema.js +16 -0
  124. package/dist/esm/models/Base/XyoBoundWitnessBaseSchema.js.map +1 -0
  125. package/dist/esm/models/Base/index.d.ts +2 -0
  126. package/dist/esm/models/Base/index.js +3 -0
  127. package/dist/esm/models/Base/index.js.map +1 -0
  128. package/dist/esm/models/Meta/XyoBoundWitnessMeta.d.ts +7 -0
  129. package/dist/esm/models/Meta/XyoBoundWitnessMeta.js +2 -0
  130. package/dist/esm/models/Meta/XyoBoundWitnessMeta.js.map +1 -0
  131. package/dist/esm/models/Meta/XyoBoundWitnessMetaSchema.d.ts +85 -0
  132. package/dist/esm/models/Meta/XyoBoundWitnessMetaSchema.js +23 -0
  133. package/dist/esm/models/Meta/XyoBoundWitnessMetaSchema.js.map +1 -0
  134. package/dist/esm/models/Meta/index.d.ts +2 -0
  135. package/dist/esm/models/Meta/index.js +3 -0
  136. package/dist/esm/models/Meta/index.js.map +1 -0
  137. package/dist/esm/models/WithXyoBoundWitnessMeta.d.ts +4 -0
  138. package/dist/esm/models/WithXyoBoundWitnessMeta.js +2 -0
  139. package/dist/esm/models/WithXyoBoundWitnessMeta.js.map +1 -0
  140. package/dist/esm/models/XyoBoundWitness.d.ts +6 -0
  141. package/dist/esm/models/XyoBoundWitness.js +2 -0
  142. package/dist/esm/models/XyoBoundWitness.js.map +1 -0
  143. package/dist/esm/models/XyoBoundWitnessSchema.d.ts +75 -0
  144. package/dist/esm/models/XyoBoundWitnessSchema.js +21 -0
  145. package/dist/esm/models/XyoBoundWitnessSchema.js.map +1 -0
  146. package/dist/esm/models/index.d.ts +5 -0
  147. package/dist/esm/models/index.js +6 -0
  148. package/dist/esm/models/index.js.map +1 -0
  149. package/jest.config.cjs +25 -0
  150. package/package.json +61 -0
  151. package/src/Builder/Builder.spec.ts +88 -0
  152. package/src/Builder/Builder.ts +83 -0
  153. package/src/Builder/index.ts +1 -0
  154. package/src/Test/index.ts +1 -0
  155. package/src/Test/testBoundWitness.ts +16 -0
  156. package/src/Validator/BodyValidator.spec.ts +11 -0
  157. package/src/Validator/BodyValidator.ts +102 -0
  158. package/src/Validator/MetaValidator.spec.ts +56 -0
  159. package/src/Validator/MetaValidator.ts +71 -0
  160. package/src/Validator/Validator.spec.ts +11 -0
  161. package/src/Validator/Validator.ts +51 -0
  162. package/src/Validator/index.ts +3 -0
  163. package/src/Validator/ip-regex.ts +39 -0
  164. package/src/Validator/is-ip.ts +17 -0
  165. package/src/Wrapper/Wrapper.ts +27 -0
  166. package/src/Wrapper/index.ts +1 -0
  167. package/src/index.ts +5 -0
  168. package/src/isXyoPayloadOfSchemaType.ts +5 -0
  169. package/src/models/Base/XyoBoundWitnessBase.ts +10 -0
  170. package/src/models/Base/XyoBoundWitnessBaseSchema.ts +15 -0
  171. package/src/models/Base/index.ts +2 -0
  172. package/src/models/Meta/XyoBoundWitnessMeta.ts +8 -0
  173. package/src/models/Meta/XyoBoundWitnessMetaSchema.ts +24 -0
  174. package/src/models/Meta/index.ts +2 -0
  175. package/src/models/WithXyoBoundWitnessMeta.ts +6 -0
  176. package/src/models/XyoBoundWitness.ts +8 -0
  177. package/src/models/XyoBoundWitnessSchema.ts +23 -0
  178. package/src/models/index.ts +5 -0
@@ -0,0 +1,102 @@
1
+ import { XyoHasher, XyoValidator } from '@xyo-network/core'
2
+ import { XyoPayload, XyoSchemaNameValidator } from '@xyo-network/payload'
3
+ import { validateType } from '@xyo-network/typeof'
4
+ import uniq from 'lodash/uniq'
5
+
6
+ import { XyoBoundWitness } from '../models'
7
+
8
+ export class XyoBoundWitnessBodyValidator<T extends XyoBoundWitness = XyoBoundWitness> extends XyoValidator<T> {
9
+ private payloads?: XyoPayload[]
10
+ constructor(boundWitness: T, payloads?: XyoPayload[]) {
11
+ super(boundWitness)
12
+ this.payloads = payloads
13
+ }
14
+
15
+ public addressesUniqueness() {
16
+ const errors: Error[] = []
17
+ const { addresses } = this.obj
18
+ const uniqAddresses = uniq(addresses)
19
+ if (addresses?.length !== uniqAddresses?.length) errors.push(new Error('addresses must be unique'))
20
+ return errors
21
+ }
22
+
23
+ public addresses() {
24
+ const errors: Error[] = []
25
+ const { addresses } = this.obj
26
+ if (!addresses?.length) errors.push(new Error('addresses missing [at least one address required]'))
27
+ errors.push(...this.addressesUniqueness())
28
+ return errors
29
+ }
30
+
31
+ private validateArrayLength(fieldName: string, compareArrayName: string) {
32
+ const errors: Error[] = []
33
+
34
+ const [array, arrayErrors] = validateType('array', this.stringKeyObj[fieldName] as [], true)
35
+ const [compareArray, compareArrayErrors] = validateType('array', this.stringKeyObj[compareArrayName] as [], true)
36
+
37
+ if (array?.length !== compareArray?.length) {
38
+ errors.push(new Error(`${fieldName}/${compareArrayName} count mismatch [${array?.length} !== ${compareArray?.length}]`))
39
+ }
40
+
41
+ return [...arrayErrors, ...compareArrayErrors, ...errors]
42
+ }
43
+
44
+ public validatePayloadHashesLength() {
45
+ const errors: Error[] = []
46
+ errors.push(...this.validateArrayLength('payload_hashes', 'payload_schemas'))
47
+ return errors
48
+ }
49
+
50
+ public validateArrayLengths() {
51
+ const errors: Error[] = []
52
+ errors.push(...this.validatePayloadHashesLength())
53
+ return errors
54
+ }
55
+
56
+ public payloadHashes() {
57
+ const errors: Error[] = []
58
+ const passedHashes = this.obj.payload_hashes
59
+ this.payloads?.forEach((payload, index) => {
60
+ const calcHash = new XyoHasher(payload).hash
61
+ const passedHash = passedHashes?.[index]
62
+ if (calcHash !== passedHash) {
63
+ errors.push(new Error(`hash mismatch [${calcHash} !== ${passedHash}]`))
64
+ }
65
+ })
66
+ return errors
67
+ }
68
+
69
+ public payloadSchemas() {
70
+ const errors: Error[] = []
71
+ const payloadSchemas = this.obj.payload_schemas
72
+ if (payloadSchemas) {
73
+ const schemaValidators: XyoSchemaNameValidator[] = payloadSchemas.map((schema: string) => {
74
+ return new XyoSchemaNameValidator(schema)
75
+ })
76
+ schemaValidators.forEach((validator) => {
77
+ errors.push(...validator.all())
78
+ })
79
+ }
80
+ return errors
81
+ }
82
+
83
+ public previousHashes() {
84
+ const errors: Error[] = []
85
+ return errors
86
+ }
87
+
88
+ public schema() {
89
+ const errors: Error[] = []
90
+ const expectedSchema = 'network.xyo.boundwitness'
91
+ if (this.obj.schema !== expectedSchema) {
92
+ errors.push(new Error(`invalid schema [${expectedSchema} !== ${this.obj.schema}]`))
93
+ }
94
+ return errors
95
+ }
96
+
97
+ public validate() {
98
+ const errors: Error[] = []
99
+ errors.push(...this.addresses(), ...this.validateArrayLengths(), ...this.payloadHashes(), ...this.payloadSchemas(), ...this.previousHashes(), ...this.schema())
100
+ return errors
101
+ }
102
+ }
@@ -0,0 +1,56 @@
1
+ import { dumpErrors } from '@xyo-network/core'
2
+
3
+ import { XyoBoundWitnessWithMeta } from '../models'
4
+ import { testBoundWitness } from '../Test'
5
+ import { XyoBoundWitnessMetaValidator } from './MetaValidator'
6
+
7
+ describe('XyoBoundWitnessMetaValidator', () => {
8
+ it('Validates valid Meta', () => {
9
+ const validator = new XyoBoundWitnessMetaValidator(testBoundWitness)
10
+ const errors = validator.validate()
11
+ dumpErrors(errors)
12
+ expect(errors.length).toBe(0)
13
+ })
14
+ describe('sourceIp', () => {
15
+ it('Validates valid IPv4 Address', () => {
16
+ const bw: XyoBoundWitnessWithMeta = {
17
+ ...testBoundWitness,
18
+ _source_ip: '127.0.0.1',
19
+ }
20
+ const validator = new XyoBoundWitnessMetaValidator(bw)
21
+ const errors = validator.validate()
22
+ dumpErrors(errors)
23
+ expect(errors.length).toBe(0)
24
+ })
25
+ it('Validates valid IPv6 Address', () => {
26
+ const bw: XyoBoundWitnessWithMeta = {
27
+ ...testBoundWitness,
28
+ _source_ip: '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
29
+ }
30
+ const validator = new XyoBoundWitnessMetaValidator(bw)
31
+ const errors = validator.validate()
32
+ dumpErrors(errors)
33
+ expect(errors.length).toBe(0)
34
+ })
35
+ it('Handles missing Address', () => {
36
+ const bw: XyoBoundWitnessWithMeta = {
37
+ ...testBoundWitness,
38
+ _source_ip: undefined,
39
+ }
40
+ const validator = new XyoBoundWitnessMetaValidator(bw)
41
+ const errors = validator.validate()
42
+ dumpErrors(errors)
43
+ expect(errors.length).toBe(0)
44
+ })
45
+ it('Detects invalid Addresses', () => {
46
+ const bw: XyoBoundWitnessWithMeta = {
47
+ ...testBoundWitness,
48
+ _source_ip: 'notAnIpAddress',
49
+ }
50
+ const validator = new XyoBoundWitnessMetaValidator(bw)
51
+ const errors = validator.validate()
52
+ dumpErrors(errors)
53
+ expect(errors.length).toBe(0)
54
+ })
55
+ })
56
+ })
@@ -0,0 +1,71 @@
1
+ import { XyoHasher, XyoValidator } from '@xyo-network/core'
2
+
3
+ import { XyoBoundWitnessMeta } from '../models'
4
+ import { isIP } from './is-ip'
5
+
6
+ const MIN_ALLOWED_TIMESTAMP = 1609459200000
7
+ const MAX_ALLOWED_TIMESTAMP = 4102444800000
8
+
9
+ export class XyoBoundWitnessMetaValidator<T extends Partial<XyoBoundWitnessMeta> = Partial<XyoBoundWitnessMeta>> extends XyoValidator<T> {
10
+ public client() {
11
+ const errors: Error[] = []
12
+ return errors
13
+ }
14
+
15
+ public hash() {
16
+ const errors: Error[] = []
17
+
18
+ const hasher = new XyoHasher(this.obj)
19
+
20
+ const bodyHash = hasher.hash
21
+ if (bodyHash !== this.obj._hash) errors.push(new Error(`Body hash mismatch: [calculated: ${bodyHash}] [found: ${this.obj._hash}] [sortedStringify: ${hasher.stringified}]`))
22
+ return errors
23
+ }
24
+
25
+ public payloads() {
26
+ const errors: Error[] = []
27
+ return errors
28
+ }
29
+
30
+ public signatures() {
31
+ const errors: Error[] = []
32
+ return errors
33
+ }
34
+
35
+ public timestamp() {
36
+ const errors: Error[] = []
37
+ const { _timestamp } = this.obj
38
+ if (_timestamp === undefined) errors.push(new Error('Missing _timestamp'))
39
+ else if (_timestamp < MIN_ALLOWED_TIMESTAMP) errors.push(new Error('_timestamp is before year 2021'))
40
+ else if (_timestamp > MAX_ALLOWED_TIMESTAMP) errors.push(new Error('_timestamp is after year 2100'))
41
+ return errors
42
+ }
43
+
44
+ public sourceIp() {
45
+ const errors: Error[] = []
46
+ const { _source_ip } = this.obj
47
+ if (_source_ip && !isIP(_source_ip)) {
48
+ errors.push(new Error(`_source_ip invalid format [${_source_ip}]`))
49
+ }
50
+ return errors
51
+ }
52
+
53
+ public userAgent() {
54
+ const errors: Error[] = []
55
+ const { _user_agent } = this.obj
56
+ if (!_user_agent) errors.push(new Error('_user_agent missing'))
57
+ return errors
58
+ }
59
+
60
+ public validate() {
61
+ const errors: Error[] = []
62
+ errors.push(...this.client(), ...this.hash(), ...this.payloads(), ...this.signatures())
63
+ return errors
64
+ }
65
+
66
+ public meta() {
67
+ const errors: Error[] = []
68
+ errors.push(...this.timestamp(), ...this.sourceIp(), ...this.userAgent())
69
+ return errors
70
+ }
71
+ }
@@ -0,0 +1,11 @@
1
+ import { dumpErrors } from '@xyo-network/core'
2
+
3
+ import { testBoundWitness } from '../Test'
4
+ import { XyoBoundWitnessValidator } from './Validator'
5
+
6
+ test('all', () => {
7
+ const validator = new XyoBoundWitnessValidator(testBoundWitness)
8
+ const errors = validator.validate()
9
+ dumpErrors(errors)
10
+ expect(errors.length).toBe(0)
11
+ })
@@ -0,0 +1,51 @@
1
+ import { assertEx } from '@xylabs/sdk-js'
2
+ import { XyoAddressValue } from '@xyo-network/account'
3
+ import { XyoValidator } from '@xyo-network/core'
4
+
5
+ import { XyoBoundWitnessWithPartialMeta } from '../models'
6
+ import { XyoBoundWitnessBodyValidator } from './BodyValidator'
7
+ import { XyoBoundWitnessMetaValidator } from './MetaValidator'
8
+
9
+ const validateArraysSameLength = (a: unknown[], b: unknown[], message = 'Array length mismatch') => {
10
+ return a.length != b.length ? [Error(`${message} []`)] : []
11
+ }
12
+
13
+ const validateSignature = (hash: string, address: string, signature?: string) => {
14
+ if (!signature) {
15
+ return [Error(`Missing signature [${address}]`)]
16
+ }
17
+ if (!new XyoAddressValue(address).verify(hash, signature)) {
18
+ return [Error(`Invalid signature [${address}] [${signature}]`)]
19
+ }
20
+ return []
21
+ }
22
+
23
+ class XyoBoundWitnessValidator<T extends XyoBoundWitnessWithPartialMeta = XyoBoundWitnessWithPartialMeta> extends XyoValidator<T> {
24
+ public body: XyoBoundWitnessBodyValidator
25
+ public meta: XyoBoundWitnessMetaValidator
26
+ constructor(bw: T) {
27
+ super(bw)
28
+ this.body = new XyoBoundWitnessBodyValidator(bw, bw._payloads)
29
+ this.meta = new XyoBoundWitnessMetaValidator(bw)
30
+ }
31
+
32
+ public signatures() {
33
+ const hash = assertEx(this.obj._hash, 'Missing _hash')
34
+ return [
35
+ ...validateArraysSameLength(this.obj._signatures ?? [], this.obj.addresses, 'Length mismatch: address/_signature'),
36
+ ...this.obj.addresses.reduce<Error[]>((errors, address, index) => {
37
+ errors.push(...validateSignature(hash, address, this.obj._signatures?.[index]))
38
+ return errors
39
+ }, []),
40
+ ]
41
+ }
42
+
43
+ public validate() {
44
+ const errors: Error[] = []
45
+ errors.push(...this.meta.validate(), ...this.body.validate())
46
+ errors.push(...this.signatures())
47
+ return errors
48
+ }
49
+ }
50
+
51
+ export { XyoBoundWitnessValidator }
@@ -0,0 +1,3 @@
1
+ export * from './BodyValidator'
2
+ export * from './MetaValidator'
3
+ export * from './Validator'
@@ -0,0 +1,39 @@
1
+ const word = '[a-fA-F\\d:]'
2
+
3
+ export interface Options {
4
+ readonly exact?: boolean
5
+ readonly includeBoundaries?: boolean
6
+ }
7
+
8
+ const boundry = (options: Options) => (options && options.includeBoundaries ? `(?:(?<=\\s|^)(?=${word})|(?<=${word})(?=\\s|$))` : '')
9
+
10
+ const v4 = '(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}'
11
+
12
+ const v6segment = '[a-fA-F\\d]{1,4}'
13
+
14
+ const v6 = `
15
+ (?:
16
+ (?:${v6segment}:){7}(?:${v6segment}|:)| // 1:2:3:4:5:6:7:: 1:2:3:4:5:6:7:8
17
+ (?:${v6segment}:){6}(?:${v4}|:${v6segment}|:)| // 1:2:3:4:5:6:: 1:2:3:4:5:6::8 1:2:3:4:5:6::8 1:2:3:4:5:6::1.2.3.4
18
+ (?:${v6segment}:){5}(?::${v4}|(?::${v6segment}){1,2}|:)| // 1:2:3:4:5:: 1:2:3:4:5::7:8 1:2:3:4:5::8 1:2:3:4:5::7:1.2.3.4
19
+ (?:${v6segment}:){4}(?:(?::${v6segment}){0,1}:${v4}|(?::${v6segment}){1,3}|:)| // 1:2:3:4:: 1:2:3:4::6:7:8 1:2:3:4::8 1:2:3:4::6:7:1.2.3.4
20
+ (?:${v6segment}:){3}(?:(?::${v6segment}){0,2}:${v4}|(?::${v6segment}){1,4}|:)| // 1:2:3:: 1:2:3::5:6:7:8 1:2:3::8 1:2:3::5:6:7:1.2.3.4
21
+ (?:${v6segment}:){2}(?:(?::${v6segment}){0,3}:${v4}|(?::${v6segment}){1,5}|:)| // 1:2:: 1:2::4:5:6:7:8 1:2::8 1:2::4:5:6:7:1.2.3.4
22
+ (?:${v6segment}:){1}(?:(?::${v6segment}){0,4}:${v4}|(?::${v6segment}){1,6}|:)| // 1:: 1::3:4:5:6:7:8 1::8 1::3:4:5:6:7:1.2.3.4
23
+ (?::(?:(?::${v6segment}){0,5}:${v4}|(?::${v6segment}){1,7}|:)) // ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::1.2.3.4
24
+ )(?:%[0-9a-zA-Z]{1,})? // %eth0 %1
25
+ `
26
+ .replace(/\s*\/\/.*$/gm, '')
27
+ .replace(/\n/g, '')
28
+ .trim()
29
+
30
+ // Pre-compile only the exact regexes because adding a global flag make regexes stateful
31
+ const v46Exact = new RegExp(`(?:^${v4}$)|(?:^${v6}$)`)
32
+ const v4exact = new RegExp(`^${v4}$`)
33
+ const v6exact = new RegExp(`^${v6}$`)
34
+
35
+ export const ipRegex = (options: Options) =>
36
+ options && options.exact ? v46Exact : new RegExp(`(?:${boundry(options)}${v4}${boundry(options)})|(?:${boundry(options)}${v6}${boundry(options)})`, 'g')
37
+
38
+ ipRegex.v4 = (options: Options) => (options && options.exact ? v4exact : new RegExp(`${boundry(options)}${v4}${boundry(options)}`, 'g'))
39
+ ipRegex.v6 = (options: Options) => (options && options.exact ? v6exact : new RegExp(`${boundry(options)}${v6}${boundry(options)}`, 'g'))
@@ -0,0 +1,17 @@
1
+ import { ipRegex } from './ip-regex'
2
+
3
+ export function isIP(value: string) {
4
+ return ipRegex({ exact: true }).test(value)
5
+ }
6
+
7
+ export function isIPv6(value: string) {
8
+ return ipRegex.v6({ exact: true }).test(value)
9
+ }
10
+
11
+ export function isIPv4(value: string) {
12
+ return ipRegex.v4({ exact: true }).test(value)
13
+ }
14
+
15
+ export function ipVersion(value: string) {
16
+ return isIP(value) ? (isIPv6(value) ? 6 : 4) : undefined
17
+ }
@@ -0,0 +1,27 @@
1
+ import { XyoHasher } from '@xyo-network/core'
2
+ import pick from 'lodash/pick'
3
+ import { UAParser } from 'ua-parser-js'
4
+
5
+ import { XyoBoundWitness, XyoBoundWitnessWithMeta } from '../models'
6
+
7
+ const scrubbedFields = ['_archive', '_client', '_hash', '_signatures', '_timestamp', '_user_agent', 'addresses', 'payload_schemas', 'previous_hashes', 'payload_hashes', 'schema']
8
+
9
+ export class XyoBoundWitnessWrapper<T extends XyoBoundWitness> extends XyoHasher<T> {
10
+ public readonly bw: T
11
+ constructor(bw: T) {
12
+ super(bw)
13
+ this.bw = bw
14
+ }
15
+
16
+ get scrubbedFields() {
17
+ return pick(this.bw, scrubbedFields)
18
+ }
19
+ }
20
+
21
+ export class XyoBoundWitnessWithMetaWrapper<T extends XyoBoundWitnessWithMeta> extends XyoBoundWitnessWrapper<T> {
22
+ private _userAgent?: UAParser
23
+ get userAgent() {
24
+ this._userAgent = this._userAgent ?? new UAParser(this.bw._user_agent)
25
+ return this._userAgent
26
+ }
27
+ }
@@ -0,0 +1 @@
1
+ export * from './Wrapper'
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './Builder'
2
+ export * from './isXyoPayloadOfSchemaType'
3
+ export * from './models'
4
+ export * from './Validator'
5
+ export * from './Wrapper'
@@ -0,0 +1,5 @@
1
+ import { isXyoPayloadOfSchemaType } from '@xyo-network/payload'
2
+
3
+ import { XyoBoundWitness } from './models'
4
+
5
+ export const isXyoBoundWitnessPayload = isXyoPayloadOfSchemaType<XyoBoundWitness>('network.xyo.boundwitness')
@@ -0,0 +1,10 @@
1
+ import { XyoPayload } from '@xyo-network/payload'
2
+
3
+ export type XyoBoundWitnessBase = XyoPayload<{
4
+ addresses: string[]
5
+ previous_hash?: string
6
+ payload_hashes: string[]
7
+ payload_schemas: string[]
8
+ previous_hashes: (string | null)[]
9
+ schema: string
10
+ }>
@@ -0,0 +1,15 @@
1
+ //Should type as JSONSchemaType<XyoBoundWitnessBody> once ajv/eslint issue is fixed
2
+ //https://github.com/microsoft/TypeScript/issues/44851
3
+ export const XyoBoundWitnessBaseSchema = {
4
+ $id: 'https://schemas.xyo.network/2.0/boundwitness/body',
5
+ additionalProperties: false,
6
+ properties: {
7
+ addresses: { items: { type: 'string' }, type: 'array' },
8
+ payload_hashes: { items: { type: 'string' }, type: 'array' },
9
+ payload_schemas: { items: { type: 'string' }, type: 'array' },
10
+ previous_hashes: { items: { nullable: true, type: 'string' }, type: 'array' },
11
+ schema: { type: 'string' },
12
+ },
13
+ required: ['addresses', 'payload_hashes', 'payload_schemas', 'previous_hashes', 'schema'],
14
+ type: 'object',
15
+ }
@@ -0,0 +1,2 @@
1
+ export * from './XyoBoundWitnessBase'
2
+ export * from './XyoBoundWitnessBaseSchema'
@@ -0,0 +1,8 @@
1
+ import { XyoPayloadMeta, XyoPayloadWithPartialMeta } from '@xyo-network/payload'
2
+
3
+ export type XyoBoundWitnessMeta<P extends XyoPayloadWithPartialMeta = XyoPayloadWithPartialMeta> = XyoPayloadMeta<{
4
+ _payloads?: P[]
5
+ _signatures?: string[]
6
+ _source_ip?: string
7
+ _user_agent?: string
8
+ }>
@@ -0,0 +1,24 @@
1
+ //Should type as JSONSchemaType<XyoBoundWitnessMeta> once ajv/eslint issue is fixed
2
+ //https://github.com/microsoft/TypeScript/issues/44851
3
+
4
+ export const XyoBoundWitnessMetaSchemaProperties = () => {
5
+ return {
6
+ _archive: { nullable: true, type: 'string' },
7
+ _client: { nullable: true, type: 'string' },
8
+ _hash: { nullable: true, type: 'string' },
9
+ _payloads: { items: { type: 'object' }, nullable: true, type: 'array' },
10
+ _signatures: { items: { type: 'string' }, nullable: true, type: 'array' },
11
+ _source_ip: { nullable: true, type: 'string' },
12
+ _timestamp: { nullable: true, type: 'number' },
13
+ _user_agent: { nullable: true, type: 'string' },
14
+ }
15
+ }
16
+
17
+ export const XyoBoundWitnessMetaSchema = () => {
18
+ return {
19
+ $id: 'https://schemas.xyo.network/2.0/boundwitness/meta',
20
+ additionalProperties: false,
21
+ properties: XyoBoundWitnessMetaSchemaProperties,
22
+ type: 'object',
23
+ }
24
+ }
@@ -0,0 +1,2 @@
1
+ export * from './XyoBoundWitnessMeta'
2
+ export * from './XyoBoundWitnessMetaSchema'
@@ -0,0 +1,6 @@
1
+ import { XyoBoundWitnessMeta } from './Meta'
2
+ import { XyoBoundWitness } from './XyoBoundWitness'
3
+
4
+ type WithXyoBoundWitnessMeta<T extends XyoBoundWitness> = T & XyoBoundWitnessMeta
5
+
6
+ export type { WithXyoBoundWitnessMeta }
@@ -0,0 +1,8 @@
1
+ import { XyoPayloadWithPartialMeta } from '@xyo-network/payload'
2
+
3
+ import { XyoBoundWitnessBase } from './Base'
4
+ import { XyoBoundWitnessMeta } from './Meta'
5
+
6
+ export type XyoBoundWitness<T extends object = object> = T & XyoBoundWitnessBase
7
+ export type XyoBoundWitnessWithMeta<T = unknown, P extends XyoPayloadWithPartialMeta = XyoPayloadWithPartialMeta> = T & XyoBoundWitnessMeta<P> & XyoBoundWitness
8
+ export type XyoBoundWitnessWithPartialMeta<T = unknown, P extends XyoPayloadWithPartialMeta = XyoPayloadWithPartialMeta> = T & Partial<XyoBoundWitnessMeta<P>> & XyoBoundWitness
@@ -0,0 +1,23 @@
1
+ //Should type as JSONSchemaType<XyoBoundWitness> once ajv/eslint issue is fixed
2
+ //https://github.com/microsoft/TypeScript/issues/44851
3
+
4
+ import { XyoBoundWitnessMetaSchemaProperties } from './Meta'
5
+
6
+ const XyoBoundWitnessSchema = () => {
7
+ return {
8
+ $id: 'https://schemas.xyo.network/2.0/boundwitness',
9
+ additionalProperties: false,
10
+ properties: {
11
+ ...XyoBoundWitnessMetaSchemaProperties(),
12
+ addresses: { items: { type: 'string' }, type: 'array' },
13
+ payload_hashes: { items: { type: 'string' }, type: 'array' },
14
+ payload_schemas: { items: { type: 'string' }, type: 'array' },
15
+ previous_hashes: { items: { nullable: true, type: 'string' }, type: 'array' },
16
+ schema: { type: 'string' },
17
+ },
18
+ required: ['addresses', 'payload_hashes', 'payload_schemas', 'previous_hashes', 'schema'],
19
+ type: 'object',
20
+ }
21
+ }
22
+
23
+ export { XyoBoundWitnessSchema }
@@ -0,0 +1,5 @@
1
+ export * from './Base'
2
+ export * from './Meta'
3
+ export * from './WithXyoBoundWitnessMeta'
4
+ export * from './XyoBoundWitness'
5
+ export * from './XyoBoundWitnessSchema'