"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.RustCrypto = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var RustSdkCryptoJs = _interopRequireWildcard(require("@matrix-org/matrix-sdk-crypto-js"));
var _logger = require("../logger");
var _httpApi = require("../http-api");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
/*
Copyright 2022 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.
*/

/**
 * An implementation of {@link CryptoBackend} using the Rust matrix-sdk-crypto.
 */
class RustCrypto {
  /** whether {@link stop} has been called */

  /** whether {@link outgoingRequestLoop} is currently running */

  constructor(olmMachine, http, _userId, _deviceId) {
    this.olmMachine = olmMachine;
    this.http = http;
    (0, _defineProperty2.default)(this, "globalBlacklistUnverifiedDevices", false);
    (0, _defineProperty2.default)(this, "globalErrorOnUnknownDevices", false);
    (0, _defineProperty2.default)(this, "stopped", false);
    (0, _defineProperty2.default)(this, "outgoingRequestLoopRunning", false);
  }
  stop() {
    // stop() may be called multiple times, but attempting to close() the OlmMachine twice
    // will cause an error.
    if (this.stopped) {
      return;
    }
    this.stopped = true;

    // make sure we close() the OlmMachine; doing so means that all the Rust objects will be
    // cleaned up; in particular, the indexeddb connections will be closed, which means they
    // can then be deleted.
    this.olmMachine.close();
  }
  async decryptEvent(event) {
    await this.olmMachine.decryptRoomEvent("event", new RustSdkCryptoJs.RoomId("room"));
    throw new Error("not implemented");
  }
  async userHasCrossSigningKeys() {
    // TODO
    return false;
  }
  async exportRoomKeys() {
    // TODO
    return [];
  }

  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  //
  // SyncCryptoCallbacks implementation
  //
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  /** called by the sync loop to preprocess incoming to-device messages
   *
   * @param events - the received to-device messages
   * @returns A list of preprocessed to-device messages.
   */
  async preprocessToDeviceMessages(events) {
    // send the received to-device messages into receiveSyncChanges. We have no info on device-list changes,
    // one-time-keys, or fallback keys, so just pass empty data.
    const result = await this.olmMachine.receiveSyncChanges(JSON.stringify(events), new RustSdkCryptoJs.DeviceLists(), new Map(), new Set());

    // receiveSyncChanges returns a JSON-encoded list of decrypted to-device messages.
    return JSON.parse(result);
  }

  /** called by the sync loop after processing each sync.
   *
   * TODO: figure out something equivalent for sliding sync.
   *
   * @param syncState - information on the completed sync.
   */
  onSyncCompleted(syncState) {
    // Processing the /sync may have produced new outgoing requests which need sending, so kick off the outgoing
    // request loop, if it's not already running.
    this.outgoingRequestLoop();
  }

  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  //
  // Outgoing requests
  //
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  async outgoingRequestLoop() {
    if (this.outgoingRequestLoopRunning) {
      return;
    }
    this.outgoingRequestLoopRunning = true;
    try {
      while (!this.stopped) {
        const outgoingRequests = await this.olmMachine.outgoingRequests();
        if (outgoingRequests.length == 0 || this.stopped) {
          // no more messages to send (or we have been told to stop): exit the loop
          return;
        }
        for (const msg of outgoingRequests) {
          await this.doOutgoingRequest(msg);
        }
      }
    } catch (e) {
      _logger.logger.error("Error processing outgoing-message requests from rust crypto-sdk", e);
    } finally {
      this.outgoingRequestLoopRunning = false;
    }
  }
  async doOutgoingRequest(msg) {
    let resp;

    /* refer https://docs.rs/matrix-sdk-crypto/0.6.0/matrix_sdk_crypto/requests/enum.OutgoingRequests.html
     * for the complete list of request types
     */
    if (msg instanceof RustSdkCryptoJs.KeysUploadRequest) {
      resp = await this.rawJsonRequest(_httpApi.Method.Post, "/_matrix/client/v3/keys/upload", {}, msg.body);
    } else if (msg instanceof RustSdkCryptoJs.KeysQueryRequest) {
      resp = await this.rawJsonRequest(_httpApi.Method.Post, "/_matrix/client/v3/keys/query", {}, msg.body);
    } else if (msg instanceof RustSdkCryptoJs.KeysClaimRequest) {
      resp = await this.rawJsonRequest(_httpApi.Method.Post, "/_matrix/client/v3/keys/claim", {}, msg.body);
    } else if (msg instanceof RustSdkCryptoJs.SignatureUploadRequest) {
      resp = await this.rawJsonRequest(_httpApi.Method.Post, "/_matrix/client/v3/keys/signatures/upload", {}, msg.body);
    } else if (msg instanceof RustSdkCryptoJs.KeysBackupRequest) {
      resp = await this.rawJsonRequest(_httpApi.Method.Put, "/_matrix/client/v3/room_keys/keys", {}, msg.body);
    } else {
      // TODO: ToDeviceRequest, RoomMessageRequest
      _logger.logger.warn("Unsupported outgoing message", Object.getPrototypeOf(msg));
      resp = "";
    }
    if (msg.id) {
      await this.olmMachine.markRequestAsSent(msg.id, msg.type, resp);
    }
  }
  async rawJsonRequest(method, path, queryParams, body) {
    const opts = {
      // inhibit the JSON stringification and parsing within HttpApi.
      json: false,
      // nevertheless, we are sending, and accept, JSON.
      headers: {
        "Content-Type": "application/json",
        "Accept": "application/json"
      },
      // we use the full prefix
      prefix: ""
    };
    return await this.http.authedRequest(method, path, queryParams, body, opts);
  }
}
exports.RustCrypto = RustCrypto;
//# sourceMappingURL=rust-crypto.js.map