@eluvio/elv-client-js 4.0.85 → 4.0.87

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 (39) hide show
  1. package/dist/ElvClient-min.js +12 -13
  2. package/dist/ElvClient-node-min.js +13 -14
  3. package/dist/ElvFrameClient-min.js +9 -9
  4. package/dist/ElvPermissionsClient-min.js +10 -10
  5. package/dist/ElvWalletClient-min.js +13 -14
  6. package/dist/ElvWalletClient-node-min.js +13 -14
  7. package/dist/src/AuthorizationClient.js +5 -4
  8. package/dist/src/Crypto.js +2 -2
  9. package/dist/src/ElvClient.js +2 -2
  10. package/dist/src/EthClient.js +2 -2
  11. package/dist/src/FrameClient.js +3 -3
  12. package/dist/src/PermissionsClient.js +2 -2
  13. package/dist/src/Utils.js +2 -2
  14. package/dist/src/abr_profiles/abr_profile_live_to_vod.js +0 -7
  15. package/dist/src/client/ABRPublishing.js +2 -2
  16. package/dist/src/client/AccessGroups.js +2 -2
  17. package/dist/src/client/ContentAccess.js +757 -821
  18. package/dist/src/client/ContentManagement.js +6 -59
  19. package/dist/src/client/Contracts.js +2 -2
  20. package/dist/src/client/Files.js +2 -2
  21. package/dist/src/client/LiveConf.js +35 -144
  22. package/dist/src/client/LiveStream.js +529 -1054
  23. package/dist/src/client/NFT.js +2 -2
  24. package/dist/src/walletClient/ClientMethods.js +2 -2
  25. package/dist/src/walletClient/Profile.js +2 -2
  26. package/dist/src/walletClient/Utils.js +2 -2
  27. package/dist/src/walletClient/index.js +2 -2
  28. package/package.json +1 -1
  29. package/src/ContentObjectAudit.js +98 -0
  30. package/src/ElvClient.js +86 -83
  31. package/src/FrameClient.js +2 -1
  32. package/src/HttpClient.js +36 -4
  33. package/src/RemoteSigner.js +54 -0
  34. package/src/client/ContentAccess.js +17 -14
  35. package/src/client/ContentManagement.js +0 -1
  36. package/src/client/LiveConf.js +13 -13
  37. package/src/client/LiveStream.js +40 -12
  38. package/src/walletClient/index.js +40 -13
  39. package/src/ContentObjectVerification.js +0 -210
@@ -157,7 +157,7 @@ class LiveConf {
157
157
  recordingBitrate: Math.max(this.probeData.streams[index].bit_rate, 128000),
158
158
  recordingChannels: this.probeData.streams[index].channels,
159
159
  playoutLabel: `Audio ${index}`
160
- }
160
+ };
161
161
  }
162
162
  }
163
163
  return audioStreams;
@@ -232,13 +232,13 @@ class LiveConf {
232
232
  return seg;
233
233
  }
234
234
 
235
- /*
235
+ /*
236
236
  * Calculate output timebase from the encoder (codec) timebase. The videoTimeBase parameter
237
237
  * represents the encoder timebase. The format muxer will change it so it is greater than 10000.
238
238
  */
239
239
  calcOutputTimebase(codecTimebase) {
240
240
  let outputTimebase = codecTimebase;
241
- while (outputTimebase < 10000)
241
+ while(outputTimebase < 10000)
242
242
  outputTimebase = outputTimebase * 2;
243
243
  return outputTimebase;
244
244
  }
@@ -382,36 +382,36 @@ class LiveConf {
382
382
  return sync_id;
383
383
  }
384
384
 
385
- /*
385
+ /*
386
386
  * Generate audio streams recording configuration based on the optional custom settings.
387
387
  * If no custom "audio" section is present, record all the acceptable audio streams found in the probe
388
388
  */
389
389
  generateAudioStreamsConfig({customSettings}) {
390
390
 
391
391
  let audioStreams = {};
392
- if (customSettings && customSettings.audio) {
393
- for (let i = 0; i < Object.keys(customSettings.audio).length; i ++) {
392
+ if(customSettings && customSettings.audio) {
393
+ for(let i = 0; i < Object.keys(customSettings.audio).length; i ++) {
394
394
  let audioIdx = Object.keys(customSettings.audio)[i];
395
395
  let audio = customSettings.audio[audioIdx];
396
396
  audioStreams[audioIdx] = {
397
397
  recordingBitrate: audio.recording_bitrate || 192000,
398
398
  recordingChannels: audio.recording_channels || 2,
399
399
  };
400
- if (audio.playout) {
401
- audioStreams[audioIdx].playoutLabel = audio.playout_label || `Audio ${audioIdx}`
400
+ if(audio.playout) {
401
+ audioStreams[audioIdx].playoutLabel = audio.playout_label || `Audio ${audioIdx}`;
402
402
  }
403
403
  }
404
404
  }
405
405
 
406
406
  // If no audio streams specified in custom config, set up all the suitable audio streams in the probe
407
- if (!customSettings.audio) {
407
+ if(!customSettings.audio) {
408
408
  audioStreams = this.getAudioStreamsFromProbe();
409
409
  }
410
410
 
411
411
  return audioStreams;
412
412
  }
413
413
 
414
- /*
414
+ /*
415
415
  * Generate the live recording config as required by QFAB, based on defaults and optional custom settings.
416
416
  */
417
417
  generateLiveConf({customSettings}) {
@@ -439,7 +439,7 @@ class LiveConf {
439
439
  conf.live_recording.recording_config.recording_params.xc_params.enc_height = videoStream.height;
440
440
  conf.live_recording.recording_config.recording_params.xc_params.enc_width = videoStream.width;
441
441
 
442
- for (let i =0; i < Object.keys(audioStreams).length; i ++) {
442
+ for(let i =0; i < Object.keys(audioStreams).length; i ++) {
443
443
  conf.live_recording.recording_config.recording_params.xc_params.audio_index[i] = parseInt(Object.keys(audioStreams)[i]);
444
444
  }
445
445
 
@@ -549,7 +549,7 @@ class LiveConf {
549
549
  let globalAudioBitrate = 0;
550
550
  let nAudio = 0;
551
551
 
552
- for (let i = 0; i < Object.keys(audioStreams).length; i ++ ) {
552
+ for(let i = 0; i < Object.keys(audioStreams).length; i ++ ) {
553
553
  let audioLadderSpec = {...LadderSpecAudio};
554
554
  const audioIndex = Object.keys(audioStreams)[i];
555
555
  const audio = audioStreams[audioIndex];
@@ -561,7 +561,7 @@ class LiveConf {
561
561
  audioLadderSpec.stream_label = audio.playoutLabel ? audio.playoutLabel : null;
562
562
 
563
563
  conf.live_recording.recording_config.recording_params.ladder_specs.push(audioLadderSpec);
564
- if (audio.recordingBitrate > globalAudioBitrate) {
564
+ if(audio.recordingBitrate > globalAudioBitrate) {
565
565
  globalAudioBitrate = audio.recordingBitrate;
566
566
  }
567
567
  nAudio ++;
@@ -10,6 +10,7 @@ const fs = require("fs");
10
10
  const HttpClient = require("../HttpClient");
11
11
  const Fraction = require("fraction.js");
12
12
  const {ValidateObject, ValidatePresence} = require("../Validation");
13
+ const ContentObjectAudit = require("../ContentObjectAudit");
13
14
 
14
15
  const MakeTxLessToken = async({client, libraryId, objectId, versionHash}) => {
15
16
  const tok = await client.authClient.AuthorizationToken({libraryId, objectId,
@@ -29,18 +30,18 @@ const CueInfo = async ({eventId, status}) => {
29
30
  const lroStatusResponse = await this.utils.ResponseToJson(
30
31
  await HttpClient.Fetch(status.lro_status_url)
31
32
  );
32
- console.log("lroStatusResponse", lroStatusResponse)
33
+ console.log("lroStatusResponse", lroStatusResponse);
33
34
  cues = lroStatusResponse.custom.cues;
34
- } catch (error) {
35
+ } catch(error) {
35
36
  console.log("LRO status failed", error);
36
37
  return {error: "failed to retrieve status", eventId};
37
38
  }
38
39
 
39
40
  let eventStart, eventEnd;
40
- for (const value of Object.values(cues)) {
41
- for (const event of Object.values(value.descriptors)) {
42
- if (event.id == eventId) {
43
- switch (event.type_id) {
41
+ for(const value of Object.values(cues)) {
42
+ for(const event of Object.values(value.descriptors)) {
43
+ if(event.id == eventId) {
44
+ switch(event.type_id) {
44
45
  case 32:
45
46
  case 16:
46
47
  eventStart = value.insertion_time;
@@ -56,7 +57,7 @@ const CueInfo = async ({eventId, status}) => {
56
57
  }
57
58
 
58
59
  return {eventStart, eventEnd, eventId};
59
- }
60
+ };
60
61
 
61
62
  /**
62
63
  * Set the offering for the live stream
@@ -445,7 +446,7 @@ exports.StreamStatus = async function({name, stopLro=false, showParams=false}) {
445
446
  let videoLastFinalizationTimeEpochSec = -1;
446
447
  let videoFinalizedParts = 0;
447
448
  let sinceLastFinalize = -1;
448
- if (period.finalized_parts_info && period.finalized_parts_info.video && period.finalized_parts_info.video.last_finalization_time) {
449
+ if(period.finalized_parts_info && period.finalized_parts_info.video && period.finalized_parts_info.video.last_finalization_time) {
449
450
  videoLastFinalizationTimeEpochSec = period.finalized_parts_info.video.last_finalization_time / 1000000;
450
451
  videoFinalizedParts = period.finalized_parts_info.video.n_parts;
451
452
  sinceLastFinalize = Math.floor(new Date().getTime() / 1000) - videoLastFinalizationTimeEpochSec;
@@ -733,7 +734,7 @@ exports.StreamCreate = async function({name, start=false}) {
733
734
  */
734
735
  exports.StreamStartOrStopOrReset = async function({name, op}) {
735
736
  try {
736
- let status = await this.StreamStatus({name})
737
+ let status = await this.StreamStatus({name});
737
738
  if(status.state != "stopped") {
738
739
  if(op === "start") {
739
740
  status.error = "Unable to start stream - state: " + status.state;
@@ -860,7 +861,7 @@ exports.StreamStopSession = async function({name}) {
860
861
  return {
861
862
  state: status.state,
862
863
  error: "The stream must be stopped before terminating"
863
- }
864
+ };
864
865
  }
865
866
 
866
867
  await this.DeleteWriteToken({
@@ -1355,7 +1356,10 @@ exports.StreamConfig = async function({name, customSettings={}, probeMetadata})
1355
1356
  status.error = "No node matching stream URL " + streamUrl.href;
1356
1357
  return status;
1357
1358
  }
1358
- const node = nodes[0];
1359
+ const node = {
1360
+ endpoints: nodes[0].services.fabric_api.urls,
1361
+ id: nodes[0].id
1362
+ };
1359
1363
  status.node = node;
1360
1364
  let endpoint = node.endpoints[0];
1361
1365
 
@@ -1547,7 +1551,7 @@ exports.StreamListUrls = async function({siteId}={}) {
1547
1551
  url,
1548
1552
  active: activeUrlMap[url] || false
1549
1553
  };
1550
- })
1554
+ });
1551
1555
  });
1552
1556
 
1553
1557
  return streamUrlStatus;
@@ -1934,3 +1938,27 @@ exports.StreamAddWatermark = async function({
1934
1938
 
1935
1939
  return response;
1936
1940
  };
1941
+
1942
+ /**
1943
+ * Audit the specified live stream against several content fabric nodes
1944
+ *
1945
+ * @methodGroup Live Stream
1946
+ * @namedParams
1947
+ * @param {string=} objectId - Object ID of the live stream
1948
+ * @param {string=} versionHash - Version hash of the live stream -- if not specified, latest version is returned
1949
+ * @param {string=} salt - base64-encoded byte sequence for salting the audit hash
1950
+ * @param {Array<number>=} samples - list of percentages (0.0 - <1.0) used for sampling the content part list, up to 3
1951
+ *
1952
+ * @returns {Promise<Object>} - Response describing audit results
1953
+ */
1954
+ exports.AuditStream = async function({objectId, versionHash, salt, samples}) {
1955
+ return await ContentObjectAudit.AuditContentObject({
1956
+ client: this,
1957
+ libraryId,
1958
+ objectId,
1959
+ versionHash,
1960
+ salt,
1961
+ samples,
1962
+ live: true
1963
+ });
1964
+ };
@@ -395,7 +395,15 @@ class ElvWalletClient {
395
395
  *
396
396
  * @methodGroup Login
397
397
  */
398
- LogOut() {
398
+ async LogOut() {
399
+ if(this.__authorization.nonce) {
400
+ try {
401
+ await this.client.signer.ReleaseCSAT({accessToken: this.AuthToken()});
402
+ } catch(error) {
403
+ this.Log("Failed to release token", true, error);
404
+ }
405
+ }
406
+
399
407
  this.__authorization = {};
400
408
  this.loggedIn = false;
401
409
 
@@ -410,6 +418,14 @@ class ElvWalletClient {
410
418
  }
411
419
  }
412
420
 
421
+ async TokenStatus() {
422
+ if(!this.__authorization || !this.__authorization.nonce) {
423
+ return true;
424
+ }
425
+
426
+ return await this.client.signer.CSATStatus({accessToken: this.AuthToken()});
427
+ }
428
+
413
429
  /**
414
430
  * Authenticate with an ElvWalletClient authorization token
415
431
  *
@@ -457,7 +473,7 @@ class ElvWalletClient {
457
473
  * - signingToken - Identical to `authToken`, but also includes the ability to perform arbitrary signatures with the custodial wallet. This token should be protected and should not be
458
474
  * shared with third parties.
459
475
  */
460
- async AuthenticateOAuth({idToken, tenantId, email, signerURIs, shareEmail=false}) {
476
+ async AuthenticateOAuth({idToken, tenantId, email, signerURIs, shareEmail=false, extraData={}, nonce, createRemoteToken=true, force=false}) {
461
477
  let tokenDuration = 24;
462
478
 
463
479
  if(!tenantId && this.selectedMarketplaceInfo) {
@@ -466,13 +482,21 @@ class ElvWalletClient {
466
482
  tenantId = this.selectedMarketplaceInfo.tenantId;
467
483
  }
468
484
 
469
- await this.client.SetRemoteSigner({idToken, tenantId, signerURIs, extraData: { share_email: shareEmail }, unsignedPublicAuth: true});
485
+ await this.client.SetRemoteSigner({idToken, tenantId, signerURIs, extraData: { ...extraData, share_email: shareEmail }, unsignedPublicAuth: true});
470
486
 
471
- const expiresAt = Date.now() + tokenDuration * 60 * 60 * 1000;
472
- const fabricToken = await this.client.CreateFabricToken({
473
- duration: tokenDuration * 60 * 60 * 1000,
474
- //context: email ? {usr: {email}} : {}
475
- });
487
+ let fabricToken, expiresAt;
488
+ if(createRemoteToken && this.client.signer.remoteSigner) {
489
+ expiresAt = Date.now() + 24 * 60 * 60 * 1000;
490
+ const tokenResponse = await this.client.signer.RetrieveCSAT({email, nonce, force});
491
+ fabricToken = tokenResponse.token;
492
+ nonce = tokenResponse.nonce;
493
+ } else {
494
+ expiresAt = Date.now() + tokenDuration * 60 * 60 * 1000;
495
+ fabricToken = await this.client.CreateFabricToken({
496
+ duration: tokenDuration * 60 * 60 * 1000,
497
+ context: email ? {usr: {email}} : {}
498
+ });
499
+ }
476
500
  const address = this.client.utils.FormatAddress(this.client.CurrentAccountAddress());
477
501
 
478
502
  if(!email) {
@@ -496,7 +520,8 @@ class ElvWalletClient {
496
520
  signerURIs,
497
521
  walletType: "Custodial",
498
522
  walletName: "Eluvio",
499
- register: true
523
+ register: true,
524
+ nonce
500
525
  }),
501
526
  signingToken: this.SetAuthorization({
502
527
  clusterToken: this.client.signer.authToken,
@@ -507,7 +532,8 @@ class ElvWalletClient {
507
532
  expiresAt,
508
533
  signerURIs,
509
534
  walletType: "Custodial",
510
- walletName: "Eluvio"
535
+ walletName: "Eluvio",
536
+ nonce
511
537
  })
512
538
  };
513
539
  }
@@ -568,7 +594,7 @@ class ElvWalletClient {
568
594
  return this.__authorization.fabricToken;
569
595
  }
570
596
 
571
- SetAuthorization({clusterToken, fabricToken, tenantId, address, email, expiresAt, signerURIs, walletType, walletName, register=false}) {
597
+ SetAuthorization({clusterToken, fabricToken, tenantId, address, email, expiresAt, signerURIs, walletType, walletName, nonce, register=false}) {
572
598
  address = this.client.utils.FormatAddress(address);
573
599
 
574
600
  this.__authorization = {
@@ -578,7 +604,8 @@ class ElvWalletClient {
578
604
  email,
579
605
  expiresAt,
580
606
  walletType,
581
- walletName
607
+ walletName,
608
+ nonce
582
609
  };
583
610
 
584
611
  if(clusterToken) {
@@ -1328,7 +1355,7 @@ class ElvWalletClient {
1328
1355
 
1329
1356
  if(op === "nft-claim-entitlement") {
1330
1357
  let [op, marketplace, sku, purchaseId ] = status.op.split(":");
1331
- confirmationId = purchaseId
1358
+ confirmationId = purchaseId;
1332
1359
  if(status.extra && status.extra["0"]) {
1333
1360
  address = status.extra["0"].token_addr;
1334
1361
  tokenId = status.extra["0"].token_id;
@@ -1,210 +0,0 @@
1
- const CBOR = require("cbor");
2
- const SJCL = require("sjcl");
3
- const MultiHash = require("multihashes");
4
- const DeepEqual = require("deep-equal");
5
- const Utils = require("./Utils");
6
-
7
- const ContentObjectVerification = {
8
- async VerifyContentObject({client, libraryId, objectId, versionHash}) {
9
- let response = {
10
- hash: versionHash
11
- };
12
-
13
- const partHash = Utils.DecodeVersionHash(versionHash).partHash;
14
-
15
- const qpartsResponse = await client.QParts({libraryId, objectId, partHash, format: "arrayBuffer"})
16
- .then(response => Buffer.from(response));
17
- const partVerification = ContentObjectVerification._VerifyPart({partHash: partHash, qpartsResponse: qpartsResponse});
18
-
19
- if(partVerification.valid) {
20
- response.qref = { valid: true };
21
- } else {
22
- response.qref = { valid: false, error: partVerification.error.message };
23
- }
24
-
25
- response.qref.hash = partHash;
26
-
27
- if(response.qref.valid) {
28
- // Validate Metadata
29
- const qmdHash = partVerification.cbor.QmdHash.value;
30
- const metadataPartHash = "hqp_" + MultiHash.toB58String(qmdHash.slice(1, qmdHash.length));
31
- const metadataPartResponse = await client.QParts({libraryId, objectId, partHash: metadataPartHash, format: "arrayBuffer"})
32
- .then(response => Buffer.from(response));
33
-
34
- const metadataVerification = ContentObjectVerification._VerifyPart({partHash: metadataPartHash, qpartsResponse: metadataPartResponse});
35
-
36
- if(metadataVerification.valid) {
37
- response.qmd = { valid: true };
38
- } else {
39
- response.qmd = { valid: false, error: metadataVerification.error.message };
40
- }
41
-
42
- response.qmd.hash = metadataPartHash;
43
-
44
- if(response.qmd.valid && libraryId) {
45
- // If the library ID is provided, compare some metadata in the CBOR response
46
- // to the metadata from the /meta endpoint
47
- const metadata = await client.ContentObjectMetadata({
48
- libraryId: libraryId,
49
- objectId,
50
- versionHash: partHash.replace("hqp_", "hq__")
51
- });
52
-
53
- response.qmd.check = ContentObjectVerification._VerifyMetadata({metadataCbor: metadataVerification.cbor, metadata: metadata});
54
- }
55
-
56
- // Validate Qstruct
57
-
58
- const qstructHash = partVerification.cbor.QstructHash.value;
59
- const structPartHash = "hqp_" + MultiHash.toB58String(qstructHash.slice(1, qstructHash.length));
60
- const structPartResponse = await client.QParts({libraryId, objectId, partHash: structPartHash, format: "arrayBuffer"})
61
- .then(response => Buffer.from(response));
62
- const structVerification = ContentObjectVerification._VerifyPart({partHash: structPartHash, qpartsResponse: structPartResponse});
63
-
64
- if(structVerification.valid) {
65
- response.qstruct = { valid: true };
66
- } else {
67
- response.qstruct = { valid: false, error: structVerification.error.message };
68
- }
69
-
70
- response.qstruct.hash = structPartHash;
71
-
72
- if(response.qstruct.valid) {
73
- response.qstruct.parts = ContentObjectVerification._FormatQStruct(structVerification.cbor.Parts);
74
- }
75
- }
76
-
77
- response.valid =
78
- response.qref.valid &&
79
- response.qmd.valid &&
80
- response.qstruct.valid &&
81
- (!response.qmd.check || response.qmd.check.valid);
82
-
83
- return response;
84
- },
85
-
86
- // Content verification methods //
87
-
88
- _FormatQStruct(structParts) {
89
- if(!structParts) { return []; }
90
-
91
- return structParts.map(structPart => {
92
- return {
93
- hash: "hqp_" + MultiHash.toB58String(structPart.Hash.value.slice(1, structPart.Hash.length)),
94
- size: structPart.Size
95
- };
96
- });
97
- },
98
-
99
- _Hash(thing) {
100
- function fromBits(arr) {
101
- var out = [], bl = SJCL.bitArray.bitLength(arr), i, tmp;
102
- for(i=0; i<bl/8; i++) {
103
- if((i&3) === 0) {
104
- tmp = arr[i/4];
105
- }
106
- out.push(tmp >>> 24);
107
- tmp <<= 8;
108
- }
109
- return out;
110
- }
111
-
112
- function toBits(bytes) {
113
- var out = [], i, tmp=0;
114
- for(i=0; i<bytes.length; i++) {
115
- tmp = tmp << 8 | bytes[i];
116
- if((i&3) === 3) {
117
- out.push(tmp);
118
- tmp = 0;
119
- }
120
- }
121
- if(i&3) {
122
- out.push(SJCL.bitArray.partial(8*(i&3), tmp));
123
- }
124
- return out;
125
- }
126
-
127
- let digest = SJCL.hash.sha256.hash(toBits(thing));
128
- let bytes = fromBits(digest);
129
- let out = Buffer.from(bytes, "binary");
130
-
131
- return MultiHash.toB58String(MultiHash.encode(out, "sha2-256"));
132
- },
133
-
134
- _ParseCBOR(cborResponse) {
135
- let buffer = cborResponse.slice(7, cborResponse.length);
136
- let hex = buffer.toString("hex");
137
- return CBOR.decodeFirstSync(hex);
138
- },
139
-
140
- _VerifyPart({partHash, qpartsResponse}) {
141
- try {
142
- if(ContentObjectVerification._Hash(qpartsResponse) !== partHash.replace("hqp_", "")) {
143
- throw Error("Hashes do not match");
144
- }
145
-
146
- let cbor = ContentObjectVerification._ParseCBOR(qpartsResponse);
147
-
148
- return {
149
- valid: true,
150
- cbor: cbor
151
- };
152
- } catch(error) {
153
- return {
154
- valid: false,
155
- error: error
156
- };
157
- }
158
- },
159
-
160
- _VerifyMetadata({metadataCbor, metadata}) {
161
- if(!metadataCbor) { metadataCbor = {}; }
162
- if(!metadata) { metadata = {}; }
163
-
164
- let response = {
165
- valid: true,
166
- invalidValues: []
167
- };
168
-
169
- const cborKeys = Object.keys(metadataCbor);
170
- const metadataKeys = Object.keys(metadata);
171
-
172
- // Find any difference between top level keys
173
- const differentKeys = cborKeys
174
- .filter(x => !metadataKeys.includes(x))
175
- .concat(metadataKeys.filter(x => !cborKeys.includes(x)));
176
-
177
- for(const key of differentKeys) {
178
- const cborValue = metadataCbor[key];
179
- const metadataValue = metadata[key];
180
-
181
- response.invalidValues.push({
182
- key: key,
183
- cborValue: cborValue,
184
- metadataValue: metadataValue
185
- });
186
- }
187
-
188
- // Deep comparison of up to 5 keys
189
- for(const fieldToValidate of Object.keys(metadataCbor).slice(0, 5)) {
190
- const cborValue = metadataCbor[fieldToValidate];
191
- const metadataValue = metadata[fieldToValidate];
192
-
193
- if(!DeepEqual(cborValue, metadataValue)) {
194
- response.invalidValues.push({
195
- key: fieldToValidate,
196
- cborValue: cborValue,
197
- metadataValue: metadataValue
198
- });
199
- }
200
- }
201
-
202
- if(response.invalidValues.length !== 0) {
203
- response.valid = false;
204
- }
205
-
206
- return response;
207
- },
208
- };
209
-
210
- module.exports = ContentObjectVerification;