@ironcorelabs/ironweb 4.2.42 → 4.3.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/commonjs/Constants.js +3 -1
- package/commonjs/lib/Utils.js +40 -1
- package/commonjs/shim/FrameMediator.js +11 -7
- package/commonjs/shim/sdk/DocumentSDK.js +283 -19
- package/es/Constants.js +3 -1
- package/es/lib/Utils.js +37 -0
- package/es/shim/FrameMediator.js +11 -7
- package/es/shim/sdk/DocumentSDK.js +280 -18
- package/ironweb.d.ts +25 -0
- package/ironweb.min.js +1 -1
- package/ironweb.min.js.map +1 -1
- package/package.json +5 -1
package/commonjs/Constants.js
CHANGED
|
@@ -61,6 +61,8 @@ var ErrorCodes;
|
|
|
61
61
|
ErrorCodes[ErrorCodes["DOCUMENT_CREATE_WITH_ACCESS_FAILURE"] = 311] = "DOCUMENT_CREATE_WITH_ACCESS_FAILURE";
|
|
62
62
|
ErrorCodes[ErrorCodes["DOCUMENT_HEADER_PARSE_FAILURE"] = 312] = "DOCUMENT_HEADER_PARSE_FAILURE";
|
|
63
63
|
ErrorCodes[ErrorCodes["DOCUMENT_TRANSFORM_REQUEST_FAILURE"] = 313] = "DOCUMENT_TRANSFORM_REQUEST_FAILURE";
|
|
64
|
+
ErrorCodes[ErrorCodes["DOCUMENT_STREAM_DECRYPT_FAILURE"] = 314] = "DOCUMENT_STREAM_DECRYPT_FAILURE";
|
|
65
|
+
ErrorCodes[ErrorCodes["DOCUMENT_STREAM_ENCRYPT_FAILURE"] = 315] = "DOCUMENT_STREAM_ENCRYPT_FAILURE";
|
|
64
66
|
ErrorCodes[ErrorCodes["GROUP_LIST_REQUEST_FAILURE"] = 400] = "GROUP_LIST_REQUEST_FAILURE";
|
|
65
67
|
ErrorCodes[ErrorCodes["GROUP_GET_REQUEST_FAILURE"] = 401] = "GROUP_GET_REQUEST_FAILURE";
|
|
66
68
|
ErrorCodes[ErrorCodes["GROUP_CREATE_REQUEST_FAILURE"] = 402] = "GROUP_CREATE_REQUEST_FAILURE";
|
|
@@ -112,5 +114,5 @@ exports.UserAndGroupTypes = {
|
|
|
112
114
|
};
|
|
113
115
|
exports.Versions = {
|
|
114
116
|
//This define is replaced at runtime during development, and at build time in the build script with the proper version
|
|
115
|
-
SDK_VERSION: "4.
|
|
117
|
+
SDK_VERSION: "4.3.1",
|
|
116
118
|
};
|
package/commonjs/lib/Utils.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.sliceArrayBuffer = exports.concatArrayBuffers = exports.transformKeyToBase64 = exports.publicKeyToBytes = exports.publicKeyToBase64 = exports.arrayBufferToUtf8String = exports.utf8StringToArrayBuffer = void 0;
|
|
3
|
+
exports.parseDocumentHeader = exports.sliceArrayBuffer = exports.toTransferables = exports.concatArrayBuffers = exports.transformKeyToBase64 = exports.publicKeyToBytes = exports.publicKeyToBase64 = exports.arrayBufferToUtf8String = exports.utf8StringToArrayBuffer = void 0;
|
|
4
4
|
var UTF8 = require("@stablelib/utf8");
|
|
5
5
|
var base64_js_1 = require("base64-js");
|
|
6
|
+
var futurejs_1 = require("futurejs");
|
|
7
|
+
var Constants_1 = require("../Constants");
|
|
8
|
+
var SDKError_1 = require("./SDKError");
|
|
6
9
|
/**
|
|
7
10
|
* Convert a string into a ArrayBuffer, specifically a Uint8Array
|
|
8
11
|
*/
|
|
@@ -68,6 +71,14 @@ function concatArrayBuffers() {
|
|
|
68
71
|
}, new Uint8Array(length));
|
|
69
72
|
}
|
|
70
73
|
exports.concatArrayBuffers = concatArrayBuffers;
|
|
74
|
+
/**
|
|
75
|
+
* Convert a transfer list of Uint8Arrays and Transferables into a Transferable[].
|
|
76
|
+
* Uint8Arrays are unwrapped to their underlying ArrayBuffer; other items pass through.
|
|
77
|
+
*/
|
|
78
|
+
function toTransferables(items) {
|
|
79
|
+
return items.map(function (item) { return (item instanceof Uint8Array ? item.buffer : item); });
|
|
80
|
+
}
|
|
81
|
+
exports.toTransferables = toTransferables;
|
|
71
82
|
/**
|
|
72
83
|
* Polyfill since some environments (notably Phantom) don't support ArrayBuffer.slice
|
|
73
84
|
*/
|
|
@@ -78,3 +89,31 @@ function sliceArrayBuffer(buffer, start, end) {
|
|
|
78
89
|
return new Uint8Array(Array.prototype.slice.call(buffer, start, end));
|
|
79
90
|
}
|
|
80
91
|
exports.sliceArrayBuffer = sliceArrayBuffer;
|
|
92
|
+
/**
|
|
93
|
+
* Parse the IronCore document header from encrypted document bytes.
|
|
94
|
+
* Extracts the document ID (if v2), IV, and the byte offset where ciphertext begins.
|
|
95
|
+
*/
|
|
96
|
+
function parseDocumentHeader(data) {
|
|
97
|
+
return futurejs_1.default.tryF(function () {
|
|
98
|
+
var version = data[0];
|
|
99
|
+
var documentID = null;
|
|
100
|
+
var headerTotalLength;
|
|
101
|
+
if (version === 1) {
|
|
102
|
+
headerTotalLength = Constants_1.VERSION_HEADER_LENGTH;
|
|
103
|
+
}
|
|
104
|
+
else if (version === 2) {
|
|
105
|
+
var headerJsonLength = new DataView(data.buffer, data.byteOffset).getUint16(Constants_1.VERSION_HEADER_LENGTH, false);
|
|
106
|
+
headerTotalLength = Constants_1.VERSION_HEADER_LENGTH + Constants_1.HEADER_META_LENGTH_LENGTH + headerJsonLength;
|
|
107
|
+
var headerContent = data.slice(Constants_1.VERSION_HEADER_LENGTH + Constants_1.HEADER_META_LENGTH_LENGTH, headerTotalLength);
|
|
108
|
+
var headerObject = JSON.parse(UTF8.decode(headerContent));
|
|
109
|
+
documentID = headerObject._did_;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
throw new Error("Provided encrypted document doesn't appear to be valid. Invalid version.");
|
|
113
|
+
}
|
|
114
|
+
var contentOffset = headerTotalLength + Constants_1.CryptoConstants.IV_LENGTH;
|
|
115
|
+
var iv = data.slice(headerTotalLength, contentOffset);
|
|
116
|
+
return { documentID: documentID, iv: iv, contentOffset: contentOffset };
|
|
117
|
+
}).errorMap(function (error) { return new SDKError_1.default(error, Constants_1.ErrorCodes.DOCUMENT_HEADER_PARSE_FAILURE); });
|
|
118
|
+
}
|
|
119
|
+
exports.parseDocumentHeader = parseDocumentHeader;
|
|
@@ -4,6 +4,7 @@ exports.sendMessage = exports.messenger = exports.ShimMessenger = void 0;
|
|
|
4
4
|
var futurejs_1 = require("futurejs");
|
|
5
5
|
var Constants_1 = require("../Constants");
|
|
6
6
|
var SDKError_1 = require("../lib/SDKError");
|
|
7
|
+
var Utils_1 = require("../lib/Utils");
|
|
7
8
|
/**
|
|
8
9
|
* Class which handles messaging from the shim into the frame. Holds callback messages so that users can interact with this
|
|
9
10
|
* class via Futures. Also handles the creation of all the ChannelMessage ports to pass down to the frame.
|
|
@@ -36,7 +37,7 @@ var ShimMessenger = /** @class */ (function () {
|
|
|
36
37
|
/**
|
|
37
38
|
* Post request message to child iFrame
|
|
38
39
|
* @param {RequestMessage} data RequestMessage to post to child iFrame
|
|
39
|
-
* @param {Uint8Array[]} transferList List of byte arrays to transfer to frame
|
|
40
|
+
* @param {Uint8Array[]} transferList List of byte arrays or transferables to transfer to frame
|
|
40
41
|
*/
|
|
41
42
|
ShimMessenger.prototype.postMessageToFrame = function (data, transferList) {
|
|
42
43
|
var _this = this;
|
|
@@ -46,16 +47,19 @@ var ShimMessenger = /** @class */ (function () {
|
|
|
46
47
|
data: data,
|
|
47
48
|
};
|
|
48
49
|
try {
|
|
49
|
-
this.messagePort.postMessage(message,
|
|
50
|
-
var buffer = _a.buffer;
|
|
51
|
-
return buffer;
|
|
52
|
-
}));
|
|
50
|
+
this.messagePort.postMessage(message, (0, Utils_1.toTransferables)(transferList));
|
|
53
51
|
return new futurejs_1.default(function (_, resolve) {
|
|
54
52
|
_this.callbacks[message.replyID] = resolve;
|
|
55
53
|
});
|
|
56
54
|
}
|
|
57
|
-
catch (
|
|
58
|
-
|
|
55
|
+
catch (_e) {
|
|
56
|
+
var hasStreams = transferList.some(function (item) { return item instanceof ReadableStream || item instanceof WritableStream; });
|
|
57
|
+
// Safari is the notable holdout here (https://github.com/WebKit/standards-positions/issues/643). For now,
|
|
58
|
+
// give an informative message about support.
|
|
59
|
+
var message_1 = hasStreams
|
|
60
|
+
? "Streaming encrypt/decrypt requires transferable streams, which is not supported by this browser. It is known to be supported by Chrome, Firefox, and Edge."
|
|
61
|
+
: "Failure occurred when passing message due to the lack of browser support.";
|
|
62
|
+
return futurejs_1.default.reject(new SDKError_1.default(new Error(message_1), Constants_1.ErrorCodes.BROWSER_FRAME_MESSAGE_FAILURE));
|
|
59
63
|
}
|
|
60
64
|
};
|
|
61
65
|
return ShimMessenger;
|
|
@@ -1,4 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (_) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
2
38
|
var __read = (this && this.__read) || function (o, n) {
|
|
3
39
|
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
4
40
|
if (!m) return o;
|
|
@@ -15,14 +51,23 @@ var __read = (this && this.__read) || function (o, n) {
|
|
|
15
51
|
}
|
|
16
52
|
return ar;
|
|
17
53
|
};
|
|
54
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
55
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
56
|
+
if (ar || !(i in from)) {
|
|
57
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
58
|
+
ar[i] = from[i];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
62
|
+
};
|
|
18
63
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.advanced = exports.revokeAccess = exports.grantAccess = exports.updateName = exports.updateEncryptedData = exports.updateEncryptedDataInStore = exports.encrypt = exports.encryptToStore = exports.decrypt = exports.decryptFromStore = exports.getDocumentIDFromBytes = exports.getMetadata = exports.list = void 0;
|
|
64
|
+
exports.advanced = exports.decryptStream = exports.encryptStream = exports.revokeAccess = exports.grantAccess = exports.updateName = exports.updateEncryptedData = exports.updateEncryptedDataInStore = exports.encrypt = exports.encryptToStore = exports.decrypt = exports.decryptFromStore = exports.getDocumentIDFromBytes = exports.getMetadata = exports.list = void 0;
|
|
20
65
|
var futurejs_1 = require("futurejs");
|
|
21
66
|
var Constants_1 = require("../../Constants");
|
|
22
67
|
var SDKError_1 = require("../../lib/SDKError");
|
|
68
|
+
var Utils_1 = require("../../lib/Utils");
|
|
23
69
|
var FrameMediator = require("../FrameMediator");
|
|
24
70
|
var ShimUtils = require("../ShimUtils");
|
|
25
|
-
var CodecSDK_1 = require("./CodecSDK");
|
|
26
71
|
var MAX_DOCUMENT_SIZE = 1024 * 2 * 1000; //2MB
|
|
27
72
|
/**
|
|
28
73
|
* Takes the document encrypt options object and normalizes it to a complete object with proper default values.
|
|
@@ -88,23 +133,12 @@ exports.getMetadata = getMetadata;
|
|
|
88
133
|
function getDocumentIDFromBytes(documentData) {
|
|
89
134
|
ShimUtils.checkSDKInitialized();
|
|
90
135
|
ShimUtils.validateEncryptedDocument(documentData);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return Promise.reject(new SDKError_1.default(new Error("Provided encrypted document doesn't appear to be valid. Invalid version."), Constants_1.ErrorCodes.DOCUMENT_HEADER_PARSE_FAILURE));
|
|
98
|
-
}
|
|
99
|
-
var headerLength = new DataView(documentData.buffer).getUint16(documentData.byteOffset + Constants_1.VERSION_HEADER_LENGTH, false);
|
|
100
|
-
var headerContent = documentData.slice(Constants_1.VERSION_HEADER_LENGTH + Constants_1.HEADER_META_LENGTH_LENGTH, Constants_1.VERSION_HEADER_LENGTH + Constants_1.HEADER_META_LENGTH_LENGTH + headerLength);
|
|
101
|
-
try {
|
|
102
|
-
var headerObject = JSON.parse(CodecSDK_1.utf8.fromBytes(headerContent));
|
|
103
|
-
return Promise.resolve(headerObject._did_);
|
|
104
|
-
}
|
|
105
|
-
catch (_a) {
|
|
106
|
-
return Promise.reject(new SDKError_1.default(new Error("Unable to parse document header. Header value is corrupted."), Constants_1.ErrorCodes.DOCUMENT_HEADER_PARSE_FAILURE));
|
|
107
|
-
}
|
|
136
|
+
return (0, Utils_1.parseDocumentHeader)(documentData)
|
|
137
|
+
.map(function (_a) {
|
|
138
|
+
var documentID = _a.documentID;
|
|
139
|
+
return documentID;
|
|
140
|
+
})
|
|
141
|
+
.toPromise();
|
|
108
142
|
}
|
|
109
143
|
exports.getDocumentIDFromBytes = getDocumentIDFromBytes;
|
|
110
144
|
/**
|
|
@@ -369,6 +403,176 @@ function revokeAccess(documentID, revokeList) {
|
|
|
369
403
|
.toPromise();
|
|
370
404
|
}
|
|
371
405
|
exports.revokeAccess = revokeAccess;
|
|
406
|
+
/**
|
|
407
|
+
* Parse the version header, header JSON, and IV from the beginning of an encrypted ReadableStream.
|
|
408
|
+
* Returns the document ID, IV, and a new ReadableStream starting after the header+IV (ciphertext only).
|
|
409
|
+
*/
|
|
410
|
+
function parseStreamHeader(encryptedStream) {
|
|
411
|
+
var _this = this;
|
|
412
|
+
return futurejs_1.default.tryP(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
413
|
+
var reader, chunks_1, totalLen_1, readAtLeastIntoChunks, initialHeaderBytes, headerJsonLength, e_1;
|
|
414
|
+
var _this = this;
|
|
415
|
+
return __generator(this, function (_a) {
|
|
416
|
+
switch (_a.label) {
|
|
417
|
+
case 0:
|
|
418
|
+
reader = encryptedStream.getReader();
|
|
419
|
+
_a.label = 1;
|
|
420
|
+
case 1:
|
|
421
|
+
_a.trys.push([1, 7, , 8]);
|
|
422
|
+
chunks_1 = [];
|
|
423
|
+
totalLen_1 = 0;
|
|
424
|
+
readAtLeastIntoChunks = function (n) { return __awaiter(_this, void 0, void 0, function () {
|
|
425
|
+
var _a, done, value;
|
|
426
|
+
return __generator(this, function (_b) {
|
|
427
|
+
switch (_b.label) {
|
|
428
|
+
case 0:
|
|
429
|
+
if (!(totalLen_1 < n)) return [3 /*break*/, 2];
|
|
430
|
+
return [4 /*yield*/, reader.read()];
|
|
431
|
+
case 1:
|
|
432
|
+
_a = _b.sent(), done = _a.done, value = _a.value;
|
|
433
|
+
if (done)
|
|
434
|
+
throw new SDKError_1.default(new Error("Encrypted stream ended before header could be parsed"), Constants_1.ErrorCodes.DOCUMENT_HEADER_PARSE_FAILURE);
|
|
435
|
+
chunks_1.push(value);
|
|
436
|
+
totalLen_1 += value.length;
|
|
437
|
+
return [3 /*break*/, 0];
|
|
438
|
+
case 2: return [2 /*return*/];
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
}); };
|
|
442
|
+
// Need to read the header length prefix to know total size.
|
|
443
|
+
return [4 /*yield*/, readAtLeastIntoChunks(Constants_1.VERSION_HEADER_LENGTH + Constants_1.HEADER_META_LENGTH_LENGTH)];
|
|
444
|
+
case 2:
|
|
445
|
+
// Need to read the header length prefix to know total size.
|
|
446
|
+
_a.sent();
|
|
447
|
+
initialHeaderBytes = Utils_1.concatArrayBuffers.apply(void 0, __spreadArray([], __read(chunks_1), false));
|
|
448
|
+
if (!(initialHeaderBytes[0] === 2)) return [3 /*break*/, 4];
|
|
449
|
+
headerJsonLength = new DataView(initialHeaderBytes.buffer, initialHeaderBytes.byteOffset).getUint16(Constants_1.VERSION_HEADER_LENGTH, false);
|
|
450
|
+
return [4 /*yield*/, readAtLeastIntoChunks(Constants_1.VERSION_HEADER_LENGTH + Constants_1.HEADER_META_LENGTH_LENGTH + headerJsonLength + 12)];
|
|
451
|
+
case 3:
|
|
452
|
+
_a.sent();
|
|
453
|
+
return [3 /*break*/, 6];
|
|
454
|
+
case 4: return [4 /*yield*/, readAtLeastIntoChunks(Constants_1.VERSION_HEADER_LENGTH + 12)];
|
|
455
|
+
case 5:
|
|
456
|
+
_a.sent();
|
|
457
|
+
_a.label = 6;
|
|
458
|
+
case 6: return [2 /*return*/, { reader: reader, buffer: Utils_1.concatArrayBuffers.apply(void 0, __spreadArray([], __read(chunks_1), false)) }];
|
|
459
|
+
case 7:
|
|
460
|
+
e_1 = _a.sent();
|
|
461
|
+
// On any error in reading header chunks we need to release the reader
|
|
462
|
+
reader.releaseLock();
|
|
463
|
+
throw e_1;
|
|
464
|
+
case 8: return [2 /*return*/];
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
}); }).flatMap(function (_a) {
|
|
468
|
+
var reader = _a.reader, buffer = _a.buffer;
|
|
469
|
+
return (0, Utils_1.parseDocumentHeader)(buffer)
|
|
470
|
+
.map(function (parsed) {
|
|
471
|
+
var remainder = buffer.slice(parsed.contentOffset);
|
|
472
|
+
// Once we've parsed the header we might have remaining bytes. If
|
|
473
|
+
// we do we start out the ciphertextStream by writing them and then pull
|
|
474
|
+
// can just pull from the reader we had previously read from.
|
|
475
|
+
var ciphertextStream = new ReadableStream({
|
|
476
|
+
start: function (controller) {
|
|
477
|
+
if (remainder.length > 0) {
|
|
478
|
+
controller.enqueue(remainder);
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
pull: function (controller) {
|
|
482
|
+
return reader.read().then(function (_a) {
|
|
483
|
+
var done = _a.done, value = _a.value;
|
|
484
|
+
done ? controller.close() : controller.enqueue(value);
|
|
485
|
+
});
|
|
486
|
+
},
|
|
487
|
+
cancel: function () {
|
|
488
|
+
return reader.cancel();
|
|
489
|
+
},
|
|
490
|
+
});
|
|
491
|
+
return { documentID: parsed.documentID, iv: parsed.iv, ciphertextStream: ciphertextStream };
|
|
492
|
+
})
|
|
493
|
+
.errorMap(function (e) {
|
|
494
|
+
// On any error in preparing the new stream we need to release the reader lock
|
|
495
|
+
// This is purely defensive.
|
|
496
|
+
reader.releaseLock();
|
|
497
|
+
return e;
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Encrypt a plaintext stream. Returns a Promise which resolves with the encrypted stream and document metadata.
|
|
503
|
+
* The output stream produces bytes in the same format as encrypt(): [header][IV][ciphertext][auth_tag].
|
|
504
|
+
*
|
|
505
|
+
* @param {ReadableStream<Uint8Array>} plaintextStream Plaintext data as a ReadableStream
|
|
506
|
+
* @param {DocumentCreateOptions} options Document create options
|
|
507
|
+
*/
|
|
508
|
+
function encryptStream(plaintextStream, options) {
|
|
509
|
+
ShimUtils.checkSDKInitialized();
|
|
510
|
+
var encryptOptions = calculateDocumentCreateOptionsDefault(options);
|
|
511
|
+
if (encryptOptions.documentID) {
|
|
512
|
+
ShimUtils.validateID(encryptOptions.documentID);
|
|
513
|
+
}
|
|
514
|
+
var _a = __read(ShimUtils.dedupeAccessLists(encryptOptions.accessList), 2), userGrants = _a[0], groupGrants = _a[1];
|
|
515
|
+
var payload = {
|
|
516
|
+
type: "DOCUMENT_STREAM_ENCRYPT",
|
|
517
|
+
message: {
|
|
518
|
+
documentID: encryptOptions.documentID,
|
|
519
|
+
documentName: encryptOptions.documentName,
|
|
520
|
+
plaintextStream: plaintextStream,
|
|
521
|
+
userGrants: userGrants,
|
|
522
|
+
groupGrants: groupGrants,
|
|
523
|
+
grantToAuthor: encryptOptions.accessList.grantToAuthor,
|
|
524
|
+
policy: encryptOptions.policy,
|
|
525
|
+
},
|
|
526
|
+
};
|
|
527
|
+
// Cast needed because TS's Transferable type doesn't yet include ReadableStream/WritableStream
|
|
528
|
+
return FrameMediator.sendMessage(payload, [plaintextStream])
|
|
529
|
+
.map(function (_a) {
|
|
530
|
+
var message = _a.message;
|
|
531
|
+
return ({
|
|
532
|
+
documentID: message.documentID,
|
|
533
|
+
documentName: message.documentName,
|
|
534
|
+
encryptedStream: message.encryptedStream,
|
|
535
|
+
created: message.created,
|
|
536
|
+
updated: message.updated,
|
|
537
|
+
});
|
|
538
|
+
})
|
|
539
|
+
.toPromise();
|
|
540
|
+
}
|
|
541
|
+
exports.encryptStream = encryptStream;
|
|
542
|
+
/**
|
|
543
|
+
* Decrypt an encrypted document stream. Parses the header and IV from the stream, then streams decrypted
|
|
544
|
+
* plaintext back via the returned ReadableStream. If the auth tag fails at the end of the stream, the
|
|
545
|
+
* readable side errors — which propagates through pipeTo() to abort any destination WritableStream.
|
|
546
|
+
*
|
|
547
|
+
* @param {string} documentID ID of the document to decrypt
|
|
548
|
+
* @param {ReadableStream<Uint8Array>} encryptedStream Encrypted document as a ReadableStream (from fetch().body, file.stream(), etc.)
|
|
549
|
+
*/
|
|
550
|
+
function decryptStream(documentID, encryptedStream) {
|
|
551
|
+
ShimUtils.checkSDKInitialized();
|
|
552
|
+
ShimUtils.validateID(documentID);
|
|
553
|
+
return parseStreamHeader(encryptedStream)
|
|
554
|
+
.flatMap(function (_a) {
|
|
555
|
+
var iv = _a.iv, ciphertextStream = _a.ciphertextStream;
|
|
556
|
+
var payload = {
|
|
557
|
+
type: "DOCUMENT_STREAM_DECRYPT",
|
|
558
|
+
message: { documentID: documentID, iv: iv, encryptedStream: ciphertextStream },
|
|
559
|
+
};
|
|
560
|
+
return FrameMediator.sendMessage(payload, [ciphertextStream]).map(function (_a) {
|
|
561
|
+
var message = _a.message;
|
|
562
|
+
return ({
|
|
563
|
+
documentID: documentID,
|
|
564
|
+
documentName: message.documentName,
|
|
565
|
+
visibleTo: message.visibleTo,
|
|
566
|
+
association: message.association,
|
|
567
|
+
created: message.created,
|
|
568
|
+
updated: message.updated,
|
|
569
|
+
plaintextStream: message.plaintextStream,
|
|
570
|
+
});
|
|
571
|
+
});
|
|
572
|
+
})
|
|
573
|
+
.toPromise();
|
|
574
|
+
}
|
|
575
|
+
exports.decryptStream = decryptStream;
|
|
372
576
|
/**
|
|
373
577
|
* A collection of methods for advanced encryption/decryption use cases. Currently focused on methods which require the caller to manage the encrypted
|
|
374
578
|
* DEKs.
|
|
@@ -404,6 +608,66 @@ exports.advanced = {
|
|
|
404
608
|
})
|
|
405
609
|
.toPromise();
|
|
406
610
|
},
|
|
611
|
+
/**
|
|
612
|
+
* Streaming decrypt with caller-provided EDEKs. Parses the header/IV from the stream, then decrypts.
|
|
613
|
+
* If the auth tag fails, the returned plaintextStream errors.
|
|
614
|
+
*/
|
|
615
|
+
decryptStreamUnmanaged: function (encryptedStream, edeks) {
|
|
616
|
+
ShimUtils.checkSDKInitialized();
|
|
617
|
+
ShimUtils.validateEncryptedDeks(edeks);
|
|
618
|
+
return parseStreamHeader(encryptedStream)
|
|
619
|
+
.flatMap(function (_a) {
|
|
620
|
+
var documentID = _a.documentID, iv = _a.iv, ciphertextStream = _a.ciphertextStream;
|
|
621
|
+
var payload = {
|
|
622
|
+
type: "DOCUMENT_UNMANAGED_STREAM_DECRYPT",
|
|
623
|
+
message: { edeks: edeks, iv: iv, encryptedStream: ciphertextStream },
|
|
624
|
+
};
|
|
625
|
+
return FrameMediator.sendMessage(payload, [
|
|
626
|
+
ciphertextStream,
|
|
627
|
+
]).map(function (_a) {
|
|
628
|
+
var message = _a.message;
|
|
629
|
+
return ({
|
|
630
|
+
documentID: documentID,
|
|
631
|
+
plaintextStream: message.plaintextStream,
|
|
632
|
+
accessVia: message.accessVia,
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
})
|
|
636
|
+
.toPromise();
|
|
637
|
+
},
|
|
638
|
+
/**
|
|
639
|
+
* Streaming encrypt with caller-managed EDEKs. Returns the encrypted stream and EDEKs to the caller.
|
|
640
|
+
* The output stream produces bytes in the same format as encrypt(): [header][IV][ciphertext][auth_tag].
|
|
641
|
+
*/
|
|
642
|
+
encryptStreamUnmanaged: function (plaintextStream, options) {
|
|
643
|
+
ShimUtils.checkSDKInitialized();
|
|
644
|
+
var encryptOptions = calculateDocumentCreateOptionsDefault(options);
|
|
645
|
+
if (encryptOptions.documentID) {
|
|
646
|
+
ShimUtils.validateID(encryptOptions.documentID);
|
|
647
|
+
}
|
|
648
|
+
var _a = __read(ShimUtils.dedupeAccessLists(encryptOptions.accessList), 2), userGrants = _a[0], groupGrants = _a[1];
|
|
649
|
+
var payload = {
|
|
650
|
+
type: "DOCUMENT_UNMANAGED_STREAM_ENCRYPT",
|
|
651
|
+
message: {
|
|
652
|
+
documentID: encryptOptions.documentID,
|
|
653
|
+
plaintextStream: plaintextStream,
|
|
654
|
+
userGrants: userGrants,
|
|
655
|
+
groupGrants: groupGrants,
|
|
656
|
+
grantToAuthor: encryptOptions.accessList.grantToAuthor,
|
|
657
|
+
policy: encryptOptions.policy,
|
|
658
|
+
},
|
|
659
|
+
};
|
|
660
|
+
return FrameMediator.sendMessage(payload, [plaintextStream])
|
|
661
|
+
.map(function (_a) {
|
|
662
|
+
var message = _a.message;
|
|
663
|
+
return ({
|
|
664
|
+
documentID: message.documentID,
|
|
665
|
+
encryptedStream: message.encryptedStream,
|
|
666
|
+
edeks: message.edeks,
|
|
667
|
+
});
|
|
668
|
+
})
|
|
669
|
+
.toPromise();
|
|
670
|
+
},
|
|
407
671
|
/**
|
|
408
672
|
* Encrypt the provided document with various document create options. Does not store any part of the document within IronCore and instead returns
|
|
409
673
|
* the encrypted DEKs to the caller. These encrypted DEKs must be then be provided as input in order to decrypt the document.
|
package/es/Constants.js
CHANGED
|
@@ -58,6 +58,8 @@ export var ErrorCodes;
|
|
|
58
58
|
ErrorCodes[ErrorCodes["DOCUMENT_CREATE_WITH_ACCESS_FAILURE"] = 311] = "DOCUMENT_CREATE_WITH_ACCESS_FAILURE";
|
|
59
59
|
ErrorCodes[ErrorCodes["DOCUMENT_HEADER_PARSE_FAILURE"] = 312] = "DOCUMENT_HEADER_PARSE_FAILURE";
|
|
60
60
|
ErrorCodes[ErrorCodes["DOCUMENT_TRANSFORM_REQUEST_FAILURE"] = 313] = "DOCUMENT_TRANSFORM_REQUEST_FAILURE";
|
|
61
|
+
ErrorCodes[ErrorCodes["DOCUMENT_STREAM_DECRYPT_FAILURE"] = 314] = "DOCUMENT_STREAM_DECRYPT_FAILURE";
|
|
62
|
+
ErrorCodes[ErrorCodes["DOCUMENT_STREAM_ENCRYPT_FAILURE"] = 315] = "DOCUMENT_STREAM_ENCRYPT_FAILURE";
|
|
61
63
|
ErrorCodes[ErrorCodes["GROUP_LIST_REQUEST_FAILURE"] = 400] = "GROUP_LIST_REQUEST_FAILURE";
|
|
62
64
|
ErrorCodes[ErrorCodes["GROUP_GET_REQUEST_FAILURE"] = 401] = "GROUP_GET_REQUEST_FAILURE";
|
|
63
65
|
ErrorCodes[ErrorCodes["GROUP_CREATE_REQUEST_FAILURE"] = 402] = "GROUP_CREATE_REQUEST_FAILURE";
|
|
@@ -109,5 +111,5 @@ export var UserAndGroupTypes = {
|
|
|
109
111
|
};
|
|
110
112
|
export var Versions = {
|
|
111
113
|
//This define is replaced at runtime during development, and at build time in the build script with the proper version
|
|
112
|
-
SDK_VERSION: "4.
|
|
114
|
+
SDK_VERSION: "4.3.1",
|
|
113
115
|
};
|
package/es/lib/Utils.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import * as UTF8 from "@stablelib/utf8";
|
|
2
2
|
import { fromByteArray, toByteArray } from "base64-js";
|
|
3
|
+
import Future from "futurejs";
|
|
4
|
+
import { CryptoConstants, ErrorCodes, VERSION_HEADER_LENGTH, HEADER_META_LENGTH_LENGTH } from "../Constants";
|
|
5
|
+
import SDKError from "./SDKError";
|
|
3
6
|
/**
|
|
4
7
|
* Convert a string into a ArrayBuffer, specifically a Uint8Array
|
|
5
8
|
*/
|
|
@@ -59,6 +62,13 @@ export function concatArrayBuffers() {
|
|
|
59
62
|
return newBuffer;
|
|
60
63
|
}, new Uint8Array(length));
|
|
61
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Convert a transfer list of Uint8Arrays and Transferables into a Transferable[].
|
|
67
|
+
* Uint8Arrays are unwrapped to their underlying ArrayBuffer; other items pass through.
|
|
68
|
+
*/
|
|
69
|
+
export function toTransferables(items) {
|
|
70
|
+
return items.map(function (item) { return (item instanceof Uint8Array ? item.buffer : item); });
|
|
71
|
+
}
|
|
62
72
|
/**
|
|
63
73
|
* Polyfill since some environments (notably Phantom) don't support ArrayBuffer.slice
|
|
64
74
|
*/
|
|
@@ -68,3 +78,30 @@ export function sliceArrayBuffer(buffer, start, end) {
|
|
|
68
78
|
}
|
|
69
79
|
return new Uint8Array(Array.prototype.slice.call(buffer, start, end));
|
|
70
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Parse the IronCore document header from encrypted document bytes.
|
|
83
|
+
* Extracts the document ID (if v2), IV, and the byte offset where ciphertext begins.
|
|
84
|
+
*/
|
|
85
|
+
export function parseDocumentHeader(data) {
|
|
86
|
+
return Future.tryF(function () {
|
|
87
|
+
var version = data[0];
|
|
88
|
+
var documentID = null;
|
|
89
|
+
var headerTotalLength;
|
|
90
|
+
if (version === 1) {
|
|
91
|
+
headerTotalLength = VERSION_HEADER_LENGTH;
|
|
92
|
+
}
|
|
93
|
+
else if (version === 2) {
|
|
94
|
+
var headerJsonLength = new DataView(data.buffer, data.byteOffset).getUint16(VERSION_HEADER_LENGTH, false);
|
|
95
|
+
headerTotalLength = VERSION_HEADER_LENGTH + HEADER_META_LENGTH_LENGTH + headerJsonLength;
|
|
96
|
+
var headerContent = data.slice(VERSION_HEADER_LENGTH + HEADER_META_LENGTH_LENGTH, headerTotalLength);
|
|
97
|
+
var headerObject = JSON.parse(UTF8.decode(headerContent));
|
|
98
|
+
documentID = headerObject._did_;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
throw new Error("Provided encrypted document doesn't appear to be valid. Invalid version.");
|
|
102
|
+
}
|
|
103
|
+
var contentOffset = headerTotalLength + CryptoConstants.IV_LENGTH;
|
|
104
|
+
var iv = data.slice(headerTotalLength, contentOffset);
|
|
105
|
+
return { documentID: documentID, iv: iv, contentOffset: contentOffset };
|
|
106
|
+
}).errorMap(function (error) { return new SDKError(error, ErrorCodes.DOCUMENT_HEADER_PARSE_FAILURE); });
|
|
107
|
+
}
|
package/es/shim/FrameMediator.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Future from "futurejs";
|
|
2
2
|
import { ErrorCodes, Frame, Versions } from "../Constants";
|
|
3
3
|
import SDKError from "../lib/SDKError";
|
|
4
|
+
import { toTransferables } from "../lib/Utils";
|
|
4
5
|
/**
|
|
5
6
|
* Class which handles messaging from the shim into the frame. Holds callback messages so that users can interact with this
|
|
6
7
|
* class via Futures. Also handles the creation of all the ChannelMessage ports to pass down to the frame.
|
|
@@ -33,7 +34,7 @@ var ShimMessenger = /** @class */ (function () {
|
|
|
33
34
|
/**
|
|
34
35
|
* Post request message to child iFrame
|
|
35
36
|
* @param {RequestMessage} data RequestMessage to post to child iFrame
|
|
36
|
-
* @param {Uint8Array[]} transferList List of byte arrays to transfer to frame
|
|
37
|
+
* @param {Uint8Array[]} transferList List of byte arrays or transferables to transfer to frame
|
|
37
38
|
*/
|
|
38
39
|
ShimMessenger.prototype.postMessageToFrame = function (data, transferList) {
|
|
39
40
|
var _this = this;
|
|
@@ -43,16 +44,19 @@ var ShimMessenger = /** @class */ (function () {
|
|
|
43
44
|
data: data,
|
|
44
45
|
};
|
|
45
46
|
try {
|
|
46
|
-
this.messagePort.postMessage(message, transferList
|
|
47
|
-
var buffer = _a.buffer;
|
|
48
|
-
return buffer;
|
|
49
|
-
}));
|
|
47
|
+
this.messagePort.postMessage(message, toTransferables(transferList));
|
|
50
48
|
return new Future(function (_, resolve) {
|
|
51
49
|
_this.callbacks[message.replyID] = resolve;
|
|
52
50
|
});
|
|
53
51
|
}
|
|
54
|
-
catch (
|
|
55
|
-
|
|
52
|
+
catch (_e) {
|
|
53
|
+
var hasStreams = transferList.some(function (item) { return item instanceof ReadableStream || item instanceof WritableStream; });
|
|
54
|
+
// Safari is the notable holdout here (https://github.com/WebKit/standards-positions/issues/643). For now,
|
|
55
|
+
// give an informative message about support.
|
|
56
|
+
var message_1 = hasStreams
|
|
57
|
+
? "Streaming encrypt/decrypt requires transferable streams, which is not supported by this browser. It is known to be supported by Chrome, Firefox, and Edge."
|
|
58
|
+
: "Failure occurred when passing message due to the lack of browser support.";
|
|
59
|
+
return Future.reject(new SDKError(new Error(message_1), ErrorCodes.BROWSER_FRAME_MESSAGE_FAILURE));
|
|
56
60
|
}
|
|
57
61
|
};
|
|
58
62
|
return ShimMessenger;
|