@stacks/storage 4.3.6-pr.f9a3196.0 → 4.3.7-beta.1
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/dist/esm/fileContentLoader.d.ts +4 -3
- package/dist/esm/fileContentLoader.js +14 -13
- package/dist/esm/fileContentLoader.js.map +1 -1
- package/dist/esm/hub.d.ts +2 -1
- package/dist/esm/hub.js +9 -8
- package/dist/esm/hub.js.map +1 -1
- package/dist/esm/storage.d.ts +3 -2
- package/dist/esm/storage.js +46 -25
- package/dist/esm/storage.js.map +1 -1
- package/dist/fileContentLoader.d.ts +4 -3
- package/dist/fileContentLoader.js +13 -12
- package/dist/fileContentLoader.js.map +1 -1
- package/dist/hub.d.ts +2 -1
- package/dist/hub.js +8 -7
- package/dist/hub.js.map +1 -1
- package/dist/polyfill/index.js +16 -0
- package/dist/polyfill/index.js.map +1 -0
- package/dist/storage.d.ts +3 -2
- package/dist/storage.js +44 -23
- package/dist/storage.js.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.LICENSE.txt +11 -0
- package/dist/umd/index.js.map +1 -1
- package/package.json +15 -10
- package/src/fileContentLoader.ts +21 -27
- package/src/hub.ts +11 -10
- package/src/storage.ts +47 -39
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacks/storage",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.7-beta.1",
|
|
4
4
|
"description": "Stacks storage library",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Hiro Systems PBC (https://hiro.so)",
|
|
7
7
|
"homepage": "https://hiro.so/stacks-js",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"build": "npm run clean && npm run build:cjs && npm run build:esm && npm run build:umd",
|
|
9
|
+
"build": "npm run clean && npm run build:cjs && npm run build:esm && npm run build:umd && npm run build:polyfill",
|
|
10
10
|
"build:cjs": "tsc -b tsconfig.build.json",
|
|
11
11
|
"build:esm": "tsc -p tsconfig.build.json --module ES6 --outDir ./dist/esm",
|
|
12
|
+
"build:polyfill": "NODE_OPTIONS=--max-old-space-size=8192 rollup -c ../../configs/rollup.config.js && rimraf dist/polyfill/dist",
|
|
12
13
|
"build:umd": "NODE_OPTIONS=--max-old-space-size=8192 webpack --config webpack.config.js",
|
|
13
14
|
"clean": "rimraf dist && tsc -b tsconfig.build.json --clean",
|
|
14
15
|
"pack": "npm pack",
|
|
@@ -20,12 +21,11 @@
|
|
|
20
21
|
"typecheck:watch": "npm run typecheck -- --watch"
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
23
|
-
"@stacks/auth": "^4.3.
|
|
24
|
-
"@stacks/common": "^4.3.
|
|
25
|
-
"@stacks/encryption": "^4.3.
|
|
26
|
-
"@stacks/network": "^4.3.
|
|
27
|
-
"
|
|
28
|
-
"jsontokens": "^4.0.1"
|
|
24
|
+
"@stacks/auth": "^4.3.7-beta.1",
|
|
25
|
+
"@stacks/common": "^4.3.7-beta.1",
|
|
26
|
+
"@stacks/encryption": "^4.3.7-beta.1",
|
|
27
|
+
"@stacks/network": "^4.3.7-beta.1",
|
|
28
|
+
"jsontokens": "^3.1.1"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@stacks/network": "^4.1.0",
|
|
@@ -38,7 +38,12 @@
|
|
|
38
38
|
"process": "^0.11.10",
|
|
39
39
|
"rimraf": "^3.0.2",
|
|
40
40
|
"stream-browserify": "^3.0.0",
|
|
41
|
-
"ts-jest": "^26.5.5"
|
|
41
|
+
"ts-jest": "^26.5.5",
|
|
42
|
+
"ts-loader": "^9.1.1",
|
|
43
|
+
"typescript": "^4.2.4",
|
|
44
|
+
"webpack": "^5.36.1",
|
|
45
|
+
"webpack-bundle-analyzer": "^4.5.0",
|
|
46
|
+
"webpack-cli": "^4.6.0"
|
|
42
47
|
},
|
|
43
48
|
"sideEffects": false,
|
|
44
49
|
"typings": "dist/index.d.ts",
|
|
@@ -60,5 +65,5 @@
|
|
|
60
65
|
"bugs": {
|
|
61
66
|
"url": "https://github.com/blockstack/blockstack.js/issues"
|
|
62
67
|
},
|
|
63
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "2d22629a8d0c29b5ba5b29871014c98f40bbda0f"
|
|
64
69
|
}
|
package/src/fileContentLoader.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { Buffer } from '@stacks/common';
|
|
3
2
|
/**
|
|
4
3
|
* Retrieves the specified file from the app's data store.
|
|
5
4
|
* @param {String} path - the path to the file to read
|
|
@@ -7,11 +6,11 @@ import { utf8ToBytes } from '@stacks/common';
|
|
|
7
6
|
* or rejects with an error
|
|
8
7
|
*/
|
|
9
8
|
export /** @ignore */
|
|
10
|
-
type PutFileContent = string |
|
|
9
|
+
type PutFileContent = string | Buffer | ArrayBufferView | ArrayBufferLike | Blob;
|
|
11
10
|
|
|
12
11
|
/** @ignore */
|
|
13
12
|
export class FileContentLoader {
|
|
14
|
-
readonly content:
|
|
13
|
+
readonly content: Buffer | Blob;
|
|
15
14
|
|
|
16
15
|
readonly wasString: boolean;
|
|
17
16
|
|
|
@@ -19,11 +18,11 @@ export class FileContentLoader {
|
|
|
19
18
|
|
|
20
19
|
readonly contentByteLength: number;
|
|
21
20
|
|
|
22
|
-
private loadedData?: Promise<
|
|
21
|
+
private loadedData?: Promise<Buffer>;
|
|
23
22
|
|
|
24
23
|
static readonly supportedTypesMsg =
|
|
25
24
|
'Supported types are: `string` (to be UTF8 encoded), ' +
|
|
26
|
-
'`Blob`, `File`, `ArrayBuffer`, `UInt8Array` or any other typed array buffer. ';
|
|
25
|
+
'`Buffer`, `Blob`, `File`, `ArrayBuffer`, `UInt8Array` or any other typed array buffer. ';
|
|
27
26
|
|
|
28
27
|
constructor(content: PutFileContent, contentType: string) {
|
|
29
28
|
this.wasString = typeof content === 'string';
|
|
@@ -35,7 +34,7 @@ export class FileContentLoader {
|
|
|
35
34
|
private static normalizeContentDataType(
|
|
36
35
|
content: PutFileContent,
|
|
37
36
|
contentType: string
|
|
38
|
-
):
|
|
37
|
+
): Buffer | Blob {
|
|
39
38
|
try {
|
|
40
39
|
if (typeof content === 'string') {
|
|
41
40
|
// If a charset is specified it must be either utf8 or ascii, otherwise the encoded content
|
|
@@ -50,19 +49,17 @@ export class FileContentLoader {
|
|
|
50
49
|
}
|
|
51
50
|
if (typeof TextEncoder !== 'undefined') {
|
|
52
51
|
const encodedString = new TextEncoder().encode(content);
|
|
53
|
-
return
|
|
52
|
+
return Buffer.from(encodedString.buffer);
|
|
54
53
|
}
|
|
55
|
-
return
|
|
56
|
-
} else if (content
|
|
54
|
+
return Buffer.from(content);
|
|
55
|
+
} else if (Buffer.isBuffer(content)) {
|
|
57
56
|
return content;
|
|
58
57
|
} else if (ArrayBuffer.isView(content)) {
|
|
59
|
-
return
|
|
60
|
-
content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength)
|
|
61
|
-
);
|
|
58
|
+
return Buffer.from(content.buffer, content.byteOffset, content.byteLength);
|
|
62
59
|
} else if (typeof Blob !== 'undefined' && content instanceof Blob) {
|
|
63
60
|
return content;
|
|
64
61
|
} else if (typeof ArrayBuffer !== 'undefined' && content instanceof ArrayBuffer) {
|
|
65
|
-
return
|
|
62
|
+
return Buffer.from(content);
|
|
66
63
|
} else if (Array.isArray(content)) {
|
|
67
64
|
// Provided with a regular number `Array` -- this is either an (old) method
|
|
68
65
|
// of representing an octet array, or a dev error. Perform basic check for octet array.
|
|
@@ -74,7 +71,7 @@ export class FileContentLoader {
|
|
|
74
71
|
`Unexpected array values provided as file data: value "${content[0]}" at index 0 is not an octet number. ${this.supportedTypesMsg}`
|
|
75
72
|
);
|
|
76
73
|
}
|
|
77
|
-
return
|
|
74
|
+
return Buffer.from(content);
|
|
78
75
|
} else {
|
|
79
76
|
const typeName = Object.prototype.toString.call(content);
|
|
80
77
|
throw new Error(
|
|
@@ -98,7 +95,7 @@ export class FileContentLoader {
|
|
|
98
95
|
}
|
|
99
96
|
|
|
100
97
|
private detectContentLength(): number {
|
|
101
|
-
if (ArrayBuffer.isView(this.content) || this.content
|
|
98
|
+
if (ArrayBuffer.isView(this.content) || Buffer.isBuffer(this.content)) {
|
|
102
99
|
return this.content.byteLength;
|
|
103
100
|
} else if (typeof Blob !== 'undefined' && this.content instanceof Blob) {
|
|
104
101
|
return this.content.size;
|
|
@@ -109,29 +106,26 @@ export class FileContentLoader {
|
|
|
109
106
|
throw error;
|
|
110
107
|
}
|
|
111
108
|
|
|
112
|
-
private async loadContent(): Promise<
|
|
109
|
+
private async loadContent(): Promise<Buffer> {
|
|
113
110
|
try {
|
|
114
|
-
if (this.content
|
|
111
|
+
if (Buffer.isBuffer(this.content)) {
|
|
115
112
|
return this.content;
|
|
116
113
|
} else if (ArrayBuffer.isView(this.content)) {
|
|
117
|
-
return
|
|
118
|
-
this.content.buffer,
|
|
119
|
-
this.content.byteOffset,
|
|
120
|
-
this.content.byteLength
|
|
121
|
-
);
|
|
114
|
+
return Buffer.from(this.content.buffer, this.content.byteOffset, this.content.byteLength);
|
|
122
115
|
} else if (typeof Blob !== 'undefined' && this.content instanceof Blob) {
|
|
123
116
|
const reader = new FileReader();
|
|
124
|
-
const readPromise = new Promise<
|
|
117
|
+
const readPromise = new Promise<Buffer>((resolve, reject) => {
|
|
125
118
|
reader.onerror = err => {
|
|
126
119
|
reject(err);
|
|
127
120
|
};
|
|
128
121
|
reader.onload = () => {
|
|
129
122
|
const arrayBuffer = reader.result as ArrayBuffer;
|
|
130
|
-
resolve(
|
|
123
|
+
resolve(Buffer.from(arrayBuffer));
|
|
131
124
|
};
|
|
132
125
|
reader.readAsArrayBuffer(this.content as Blob);
|
|
133
126
|
});
|
|
134
|
-
|
|
127
|
+
const result = await readPromise;
|
|
128
|
+
return result;
|
|
135
129
|
} else {
|
|
136
130
|
const typeName = Object.prototype.toString.call(this.content);
|
|
137
131
|
throw new Error(`Unexpected type ${typeName}`);
|
|
@@ -144,7 +138,7 @@ export class FileContentLoader {
|
|
|
144
138
|
}
|
|
145
139
|
}
|
|
146
140
|
|
|
147
|
-
load(): Promise<
|
|
141
|
+
load(): Promise<Buffer | string> {
|
|
148
142
|
if (this.loadedData === undefined) {
|
|
149
143
|
this.loadedData = this.loadContent();
|
|
150
144
|
}
|
package/src/hub.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BadPathError,
|
|
3
|
-
|
|
3
|
+
Buffer,
|
|
4
4
|
ConflictError,
|
|
5
5
|
DoesNotExist,
|
|
6
6
|
GaiaHubErrorResponse,
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
NotEnoughProofError,
|
|
10
10
|
PayloadTooLargeError,
|
|
11
11
|
PreconditionFailedError,
|
|
12
|
-
utf8ToBytes,
|
|
13
12
|
ValidationError,
|
|
14
13
|
} from '@stacks/common';
|
|
15
14
|
import {
|
|
@@ -22,7 +21,6 @@ import {
|
|
|
22
21
|
Signature,
|
|
23
22
|
} from '@stacks/encryption';
|
|
24
23
|
import { createFetchFn, FetchFn } from '@stacks/network';
|
|
25
|
-
import { fromByteArray } from 'base64-js';
|
|
26
24
|
import { TokenSigner } from 'jsontokens';
|
|
27
25
|
|
|
28
26
|
/**
|
|
@@ -59,7 +57,7 @@ interface UploadResponse {
|
|
|
59
57
|
*/
|
|
60
58
|
export async function uploadToGaiaHub(
|
|
61
59
|
filename: string,
|
|
62
|
-
contents: Blob |
|
|
60
|
+
contents: Blob | Buffer | ArrayBufferView | string,
|
|
63
61
|
hubConfig: GaiaHubConfig,
|
|
64
62
|
contentType = 'application/octet-stream',
|
|
65
63
|
newFile = true,
|
|
@@ -150,16 +148,19 @@ function makeLegacyAuthToken(challengeText: string, signerKeyHex: string): strin
|
|
|
150
148
|
throw new Error('Failed in parsing legacy challenge text from the gaia hub.');
|
|
151
149
|
}
|
|
152
150
|
if (parsedChallenge[0] === 'gaiahub' && parsedChallenge[3] === 'blockstack_storage_please_sign') {
|
|
153
|
-
const digest = hashSha256Sync(
|
|
154
|
-
const
|
|
151
|
+
const digest = hashSha256Sync(Buffer.from(challengeText));
|
|
152
|
+
const signatureBuffer = ecSign(digest, compressPrivateKey(signerKeyHex));
|
|
155
153
|
// We only want the DER encoding so use toDERHex provided by @noble/secp256k1
|
|
156
|
-
const signature = Signature.fromCompact(
|
|
154
|
+
const signature = Signature.fromCompact(signatureBuffer.toString('hex')).toDERHex();
|
|
157
155
|
|
|
158
156
|
const publickey = getPublicKeyFromPrivate(signerKeyHex);
|
|
159
|
-
const token =
|
|
157
|
+
const token = Buffer.from(JSON.stringify({ publickey, signature })).toString('base64');
|
|
160
158
|
return token;
|
|
159
|
+
} else {
|
|
160
|
+
throw new Error(
|
|
161
|
+
'Failed to connect to legacy gaia hub. If you operate this hub, please update.'
|
|
162
|
+
);
|
|
161
163
|
}
|
|
162
|
-
throw new Error('Failed to connect to legacy gaia hub. If you operate this hub, please update.');
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
/**
|
|
@@ -186,7 +187,7 @@ function makeV1GaiaAuthToken(
|
|
|
186
187
|
return makeLegacyAuthToken(challengeText, signerKeyHex);
|
|
187
188
|
}
|
|
188
189
|
|
|
189
|
-
const salt =
|
|
190
|
+
const salt = randomBytes(16).toString('hex');
|
|
190
191
|
const payload = {
|
|
191
192
|
gaiaChallenge: challengeText,
|
|
192
193
|
hubUrl,
|
package/src/storage.ts
CHANGED
|
@@ -8,14 +8,12 @@ import {
|
|
|
8
8
|
megabytesToBytes,
|
|
9
9
|
PayloadTooLargeError,
|
|
10
10
|
SignatureVerificationError,
|
|
11
|
-
utf8ToBytes,
|
|
12
11
|
} from '@stacks/common';
|
|
13
12
|
import {
|
|
14
13
|
eciesGetJsonStringLength,
|
|
15
14
|
EncryptionOptions,
|
|
16
15
|
getPublicKeyFromPrivate,
|
|
17
16
|
publicKeyToAddress,
|
|
18
|
-
publicKeyToBtcAddress,
|
|
19
17
|
signECDSA,
|
|
20
18
|
verifyECDSA,
|
|
21
19
|
} from '@stacks/encryption';
|
|
@@ -323,19 +321,20 @@ export class Storage {
|
|
|
323
321
|
this.getGaiaAddress(opt.app!, opt.username, opt.zoneFileLookupURL),
|
|
324
322
|
]);
|
|
325
323
|
|
|
326
|
-
if (!fileContents)
|
|
327
|
-
|
|
328
|
-
|
|
324
|
+
if (!fileContents) {
|
|
325
|
+
return fileContents;
|
|
326
|
+
}
|
|
327
|
+
if (!gaiaAddress) {
|
|
329
328
|
throw new SignatureVerificationError(
|
|
330
329
|
`Failed to get gaia address for verification of: ${path}`
|
|
331
330
|
);
|
|
332
|
-
|
|
333
|
-
if (!signatureContents || typeof signatureContents !== 'string')
|
|
331
|
+
}
|
|
332
|
+
if (!signatureContents || typeof signatureContents !== 'string') {
|
|
334
333
|
throw new SignatureVerificationError(
|
|
335
334
|
'Failed to obtain signature for file: ' +
|
|
336
335
|
`${path} -- looked in ${path}${SIGNATURE_FILE_SUFFIX}`
|
|
337
336
|
);
|
|
338
|
-
|
|
337
|
+
}
|
|
339
338
|
let signature;
|
|
340
339
|
let publicKey;
|
|
341
340
|
try {
|
|
@@ -343,39 +342,40 @@ export class Storage {
|
|
|
343
342
|
signature = sigObject.signature;
|
|
344
343
|
publicKey = sigObject.publicKey;
|
|
345
344
|
} catch (err) {
|
|
346
|
-
if (err instanceof SyntaxError)
|
|
345
|
+
if (err instanceof SyntaxError) {
|
|
347
346
|
throw new Error(
|
|
348
|
-
|
|
347
|
+
'Failed to parse signature content JSON ' +
|
|
348
|
+
`(path: ${path}${SIGNATURE_FILE_SUFFIX})` +
|
|
349
|
+
' The content may be corrupted.'
|
|
349
350
|
);
|
|
350
|
-
|
|
351
|
+
} else {
|
|
352
|
+
throw err;
|
|
353
|
+
}
|
|
351
354
|
}
|
|
352
355
|
const signerAddress = publicKeyToAddress(publicKey);
|
|
353
|
-
if (gaiaAddress !== signerAddress)
|
|
356
|
+
if (gaiaAddress !== signerAddress) {
|
|
354
357
|
throw new SignatureVerificationError(
|
|
355
|
-
`Signer pubkey address (${signerAddress}) doesn't
|
|
358
|
+
`Signer pubkey address (${signerAddress}) doesn't` +
|
|
359
|
+
` match gaia address (${gaiaAddress})`
|
|
356
360
|
);
|
|
357
|
-
|
|
358
|
-
if (
|
|
359
|
-
!verifyECDSA(
|
|
360
|
-
typeof fileContents === 'string'
|
|
361
|
-
? utf8ToBytes(fileContents)
|
|
362
|
-
: new Uint8Array(fileContents),
|
|
363
|
-
publicKey,
|
|
364
|
-
signature
|
|
365
|
-
)
|
|
366
|
-
) {
|
|
361
|
+
} else if (!verifyECDSA(fileContents, publicKey, signature)) {
|
|
367
362
|
throw new SignatureVerificationError(
|
|
368
|
-
|
|
363
|
+
'Contents do not match ECDSA signature: ' +
|
|
364
|
+
`path: ${path}, signature: ${path}${SIGNATURE_FILE_SUFFIX}`
|
|
369
365
|
);
|
|
366
|
+
} else {
|
|
367
|
+
return fileContents;
|
|
370
368
|
}
|
|
371
|
-
return fileContents;
|
|
372
369
|
} catch (err) {
|
|
373
370
|
// For missing .sig files, throw `SignatureVerificationError` instead of `DoesNotExist` error.
|
|
374
|
-
if (err instanceof DoesNotExist && err.message.indexOf(sigPath) >= 0)
|
|
371
|
+
if (err instanceof DoesNotExist && err.message.indexOf(sigPath) >= 0) {
|
|
375
372
|
throw new SignatureVerificationError(
|
|
376
|
-
|
|
373
|
+
'Failed to obtain signature for file: ' +
|
|
374
|
+
`${path} -- looked in ${path}${SIGNATURE_FILE_SUFFIX}`
|
|
377
375
|
);
|
|
378
|
-
|
|
376
|
+
} else {
|
|
377
|
+
throw err;
|
|
378
|
+
}
|
|
379
379
|
}
|
|
380
380
|
}
|
|
381
381
|
|
|
@@ -393,14 +393,18 @@ export class Storage {
|
|
|
393
393
|
privateKey?: string,
|
|
394
394
|
username?: string,
|
|
395
395
|
zoneFileLookupURL?: string
|
|
396
|
-
|
|
396
|
+
// eslint-disable-next-line node/prefer-global/buffer
|
|
397
|
+
): Promise<string | Buffer> {
|
|
397
398
|
const appPrivateKey = privateKey || this.userSession.loadUserData().appPrivateKey;
|
|
398
399
|
|
|
399
400
|
const appPublicKey = getPublicKeyFromPrivate(appPrivateKey);
|
|
400
401
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
402
|
+
let address: string;
|
|
403
|
+
if (username) {
|
|
404
|
+
address = await this.getGaiaAddress(app, username, zoneFileLookupURL);
|
|
405
|
+
} else {
|
|
406
|
+
address = publicKeyToAddress(appPublicKey);
|
|
407
|
+
}
|
|
404
408
|
if (!address) {
|
|
405
409
|
throw new SignatureVerificationError(
|
|
406
410
|
`Failed to get gaia address for verification of: ${path}`
|
|
@@ -412,7 +416,9 @@ export class Storage {
|
|
|
412
416
|
} catch (err) {
|
|
413
417
|
if (err instanceof SyntaxError) {
|
|
414
418
|
throw new Error(
|
|
415
|
-
'Failed to parse encrypted, signed content JSON. The content may not
|
|
419
|
+
'Failed to parse encrypted, signed content JSON. The content may not ' +
|
|
420
|
+
'be encrypted. If using getFile, try passing' +
|
|
421
|
+
' { verify: false, decrypt: false }.'
|
|
416
422
|
);
|
|
417
423
|
} else {
|
|
418
424
|
throw err;
|
|
@@ -425,15 +431,15 @@ export class Storage {
|
|
|
425
431
|
|
|
426
432
|
if (!signerPublicKey || !cipherText || !signature) {
|
|
427
433
|
throw new SignatureVerificationError(
|
|
428
|
-
|
|
434
|
+
'Failed to get signature verification data from file:' + ` ${path}`
|
|
429
435
|
);
|
|
430
436
|
} else if (signerAddress !== address) {
|
|
431
437
|
throw new SignatureVerificationError(
|
|
432
|
-
`Signer pubkey address (${signerAddress}) doesn't match gaia address (${address})`
|
|
438
|
+
`Signer pubkey address (${signerAddress}) doesn't` + ` match gaia address (${address})`
|
|
433
439
|
);
|
|
434
440
|
} else if (!verifyECDSA(cipherText, signerPublicKey, signature)) {
|
|
435
441
|
throw new SignatureVerificationError(
|
|
436
|
-
|
|
442
|
+
'Contents do not match ECDSA signature in file:' + ` ${path}`
|
|
437
443
|
);
|
|
438
444
|
} else if (typeof privateKey === 'string') {
|
|
439
445
|
const decryptOpt = { privateKey };
|
|
@@ -446,7 +452,7 @@ export class Storage {
|
|
|
446
452
|
/**
|
|
447
453
|
* Stores the data provided in the app's data store to to the file specified.
|
|
448
454
|
* @param {String} path - the path to store the data in
|
|
449
|
-
* @param {String|
|
|
455
|
+
* @param {String|Buffer} content - the data to store in the file
|
|
450
456
|
* @param options a [[PutFileOptions]] object
|
|
451
457
|
*
|
|
452
458
|
* @returns {Promise} that resolves if the operation succeed and rejects
|
|
@@ -454,7 +460,8 @@ export class Storage {
|
|
|
454
460
|
*/
|
|
455
461
|
async putFile(
|
|
456
462
|
path: string,
|
|
457
|
-
|
|
463
|
+
// eslint-disable-next-line node/prefer-global/buffer
|
|
464
|
+
content: string | Buffer | ArrayBufferView | Blob,
|
|
458
465
|
options?: PutFileOptions
|
|
459
466
|
): Promise<string> {
|
|
460
467
|
const defaults: PutFileOptions = {
|
|
@@ -550,7 +557,8 @@ export class Storage {
|
|
|
550
557
|
};
|
|
551
558
|
} else {
|
|
552
559
|
// In all other cases, we only need one upload.
|
|
553
|
-
|
|
560
|
+
// eslint-disable-next-line node/prefer-global/buffer
|
|
561
|
+
let contentForUpload: string | Buffer | Blob;
|
|
554
562
|
if (!opt.encrypt && !opt.sign) {
|
|
555
563
|
// If content does not need encrypted or signed, it can be passed directly
|
|
556
564
|
// to the fetch request without loading into memory.
|