@eluvio/elv-client-js 4.2.25 → 4.2.29
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.
- package/package.json +5 -1
- package/src/EthClient.js +2 -1
- package/src/client/ABRPublishing.js +33 -19
- package/src/client/ContentAccess.js +70 -1
- package/src/client/Files.js +425 -219
- package/src/client/LiveStream.js +47 -21
- package/utilities/MediaIngest.js +424 -0
- package/utilities/MigrateEncryptionConkForNewUser.js +62 -0
- package/utilities/ObjectAddFiles.js +29 -9
- package/utilities/README_INGEST.md +332 -0
- package/utilities/lib/abr_profiles/abr_profile_4k_all.json +181 -0
- package/utilities/lib/concerns/Client.js +71 -10
- package/utilities/lib/concerns/CloudAccess.js +2 -2
- package/utilities/lib/concerns/CloudFile.js +16 -8
- package/utilities/lib/concerns/LocalFile.js +2 -1
- package/utilities/lib/data/network_specs.json +13 -0
- package/utilities/lib/models/CredentialSet.js +26 -7
- package/utilities/tests/unit/lib/concerns/Client.test.js +96 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eluvio/elv-client-js",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.29",
|
|
4
4
|
"description": "Javascript client for the Eluvio Content Fabric",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"author": "Kevin Talmadge",
|
|
@@ -35,6 +35,10 @@
|
|
|
35
35
|
"browser": {
|
|
36
36
|
"fs": false
|
|
37
37
|
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/eluv-io/elv-client-js.git"
|
|
41
|
+
},
|
|
38
42
|
"files": [
|
|
39
43
|
"/build",
|
|
40
44
|
"/dist",
|
package/src/EthClient.js
CHANGED
|
@@ -309,6 +309,7 @@ class EthClient {
|
|
|
309
309
|
methodName,
|
|
310
310
|
methodArgs,
|
|
311
311
|
value,
|
|
312
|
+
overrides={},
|
|
312
313
|
timeout,
|
|
313
314
|
formatArguments=true,
|
|
314
315
|
cacheContract=true,
|
|
@@ -319,7 +320,6 @@ class EthClient {
|
|
|
319
320
|
if(!abi) { abi = await this.client.ContractAbi({contractAddress}); }
|
|
320
321
|
|
|
321
322
|
const contract = this.Contract({contractAddress, abi, cacheContract, overrideCachedContract});
|
|
322
|
-
|
|
323
323
|
// Make method call
|
|
324
324
|
const createMethodCall = await this.CallContractMethod({
|
|
325
325
|
contract,
|
|
@@ -327,6 +327,7 @@ class EthClient {
|
|
|
327
327
|
methodName,
|
|
328
328
|
methodArgs,
|
|
329
329
|
value,
|
|
330
|
+
overrides,
|
|
330
331
|
formatArguments,
|
|
331
332
|
cacheContract
|
|
332
333
|
});
|
|
@@ -78,6 +78,11 @@ const MezJobMainOfferingKey = function(abrMezOfferings) {
|
|
|
78
78
|
* - ...
|
|
79
79
|
* - ]
|
|
80
80
|
* -
|
|
81
|
+
* - For a presigned URL, `path` and `storage_endpoint` are not required and `cloud_credentials` should be:
|
|
82
|
+
* - {
|
|
83
|
+
* - signed_url: "YOUR_PRESIGNED_S3_URL"
|
|
84
|
+
* - }
|
|
85
|
+
* -
|
|
81
86
|
* - The simplest case is a one element array with .path_matchers == [".*"], in which case the same credentials will be used for all items in fileInfo
|
|
82
87
|
*
|
|
83
88
|
* @throws {Object} error - If the initialization of the master fails, error details can be found in error.body
|
|
@@ -127,8 +132,11 @@ exports.CreateProductionMaster = async function({
|
|
|
127
132
|
let matched = false;
|
|
128
133
|
for(let j = 0; !matched && j < access.length; j++) {
|
|
129
134
|
let credentialSet = access[j];
|
|
135
|
+
const remoteAccess = credentialSet.remote_access;
|
|
130
136
|
// strip trailing slash to get bucket name for credential set
|
|
131
|
-
const credentialSetBucket =
|
|
137
|
+
const credentialSetBucket = remoteAccess.path
|
|
138
|
+
? remoteAccess.path.replace(/\/$/, "")
|
|
139
|
+
: undefined;
|
|
132
140
|
const matchers = credentialSet.path_matchers;
|
|
133
141
|
for(let k = 0; !matched && k < matchers.length; k++) {
|
|
134
142
|
const matcher = new RegExp(matchers[k]);
|
|
@@ -139,7 +147,7 @@ exports.CreateProductionMaster = async function({
|
|
|
139
147
|
const s3prefixMatch = (s3prefixRegex.exec(fileSourcePath));
|
|
140
148
|
if(s3prefixMatch) {
|
|
141
149
|
const bucketName = s3prefixMatch[1];
|
|
142
|
-
if(bucketName !== credentialSetBucket) {
|
|
150
|
+
if(credentialSetBucket && bucketName !== credentialSetBucket) {
|
|
143
151
|
throw Error("Full S3 file path \"" + fileSourcePath + "\" matched to credential set with different bucket name '" + credentialSetBucket + "'");
|
|
144
152
|
}
|
|
145
153
|
}
|
|
@@ -154,7 +162,7 @@ exports.CreateProductionMaster = async function({
|
|
|
154
162
|
}
|
|
155
163
|
}
|
|
156
164
|
if(!matched) {
|
|
157
|
-
throw Error("no credential set found for file path: \"" +
|
|
165
|
+
throw Error("no credential set found for file path: \"" + oneFileInfo.source + "\"");
|
|
158
166
|
}
|
|
159
167
|
}
|
|
160
168
|
|
|
@@ -162,10 +170,13 @@ exports.CreateProductionMaster = async function({
|
|
|
162
170
|
for(let i = 0; i < access.length; i++) {
|
|
163
171
|
const credentialSet = access[i];
|
|
164
172
|
if(credentialSet.hasOwnProperty("matched") && credentialSet.matched.length > 0) {
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
const
|
|
168
|
-
const
|
|
173
|
+
const remoteAccess = credentialSet.remote_access;
|
|
174
|
+
const cloudCredentials = remoteAccess.cloud_credentials;
|
|
175
|
+
const region = remoteAccess.storage_endpoint && remoteAccess.storage_endpoint.region;
|
|
176
|
+
const bucket = remoteAccess.path && remoteAccess.path.replace(/\/$/, "");
|
|
177
|
+
const accessKey = cloudCredentials.access_key_id;
|
|
178
|
+
const secret = cloudCredentials.secret_access_key;
|
|
179
|
+
const signedUrl = cloudCredentials.signed_url;
|
|
169
180
|
|
|
170
181
|
await this.UploadFilesFromS3({
|
|
171
182
|
libraryId,
|
|
@@ -176,6 +187,7 @@ exports.CreateProductionMaster = async function({
|
|
|
176
187
|
bucket,
|
|
177
188
|
accessKey,
|
|
178
189
|
secret,
|
|
190
|
+
signedUrl,
|
|
179
191
|
copy,
|
|
180
192
|
callback,
|
|
181
193
|
encryption: encrypt ? "cgck" : "none"
|
|
@@ -212,22 +224,24 @@ exports.CreateProductionMaster = async function({
|
|
|
212
224
|
constant: false
|
|
213
225
|
});
|
|
214
226
|
|
|
227
|
+
const mergeMetadata = {
|
|
228
|
+
...(metadata || {}),
|
|
229
|
+
name: name !== undefined ? name : (metadata || {}).name,
|
|
230
|
+
description: description !== undefined ? description : (metadata || {}).description,
|
|
231
|
+
reference: access && !copy,
|
|
232
|
+
public: {
|
|
233
|
+
...((metadata || {}).public || {}),
|
|
234
|
+
name: name !== undefined ? name : ((metadata || {}).public || {}).name,
|
|
235
|
+
description: description !== undefined ? description : ((metadata || {}).public || {}).description
|
|
236
|
+
},
|
|
237
|
+
elv_created_at: new Date().getTime(),
|
|
238
|
+
};
|
|
239
|
+
|
|
215
240
|
await this.MergeMetadata({
|
|
216
241
|
libraryId,
|
|
217
242
|
objectId,
|
|
218
243
|
writeToken,
|
|
219
|
-
metadata:
|
|
220
|
-
...(metadata || {}),
|
|
221
|
-
name,
|
|
222
|
-
description,
|
|
223
|
-
reference: access && !copy,
|
|
224
|
-
public: {
|
|
225
|
-
...((metadata || {}).public || {}),
|
|
226
|
-
name: name || "",
|
|
227
|
-
description: description || ""
|
|
228
|
-
},
|
|
229
|
-
elv_created_at: new Date().getTime(),
|
|
230
|
-
}
|
|
244
|
+
metadata: mergeMetadata
|
|
231
245
|
});
|
|
232
246
|
|
|
233
247
|
let additionalReturnVals;
|
|
@@ -9,6 +9,7 @@ const objectPath = require("object-path");
|
|
|
9
9
|
|
|
10
10
|
const HttpClient = require("../HttpClient");
|
|
11
11
|
const ContentObjectAudit = require("../ContentObjectAudit");
|
|
12
|
+
const bs58 = require("bs58");
|
|
12
13
|
|
|
13
14
|
const {
|
|
14
15
|
ValidateLibrary,
|
|
@@ -17,6 +18,7 @@ const {
|
|
|
17
18
|
ValidatePartHash,
|
|
18
19
|
ValidateWriteToken,
|
|
19
20
|
ValidateParameters,
|
|
21
|
+
ValidatePresence,
|
|
20
22
|
} = require("../Validation");
|
|
21
23
|
|
|
22
24
|
const MergeWith = require("lodash/mergeWith");
|
|
@@ -2713,7 +2715,6 @@ exports.LinkData = async function({libraryId, objectId, versionHash, writeToken,
|
|
|
2713
2715
|
);
|
|
2714
2716
|
};
|
|
2715
2717
|
|
|
2716
|
-
|
|
2717
2718
|
/* Encryption */
|
|
2718
2719
|
|
|
2719
2720
|
exports.CreateEncryptionConk = async function({libraryId, objectId, versionHash, writeToken, createKMSConk=true}) {
|
|
@@ -2793,6 +2794,74 @@ exports.CreateEncryptionConk = async function({libraryId, objectId, versionHash,
|
|
|
2793
2794
|
return this.encryptionConks[objectId];
|
|
2794
2795
|
};
|
|
2795
2796
|
|
|
2797
|
+
/**
|
|
2798
|
+
* Encrypt the owner encryption key using the new user details provided
|
|
2799
|
+
*
|
|
2800
|
+
* @methodGroup Encryption
|
|
2801
|
+
* @namedParams
|
|
2802
|
+
* @param {string=} libraryId - ID of a library
|
|
2803
|
+
* @param {string=} objectId - ID of an object
|
|
2804
|
+
* @param {string=} versionHash - Hash of an object version
|
|
2805
|
+
* @param {string=} writeToken - The write token for the object
|
|
2806
|
+
* @param {Object=} newEncodedUserPublicKey - raw public key or base-58 encoded publicKey of the new user prefixed 'kupk'
|
|
2807
|
+
*/
|
|
2808
|
+
exports.MigrateEncryptionConkForUserProvided = async function({libraryId, objectId, versionHash, writeToken, newEncodedUserPublicKey}) {
|
|
2809
|
+
if(this.signer.remoteSigner) {
|
|
2810
|
+
return;
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
ValidateParameters({libraryId, objectId, versionHash});
|
|
2814
|
+
ValidateWriteToken(writeToken);
|
|
2815
|
+
|
|
2816
|
+
if(!objectId) {
|
|
2817
|
+
objectId = this.utils.DecodeVersionHash(versionHash).objectId;
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
ValidatePresence("newEncodedUserPublicKey", newEncodedUserPublicKey);
|
|
2821
|
+
|
|
2822
|
+
let publicKey;
|
|
2823
|
+
if(!newEncodedUserPublicKey.startsWith("kupk")){
|
|
2824
|
+
publicKey = newEncodedUserPublicKey;
|
|
2825
|
+
} else {
|
|
2826
|
+
const publicKeyBytes = bs58.decode(newEncodedUserPublicKey.slice(4));
|
|
2827
|
+
if(publicKeyBytes.length !== 65) {
|
|
2828
|
+
publicKey = "0x" + Buffer.concat([Buffer.from([0x04]), publicKeyBytes]).toString("hex");
|
|
2829
|
+
} else {
|
|
2830
|
+
publicKey = "0x" + publicKeyBytes.toString("hex");
|
|
2831
|
+
}
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
// Decrypt using existing user key
|
|
2835
|
+
const existingCapKey = `eluv.caps.iusr${this.utils.AddressToHash(this.signer.address)}`;
|
|
2836
|
+
const existingUserCap =
|
|
2837
|
+
await this.ContentObjectMetadata({
|
|
2838
|
+
libraryId,
|
|
2839
|
+
objectId,
|
|
2840
|
+
writeToken,
|
|
2841
|
+
metadataSubtree: existingCapKey
|
|
2842
|
+
});
|
|
2843
|
+
|
|
2844
|
+
if(!existingUserCap) {
|
|
2845
|
+
throw (`No encryption conk present for ${objectId} for user ${this.signer.address}`);
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
this.encryptionConks[objectId] = await this.Crypto.DecryptCap(existingUserCap, this.signer._signingKey().privateKey);
|
|
2849
|
+
|
|
2850
|
+
// Encrypt with the new key
|
|
2851
|
+
const encryptedConk = await this.Crypto.EncryptConk(this.encryptionConks[objectId], publicKey);
|
|
2852
|
+
const newUserCap = `eluv.caps.iusr${this.utils.AddressToHash(this.utils.PublicKeyToAddress(publicKey))}`;
|
|
2853
|
+
|
|
2854
|
+
await this.ReplaceMetadata({
|
|
2855
|
+
libraryId,
|
|
2856
|
+
objectId,
|
|
2857
|
+
writeToken,
|
|
2858
|
+
metadataSubtree: newUserCap,
|
|
2859
|
+
metadata: encryptedConk
|
|
2860
|
+
});
|
|
2861
|
+
|
|
2862
|
+
return this.encryptionConks[objectId];
|
|
2863
|
+
};
|
|
2864
|
+
|
|
2796
2865
|
/**
|
|
2797
2866
|
* Retrieve the encryption conk for the specified object. If one has not yet been created
|
|
2798
2867
|
* and a writeToken has been specified, this method will create a new conk and
|