'use strict';

Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.SECRET_STORAGE_ALGORITHM_V1 = undefined;

var _defineProperty2 = require('babel-runtime/helpers/defineProperty');

var _defineProperty3 = _interopRequireDefault(_defineProperty2);

var _keys = require('babel-runtime/core-js/object/keys');

var _keys2 = _interopRequireDefault(_keys);

var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray');

var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);

var _getIterator2 = require('babel-runtime/core-js/get-iterator');

var _getIterator3 = _interopRequireDefault(_getIterator2);

var _regenerator = require('babel-runtime/regenerator');

var _regenerator2 = _interopRequireDefault(_regenerator);

var _bluebird = require('bluebird');

var _promise = require('babel-runtime/core-js/promise');

var _promise2 = _interopRequireDefault(_promise);

var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');

var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require('babel-runtime/helpers/createClass');

var _createClass3 = _interopRequireDefault(_createClass2);

var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');

var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);

var _inherits2 = require('babel-runtime/helpers/inherits');

var _inherits3 = _interopRequireDefault(_inherits2);

var _events = require('events');

var _logger = require('../logger');

var _logger2 = _interopRequireDefault(_logger);

var _olmlib = require('./olmlib');

var _olmlib2 = _interopRequireDefault(_olmlib);

var _randomstring = require('../randomstring');

var _key_passphrase = require('./key_passphrase');

var _recoverykey = require('./recoverykey');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var SECRET_STORAGE_ALGORITHM_V1 = exports.SECRET_STORAGE_ALGORITHM_V1 = "m.secret_storage.v1.curve25519-aes-sha2";

/**
 * Implements Secure Secret Storage and Sharing (MSC1946)
 * @module crypto/SecretStorage
 */
/*
Copyright 2019 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var SecretStorage = function (_EventEmitter) {
    (0, _inherits3.default)(SecretStorage, _EventEmitter);

    function SecretStorage(baseApis, cryptoCallbacks, crossSigningInfo) {
        (0, _classCallCheck3.default)(this, SecretStorage);

        var _this = (0, _possibleConstructorReturn3.default)(this, (SecretStorage.__proto__ || (0, _getPrototypeOf2.default)(SecretStorage)).call(this));

        _this._baseApis = baseApis;
        _this._cryptoCallbacks = cryptoCallbacks;
        _this._crossSigningInfo = crossSigningInfo;
        _this._requests = {};
        _this._incomingRequests = {};
        return _this;
    }

    (0, _createClass3.default)(SecretStorage, [{
        key: 'getDefaultKeyId',
        value: function getDefaultKeyId() {
            var defaultKeyEvent = this._baseApis.getAccountData('m.secret_storage.default_key');
            if (!defaultKeyEvent) return null;
            return defaultKeyEvent.getContent().key;
        }
    }, {
        key: 'setDefaultKeyId',
        value: function setDefaultKeyId(keyId) {
            var _this2 = this;

            return new _promise2.default(function (resolve) {
                var listener = function listener(ev) {
                    if (ev.getType() === 'm.secret_storage.default_key' && ev.getContent().key === keyId) {
                        _this2._baseApis.removeListener('accountData', listener);
                        resolve();
                    }
                };
                _this2._baseApis.on('accountData', listener);

                _this2._baseApis.setAccountData('m.secret_storage.default_key', { key: keyId });
            });
        }

        /**
         * Add a key for encrypting secrets.
         *
         * @param {string} algorithm the algorithm used by the key.
         * @param {object} opts the options for the algorithm.  The properties used
         *     depend on the algorithm given.  This object may be modified to pass
         *     information back about the key.
         * @param {string} [keyId] the ID of the key.  If not given, a random
         *     ID will be generated.
         *
         * @return {string} the ID of the key
         */

    }, {
        key: 'addKey',
        value: function () {
            var _ref = (0, _bluebird.coroutine)( /*#__PURE__*/_regenerator2.default.mark(function _callee(algorithm, opts, keyId) {
                var keyData, decryption, key;
                return _regenerator2.default.wrap(function _callee$(_context) {
                    while (1) {
                        switch (_context.prev = _context.next) {
                            case 0:
                                keyData = { algorithm: algorithm };


                                if (!opts) opts = {};

                                if (opts.name) {
                                    keyData.name = opts.name;
                                }

                                _context.t0 = algorithm;
                                _context.next = _context.t0 === SECRET_STORAGE_ALGORITHM_V1 ? 6 : 22;
                                break;

                            case 6:
                                decryption = new global.Olm.PkDecryption();
                                _context.prev = 7;

                                if (!opts.passphrase) {
                                    _context.next = 17;
                                    break;
                                }

                                _context.next = 11;
                                return (0, _bluebird.resolve)((0, _key_passphrase.keyFromPassphrase)(opts.passphrase));

                            case 11:
                                key = _context.sent;

                                keyData.passphrase = {
                                    algorithm: "m.pbkdf2",
                                    iterations: key.iterations,
                                    salt: key.salt
                                };
                                opts.encodedkey = (0, _recoverykey.encodeRecoveryKey)(key.key);
                                keyData.pubkey = decryption.init_with_private_key(key.key);
                                _context.next = 18;
                                break;

                            case 17:
                                if (opts.privkey) {
                                    keyData.pubkey = decryption.init_with_private_key(opts.privkey);
                                    opts.encodedkey = (0, _recoverykey.encodeRecoveryKey)(opts.privkey);
                                } else {
                                    keyData.pubkey = decryption.generate_key();
                                    opts.encodedkey = (0, _recoverykey.encodeRecoveryKey)(decryption.get_private_key());
                                }

                            case 18:
                                _context.prev = 18;

                                decryption.free();
                                return _context.finish(18);

                            case 21:
                                return _context.abrupt('break', 23);

                            case 22:
                                throw new Error('Unknown key algorithm ' + opts.algorithm);

                            case 23:

                                if (!keyId) {
                                    do {
                                        keyId = (0, _randomstring.randomString)(32);
                                    } while (this._baseApis.getAccountData('m.secret_storage.key.' + keyId));
                                }

                                _context.next = 26;
                                return (0, _bluebird.resolve)(this._crossSigningInfo.signObject(keyData, 'master'));

                            case 26:
                                _context.next = 28;
                                return (0, _bluebird.resolve)(this._baseApis.setAccountData('m.secret_storage.key.' + keyId, keyData));

                            case 28:
                                return _context.abrupt('return', keyId);

                            case 29:
                            case 'end':
                                return _context.stop();
                        }
                    }
                }, _callee, this, [[7,, 18, 21]]);
            }));

            function addKey(_x, _x2, _x3) {
                return _ref.apply(this, arguments);
            }

            return addKey;
        }()

        // TODO: need a function to get all the secret keys

        /**
         * Store an encrypted secret on the server
         *
         * @param {string} name The name of the secret
         * @param {string} secret The secret contents.
         * @param {Array} keys The IDs of the keys to use to encrypt the secret
         *     or null/undefined to use the default key.
         */

    }, {
        key: 'store',
        value: function () {
            var _ref2 = (0, _bluebird.coroutine)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(name, secret, keys) {
                var encrypted, defaultKeyId, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, keyId, keyInfo, keyInfoContent, encryption;

                return _regenerator2.default.wrap(function _callee2$(_context2) {
                    while (1) {
                        switch (_context2.prev = _context2.next) {
                            case 0:
                                encrypted = {};

                                if (keys) {
                                    _context2.next = 6;
                                    break;
                                }

                                defaultKeyId = this.getDefaultKeyId();

                                if (defaultKeyId) {
                                    _context2.next = 5;
                                    break;
                                }

                                throw new Error("No keys specified and no default key present");

                            case 5:
                                keys = [defaultKeyId];

                            case 6:
                                if (!(keys.length === 0)) {
                                    _context2.next = 8;
                                    break;
                                }

                                throw new Error("Zero keys given to encrypt with!");

                            case 8:
                                _iteratorNormalCompletion = true;
                                _didIteratorError = false;
                                _iteratorError = undefined;
                                _context2.prev = 11;
                                _iterator = (0, _getIterator3.default)(keys);

                            case 13:
                                if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
                                    _context2.next = 30;
                                    break;
                                }

                                keyId = _step.value;

                                // get key information from key storage
                                keyInfo = this._baseApis.getAccountData("m.secret_storage.key." + keyId);

                                if (keyInfo) {
                                    _context2.next = 18;
                                    break;
                                }

                                throw new Error("Unknown key: " + keyId);

                            case 18:
                                keyInfoContent = keyInfo.getContent();

                                // check signature of key info

                                (0, _olmlib.pkVerify)(keyInfoContent, this._crossSigningInfo.getId('master'), this._crossSigningInfo.userId);

                                // encrypt secret, based on the algorithm
                                _context2.t0 = keyInfoContent.algorithm;
                                _context2.next = _context2.t0 === SECRET_STORAGE_ALGORITHM_V1 ? 23 : 26;
                                break;

                            case 23:
                                encryption = new global.Olm.PkEncryption();

                                try {
                                    encryption.set_recipient_key(keyInfoContent.pubkey);
                                    encrypted[keyId] = encryption.encrypt(secret);
                                } finally {
                                    encryption.free();
                                }
                                return _context2.abrupt('break', 27);

                            case 26:
                                _logger2.default.warn("unknown algorithm for secret storage key " + keyId + ": " + keyInfoContent.algorithm);

                            case 27:
                                _iteratorNormalCompletion = true;
                                _context2.next = 13;
                                break;

                            case 30:
                                _context2.next = 36;
                                break;

                            case 32:
                                _context2.prev = 32;
                                _context2.t1 = _context2['catch'](11);
                                _didIteratorError = true;
                                _iteratorError = _context2.t1;

                            case 36:
                                _context2.prev = 36;
                                _context2.prev = 37;

                                if (!_iteratorNormalCompletion && _iterator.return) {
                                    _iterator.return();
                                }

                            case 39:
                                _context2.prev = 39;

                                if (!_didIteratorError) {
                                    _context2.next = 42;
                                    break;
                                }

                                throw _iteratorError;

                            case 42:
                                return _context2.finish(39);

                            case 43:
                                return _context2.finish(36);

                            case 44:
                                _context2.next = 46;
                                return (0, _bluebird.resolve)(this._baseApis.setAccountData(name, { encrypted: encrypted }));

                            case 46:
                            case 'end':
                                return _context2.stop();
                        }
                    }
                }, _callee2, this, [[11, 32, 36, 44], [37,, 39, 43]]);
            }));

            function store(_x4, _x5, _x6) {
                return _ref2.apply(this, arguments);
            }

            return store;
        }()

        /**
         * Get a secret from storage.
         *
         * @param {string} name the name of the secret
         *
         * @return {string} the contents of the secret
         */

    }, {
        key: 'get',
        value: function () {
            var _ref3 = (0, _bluebird.coroutine)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(name) {
                var secretInfo, secretContent, keys, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, _keyId, keyInfo, _encInfo, keyId, decryption, _ref4, _ref5, encInfo;

                return _regenerator2.default.wrap(function _callee3$(_context3) {
                    while (1) {
                        switch (_context3.prev = _context3.next) {
                            case 0:
                                secretInfo = this._baseApis.getAccountData(name);

                                if (secretInfo) {
                                    _context3.next = 3;
                                    break;
                                }

                                return _context3.abrupt('return');

                            case 3:
                                secretContent = secretInfo.getContent();

                                if (secretContent.encrypted) {
                                    _context3.next = 6;
                                    break;
                                }

                                throw new Error("Content is not encrypted!");

                            case 6:

                                // get possible keys to decrypt
                                keys = {};
                                _iteratorNormalCompletion2 = true;
                                _didIteratorError2 = false;
                                _iteratorError2 = undefined;
                                _context3.prev = 10;
                                _iterator2 = (0, _getIterator3.default)((0, _keys2.default)(secretContent.encrypted));

                            case 12:
                                if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) {
                                    _context3.next = 24;
                                    break;
                                }

                                _keyId = _step2.value;

                                // get key information from key storage
                                keyInfo = this._baseApis.getAccountData("m.secret_storage.key." + _keyId).getContent();
                                _encInfo = secretContent.encrypted[_keyId];
                                _context3.t0 = keyInfo.algorithm;
                                _context3.next = _context3.t0 === SECRET_STORAGE_ALGORITHM_V1 ? 19 : 21;
                                break;

                            case 19:
                                if (keyInfo.pubkey && _encInfo.ciphertext && _encInfo.mac && _encInfo.ephemeral) {
                                    keys[_keyId] = keyInfo;
                                }
                                return _context3.abrupt('break', 21);

                            case 21:
                                _iteratorNormalCompletion2 = true;
                                _context3.next = 12;
                                break;

                            case 24:
                                _context3.next = 30;
                                break;

                            case 26:
                                _context3.prev = 26;
                                _context3.t1 = _context3['catch'](10);
                                _didIteratorError2 = true;
                                _iteratorError2 = _context3.t1;

                            case 30:
                                _context3.prev = 30;
                                _context3.prev = 31;

                                if (!_iteratorNormalCompletion2 && _iterator2.return) {
                                    _iterator2.return();
                                }

                            case 33:
                                _context3.prev = 33;

                                if (!_didIteratorError2) {
                                    _context3.next = 36;
                                    break;
                                }

                                throw _iteratorError2;

                            case 36:
                                return _context3.finish(33);

                            case 37:
                                return _context3.finish(30);

                            case 38:
                                keyId = void 0;
                                decryption = void 0;
                                _context3.prev = 40;
                                _context3.next = 43;
                                return (0, _bluebird.resolve)(this._getSecretStorageKey(keys));

                            case 43:
                                _ref4 = _context3.sent;
                                _ref5 = (0, _slicedToArray3.default)(_ref4, 2);
                                keyId = _ref5[0];
                                decryption = _ref5[1];


                                // decrypt secret
                                encInfo = secretContent.encrypted[keyId];
                                _context3.t2 = keys[keyId].algorithm;
                                _context3.next = _context3.t2 === SECRET_STORAGE_ALGORITHM_V1 ? 51 : 52;
                                break;

                            case 51:
                                return _context3.abrupt('return', decryption.decrypt(encInfo.ephemeral, encInfo.mac, encInfo.ciphertext));

                            case 52:
                                _context3.prev = 52;

                                if (decryption) decryption.free();
                                return _context3.finish(52);

                            case 55:
                            case 'end':
                                return _context3.stop();
                        }
                    }
                }, _callee3, this, [[10, 26, 30, 38], [31,, 33, 37], [40,, 52, 55]]);
            }));

            function get(_x7) {
                return _ref3.apply(this, arguments);
            }

            return get;
        }()

        /**
         * Check if a secret is stored on the server.
         *
         * @param {string} name the name of the secret
         * @param {boolean} checkKey check if the secret is encrypted by a trusted key
         *
         * @return {boolean} whether or not the secret is stored
         */

    }, {
        key: 'isStored',
        value: function isStored(name, checkKey) {
            // check if secret exists
            var secretInfo = this._baseApis.getAccountData(name);
            if (!secretInfo) {
                return false;
            }

            if (checkKey === undefined) checkKey = true;

            var secretContent = secretInfo.getContent();

            if (!secretContent.encrypted) {
                return false;
            }

            // check if secret is encrypted by a known/trusted secret and
            // encryption looks sane
            var _iteratorNormalCompletion3 = true;
            var _didIteratorError3 = false;
            var _iteratorError3 = undefined;

            try {
                for (var _iterator3 = (0, _getIterator3.default)((0, _keys2.default)(secretContent.encrypted)), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
                    var keyId = _step3.value;

                    // get key information from key storage
                    var keyInfo = this._baseApis.getAccountData("m.secret_storage.key." + keyId).getContent();
                    var encInfo = secretContent.encrypted[keyId];
                    if (checkKey) {
                        (0, _olmlib.pkVerify)(keyInfo, this._crossSigningInfo.getId('master'), this._crossSigningInfo.userId);
                    }
                    switch (keyInfo.algorithm) {
                        case SECRET_STORAGE_ALGORITHM_V1:
                            if (keyInfo.pubkey && encInfo.ciphertext && encInfo.mac && encInfo.ephemeral) {
                                return true;
                            }
                            break;
                        default:
                        // do nothing if we don't understand the encryption algorithm
                    }
                }
            } catch (err) {
                _didIteratorError3 = true;
                _iteratorError3 = err;
            } finally {
                try {
                    if (!_iteratorNormalCompletion3 && _iterator3.return) {
                        _iterator3.return();
                    }
                } finally {
                    if (_didIteratorError3) {
                        throw _iteratorError3;
                    }
                }
            }

            return false;
        }

        /**
         * Request a secret from another device
         *
         * @param {string} name the name of the secret to request
         * @param {string[]} devices the devices to request the secret from
         *
         * @return {string} the contents of the secret
         */

    }, {
        key: 'request',
        value: function request(name, devices) {
            var _this3 = this;

            var requestId = this._baseApis.makeTxnId();

            var requestControl = this._requests[requestId] = {
                devices: devices
            };
            var promise = new _promise2.default(function (resolve, reject) {
                requestControl.resolve = resolve;
                requestControl.reject = reject;
            });
            var cancel = function cancel(reason) {
                // send cancellation event
                var cancelData = {
                    action: "request_cancellation",
                    requesting_device_id: _this3._baseApis.deviceId,
                    request_id: requestId
                };
                var toDevice = {};
                var _iteratorNormalCompletion4 = true;
                var _didIteratorError4 = false;
                var _iteratorError4 = undefined;

                try {
                    for (var _iterator4 = (0, _getIterator3.default)(devices), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
                        var device = _step4.value;

                        toDevice[device] = cancelData;
                    }
                } catch (err) {
                    _didIteratorError4 = true;
                    _iteratorError4 = err;
                } finally {
                    try {
                        if (!_iteratorNormalCompletion4 && _iterator4.return) {
                            _iterator4.return();
                        }
                    } finally {
                        if (_didIteratorError4) {
                            throw _iteratorError4;
                        }
                    }
                }

                _this3._baseApis.sendToDevice("m.secret.request", (0, _defineProperty3.default)({}, _this3._baseApis.getUserId(), toDevice));

                // and reject the promise so that anyone waiting on it will be
                // notified
                requestControl.reject(new Error(reason || "Cancelled"));
            };

            // send request to devices
            var requestData = {
                name: name,
                action: "request",
                requesting_device_id: this._baseApis.deviceId,
                request_id: requestId
            };
            var toDevice = {};
            var _iteratorNormalCompletion5 = true;
            var _didIteratorError5 = false;
            var _iteratorError5 = undefined;

            try {
                for (var _iterator5 = (0, _getIterator3.default)(devices), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
                    var device = _step5.value;

                    toDevice[device] = requestData;
                }
            } catch (err) {
                _didIteratorError5 = true;
                _iteratorError5 = err;
            } finally {
                try {
                    if (!_iteratorNormalCompletion5 && _iterator5.return) {
                        _iterator5.return();
                    }
                } finally {
                    if (_didIteratorError5) {
                        throw _iteratorError5;
                    }
                }
            }

            this._baseApis.sendToDevice("m.secret.request", (0, _defineProperty3.default)({}, this._baseApis.getUserId(), toDevice));

            return {
                request_id: requestId,
                promise: promise,
                cancel: cancel
            };
        }
    }, {
        key: '_onRequestReceived',
        value: function () {
            var _ref6 = (0, _bluebird.coroutine)( /*#__PURE__*/_regenerator2.default.mark(function _callee4(event) {
                var sender, content, deviceId, secret, payload, encryptedContent, contentMap;
                return _regenerator2.default.wrap(function _callee4$(_context4) {
                    while (1) {
                        switch (_context4.prev = _context4.next) {
                            case 0:
                                sender = event.getSender();
                                content = event.getContent();

                                if (!(sender !== this._baseApis.getUserId() || !(content.name && content.action && content.requesting_device_id && content.request_id))) {
                                    _context4.next = 4;
                                    break;
                                }

                                return _context4.abrupt('return');

                            case 4:
                                deviceId = content.requesting_device_id;
                                // check if it's a cancel

                                if (!(content.action === "request_cancellation")) {
                                    _context4.next = 9;
                                    break;
                                }

                                if (this._incomingRequests[deviceId] && this._incomingRequests[deviceId][content.request_id]) {
                                    _logger2.default.info("received request cancellation for secret (" + sender + ", " + deviceId + ", " + content.request_id + ")");
                                    this.baseApis.emit("crypto.secrets.requestCancelled", {
                                        user_id: sender,
                                        device_id: deviceId,
                                        request_id: content.request_id
                                    });
                                }
                                _context4.next = 40;
                                break;

                            case 9:
                                if (!(content.action === "request")) {
                                    _context4.next = 40;
                                    break;
                                }

                                if (!(deviceId === this._baseApis.deviceId)) {
                                    _context4.next = 12;
                                    break;
                                }

                                return _context4.abrupt('return');

                            case 12:

                                // check if we have the secret
                                _logger2.default.info("received request for secret (" + sender + ", " + deviceId + ", " + content.request_id + ")");

                                if (this._cryptoCallbacks.onSecretRequested) {
                                    _context4.next = 15;
                                    break;
                                }

                                return _context4.abrupt('return');

                            case 15:
                                _context4.next = 17;
                                return (0, _bluebird.resolve)(this._cryptoCallbacks.onSecretRequested({
                                    user_id: sender,
                                    device_id: deviceId,
                                    request_id: content.request_id,
                                    name: content.name,
                                    device_trust: this._baseApis.checkDeviceTrust(sender, deviceId)
                                }));

                            case 17:
                                secret = _context4.sent;

                                if (!secret) {
                                    _context4.next = 40;
                                    break;
                                }

                                payload = {
                                    type: "m.secret.send",
                                    content: {
                                        request_id: content.request_id,
                                        secret: secret
                                    }
                                };
                                encryptedContent = {
                                    algorithm: _olmlib2.default.OLM_ALGORITHM,
                                    sender_key: this._baseApis._crypto._olmDevice.deviceCurve25519Key,
                                    ciphertext: {}
                                };
                                _context4.t0 = _bluebird.resolve;
                                _context4.t1 = _olmlib2.default;
                                _context4.t2 = this._baseApis._crypto._olmDevice;
                                _context4.t3 = this._baseApis;
                                _context4.t4 = _defineProperty3.default;
                                _context4.t5 = {};
                                _context4.t6 = sender;
                                _context4.next = 30;
                                return (0, _bluebird.resolve)(this._baseApis.getStoredDevice(sender, deviceId));

                            case 30:
                                _context4.t7 = _context4.sent;
                                _context4.t8 = [_context4.t7];
                                _context4.t9 = (0, _context4.t4)(_context4.t5, _context4.t6, _context4.t8);
                                _context4.t10 = _context4.t1.ensureOlmSessionsForDevices.call(_context4.t1, _context4.t2, _context4.t3, _context4.t9);
                                _context4.next = 36;
                                return (0, _context4.t0)(_context4.t10);

                            case 36:
                                _context4.next = 38;
                                return (0, _bluebird.resolve)(_olmlib2.default.encryptMessageForDevice(encryptedContent.ciphertext, this._baseApis.getUserId(), this._baseApis.deviceId, this._baseApis._crypto._olmDevice, sender, this._baseApis._crypto.getStoredDevice(sender, deviceId), payload));

                            case 38:
                                contentMap = (0, _defineProperty3.default)({}, sender, (0, _defineProperty3.default)({}, deviceId, encryptedContent));


                                this._baseApis.sendToDevice("m.room.encrypted", contentMap);

                            case 40:
                            case 'end':
                                return _context4.stop();
                        }
                    }
                }, _callee4, this);
            }));

            function _onRequestReceived(_x8) {
                return _ref6.apply(this, arguments);
            }

            return _onRequestReceived;
        }()
    }, {
        key: '_onSecretReceived',
        value: function _onSecretReceived(event) {
            if (event.getSender() !== this._baseApis.getUserId()) {
                // we shouldn't be receiving secrets from anyone else, so ignore
                // because someone could be trying to send us bogus data
                return;
            }
            var content = event.getContent();
            _logger2.default.log("got secret share for request ", content.request_id);
            var requestControl = this._requests[content.request_id];
            if (requestControl) {
                // make sure that the device that sent it is one of the devices that
                // we requested from
                var deviceInfo = this._baseApis._crypto._deviceList.getDeviceByIdentityKey(_olmlib2.default.OLM_ALGORITHM, event.getSenderKey());
                if (!deviceInfo) {
                    _logger2.default.log("secret share from unknown device with key", event.getSenderKey());
                    return;
                }
                if (!requestControl.devices.includes(deviceInfo.deviceId)) {
                    _logger2.default.log("unsolicited secret share from device", deviceInfo.deviceId);
                    return;
                }

                requestControl.resolve(content.secret);
            }
        }
    }, {
        key: '_getSecretStorageKey',
        value: function () {
            var _ref7 = (0, _bluebird.coroutine)( /*#__PURE__*/_regenerator2.default.mark(function _callee5(keys) {
                var returned, _returned, keyId, privateKey, decryption, pubkey;

                return _regenerator2.default.wrap(function _callee5$(_context5) {
                    while (1) {
                        switch (_context5.prev = _context5.next) {
                            case 0:
                                if (this._cryptoCallbacks.getSecretStorageKey) {
                                    _context5.next = 2;
                                    break;
                                }

                                throw new Error("No getSecretStorageKey callback supplied");

                            case 2:
                                _context5.next = 4;
                                return (0, _bluebird.resolve)(_promise2.default.resolve(this._cryptoCallbacks.getSecretStorageKey({ keys: keys })));

                            case 4:
                                returned = _context5.sent;

                                if (returned) {
                                    _context5.next = 7;
                                    break;
                                }

                                throw new Error("getSecretStorageKey callback returned falsey");

                            case 7:
                                if (!(returned.length < 2)) {
                                    _context5.next = 9;
                                    break;
                                }

                                throw new Error("getSecretStorageKey callback returned invalid data");

                            case 9:
                                _returned = (0, _slicedToArray3.default)(returned, 2), keyId = _returned[0], privateKey = _returned[1];

                                if (keys[keyId]) {
                                    _context5.next = 12;
                                    break;
                                }

                                throw new Error("App returned unknown key from getSecretStorageKey!");

                            case 12:
                                _context5.t0 = keys[keyId].algorithm;
                                _context5.next = _context5.t0 === SECRET_STORAGE_ALGORITHM_V1 ? 15 : 29;
                                break;

                            case 15:
                                decryption = new global.Olm.PkDecryption();
                                pubkey = void 0;
                                _context5.prev = 17;

                                pubkey = decryption.init_with_private_key(privateKey);
                                _context5.next = 25;
                                break;

                            case 21:
                                _context5.prev = 21;
                                _context5.t1 = _context5['catch'](17);

                                decryption.free();
                                throw new Error("getSecretStorageKey callback returned invalid key");

                            case 25:
                                if (!(pubkey !== keys[keyId].pubkey)) {
                                    _context5.next = 28;
                                    break;
                                }

                                decryption.free();
                                throw new Error("getSecretStorageKey callback returned incorrect key");

                            case 28:
                                return _context5.abrupt('return', [keyId, decryption]);

                            case 29:
                                throw new Error("Unknown key type: " + keys[keyId].algorithm);

                            case 30:
                            case 'end':
                                return _context5.stop();
                        }
                    }
                }, _callee5, this, [[17, 21]]);
            }));

            function _getSecretStorageKey(_x9) {
                return _ref7.apply(this, arguments);
            }

            return _getSecretStorageKey;
        }()
    }]);
    return SecretStorage;
}(_events.EventEmitter);

exports.default = SecretStorage;
//# sourceMappingURL=SecretStorage.js.map