/**
 * Copyright (c) HashiCorp, Inc.
 * SPDX-License-Identifier: MPL-2.0
 */

import { module, test } from 'qunit';
import { visit, click, fillIn, find } from '@ember/test-helpers';
import { setupApplicationTest } from 'vault/tests/helpers';
import { v4 as uuidv4 } from 'uuid';

import authPage from 'vault/tests/pages/auth';
import logout from 'vault/tests/pages/logout';
import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import { runCommands } from 'vault/tests/helpers/pki/pki-run-commands';
import { SELECTORS } from 'vault/tests/helpers/pki/pki-issuer-cross-sign';
import { verifyCertificates } from 'vault/utils/parse-pki-cert';
module('Acceptance | pki/pki cross sign', function (hooks) {
  setupApplicationTest(hooks);

  hooks.beforeEach(async function () {
    await authPage.login();
    this.parentMountPath = `parent-mount-${uuidv4()}`;
    this.oldParentIssuerName = 'old-parent-issuer'; // old parent issuer we're transferring from
    this.parentIssuerName = 'new-parent-issuer'; // issuer where cross-signing action will begin
    this.intMountPath = `intermediate-mount-${uuidv4()}`; // first input box in cross-signing page
    this.intIssuerName = 'my-intermediate-issuer'; // second input box in cross-signing page
    this.newlySignedIssuer = 'my-newly-signed-int'; // third input
    await enablePage.enable('pki', this.parentMountPath);
    await enablePage.enable('pki', this.intMountPath);

    await runCommands([
      `write "${this.parentMountPath}/root/generate/internal" common_name="Long-Lived Root X1" ttl=8960h issuer_name="${this.oldParentIssuerName}"`,
      `write "${this.parentMountPath}/root/generate/internal" common_name="Long-Lived Root X2" ttl=8960h issuer_name="${this.parentIssuerName}"`,
      `write "${this.parentMountPath}/config/issuers" default="${this.parentIssuerName}"`,
    ]);
  });

  hooks.afterEach(async function () {
    // Cleanup engine
    await runCommands([`delete sys/mounts/${this.intMountPath}`]);
    await runCommands([`delete sys/mounts/${this.parentMountPath}`]);
    await logout.visit();
  });

  test('it cross-signs an issuer', async function (assert) {
    // configure parent and intermediate mounts to make them cross-signable
    await visit(`/vault/secrets/${this.intMountPath}/pki/configuration/create`);
    await click(SELECTORS.configure.optionByKey('generate-csr'));
    await fillIn(SELECTORS.inputByName('type'), 'internal');
    await fillIn(SELECTORS.inputByName('commonName'), 'Short-Lived Int R1');
    await click('[data-test-save]');
    const csr = find(SELECTORS.copyButton('CSR')).getAttribute('data-clipboard-text');
    await visit(`vault/secrets/${this.parentMountPath}/pki/issuers/${this.oldParentIssuerName}/sign`);
    await fillIn(SELECTORS.inputByName('csr'), csr);
    await fillIn(SELECTORS.inputByName('format'), 'pem_bundle');
    await click('[data-test-pki-sign-intermediate-save]');
    const pemBundle = find(SELECTORS.copyButton('CA Chain'))
      .getAttribute('data-clipboard-text')
      .replace(/,/, '\n');
    await visit(`vault/secrets/${this.intMountPath}/pki/configuration/create`);
    await click(SELECTORS.configure.optionByKey('import'));
    await click('[data-test-text-toggle]');
    await fillIn('[data-test-text-file-textarea]', pemBundle);
    await click(SELECTORS.configure.importSubmit);
    await visit(`vault/secrets/${this.intMountPath}/pki/issuers`);
    await click('[data-test-is-default]');
    // name default issuer of intermediate
    const oldIntIssuerId = find(SELECTORS.rowValue('Issuer ID')).innerText;
    const oldIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-clipboard-text');
    await click(SELECTORS.details.configure);
    await fillIn(SELECTORS.inputByName('issuerName'), this.intIssuerName);
    await click('[data-test-save]');

    // perform cross-sign
    await visit(`vault/secrets/${this.parentMountPath}/pki/issuers/${this.parentIssuerName}/cross-sign`);
    await fillIn(SELECTORS.objectListInput('intermediateMount'), this.intMountPath);
    await fillIn(SELECTORS.objectListInput('intermediateIssuer'), this.intIssuerName);
    await fillIn(SELECTORS.objectListInput('newCrossSignedIssuer'), this.newlySignedIssuer);
    await click(SELECTORS.submitButton);
    assert
      .dom(`${SELECTORS.signedIssuerCol('intermediateMount')} a`)
      .hasAttribute('href', `/ui/vault/secrets/${this.intMountPath}/pki/overview`);
    assert
      .dom(`${SELECTORS.signedIssuerCol('intermediateIssuer')} a`)
      .hasAttribute('href', `/ui/vault/secrets/${this.intMountPath}/pki/issuers/${oldIntIssuerId}/details`);

    // get certificate data of newly signed issuer
    await click(`${SELECTORS.signedIssuerCol('newCrossSignedIssuer')} a`);
    const newIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-clipboard-text');

    // verify cross-sign was accurate by creating a role to issue a leaf certificate
    const myRole = 'some-role';
    await runCommands([
      `write ${this.intMountPath}/roles/${myRole} \
    issuer_ref=${this.newlySignedIssuer}\
    allow_any_name=true \
    max_ttl="720h"`,
    ]);
    await visit(`vault/secrets/${this.intMountPath}/pki/roles/${myRole}/generate`);
    await fillIn(SELECTORS.inputByName('commonName'), 'my-leaf');
    await fillIn('[data-test-ttl-value="TTL"]', '3600');
    await click('[data-test-pki-generate-button]');
    const myLeafCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-clipboard-text');

    // see comments in utils/parse-pki-cert.js for step-by-step explanation of of verifyCertificates method
    assert.true(
      await verifyCertificates(oldIntCert, newIntCert, myLeafCert),
      'the leaf certificate validates against both intermediate certificates'
    );
  });
});
