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