/*! @azure/msal-browser v2.30.0 2022-10-10 */
'use strict';
import { __awaiter, __generator } from '../_virtual/_tslib.js';
import { PerformanceEvents, JoseHeader } from '@azure/msal-common';
import { GuidGenerator } from './GuidGenerator.js';
import { Base64Encode } from '../encode/Base64Encode.js';
import { Base64Decode } from '../encode/Base64Decode.js';
import { PkceGenerator } from './PkceGenerator.js';
import { BrowserCrypto } from './BrowserCrypto.js';
import { BrowserStringUtils } from '../utils/BrowserStringUtils.js';
import { BrowserAuthError } from '../error/BrowserAuthError.js';
import { CryptoKeyStore } from '../cache/CryptoKeyStore.js';

/*
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */
/**
 * This class implements MSAL's crypto interface, which allows it to perform base64 encoding and decoding, generating cryptographically random GUIDs and
 * implementing Proof Key for Code Exchange specs for the OAuth Authorization Code Flow using PKCE (rfc here: https://tools.ietf.org/html/rfc7636).
 */
var CryptoOps = /** @class */ (function () {
    function CryptoOps(logger, performanceClient, cryptoConfig) {
        this.logger = logger;
        // Browser crypto needs to be validated first before any other classes can be set.
        this.browserCrypto = new BrowserCrypto(this.logger, cryptoConfig);
        this.b64Encode = new Base64Encode();
        this.b64Decode = new Base64Decode();
        this.guidGenerator = new GuidGenerator(this.browserCrypto);
        this.pkceGenerator = new PkceGenerator(this.browserCrypto);
        this.cache = new CryptoKeyStore(this.logger);
        this.performanceClient = performanceClient;
    }
    /**
     * Creates a new random GUID - used to populate state and nonce.
     * @returns string (GUID)
     */
    CryptoOps.prototype.createNewGuid = function () {
        return this.guidGenerator.generateGuid();
    };
    /**
     * Encodes input string to base64.
     * @param input
     */
    CryptoOps.prototype.base64Encode = function (input) {
        return this.b64Encode.encode(input);
    };
    /**
     * Decodes input string from base64.
     * @param input
     */
    CryptoOps.prototype.base64Decode = function (input) {
        return this.b64Decode.decode(input);
    };
    /**
     * Generates PKCE codes used in Authorization Code Flow.
     */
    CryptoOps.prototype.generatePkceCodes = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                return [2 /*return*/, this.pkceGenerator.generateCodes()];
            });
        });
    };
    /**
     * Generates a keypair, stores it and returns a thumbprint
     * @param request
     */
    CryptoOps.prototype.getPublicKeyThumbprint = function (request) {
        var _a;
        return __awaiter(this, void 0, void 0, function () {
            var publicKeyThumbMeasurement, keyPair, publicKeyJwk, pubKeyThumprintObj, publicJwkString, publicJwkHash, privateKeyJwk, unextractablePrivateKey;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        publicKeyThumbMeasurement = (_a = this.performanceClient) === null || _a === void 0 ? void 0 : _a.startMeasurement(PerformanceEvents.CryptoOptsGetPublicKeyThumbprint, request.correlationId);
                        return [4 /*yield*/, this.browserCrypto.generateKeyPair(CryptoOps.EXTRACTABLE, CryptoOps.POP_KEY_USAGES)];
                    case 1:
                        keyPair = _b.sent();
                        return [4 /*yield*/, this.browserCrypto.exportJwk(keyPair.publicKey)];
                    case 2:
                        publicKeyJwk = _b.sent();
                        pubKeyThumprintObj = {
                            e: publicKeyJwk.e,
                            kty: publicKeyJwk.kty,
                            n: publicKeyJwk.n
                        };
                        publicJwkString = BrowserStringUtils.getSortedObjectString(pubKeyThumprintObj);
                        return [4 /*yield*/, this.hashString(publicJwkString)];
                    case 3:
                        publicJwkHash = _b.sent();
                        return [4 /*yield*/, this.browserCrypto.exportJwk(keyPair.privateKey)];
                    case 4:
                        privateKeyJwk = _b.sent();
                        return [4 /*yield*/, this.browserCrypto.importJwk(privateKeyJwk, false, ["sign"])];
                    case 5:
                        unextractablePrivateKey = _b.sent();
                        // Store Keypair data in keystore
                        return [4 /*yield*/, this.cache.asymmetricKeys.setItem(publicJwkHash, {
                                privateKey: unextractablePrivateKey,
                                publicKey: keyPair.publicKey,
                                requestMethod: request.resourceRequestMethod,
                                requestUri: request.resourceRequestUri
                            })];
                    case 6:
                        // Store Keypair data in keystore
                        _b.sent();
                        if (publicKeyThumbMeasurement) {
                            publicKeyThumbMeasurement.endMeasurement({
                                success: true
                            });
                        }
                        return [2 /*return*/, publicJwkHash];
                }
            });
        });
    };
    /**
     * Removes cryptographic keypair from key store matching the keyId passed in
     * @param kid
     */
    CryptoOps.prototype.removeTokenBindingKey = function (kid) {
        return __awaiter(this, void 0, void 0, function () {
            var keyFound;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.cache.asymmetricKeys.removeItem(kid)];
                    case 1:
                        _a.sent();
                        return [4 /*yield*/, this.cache.asymmetricKeys.containsKey(kid)];
                    case 2:
                        keyFound = _a.sent();
                        return [2 /*return*/, !keyFound];
                }
            });
        });
    };
    /**
     * Removes all cryptographic keys from IndexedDB storage
     */
    CryptoOps.prototype.clearKeystore = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.cache.clear()];
                    case 1: return [2 /*return*/, _a.sent()];
                }
            });
        });
    };
    /**
     * Signs the given object as a jwt payload with private key retrieved by given kid.
     * @param payload
     * @param kid
     */
    CryptoOps.prototype.signJwt = function (payload, kid, correlationId) {
        var _a;
        return __awaiter(this, void 0, void 0, function () {
            var signJwtMeasurement, cachedKeyPair, publicKeyJwk, publicKeyJwkString, encodedKeyIdThumbprint, shrHeader, encodedShrHeader, encodedPayload, tokenString, tokenBuffer, signatureBuffer, encodedSignature, signedJwt;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        signJwtMeasurement = (_a = this.performanceClient) === null || _a === void 0 ? void 0 : _a.startMeasurement(PerformanceEvents.CryptoOptsSignJwt, correlationId);
                        return [4 /*yield*/, this.cache.asymmetricKeys.getItem(kid)];
                    case 1:
                        cachedKeyPair = _b.sent();
                        if (!cachedKeyPair) {
                            throw BrowserAuthError.createSigningKeyNotFoundInStorageError(kid);
                        }
                        return [4 /*yield*/, this.browserCrypto.exportJwk(cachedKeyPair.publicKey)];
                    case 2:
                        publicKeyJwk = _b.sent();
                        publicKeyJwkString = BrowserStringUtils.getSortedObjectString(publicKeyJwk);
                        encodedKeyIdThumbprint = this.b64Encode.urlEncode(JSON.stringify({ kid: kid }));
                        shrHeader = JoseHeader.getShrHeaderString({ kid: encodedKeyIdThumbprint, alg: publicKeyJwk.alg });
                        encodedShrHeader = this.b64Encode.urlEncode(shrHeader);
                        // Generate payload
                        payload.cnf = {
                            jwk: JSON.parse(publicKeyJwkString)
                        };
                        encodedPayload = this.b64Encode.urlEncode(JSON.stringify(payload));
                        tokenString = encodedShrHeader + "." + encodedPayload;
                        tokenBuffer = BrowserStringUtils.stringToArrayBuffer(tokenString);
                        return [4 /*yield*/, this.browserCrypto.sign(cachedKeyPair.privateKey, tokenBuffer)];
                    case 3:
                        signatureBuffer = _b.sent();
                        encodedSignature = this.b64Encode.urlEncodeArr(new Uint8Array(signatureBuffer));
                        signedJwt = tokenString + "." + encodedSignature;
                        if (signJwtMeasurement) {
                            signJwtMeasurement.endMeasurement({
                                success: true
                            });
                        }
                        return [2 /*return*/, signedJwt];
                }
            });
        });
    };
    /**
     * Returns the SHA-256 hash of an input string
     * @param plainText
     */
    CryptoOps.prototype.hashString = function (plainText) {
        return __awaiter(this, void 0, void 0, function () {
            var hashBuffer, hashBytes;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.browserCrypto.sha256Digest(plainText)];
                    case 1:
                        hashBuffer = _a.sent();
                        hashBytes = new Uint8Array(hashBuffer);
                        return [2 /*return*/, this.b64Encode.urlEncodeArr(hashBytes)];
                }
            });
        });
    };
    CryptoOps.POP_KEY_USAGES = ["sign", "verify"];
    CryptoOps.EXTRACTABLE = true;
    return CryptoOps;
}());

export { CryptoOps };
//# sourceMappingURL=CryptoOps.js.map
