"use strict";
/*
 * Wire
 * Copyright (C) 2018 Wire Swiss GmbH
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
 *
 */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CryptoboxCRUDStore = exports.CRUDStoreStores = exports.CRUDStoreKeys = void 0;
const proteus_1 = require("@wireapp/proteus");
const store_engine_1 = require("@wireapp/store-engine");
const bazinga64_1 = require("bazinga64");
const store_1 = require("../store/");
var CRUDStoreKeys;
(function (CRUDStoreKeys) {
    CRUDStoreKeys["LOCAL_IDENTITY"] = "local_identity";
})(CRUDStoreKeys = exports.CRUDStoreKeys || (exports.CRUDStoreKeys = {}));
var CRUDStoreStores;
(function (CRUDStoreStores) {
    CRUDStoreStores["LOCAL_IDENTITY"] = "keys";
    CRUDStoreStores["PRE_KEYS"] = "prekeys";
    CRUDStoreStores["SESSIONS"] = "sessions";
})(CRUDStoreStores = exports.CRUDStoreStores || (exports.CRUDStoreStores = {}));
let CryptoboxCRUDStore = /** @class */ (() => {
    class CryptoboxCRUDStore {
        constructor(engine) {
            this.engine = engine;
        }
        from_store(record) {
            return typeof record.serialised === 'string'
                ? bazinga64_1.Decoder.fromBase64(record.serialised).asBytes.buffer
                : record.serialised;
        }
        to_store(serialised) {
            return bazinga64_1.Encoder.toBase64(serialised).asString;
        }
        delete_all() {
            return __awaiter(this, void 0, void 0, function* () {
                yield this.engine.deleteAll(CryptoboxCRUDStore.STORES.LOCAL_IDENTITY);
                yield this.engine.deleteAll(CryptoboxCRUDStore.STORES.PRE_KEYS);
                yield this.engine.deleteAll(CryptoboxCRUDStore.STORES.SESSIONS);
                return true;
            });
        }
        /**
         * Deletes a specified PreKey.
         * @returns Resolves with the "ID" from the record, which has been deleted.
         */
        delete_prekey(prekeyId) {
            return __awaiter(this, void 0, void 0, function* () {
                yield this.engine.delete(CryptoboxCRUDStore.STORES.PRE_KEYS, prekeyId.toString());
                return prekeyId;
            });
        }
        /**
         * Loads the local identity.
         * @returns Resolves with the "key pair" from the local identity.
         */
        load_identity() {
            return __awaiter(this, void 0, void 0, function* () {
                try {
                    const record = yield this.engine.read(CryptoboxCRUDStore.STORES.LOCAL_IDENTITY, CryptoboxCRUDStore.KEYS.LOCAL_IDENTITY);
                    const payload = this.from_store(record);
                    return proteus_1.keys.IdentityKeyPair.deserialise(payload);
                }
                catch (error) {
                    if (error instanceof store_engine_1.error.RecordNotFoundError) {
                        return undefined;
                    }
                    throw error;
                }
            });
        }
        /**
         * Loads and deserializes a specified PreKey.
         * @returns Resolves with the specified "PreKey".
         */
        load_prekey(prekeyId) {
            return __awaiter(this, void 0, void 0, function* () {
                try {
                    const record = yield this.engine.read(CryptoboxCRUDStore.STORES.PRE_KEYS, prekeyId.toString());
                    const payload = this.from_store(record);
                    return proteus_1.keys.PreKey.deserialise(payload);
                }
                catch (error) {
                    if (error instanceof store_engine_1.error.RecordNotFoundError) {
                        return undefined;
                    }
                    throw error;
                }
            });
        }
        /**
         * Loads all available PreKeys.
         */
        load_prekeys() {
            return __awaiter(this, void 0, void 0, function* () {
                const records = yield this.engine.readAll(CryptoboxCRUDStore.STORES.PRE_KEYS);
                return records.map(record => {
                    const payload = this.from_store(record);
                    return proteus_1.keys.PreKey.deserialise(payload);
                });
            });
        }
        /**
         * Saves the local identity.
         * @returns Resolves with the "fingerprint" from the saved local identity.
         */
        save_identity(identity) {
            return __awaiter(this, void 0, void 0, function* () {
                const serialised = this.to_store(identity.serialise());
                const payload = new store_1.SerialisedRecord(serialised, CryptoboxCRUDStore.KEYS.LOCAL_IDENTITY);
                yield this.engine.create(CryptoboxCRUDStore.STORES.LOCAL_IDENTITY, payload.id, payload);
                return identity;
            });
        }
        /**
         * Saves the serialised format of a specified PreKey.
         * @returns Resolves with the "ID" from the saved PreKey record.
         */
        save_prekey(preKey) {
            return __awaiter(this, void 0, void 0, function* () {
                const serialised = this.to_store(preKey.serialise());
                const payload = new store_1.SerialisedRecord(serialised, preKey.key_id.toString());
                yield this.engine.create(CryptoboxCRUDStore.STORES.PRE_KEYS, payload.id, payload);
                return preKey;
            });
        }
        /**
         * Saves the serialised formats from a batch of PreKeys.
         */
        save_prekeys(preKeys) {
            return __awaiter(this, void 0, void 0, function* () {
                yield Promise.all(preKeys.map(pre_key => this.save_prekey(pre_key)));
                return preKeys;
            });
        }
        /**
         * Saves a specified session.
         * @returns Resolves with the saved session.
         */
        create_session(sessionId, session) {
            return __awaiter(this, void 0, void 0, function* () {
                const serialised = this.to_store(session.serialise());
                const payload = new store_1.SerialisedRecord(serialised, sessionId);
                yield this.engine.create(CryptoboxCRUDStore.STORES.SESSIONS, payload.id, payload);
                return session;
            });
        }
        /**
         * Loads a specified session.
         * @returns Resolves with the specified "session".
         */
        read_session(identity, sessionId) {
            return __awaiter(this, void 0, void 0, function* () {
                const record = yield this.engine.read(CryptoboxCRUDStore.STORES.SESSIONS, sessionId);
                const payload = this.from_store(record);
                return proteus_1.session.Session.deserialise(identity, payload);
            });
        }
        read_sessions(identity) {
            return __awaiter(this, void 0, void 0, function* () {
                const sessionIds = yield this.engine.readAllPrimaryKeys(CryptoboxCRUDStore.STORES.SESSIONS);
                const sessions = {};
                yield Promise.all(sessionIds.map((sessionId) => __awaiter(this, void 0, void 0, function* () {
                    sessions[sessionId] = yield this.read_session(identity, sessionId);
                })));
                return sessions;
            });
        }
        update_session(sessionId, session) {
            return __awaiter(this, void 0, void 0, function* () {
                const serialised = this.to_store(session.serialise());
                const payload = new store_1.SerialisedRecord(serialised, sessionId);
                yield this.engine.update(CryptoboxCRUDStore.STORES.SESSIONS, payload.id, { serialised: payload.serialised });
                return session;
            });
        }
        /**
         * Deletes a specified session.
         * @returns Resolves with the "ID" from the record, which has been deleted.
         */
        delete_session(sessionId) {
            return __awaiter(this, void 0, void 0, function* () {
                const primary_key = yield this.engine.delete(CryptoboxCRUDStore.STORES.SESSIONS, sessionId);
                return primary_key;
            });
        }
    }
    CryptoboxCRUDStore.KEYS = CRUDStoreKeys;
    CryptoboxCRUDStore.STORES = CRUDStoreStores;
    return CryptoboxCRUDStore;
})();
exports.CryptoboxCRUDStore = CryptoboxCRUDStore;
//# sourceMappingURL=CryptoboxCRUDStore.js.map