'use strict';

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

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

var _regenerator2 = _interopRequireDefault(_regenerator);

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 _entries = require('babel-runtime/core-js/object/entries');

var _entries2 = _interopRequireDefault(_entries);

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

var _getIterator3 = _interopRequireDefault(_getIterator2);

var _bluebird = require('bluebird');

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

var _defineProperty3 = _interopRequireDefault(_defineProperty2);

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 _event = require('../../models/event');

var _events = require('events');

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

/*
Copyright 2018 New Vector Ltd

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.
*/

/**
 * Base class for verification methods.
 * @module crypto/verification/Base
 */

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

    /**
     * Base class for verification methods.
     *
     * <p>Once a verifier object is created, the verification can be started by
     * calling the verify() method, which will return a promise that will
     * resolve when the verification is completed, or reject if it could not
     * complete.</p>
     *
     * <p>Subclasses must have a NAME class property.</p>
     *
     * @class
     *
     * @param {module:base-apis~MatrixBaseApis} baseApis base matrix api interface
     *
     * @param {string} userId the user ID that is being verified
     *
     * @param {string} deviceId the device ID that is being verified
     *
     * @param {string} transactionId the transaction ID to be used when sending events
     *
     * @param {object} startEvent the m.key.verification.start event that
     * initiated this verification, if any
     *
     * @param {object} request the key verification request object related to
     * this verification, if any
     *
     * @param {object} parent parent verification for this verification, if any
     */
    function VerificationBase(baseApis, userId, deviceId, transactionId, startEvent, request, parent) {
        (0, _classCallCheck3.default)(this, VerificationBase);

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

        _this._baseApis = baseApis;
        _this.userId = userId;
        _this.deviceId = deviceId;
        _this.transactionId = transactionId;
        _this.startEvent = startEvent;
        _this.request = request;
        _this._parent = parent;
        _this._done = false;
        _this._promise = null;
        return _this;
    }

    (0, _createClass3.default)(VerificationBase, [{
        key: '_sendToDevice',
        value: function _sendToDevice(type, content) {
            if (this._done) {
                return _promise2.default.reject(new Error("Verification is already done"));
            }
            content.transaction_id = this.transactionId;
            return this._baseApis.sendToDevice(type, (0, _defineProperty3.default)({}, this.userId, (0, _defineProperty3.default)({}, this.deviceId, content)));
        }
    }, {
        key: '_waitForEvent',
        value: function _waitForEvent(type) {
            var _this2 = this;

            if (this._done) {
                return _promise2.default.reject(new Error("Verification is already done"));
            }
            this._expectedEvent = type;
            return new _promise2.default(function (resolve, reject) {
                _this2._resolveEvent = resolve;
                _this2._rejectEvent = reject;
            });
        }
    }, {
        key: 'handleEvent',
        value: function handleEvent(e) {
            if (this._done) {
                return;
            } else if (e.getType() === this._expectedEvent) {
                this._expectedEvent = undefined;
                this._rejectEvent = undefined;
                this._resolveEvent(e);
            } else {
                this._expectedEvent = undefined;
                var exception = new Error("Unexpected message: expecting " + this._expectedEvent + " but got " + e.getType());
                if (this._rejectEvent) {
                    var reject = this._rejectEvent;
                    this._rejectEvent = undefined;
                    reject(exception);
                }
                this.cancel(exception);
            }
        }
    }, {
        key: 'done',
        value: function done() {
            if (!this._done) {
                this._resolve();
            }
        }
    }, {
        key: 'cancel',
        value: function cancel(e) {
            if (!this._done) {
                if (this.userId && this.deviceId && this.transactionId) {
                    // send a cancellation to the other user (if it wasn't
                    // cancelled by the other user)
                    if (e instanceof _event.MatrixEvent) {
                        var sender = e.getSender();
                        if (sender !== this.userId) {
                            var content = e.getContent();
                            if (e.getType() === "m.key.verification.cancel") {
                                content.code = content.code || "m.unknown";
                                content.reason = content.reason || content.body || "Unknown reason";
                                content.transaction_id = this.transactionId;
                                this._sendToDevice("m.key.verification.cancel", content);
                            } else {
                                this._sendToDevice("m.key.verification.cancel", {
                                    code: "m.unknown",
                                    reason: content.body || "Unknown reason",
                                    transaction_id: this.transactionId
                                });
                            }
                        }
                    } else {
                        this._sendToDevice("m.key.verification.cancel", {
                            code: "m.unknown",
                            reason: e.toString(),
                            transaction_id: this.transactionId
                        });
                    }
                }
                if (this._promise !== null) {
                    this._reject(e);
                } else {
                    this._promise = _promise2.default.reject(e);
                }
                // Also emit a 'cancel' event that the app can listen for to detect cancellation
                // before calling verify()
                this.emit('cancel', e);
            }
        }

        /**
         * Begin the key verification
         *
         * @returns {Promise} Promise which resolves when the verification has
         *     completed.
         */

    }, {
        key: 'verify',
        value: function verify() {
            var _this3 = this;

            if (this._promise) return this._promise;

            this._promise = new _promise2.default(function (resolve, reject) {
                _this3._resolve = function () {
                    _this3._done = true;
                    resolve.apply(undefined, arguments);
                };
                _this3._reject = function () {
                    _this3._done = true;
                    reject.apply(undefined, arguments);
                };
            });
            if (this._doVerification && !this._started) {
                this._started = true;
                _promise2.default.resolve(this._doVerification()).then(this.done.bind(this), this.cancel.bind(this));
            }
            return this._promise;
        }
    }, {
        key: '_verifyKeys',
        value: function () {
            var _ref = (0, _bluebird.coroutine)( /*#__PURE__*/_regenerator2.default.mark(function _callee(userId, keys, verifier) {
                var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _step$value, keyId, keyInfo, deviceId, device, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, _deviceId;

                return _regenerator2.default.wrap(function _callee$(_context) {
                    while (1) {
                        switch (_context.prev = _context.next) {
                            case 0:
                                _iteratorNormalCompletion = true;
                                _didIteratorError = false;
                                _iteratorError = undefined;
                                _context.prev = 3;
                                _iterator = (0, _getIterator3.default)((0, _entries2.default)(keys));

                            case 5:
                                if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
                                    _context.next = 20;
                                    break;
                                }

                                _step$value = (0, _slicedToArray3.default)(_step.value, 2), keyId = _step$value[0], keyInfo = _step$value[1];
                                deviceId = keyId.split(':', 2)[1];
                                _context.next = 10;
                                return (0, _bluebird.resolve)(this._baseApis.getStoredDevice(userId, deviceId));

                            case 10:
                                device = _context.sent;

                                if (device) {
                                    _context.next = 15;
                                    break;
                                }

                                throw new Error('Could not find device ' + deviceId);

                            case 15:
                                _context.next = 17;
                                return (0, _bluebird.resolve)(verifier(keyId, device, keyInfo));

                            case 17:
                                _iteratorNormalCompletion = true;
                                _context.next = 5;
                                break;

                            case 20:
                                _context.next = 26;
                                break;

                            case 22:
                                _context.prev = 22;
                                _context.t0 = _context['catch'](3);
                                _didIteratorError = true;
                                _iteratorError = _context.t0;

                            case 26:
                                _context.prev = 26;
                                _context.prev = 27;

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

                            case 29:
                                _context.prev = 29;

                                if (!_didIteratorError) {
                                    _context.next = 32;
                                    break;
                                }

                                throw _iteratorError;

                            case 32:
                                return _context.finish(29);

                            case 33:
                                return _context.finish(26);

                            case 34:
                                _iteratorNormalCompletion2 = true;
                                _didIteratorError2 = false;
                                _iteratorError2 = undefined;
                                _context.prev = 37;
                                _iterator2 = (0, _getIterator3.default)((0, _keys2.default)(keys));

                            case 39:
                                if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) {
                                    _context.next = 47;
                                    break;
                                }

                                keyId = _step2.value;
                                _deviceId = keyId.split(':', 2)[1];
                                _context.next = 44;
                                return (0, _bluebird.resolve)(this._baseApis.setDeviceVerified(userId, _deviceId));

                            case 44:
                                _iteratorNormalCompletion2 = true;
                                _context.next = 39;
                                break;

                            case 47:
                                _context.next = 53;
                                break;

                            case 49:
                                _context.prev = 49;
                                _context.t1 = _context['catch'](37);
                                _didIteratorError2 = true;
                                _iteratorError2 = _context.t1;

                            case 53:
                                _context.prev = 53;
                                _context.prev = 54;

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

                            case 56:
                                _context.prev = 56;

                                if (!_didIteratorError2) {
                                    _context.next = 59;
                                    break;
                                }

                                throw _iteratorError2;

                            case 59:
                                return _context.finish(56);

                            case 60:
                                return _context.finish(53);

                            case 61:
                            case 'end':
                                return _context.stop();
                        }
                    }
                }, _callee, this, [[3, 22, 26, 34], [27,, 29, 33], [37, 49, 53, 61], [54,, 56, 60]]);
            }));

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

            return _verifyKeys;
        }()
    }]);
    return VerificationBase;
}(_events.EventEmitter);

exports.default = VerificationBase;
//# sourceMappingURL=Base.js.map