@eluvio/elv-client-js 4.2.12 → 4.2.14

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.
@@ -619,11 +619,11 @@ var ElvWalletClient = /*#__PURE__*/function () {
619
619
  key: "AuthenticateOAuth",
620
620
  value: function () {
621
621
  var _AuthenticateOAuth = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee11(_ref8) {
622
- var idToken, tenantId, email, signerURIs, _ref8$shareEmail, shareEmail, _ref8$extraData, extraData, nonce, installId, appName, _ref8$createRemoteTok, createRemoteToken, _ref8$force, force, _ref8$tokenDuration, tokenDuration, fabricToken, refreshToken, expiresAt, tokenResponse, address, decodedToken;
622
+ var idToken, userIdCode, tenantId, email, signerURIs, _ref8$shareEmail, shareEmail, _ref8$extraData, extraData, nonce, installId, appName, _ref8$createRemoteTok, createRemoteToken, _ref8$force, force, _ref8$tokenDuration, tokenDuration, fabricToken, refreshToken, expiresAt, tokenResponse, address, decodedToken;
623
623
  return _regeneratorRuntime.wrap(function _callee11$(_context11) {
624
624
  while (1) switch (_context11.prev = _context11.next) {
625
625
  case 0:
626
- idToken = _ref8.idToken, tenantId = _ref8.tenantId, email = _ref8.email, signerURIs = _ref8.signerURIs, _ref8$shareEmail = _ref8.shareEmail, shareEmail = _ref8$shareEmail === void 0 ? false : _ref8$shareEmail, _ref8$extraData = _ref8.extraData, extraData = _ref8$extraData === void 0 ? {} : _ref8$extraData, nonce = _ref8.nonce, installId = _ref8.installId, appName = _ref8.appName, _ref8$createRemoteTok = _ref8.createRemoteToken, createRemoteToken = _ref8$createRemoteTok === void 0 ? true : _ref8$createRemoteTok, _ref8$force = _ref8.force, force = _ref8$force === void 0 ? false : _ref8$force, _ref8$tokenDuration = _ref8.tokenDuration, tokenDuration = _ref8$tokenDuration === void 0 ? 24 : _ref8$tokenDuration;
626
+ idToken = _ref8.idToken, userIdCode = _ref8.userIdCode, tenantId = _ref8.tenantId, email = _ref8.email, signerURIs = _ref8.signerURIs, _ref8$shareEmail = _ref8.shareEmail, shareEmail = _ref8$shareEmail === void 0 ? false : _ref8$shareEmail, _ref8$extraData = _ref8.extraData, extraData = _ref8$extraData === void 0 ? {} : _ref8$extraData, nonce = _ref8.nonce, installId = _ref8.installId, appName = _ref8.appName, _ref8$createRemoteTok = _ref8.createRemoteToken, createRemoteToken = _ref8$createRemoteTok === void 0 ? true : _ref8$createRemoteTok, _ref8$force = _ref8.force, force = _ref8$force === void 0 ? false : _ref8$force, _ref8$tokenDuration = _ref8.tokenDuration, tokenDuration = _ref8$tokenDuration === void 0 ? 24 : _ref8$tokenDuration;
627
627
  if (!(!tenantId && this.selectedMarketplaceInfo)) {
628
628
  _context11.next = 5;
629
629
  break;
@@ -636,6 +636,7 @@ var ElvWalletClient = /*#__PURE__*/function () {
636
636
  _context11.next = 7;
637
637
  return this.client.SetRemoteSigner({
638
638
  idToken: idToken,
639
+ userIdCode: userIdCode,
639
640
  tenantId: tenantId,
640
641
  signerURIs: signerURIs,
641
642
  extraData: _objectSpread(_objectSpread({}, extraData), {}, {
@@ -682,7 +683,7 @@ var ElvWalletClient = /*#__PURE__*/function () {
682
683
  fabricToken = _context11.sent;
683
684
  case 22:
684
685
  address = this.client.utils.FormatAddress(this.client.CurrentAccountAddress());
685
- if (email) {
686
+ if (!(!email && idToken)) {
686
687
  _context11.next = 32;
687
688
  break;
688
689
  }
@@ -1767,7 +1768,7 @@ var ElvWalletClient = /*#__PURE__*/function () {
1767
1768
  op = _status$op$split2[0],
1768
1769
  address = _status$op$split2[1],
1769
1770
  id = _status$op$split2[2];
1770
- address = address.startsWith("0x") ? Utils.FormatAddress(address) : address;
1771
+ address = address && address.startsWith("0x") ? Utils.FormatAddress(address) : address;
1771
1772
  var confirmationId, tokenId, offerId, giftId;
1772
1773
  if (op === "nft-buy") {
1773
1774
  confirmationId = id;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eluvio/elv-client-js",
3
- "version": "4.2.12",
3
+ "version": "4.2.14",
4
4
  "description": "Javascript client for the Eluvio Content Fabric",
5
5
  "main": "src/index.js",
6
6
  "author": "Kevin Talmadge",
@@ -101,6 +101,8 @@
101
101
  "@babel/cli": "^7.28.0",
102
102
  "@babel/plugin-transform-runtime": "^7.8.3",
103
103
  "@babel/preset-env": "^7.4.5",
104
+ "@eslint/eslintrc": "^3.3.3",
105
+ "@eslint/js": "^9.39.1",
104
106
  "@jsdoc/salty": "^0.2.9",
105
107
  "chai": "^4.2.0",
106
108
  "chai-as-promised": "^7.1.1",
@@ -108,7 +110,6 @@
108
110
  "colors": "^1.4.0",
109
111
  "copy-webpack-plugin": "^6.0.2",
110
112
  "eslint": "^9.32.0",
111
- "eslint-plugin-html": "^5.0.0",
112
113
  "jsdoc": "^4.0.0",
113
114
  "jsdom": "^26.1.0",
114
115
  "moment": "^2.27.0",
package/src/ElvClient.js CHANGED
@@ -838,10 +838,11 @@ class ElvClient {
838
838
  * @param {Array<string>=} signerURIs - (Only if using custom OAuth) - URIs corresponding to the key server(s) to use
839
839
  * @param {boolean=} unsignedPublicAuth=false - If specified, the client will use an unsigned static token for calls that don't require authorization (reduces remote signature calls)
840
840
  */
841
- async SetRemoteSigner({idToken, authToken, tenantId, extraData, signerURIs, unsignedPublicAuth}) {
841
+ async SetRemoteSigner({idToken, userIdCode, authToken, tenantId, extraData, signerURIs, unsignedPublicAuth}) {
842
842
  const signer = new RemoteSigner({
843
843
  signerURIs: signerURIs || this.authServiceURIs,
844
844
  idToken,
845
+ userIdCode,
845
846
  authToken,
846
847
  tenantId,
847
848
  provider: await this.ethClient.Provider(),
@@ -486,6 +486,9 @@ class FrameClient {
486
486
  "SetStaticToken",
487
487
  "SetTenantContractId",
488
488
  "SetTenantId",
489
+ "TenantAdminGroup",
490
+ "ContentAdminGroup",
491
+ "TenantUsersGroup",
489
492
  "SetVisibility",
490
493
  "SetPermission",
491
494
  "ShareInfo",
package/src/LogMessage.js CHANGED
@@ -29,4 +29,4 @@ const LogMessage = (reporter, message, error = false) => {
29
29
  console.log(standardMsg);
30
30
  };
31
31
 
32
- module.exports = {LogMessage};
32
+ module.exports = {LogMessage};
@@ -8,6 +8,7 @@ class RemoteSigner extends Ethers.Signer {
8
8
  constructor({
9
9
  signerURIs,
10
10
  idToken,
11
+ userIdCode,
11
12
  authToken,
12
13
  tenantId,
13
14
  provider,
@@ -21,6 +22,7 @@ class RemoteSigner extends Ethers.Signer {
21
22
 
22
23
  this.HttpClient = new HttpClient({uris: signerURIs});
23
24
  this.idToken = idToken;
25
+ this.userIdCode = userIdCode;
24
26
  this.tenantId = tenantId;
25
27
 
26
28
  this.authToken = authToken;
@@ -33,13 +35,25 @@ class RemoteSigner extends Ethers.Signer {
33
35
 
34
36
  async Initialize() {
35
37
  if(!this.authToken) {
38
+ let body = {
39
+ ext: this.extraLoginData || {}
40
+ };
41
+
42
+ if(this.tenantId) {
43
+ body.tid = this.tenantId;
44
+ }
45
+
46
+ if(this.userIdCode) {
47
+ body.code = this.userIdCode;
48
+ }
49
+
36
50
  const {addr, eth, token} = await Utils.ResponseToJson(
37
51
  this.HttpClient.Request({
38
- path: UrlJoin("as", "wlt", "login", "jwt"),
52
+ path: UrlJoin("as", "wlt", "login", this.userIdCode ? "code" : "jwt"),
39
53
  method: "POST",
40
- body: this.tenantId ? { tid: this.tenantId, ext: this.extraLoginData || {} } : { ext: this.extraLoginData || {} },
54
+ body,
41
55
  headers: {
42
- Authorization: `Bearer ${this.idToken}`
56
+ Authorization: `Bearer ${this.userIdCode || this.idToken}`
43
57
  }
44
58
  })
45
59
  );
@@ -323,7 +323,7 @@ exports.CreateABRMezzanine = async function({
323
323
  // determine master object id if a master write token was passed in
324
324
  ValidateWriteToken(masterWriteToken);
325
325
  masterObjectId = this.utils.DecodeWriteToken(masterWriteToken).objectId;
326
- masterLibId = await client.ContentObjectLibraryId({objectId: masterObjectId});
326
+ masterLibId = await this.ContentObjectLibraryId({objectId: masterObjectId});
327
327
  }
328
328
 
329
329
  // if pre-existing mez object id passed in, validate
@@ -597,19 +597,19 @@ exports.ContentObject = async function({objectId, versionHash, writeToken, noCac
597
597
  const id = writeToken || versionHash || objectId;
598
598
  if(noCache || !this.objectInfo[id] || Date.now() - this.objectInfo[id].retrievedAt > 30000) {
599
599
  let path = UrlJoin("q", id);
600
+ const info = await this.HttpClient.RequestJsonBody({
601
+ headers: await this.authClient.AuthorizationHeader({objectId, versionHash}),
602
+ method: "GET",
603
+ path: path,
604
+ queryParams: {
605
+ details: true,
606
+ profile: true
607
+ }
608
+ })
609
+
600
610
  this.objectInfo[id] = {
601
611
  retrievedAt: Date.now(),
602
- info: (
603
- await this.HttpClient.RequestJsonBody({
604
- headers: await this.authClient.AuthorizationHeader({objectId, versionHash}),
605
- method: "GET",
606
- path: path,
607
- queryParams: {
608
- details: true,
609
- profile: true
610
- }
611
- })
612
- )
612
+ info
613
613
  };
614
614
  }
615
615
 
@@ -1909,6 +1909,7 @@ exports.MakeFileServiceRequest = async function({
1909
1909
  * @param {string=} versionHash - Hash of the object version - if not specified, latest version will be used
1910
1910
  * @param {string=} writeToken - Write token of an object draft - if calling bitcode of a draft object
1911
1911
  * @param {string} method - Bitcode method to call
1912
+ * @param {string} verb - HTTP verb (GET, POST, PUT, DELETE, ...)
1912
1913
  * @param {Object=} queryParams - Query parameters to include in the request
1913
1914
  * @param {Object=} body - Request body to include, if calling a non-constant method
1914
1915
  * @param {Object=} headers - Request headers to include
@@ -1924,6 +1925,7 @@ exports.CallBitcodeMethod = async function({
1924
1925
  versionHash,
1925
1926
  writeToken,
1926
1927
  method,
1928
+ verb,
1927
1929
  queryParams={},
1928
1930
  body={},
1929
1931
  headers={},
@@ -1952,9 +1954,10 @@ exports.CallBitcodeMethod = async function({
1952
1954
  ).Authorization;
1953
1955
  }
1954
1956
 
1957
+ verb = verb ? verb : (constant ? "GET" : "POST");
1955
1958
  this.Log(
1956
1959
  `Calling bitcode method: ${libraryId || ""} ${objectId || versionHash} ${writeToken || ""}
1957
- ${constant ? "GET" : "POST"} ${path}
1960
+ ${verb} ${path}
1958
1961
  Query Params:
1959
1962
  ${JSON.stringify(queryParams || "")}
1960
1963
  Body:
@@ -1968,7 +1971,7 @@ exports.CallBitcodeMethod = async function({
1968
1971
  await this.HttpClient.Request({
1969
1972
  body,
1970
1973
  headers,
1971
- method: constant ? "GET" : "POST",
1974
+ method: verb,
1972
1975
  path,
1973
1976
  queryParams,
1974
1977
  allowFailover: false
@@ -2457,7 +2460,7 @@ exports.EmbedUrl = async function({
2457
2460
  embedUrl.searchParams.set("data", this.utils.B64(JSON.stringify({meta_tags: data})));
2458
2461
  }
2459
2462
 
2460
- if(["owner", "editable", "viewable"].includes(permission)) {
2463
+ if(["owner", "editable", "viewable", "listable"].includes(permission)) {
2461
2464
  const token = await this.CreateSignedToken({
2462
2465
  objectId,
2463
2466
  versionHash,
@@ -785,7 +785,6 @@ exports.SetTenantContractId = async function({contractAddress, objectId, version
785
785
  if(tenantContractId && (!tenantContractId.startsWith("iten") || !Utils.ValidHash(tenantContractId))) {
786
786
  throw Error(`Invalid tenant ID: ${tenantContractId}`);
787
787
  }
788
- const tenantAddress = Utils.HashToAddress(tenantContractId);
789
788
 
790
789
  const version = await this.authClient.AccessType(tenantContractId);
791
790
  if(version !== this.authClient.ACCESS_TYPES.TENANT) {
@@ -793,12 +792,7 @@ exports.SetTenantContractId = async function({contractAddress, objectId, version
793
792
  }
794
793
 
795
794
  // get tenant admin group
796
- const tenantAdminGroupAddress = await this.CallContractMethod({
797
- contractAddress: tenantAddress,
798
- methodName: "groupsMapping",
799
- methodArgs: ["tenant_admin", 0],
800
- formatArguments: true,
801
- });
795
+ const tenantAdminGroupAddress = await this.TenantAdminGroup({tenantContractId});
802
796
 
803
797
  const hasPutMetaMethod = await this.authClient.ContractHasMethod({
804
798
  contractAddress: contractAddress,
@@ -928,6 +922,93 @@ exports.ResetTenantId = async function({contractAddress, objectId, versionHash})
928
922
  }
929
923
  };
930
924
 
925
+ async function GetTenantGroupAddress({ctx, tenantContractId, groupName}) {
926
+ if(!tenantContractId) {
927
+ throw new Error("tenantContractId is required");
928
+ }
929
+
930
+ if(!tenantContractId.startsWith("iten")) {
931
+ throw new Error(`Invalid Tenant Contract ID format: ${tenantContractId}`);
932
+ }
933
+
934
+ const tenantAddress = Utils.HashToAddress(tenantContractId);
935
+
936
+ // Needs to be tenant type
937
+ const version = await ctx.authClient.AccessType(tenantContractId);
938
+ if(version !== ctx.authClient.ACCESS_TYPES.TENANT) {
939
+ throw new Error(
940
+ `Contract ${tenantContractId} is not a Tenant. Actual version: ${version}`
941
+ );
942
+ }
943
+
944
+ try {
945
+ const groupAddress = await ctx.CallContractMethod({
946
+ contractAddress: tenantAddress,
947
+ methodName: "groupsMapping",
948
+ methodArgs: [groupName, 0],
949
+ formatArguments: true,
950
+ });
951
+
952
+ if (!groupAddress) {
953
+ throw new Error(`${groupName} group address not set.`);
954
+ }
955
+
956
+ return groupAddress;
957
+ } catch (err) {
958
+ this.Log(err);
959
+ throw new Error(`Failed to retrieve ${groupName} group address.`);
960
+ }
961
+
962
+ }
963
+
964
+ /**
965
+ * Returns the tenant_admin group address for a given tenant contract.
966
+ *
967
+ * @methodGroup Tenant
968
+ * @namedParams
969
+ * @param {string=} tenantContractId - The ID of the tenant contract
970
+ * @returns {Promise<*|undefined>}
971
+ */
972
+ exports.TenantAdminGroup = async function({ tenantContractId }) {
973
+ return GetTenantGroupAddress({
974
+ ctx : this,
975
+ tenantContractId,
976
+ groupName: "tenant_admin"
977
+ });
978
+ };
979
+
980
+ /**
981
+ * Returns the content_admin group address for a given tenant contract.
982
+ *
983
+ * @methodGroup Tenant
984
+ * @namedParams
985
+ * @param {string=} tenantContractId - The ID of the tenant contract
986
+ * @returns {Promise<*|undefined>}
987
+ */
988
+ exports.ContentAdminGroup = async function({tenantContractId}){
989
+ return GetTenantGroupAddress({
990
+ ctx : this,
991
+ tenantContractId,
992
+ groupName: "content_admin"
993
+ });
994
+ };
995
+
996
+ /**
997
+ * Returns the tenant_users group address for a given tenant contract.
998
+ *
999
+ * @methodGroup Tenant
1000
+ * @namedParams
1001
+ * @param {string=} tenantContractId - The ID of the tenant contract
1002
+ * @returns {Promise<*|undefined>}
1003
+ */
1004
+ exports.TenantUsersGroup = async function({tenantContractId}){
1005
+ return GetTenantGroupAddress({
1006
+ ctx : this,
1007
+ tenantContractId,
1008
+ groupName: "tenant_users"
1009
+ });
1010
+ };
1011
+
931
1012
  /**
932
1013
  * Enum for object types that can be cleaned up after object deletion.
933
1014
  * Used by the ObjectCleanup method to determine which associated objects to clean.
@@ -476,6 +476,7 @@ class ElvWalletClient {
476
476
  */
477
477
  async AuthenticateOAuth({
478
478
  idToken,
479
+ userIdCode,
479
480
  tenantId,
480
481
  email,
481
482
  signerURIs,
@@ -494,7 +495,17 @@ class ElvWalletClient {
494
495
  tenantId = this.selectedMarketplaceInfo.tenantId;
495
496
  }
496
497
 
497
- await this.client.SetRemoteSigner({idToken, tenantId, signerURIs, extraData: { ...extraData, share_email: shareEmail }, unsignedPublicAuth: true});
498
+ await this.client.SetRemoteSigner({
499
+ idToken,
500
+ userIdCode,
501
+ tenantId,
502
+ signerURIs,
503
+ extraData: {
504
+ ...extraData,
505
+ share_email: shareEmail
506
+ },
507
+ unsignedPublicAuth: true
508
+ });
498
509
 
499
510
  let fabricToken, refreshToken, expiresAt;
500
511
  if(createRemoteToken && this.client.signer.remoteSigner) {
@@ -511,9 +522,9 @@ class ElvWalletClient {
511
522
  context: email ? {usr: {email}} : {}
512
523
  });
513
524
  }
514
- const address = this.client.utils.FormatAddress(this.client.CurrentAccountAddress());
515
525
 
516
- if(!email) {
526
+ const address = this.client.utils.FormatAddress(this.client.CurrentAccountAddress());
527
+ if(!email && idToken) {
517
528
  try {
518
529
  const decodedToken = JSON.parse(this.utils.FromB64URL(idToken.split(".")[1]));
519
530
  email = decodedToken.email;
@@ -1253,7 +1264,7 @@ class ElvWalletClient {
1253
1264
  return response
1254
1265
  .map(status => {
1255
1266
  let [op, address, id] = status.op.split(":");
1256
- address = address.startsWith("0x") ? Utils.FormatAddress(address) : address;
1267
+ address = address && address.startsWith("0x") ? Utils.FormatAddress(address) : address;
1257
1268
 
1258
1269
  let confirmationId, tokenId, offerId, giftId;
1259
1270
  if(op === "nft-buy") {
@@ -1,281 +0,0 @@
1
- var _regeneratorRuntime = require("@babel/runtime/regenerator");
2
- var _asyncToGenerator = require("@babel/runtime/helpers/asyncToGenerator");
3
- function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
4
- function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
5
- function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
6
- var CBOR = require("cbor");
7
- var SJCL = require("sjcl");
8
- var MultiHash = require("multihashes");
9
- var DeepEqual = require("deep-equal");
10
- var Utils = require("./Utils");
11
- var ContentObjectVerification = {
12
- VerifyContentObject: function VerifyContentObject(_ref) {
13
- return _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
14
- var client, libraryId, objectId, versionHash, response, partHash, qpartsResponse, partVerification, qmdHash, metadataPartHash, metadataPartResponse, metadataVerification, metadata, qstructHash, structPartHash, structPartResponse, structVerification;
15
- return _regeneratorRuntime.wrap(function _callee$(_context) {
16
- while (1) switch (_context.prev = _context.next) {
17
- case 0:
18
- client = _ref.client, libraryId = _ref.libraryId, objectId = _ref.objectId, versionHash = _ref.versionHash;
19
- response = {
20
- hash: versionHash
21
- };
22
- partHash = Utils.DecodeVersionHash(versionHash).partHash;
23
- _context.next = 5;
24
- return client.QParts({
25
- libraryId: libraryId,
26
- objectId: objectId,
27
- partHash: partHash,
28
- format: "arrayBuffer"
29
- }).then(function (response) {
30
- return Buffer.from(response);
31
- });
32
- case 5:
33
- qpartsResponse = _context.sent;
34
- partVerification = ContentObjectVerification._VerifyPart({
35
- partHash: partHash,
36
- qpartsResponse: qpartsResponse
37
- });
38
- if (partVerification.valid) {
39
- response.qref = {
40
- valid: true
41
- };
42
- } else {
43
- response.qref = {
44
- valid: false,
45
- error: partVerification.error.message
46
- };
47
- }
48
- response.qref.hash = partHash;
49
- if (!response.qref.valid) {
50
- _context.next = 32;
51
- break;
52
- }
53
- // Validate Metadata
54
- qmdHash = partVerification.cbor.QmdHash.value;
55
- metadataPartHash = "hqp_" + MultiHash.toB58String(qmdHash.slice(1, qmdHash.length));
56
- _context.next = 14;
57
- return client.QParts({
58
- libraryId: libraryId,
59
- objectId: objectId,
60
- partHash: metadataPartHash,
61
- format: "arrayBuffer"
62
- }).then(function (response) {
63
- return Buffer.from(response);
64
- });
65
- case 14:
66
- metadataPartResponse = _context.sent;
67
- metadataVerification = ContentObjectVerification._VerifyPart({
68
- partHash: metadataPartHash,
69
- qpartsResponse: metadataPartResponse
70
- });
71
- if (metadataVerification.valid) {
72
- response.qmd = {
73
- valid: true
74
- };
75
- } else {
76
- response.qmd = {
77
- valid: false,
78
- error: metadataVerification.error.message
79
- };
80
- }
81
- response.qmd.hash = metadataPartHash;
82
- if (!(response.qmd.valid && libraryId)) {
83
- _context.next = 23;
84
- break;
85
- }
86
- _context.next = 21;
87
- return client.ContentObjectMetadata({
88
- libraryId: libraryId,
89
- objectId: objectId,
90
- versionHash: partHash.replace("hqp_", "hq__")
91
- });
92
- case 21:
93
- metadata = _context.sent;
94
- response.qmd.check = ContentObjectVerification._VerifyMetadata({
95
- metadataCbor: metadataVerification.cbor,
96
- metadata: metadata
97
- });
98
- case 23:
99
- // Validate Qstruct
100
- qstructHash = partVerification.cbor.QstructHash.value;
101
- structPartHash = "hqp_" + MultiHash.toB58String(qstructHash.slice(1, qstructHash.length));
102
- _context.next = 27;
103
- return client.QParts({
104
- libraryId: libraryId,
105
- objectId: objectId,
106
- partHash: structPartHash,
107
- format: "arrayBuffer"
108
- }).then(function (response) {
109
- return Buffer.from(response);
110
- });
111
- case 27:
112
- structPartResponse = _context.sent;
113
- structVerification = ContentObjectVerification._VerifyPart({
114
- partHash: structPartHash,
115
- qpartsResponse: structPartResponse
116
- });
117
- if (structVerification.valid) {
118
- response.qstruct = {
119
- valid: true
120
- };
121
- } else {
122
- response.qstruct = {
123
- valid: false,
124
- error: structVerification.error.message
125
- };
126
- }
127
- response.qstruct.hash = structPartHash;
128
- if (response.qstruct.valid) {
129
- response.qstruct.parts = ContentObjectVerification._FormatQStruct(structVerification.cbor.Parts);
130
- }
131
- case 32:
132
- response.valid = response.qref.valid && response.qmd.valid && response.qstruct.valid && (!response.qmd.check || response.qmd.check.valid);
133
- return _context.abrupt("return", response);
134
- case 34:
135
- case "end":
136
- return _context.stop();
137
- }
138
- }, _callee);
139
- }))();
140
- },
141
- // Content verification methods //
142
- _FormatQStruct: function _FormatQStruct(structParts) {
143
- if (!structParts) {
144
- return [];
145
- }
146
- return structParts.map(function (structPart) {
147
- return {
148
- hash: "hqp_" + MultiHash.toB58String(structPart.Hash.value.slice(1, structPart.Hash.length)),
149
- size: structPart.Size
150
- };
151
- });
152
- },
153
- _Hash: function _Hash(thing) {
154
- function fromBits(arr) {
155
- var out = [],
156
- bl = SJCL.bitArray.bitLength(arr),
157
- i,
158
- tmp;
159
- for (i = 0; i < bl / 8; i++) {
160
- if ((i & 3) === 0) {
161
- tmp = arr[i / 4];
162
- }
163
- out.push(tmp >>> 24);
164
- tmp <<= 8;
165
- }
166
- return out;
167
- }
168
- function toBits(bytes) {
169
- var out = [],
170
- i,
171
- tmp = 0;
172
- for (i = 0; i < bytes.length; i++) {
173
- tmp = tmp << 8 | bytes[i];
174
- if ((i & 3) === 3) {
175
- out.push(tmp);
176
- tmp = 0;
177
- }
178
- }
179
- if (i & 3) {
180
- out.push(SJCL.bitArray.partial(8 * (i & 3), tmp));
181
- }
182
- return out;
183
- }
184
- var digest = SJCL.hash.sha256.hash(toBits(thing));
185
- var bytes = fromBits(digest);
186
- var out = Buffer.from(bytes, "binary");
187
- return MultiHash.toB58String(MultiHash.encode(out, "sha2-256"));
188
- },
189
- _ParseCBOR: function _ParseCBOR(cborResponse) {
190
- var buffer = cborResponse.slice(7, cborResponse.length);
191
- var hex = buffer.toString("hex");
192
- return CBOR.decodeFirstSync(hex);
193
- },
194
- _VerifyPart: function _VerifyPart(_ref2) {
195
- var partHash = _ref2.partHash,
196
- qpartsResponse = _ref2.qpartsResponse;
197
- try {
198
- if (ContentObjectVerification._Hash(qpartsResponse) !== partHash.replace("hqp_", "")) {
199
- throw Error("Hashes do not match");
200
- }
201
- var cbor = ContentObjectVerification._ParseCBOR(qpartsResponse);
202
- return {
203
- valid: true,
204
- cbor: cbor
205
- };
206
- } catch (error) {
207
- return {
208
- valid: false,
209
- error: error
210
- };
211
- }
212
- },
213
- _VerifyMetadata: function _VerifyMetadata(_ref3) {
214
- var metadataCbor = _ref3.metadataCbor,
215
- metadata = _ref3.metadata;
216
- if (!metadataCbor) {
217
- metadataCbor = {};
218
- }
219
- if (!metadata) {
220
- metadata = {};
221
- }
222
- var response = {
223
- valid: true,
224
- invalidValues: []
225
- };
226
- var cborKeys = Object.keys(metadataCbor);
227
- var metadataKeys = Object.keys(metadata);
228
-
229
- // Find any difference between top level keys
230
- var differentKeys = cborKeys.filter(function (x) {
231
- return !metadataKeys.includes(x);
232
- }).concat(metadataKeys.filter(function (x) {
233
- return !cborKeys.includes(x);
234
- }));
235
- var _iterator = _createForOfIteratorHelper(differentKeys),
236
- _step;
237
- try {
238
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
239
- var key = _step.value;
240
- var cborValue = metadataCbor[key];
241
- var metadataValue = metadata[key];
242
- response.invalidValues.push({
243
- key: key,
244
- cborValue: cborValue,
245
- metadataValue: metadataValue
246
- });
247
- }
248
-
249
- // Deep comparison of up to 5 keys
250
- } catch (err) {
251
- _iterator.e(err);
252
- } finally {
253
- _iterator.f();
254
- }
255
- var _iterator2 = _createForOfIteratorHelper(Object.keys(metadataCbor).slice(0, 5)),
256
- _step2;
257
- try {
258
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
259
- var fieldToValidate = _step2.value;
260
- var _cborValue = metadataCbor[fieldToValidate];
261
- var _metadataValue = metadata[fieldToValidate];
262
- if (!DeepEqual(_cborValue, _metadataValue)) {
263
- response.invalidValues.push({
264
- key: fieldToValidate,
265
- cborValue: _cborValue,
266
- metadataValue: _metadataValue
267
- });
268
- }
269
- }
270
- } catch (err) {
271
- _iterator2.e(err);
272
- } finally {
273
- _iterator2.f();
274
- }
275
- if (response.invalidValues.length !== 0) {
276
- response.valid = false;
277
- }
278
- return response;
279
- }
280
- };
281
- module.exports = ContentObjectVerification;