@eluvio/elv-client-js 3.1.92 → 3.1.95

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 (35) hide show
  1. package/dist/ElvClient-min.js +15 -11
  2. package/dist/ElvClient-node-min.js +17 -13
  3. package/dist/ElvFrameClient-min.js +13 -9
  4. package/dist/ElvPermissionsClient-min.js +13 -9
  5. package/dist/src/AuthorizationClient.js +2248 -1990
  6. package/dist/src/ContentObjectVerification.js +164 -173
  7. package/dist/src/Crypto.js +376 -324
  8. package/dist/src/ElvClient.js +1214 -938
  9. package/dist/src/ElvWallet.js +119 -95
  10. package/dist/src/EthClient.js +1040 -896
  11. package/dist/src/FrameClient.js +331 -300
  12. package/dist/src/HttpClient.js +153 -147
  13. package/dist/src/Id.js +1 -3
  14. package/dist/src/PermissionsClient.js +1294 -1168
  15. package/dist/src/RemoteSigner.js +260 -200
  16. package/dist/src/UserProfileClient.js +1168 -1014
  17. package/dist/src/Utils.js +382 -178
  18. package/dist/src/client/ABRPublishing.js +895 -856
  19. package/dist/src/client/AccessGroups.js +1102 -959
  20. package/dist/src/client/ContentAccess.js +3737 -3427
  21. package/dist/src/client/ContentManagement.js +2255 -2063
  22. package/dist/src/client/Contracts.js +647 -563
  23. package/dist/src/client/Files.js +1886 -1757
  24. package/dist/src/client/NFT.js +127 -158
  25. package/dist/src/client/NTP.js +478 -422
  26. package/package.json +2 -1
  27. package/src/ElvClient.js +62 -1
  28. package/src/RemoteSigner.js +22 -18
  29. package/src/Utils.js +119 -0
  30. package/src/client/ABRPublishing.js +2 -1
  31. package/src/client/NFT.js +14 -49
  32. package/testScripts/Test.js +0 -19
  33. package/testScripts/VariantABRProfile.js +45 -0
  34. package/utilities/SimpleIngest.js +245 -0
  35. package/package-lock.json +0 -12650
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eluvio/elv-client-js",
3
- "version": "3.1.92",
3
+ "version": "3.1.95",
4
4
  "description": "Javascript client for the Eluvio Content Fabric",
5
5
  "main": "src/ElvClient.js",
6
6
  "author": "Kevin Talmadge",
@@ -57,6 +57,7 @@
57
57
  "dependencies": {
58
58
  "@babel/runtime": "^7.8.4",
59
59
  "@eluvio/crypto": ">=1.0.8",
60
+ "@eluvio/elv-abr-profile": "^0.2.0",
60
61
  "@sindresorhus/slugify": "^1.1.0",
61
62
  "babel-loader": "^8.0.6",
62
63
  "bignumber.js": "^8.0.2",
package/src/ElvClient.js CHANGED
@@ -694,6 +694,67 @@ class ElvClient {
694
694
  return this.utils.FormatAddress(this.signer.address);
695
695
  }
696
696
 
697
+ /*
698
+ TOKEN 211b PREFIX + BODY | aplsjcJf1HYcDDUuCdXcSZtU86nYK162YmYJeuqwMczEBJVkD5D5EvsBvVwYDRsf4hzDvBWMoe9piBpqx...
699
+ PREFIX 6b aplsjc | apl=plain s=ES256K jc=json-compressed
700
+ BODY 205b base58(SIGNATURE + PAYLOAD)
701
+ SIGNATURE + PAYLOAD 151b 151b * 138 / 100 + 1 = 209b (>= 205b)
702
+ SIGNATURE 66b ES256K_Di9Lu83mz4wMoehCEeQhKpJJ7ApmDZLumAa2Cge48F6EHYnbn8msATGGpjucScwimei1TWGd7aeyQY45AdXd5tT1Z
703
+ PAYLOAD 85b json-compressed
704
+ json 79b {"adr":"VVf4DQU357tDnZGYQeDrntRJ5rs=","spc":"ispc3ANoVSzNA3P6t7abLR69ho5YPPZU"}
705
+ */
706
+
707
+ /**
708
+ * Create a signed authorization token that can be used to authorize against the fabric
709
+ *
710
+ * @methodGroup Authorization
711
+ * @namedParams
712
+ * @param {number} duration=86400000 - Time until the token expires, in milliseconds (1 hour = 60 * 60 * 1000 = 3600000). Default is 24 hours.
713
+ * @param {Object=} spec - Additional attributes for this token
714
+ * @param {string=} address - Address of the signing account - if not specified, the current signer address will be used.
715
+ * @param {function=} Sign - If specified, this function will be used to produce the signature instead of the client's current signer
716
+ * @param {boolean=} addEthereumPrefix=true - If specified, the 'Ethereum Signed Message' prefixed hash format will be performed. Disable this if the provided Sign method already does this (e.g. Metamask)
717
+ */
718
+ async CreateFabricToken({
719
+ duration=24 * 60 * 60 * 1000,
720
+ spec={},
721
+ address,
722
+ Sign,
723
+ addEthereumPrefix=true,
724
+ }={}) {
725
+ address = address || this.CurrentAccountAddress();
726
+
727
+ let token = {
728
+ ...spec,
729
+ sub:`iusr${Utils.AddressToHash(address)}`,
730
+ adr: Buffer.from(address.replace(/^0x/, ""), "hex").toString("base64"),
731
+ spc: await this.ContentSpaceId(),
732
+ iat: Date.now(),
733
+ exp: Date.now() + duration,
734
+ };
735
+
736
+ if(!Sign) {
737
+ Sign = async message => this.authClient.Sign(message);
738
+ }
739
+
740
+ let message = `Eluvio Content Fabric Access Token 1.0\n${JSON.stringify(token)}`;
741
+
742
+ if(addEthereumPrefix) {
743
+ message = Ethers.utils.keccak256(Buffer.from(`\x19Ethereum Signed Message:\n${message.length}${message}`, "utf-8"));
744
+ }
745
+
746
+ const signature = await Sign(message);
747
+
748
+ const compressedToken = Pako.deflateRaw(Buffer.from(JSON.stringify(token), "utf-8"));
749
+ return `acspjc${this.utils.B58(
750
+ Buffer.concat([
751
+ Buffer.from(signature.replace(/^0x/, ""), "hex"),
752
+ Buffer.from(compressedToken)
753
+ ])
754
+ )}`;
755
+ }
756
+
757
+
697
758
  /**
698
759
  * Issue a self-signed authorization token
699
760
  *
@@ -705,7 +766,7 @@ class ElvClient {
705
766
  * @param {string=} policyId - The object ID of the policy for this token
706
767
  * @param {string=} subject - The subject of the token
707
768
  * @param {string} grantType=read - Permissions to grant for this token. Options: "access", "read", "create", "update", "read-crypt"
708
- * @param {number} duration - Time until the token expires, in milliseconds (1 hour = 60 * 60 * 1000)
769
+ * @param {number} duration - Time until the token expires, in milliseconds (1 hour = 60 * 60 * 1000 = 3600000)
709
770
  * @param {boolean} allowDecryption=false - If specified, the re-encryption key will be included in the token,
710
771
  * enabling the user of this token to download encrypted content from the specified object
711
772
  * @param {Object=} context - Additional JSON context
@@ -85,24 +85,28 @@ class RemoteSigner extends Ethers.Signer {
85
85
  */
86
86
  async signDigest(digest) {
87
87
  if(!this.signatureCache[digest]) {
88
- this.signatureCache[digest] = new Promise(async resolve => {
89
- let signature = await Utils.ResponseToJson(
90
- this.HttpClient.Request({
91
- method: "POST",
92
- path: UrlJoin("as", "wlt", "sign", "eth", this.id),
93
- headers: {
94
- Authorization: `Bearer ${this.authToken}`
95
- },
96
- body: {
97
- hash: digest
98
- }
99
- })
100
- );
101
-
102
- signature.v = parseInt(signature.v, 16);
103
- signature.recoveryParam = signature.v - 27;
104
-
105
- resolve(signature);
88
+ this.signatureCache[digest] = new Promise(async (resolve, reject) => {
89
+ try {
90
+ let signature = await Utils.ResponseToJson(
91
+ this.HttpClient.Request({
92
+ method: "POST",
93
+ path: UrlJoin("as", "wlt", "sign", "eth", this.id),
94
+ headers: {
95
+ Authorization: `Bearer ${this.authToken}`
96
+ },
97
+ body: {
98
+ hash: digest
99
+ }
100
+ })
101
+ );
102
+
103
+ signature.v = parseInt(signature.v, 16);
104
+ signature.recoveryParam = signature.v - 27;
105
+
106
+ resolve(signature);
107
+ } catch(error) {
108
+ reject(error);
109
+ }
106
110
  });
107
111
  }
108
112
 
package/src/Utils.js CHANGED
@@ -150,6 +150,125 @@ const Utils = {
150
150
  };
151
151
  },
152
152
 
153
+ /**
154
+ * Decode the specified write token into its component parts
155
+ *
156
+ * @param writeToken
157
+ *
158
+ * @returns {Object} - Components of the write token.
159
+ */
160
+ DecodeWriteToken: (writeToken) => {
161
+ /*
162
+ Format:
163
+ - content write token, LRO:
164
+ - prefix: "tq__", "tqw__", "tlro"
165
+ - format:
166
+ prefix + base58(uvarint(len(QID) | QID |
167
+ uvarint(len(NID) | NID |
168
+ uvarint(len(RAND_BYTES) | RAND_BYTES)
169
+ - content part write token:
170
+ - prefix: "tqp_"
171
+ - format:
172
+ prefix + base58(scheme | flags | uvarint(len(RAND_BYTES) | RAND_BYTES)
173
+ - content write token v1, content part write token v1:
174
+ - prefix: "tqw_", "tqpw"
175
+ - format:
176
+ prefix + base58(RAND_BYTES)
177
+ */
178
+
179
+ if(writeToken.length<4){
180
+ throw new Error(`Invalid write token: ["${writeToken}"] (unknown prefix)`);
181
+ }
182
+
183
+ let tokenType;
184
+
185
+ if(writeToken.startsWith("tqw__")) {
186
+ tokenType = "tq__";
187
+ writeToken = writeToken.slice(5);
188
+ } else {
189
+ tokenType = writeToken.slice(0, 4);
190
+ writeToken = writeToken.slice(4);
191
+ }
192
+ if(writeToken.length===0){
193
+ throw new Error(`Invalid write token: ["${writeToken}"] (too short)`);
194
+ }
195
+
196
+ switch(tokenType) {
197
+ case "tqw_":
198
+ case "tq__":
199
+ case "tqpw":
200
+ case "tqp_":
201
+ case "tlro":
202
+ break;
203
+ default:
204
+ throw new Error(`Invalid write token: ["${writeToken}"] (unknown prefix)`);
205
+ }
206
+
207
+ // decode base58 payload
208
+ let bytes = Utils.FromB58(writeToken);
209
+
210
+ function decodeBytes(isID, prefix) {
211
+ let bsize = VarInt.decode(bytes,0); // decode: count of bytes to read
212
+ let offset = VarInt.decode.bytes; // offset in buffer to start read after decode
213
+ let theBytes;
214
+ let ret;
215
+
216
+ if(isID) {
217
+ theBytes = bytes.slice(offset+1, bsize+offset); // skip 1st byte (code id) at offset 0
218
+ if(theBytes.length===0){
219
+ ret = "";
220
+ } else {
221
+ ret = prefix + Utils.B58(theBytes);
222
+ }
223
+ } else {
224
+ theBytes = bytes.slice(offset, bsize+offset);
225
+ ret = "0x" + theBytes.toString("hex");
226
+ }
227
+ bytes = bytes.slice(bsize+offset);
228
+ return ret;
229
+ }
230
+
231
+ let tokenId;
232
+ let qid;
233
+ let nid;
234
+ let scheme;
235
+ let flags;
236
+
237
+ switch(tokenType) {
238
+ case "tqw_": // content write token v1
239
+ case "tqpw": // content part write token v1
240
+ tokenId = "0x" + bytes.toString("hex");
241
+ break;
242
+ case "tlro": // LRO,
243
+ case "tq__": // content write token
244
+ qid = decodeBytes(true, "iq__");
245
+ nid = decodeBytes(true, "inod");
246
+ tokenId = decodeBytes(false, "");
247
+ break;
248
+ case "tqp_": // content part write token
249
+ if(bytes.length<3) {
250
+ throw new Error(`Invalid write token: ["${writeToken}"] (token truncated)`);
251
+ }
252
+ scheme=bytes[0];
253
+ flags=bytes[1];
254
+ bytes = bytes.slice(2);
255
+ tokenId = decodeBytes(false, "");
256
+ break;
257
+ default:
258
+ // already raised
259
+ throw new Error(`Invalid write token: ["${writeToken}"] (unknown prefix)`);
260
+ }
261
+
262
+ return {
263
+ tokenType: tokenType, // type of token
264
+ tokenId: tokenId, // random bytes generated by the fabric node
265
+ objectId: qid, // content id for content write token (tq__) or LRO (tlro)
266
+ nodeId: nid, // node id where the content write token is valid (tq__)
267
+ scheme, // encryption scheme for part write token - (tqp_)
268
+ flags // flags for part write token (tqp_)
269
+ };
270
+ },
271
+
153
272
  /**
154
273
  * Convert contract address to multiformat hash
155
274
  *
@@ -478,7 +478,7 @@ exports.StartABRMezzanineJobs = async function({
478
478
  metadata: lroInfo
479
479
  });
480
480
 
481
- await this.FinalizeContentObject({
481
+ const finalizeResponse = await this.FinalizeContentObject({
482
482
  libraryId,
483
483
  objectId,
484
484
  writeToken: statusDraft.write_token,
@@ -500,6 +500,7 @@ exports.StartABRMezzanineJobs = async function({
500
500
  });
501
501
 
502
502
  return {
503
+ hash: finalizeResponse.hash,
503
504
  lro_draft: lroInfo,
504
505
  writeToken: processingDraft.write_token,
505
506
  data,
package/src/client/NFT.js CHANGED
@@ -18,9 +18,8 @@ const {
18
18
  * @methodGroup Minting
19
19
  * @namedParams
20
20
  * @param {string} tenantId - The ID of the tenant
21
- * @param {string=} email - The email of the NFT recipient
22
21
  * @param {string=} address - The address of the NFT recipient
23
- * @param {string} collectionId - The ID of the NFT collection containing the NFT
22
+ * @param {string} marketplaceId - The ID of the marketplace containing the NFT
24
23
  * @param {Array<Object>} items - List of items
25
24
  * @param {string} items.sku - SKU of the NFT
26
25
  * @param {number=} items.quantity=1 - Number to mint
@@ -30,66 +29,32 @@ const {
30
29
  *
31
30
  * @return Promise<Object> - An object containing the address for whom the NFT was minted and the transactionId of the minting request.
32
31
  */
33
- exports.MintNFT = async function({tenantId, email, address, collectionId, items, extraData={}}) {
32
+ exports.MintNFT = async function({tenantId, address, marketplaceId, items, extraData={}}) {
34
33
  ValidatePresence("tenantId", tenantId);
35
- ValidatePresence("email or address", email || address);
36
- ValidatePresence("collectionId", collectionId);
34
+ ValidatePresence("address", address);
35
+ ValidatePresence("marketplaceId", marketplaceId);
37
36
  ValidatePresence("items", items);
38
37
 
39
- ValidateObject(collectionId);
40
-
41
- // If address not specified, make call to initialize address for email
42
- let accountInitializationBody = { ts: Date.now() };
43
- if(email) {
44
- accountInitializationBody.email = email;
45
- } else {
46
- accountInitializationBody.addr = address;
47
- }
48
-
49
- const accountInitializationSignature = await this.Sign(
50
- JSON.stringify(accountInitializationBody)
51
- );
52
-
53
- const {addr} = await this.utils.ResponseToJson(
54
- await this.authClient.MakeAuthServiceRequest({
55
- method: "POST",
56
- path: `/as/tnt/prov/eth/${tenantId}`,
57
- body: accountInitializationBody,
58
- headers: {
59
- "Authorization": `Bearer ${accountInitializationSignature}`
60
- }
61
- })
62
- );
63
-
64
- address = this.utils.FormatAddress(addr);
38
+ ValidateObject(marketplaceId);
39
+ ValidateAddress(address);
65
40
 
66
41
  let requestBody = {
67
- "tickets": null,
68
- "products": items.map(item => ({
42
+ tickets: null,
43
+ products: items.map(item => ({
69
44
  sku: item.sku,
70
45
  quant: item.quantity || 1,
71
46
  extra: item.tokenId ?
72
47
  { ...(item.extraData || {}), token_id: item.tokenId } :
73
48
  { ...(item.extraData || {}) }
74
49
  })),
75
- "ident": email || address,
76
- "cust_name": email || address,
77
- "extra": {
78
- ...extraData
50
+ ident: address,
51
+ cust_name: address,
52
+ extra: {
53
+ ...extraData,
54
+ elv_addr: address
79
55
  }
80
56
  };
81
57
 
82
-
83
- ValidateAddress(address);
84
-
85
- if(email) {
86
- requestBody.email = email;
87
- } else {
88
- requestBody.addr = address;
89
- }
90
-
91
- requestBody.extra.elv_addr = address;
92
-
93
58
  const transactionId = this.utils.B58(UUID.parse(UUID.v4()));
94
59
  requestBody.ts = Date.now();
95
60
  requestBody.trans_id = transactionId;
@@ -100,7 +65,7 @@ exports.MintNFT = async function({tenantId, email, address, collectionId, items,
100
65
 
101
66
  await this.authClient.MakeAuthServiceRequest({
102
67
  method: "POST",
103
- path: `/as/otp/webhook/base/${tenantId}/${collectionId}`,
68
+ path: UrlJoin("/as/tnt/trans/base", tenantId, marketplaceId),
104
69
  body: requestBody,
105
70
  headers: {
106
71
  "Authorization": `Bearer ${mintSignature}`
@@ -13,25 +13,6 @@ const Test = async () => {
13
13
  });
14
14
 
15
15
  client.SetSigner({signer});
16
-
17
-
18
- const ethUrl = "https://host-216-66-40-19.contentfabric.io/eth";
19
- const asUrl = "https://host-66-220-3-86.contentfabric.io";
20
-
21
- client.SetNodes({
22
- ethereumURIs: [
23
- ethUrl
24
- ],
25
- authServiceURIs: [
26
- asUrl
27
- ]
28
- });
29
-
30
- console.log(
31
- await client.ContentObjectTenantId({
32
- objectId: "iq__3PXRZX5NCzPQsfTEquCctB2K3KJh"
33
- })
34
- )
35
16
  } catch(error) {
36
17
  console.error(error);
37
18
  console.error(JSON.stringify(error, null, 2));
@@ -0,0 +1,45 @@
1
+ /* eslint-disable no-console */
2
+
3
+
4
+ const ScriptVariant = require("./parentClasses/ScriptVariant");
5
+ const ABR = require("@eluvio/elv-abr-profile");
6
+
7
+ class VariantABRProfile extends ScriptVariant {
8
+
9
+ async body() {
10
+ const client = await this.client();
11
+
12
+ const libraryId = this.args.libraryId;
13
+ const objectId = this.args.objectId;
14
+
15
+ // get media info from production master
16
+ const masterMetadata = await client.ContentObjectMetadata({
17
+ libraryId,
18
+ objectId,
19
+ metadataSubtree: "/production_master"
20
+ });
21
+
22
+ // adapt ABR Profile to production master's video properties
23
+ const generatedProfile = ABR.ABRProfileForVariant(
24
+ masterMetadata.sources,
25
+ masterMetadata.variants.default
26
+ );
27
+
28
+ if(!generatedProfile.ok) {
29
+ console.error("Error generating ABR Profile:\n" + generatedProfile.errors.join("\n"));
30
+ } else {
31
+ console.log(JSON.stringify(generatedProfile.result, null, 2));
32
+ }
33
+ }
34
+
35
+ header() {
36
+ return `Generate ABR Profile for production master ${this.args.objectId}, default variant`;
37
+ }
38
+
39
+ options() {
40
+ return super.options();
41
+ }
42
+ }
43
+
44
+ const script = new VariantABRProfile;
45
+ script.run();