UI/ PKI UI Redesign (#12541)
* installs node-forge * correctly displays and formats cert metadata * removes labels * uses helper in hbs file * adds named arg to helper * pki-ca-cert displays common name, issue & expiry date * alphabetizes some attrs * adds test for date helper
This commit is contained in:
parent
b84100d4a0
commit
42ae96ed1c
3
changelog/12541.txt
Normal file
3
changelog/12541.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
ui: parse and display pki cert metadata
|
||||||
|
```
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { parsePkiCert } from '../helpers/parse-pki-cert';
|
||||||
import ApplicationAdapter from './application';
|
import ApplicationAdapter from './application';
|
||||||
|
|
||||||
export default ApplicationAdapter.extend({
|
export default ApplicationAdapter.extend({
|
||||||
|
@ -41,7 +42,14 @@ export default ApplicationAdapter.extend({
|
||||||
}
|
}
|
||||||
response.id = snapshot.id;
|
response.id = snapshot.id;
|
||||||
response.modelName = type.modelName;
|
response.modelName = type.modelName;
|
||||||
|
// only parse if certificate is attached to response
|
||||||
|
if (response.data && response.data.certificate) {
|
||||||
|
const caCertMetadata = parsePkiCert([response.data]);
|
||||||
|
const transformedResponse = { ...response, ...caCertMetadata };
|
||||||
|
store.pushPayload(type.modelName, transformedResponse);
|
||||||
|
} else {
|
||||||
store.pushPayload(type.modelName, response);
|
store.pushPayload(type.modelName, response);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
20
ui/app/helpers/parse-pki-cert.js
Normal file
20
ui/app/helpers/parse-pki-cert.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { helper } from '@ember/component/helper';
|
||||||
|
import { pki } from 'node-forge';
|
||||||
|
|
||||||
|
export function parsePkiCert([model]) {
|
||||||
|
// model has to be the responseJSON from PKI serializer
|
||||||
|
if (!model.certificate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cert = pki.certificateFromPem(model.certificate);
|
||||||
|
const commonName = cert.subject.getField('CN') ? cert.subject.getField('CN').value : null;
|
||||||
|
const issueDate = cert.validity.notBefore;
|
||||||
|
const expiryDate = cert.validity.notAfter;
|
||||||
|
return {
|
||||||
|
common_name: commonName,
|
||||||
|
issue_date: issueDate,
|
||||||
|
expiry_date: expiryDate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default helper(parsePkiCert);
|
|
@ -4,12 +4,15 @@ import { computed } from '@ember/object';
|
||||||
import Certificate from './pki-certificate';
|
import Certificate from './pki-certificate';
|
||||||
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
|
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
|
||||||
|
|
||||||
|
// TODO: alphabetize attrs
|
||||||
export default Certificate.extend({
|
export default Certificate.extend({
|
||||||
DISPLAY_FIELDS: computed(function() {
|
DISPLAY_FIELDS: computed(function() {
|
||||||
return [
|
return [
|
||||||
'csr',
|
'csr',
|
||||||
'certificate',
|
'certificate',
|
||||||
'expiration',
|
'commonName',
|
||||||
|
'issueDate',
|
||||||
|
'expiryDate',
|
||||||
'issuingCa',
|
'issuingCa',
|
||||||
'caChain',
|
'caChain',
|
||||||
'privateKey',
|
'privateKey',
|
||||||
|
@ -17,30 +20,33 @@ export default Certificate.extend({
|
||||||
'serialNumber',
|
'serialNumber',
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
|
addBasicConstraints: attr('boolean', {
|
||||||
|
label: 'Add a Basic Constraints extension with CA: true',
|
||||||
|
helpText:
|
||||||
|
'Only needed as a workaround in some compatibility scenarios with Active Directory Certificate Services',
|
||||||
|
}),
|
||||||
backend: attr('string', {
|
backend: attr('string', {
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
caType: attr('string', {
|
caType: attr('string', {
|
||||||
possibleValues: ['root', 'intermediate'],
|
possibleValues: ['root', 'intermediate'],
|
||||||
defaultValue: 'root',
|
defaultValue: 'root',
|
||||||
label: 'CA Type',
|
label: 'CA Type',
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
}),
|
}),
|
||||||
uploadPemBundle: attr('boolean', {
|
commonName: attr('string'),
|
||||||
label: 'Upload PEM bundle',
|
expiryDate: attr('string', {
|
||||||
readOnly: true,
|
label: 'Expiration date',
|
||||||
}),
|
}),
|
||||||
|
issueDate: attr('string'),
|
||||||
pemBundle: attr('string', {
|
pemBundle: attr('string', {
|
||||||
label: 'PEM bundle',
|
label: 'PEM bundle',
|
||||||
editType: 'file',
|
editType: 'file',
|
||||||
}),
|
}),
|
||||||
addBasicConstraints: attr('boolean', {
|
uploadPemBundle: attr('boolean', {
|
||||||
label: 'Add a Basic Constraints extension with CA: true',
|
label: 'Upload PEM bundle',
|
||||||
helpText:
|
readOnly: true,
|
||||||
'Only needed as a workaround in some compatibility scenarios with Active Directory Certificate Services',
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
fieldDefinition: computed('caType', 'uploadPemBundle', function() {
|
fieldDefinition: computed('caType', 'uploadPemBundle', function() {
|
||||||
const type = this.caType;
|
const type = this.caType;
|
||||||
const isUpload = this.uploadPemBundle;
|
const isUpload = this.uploadPemBundle;
|
||||||
|
@ -92,7 +98,6 @@ export default Certificate.extend({
|
||||||
|
|
||||||
return groups;
|
return groups;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
type: attr('string', {
|
type: attr('string', {
|
||||||
possibleValues: ['internal', 'exported'],
|
possibleValues: ['internal', 'exported'],
|
||||||
defaultValue: 'internal',
|
defaultValue: 'internal',
|
||||||
|
@ -145,7 +150,6 @@ export default Certificate.extend({
|
||||||
label: 'CSR',
|
label: 'CSR',
|
||||||
masked: true,
|
masked: true,
|
||||||
}),
|
}),
|
||||||
expiration: attr(),
|
|
||||||
|
|
||||||
deletePath: lazyCapabilities(apiPath`${'backend'}/root`, 'backend'),
|
deletePath: lazyCapabilities(apiPath`${'backend'}/root`, 'backend'),
|
||||||
canDeleteRoot: and('deletePath.canDelete', 'deletePath.canSudo'),
|
canDeleteRoot: and('deletePath.canDelete', 'deletePath.canSudo'),
|
||||||
|
|
|
@ -17,27 +17,30 @@ export default Model.extend({
|
||||||
DISPLAY_FIELDS: computed(function() {
|
DISPLAY_FIELDS: computed(function() {
|
||||||
return [
|
return [
|
||||||
'certificate',
|
'certificate',
|
||||||
|
'commonName',
|
||||||
'issuingCa',
|
'issuingCa',
|
||||||
'caChain',
|
'caChain',
|
||||||
'privateKey',
|
'privateKey',
|
||||||
'privateKeyType',
|
'privateKeyType',
|
||||||
'serialNumber',
|
|
||||||
'revocationTime',
|
'revocationTime',
|
||||||
|
'issueDate',
|
||||||
|
'expiryDate',
|
||||||
|
'serialNumber',
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
commonName: attr('string'),
|
||||||
|
expiryDate: attr('string', {
|
||||||
|
label: 'Expiration date',
|
||||||
|
}),
|
||||||
|
issueDate: attr('string'),
|
||||||
role: attr('object', {
|
role: attr('object', {
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
revocationTime: attr('number'),
|
revocationTime: attr('number'),
|
||||||
commonName: attr('string', {
|
|
||||||
label: 'Common Name',
|
|
||||||
}),
|
|
||||||
|
|
||||||
altNames: attr('string', {
|
altNames: attr('string', {
|
||||||
label: 'DNS/Email Subject Alternative Names (SANs)',
|
label: 'DNS/Email Subject Alternative Names (SANs)',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
ipSans: attr('string', {
|
ipSans: attr('string', {
|
||||||
label: 'IP Subject Alternative Names (SANs)',
|
label: 'IP Subject Alternative Names (SANs)',
|
||||||
}),
|
}),
|
||||||
|
@ -47,22 +50,18 @@ export default Model.extend({
|
||||||
helpText:
|
helpText:
|
||||||
'The format is the same as OpenSSL: <oid>;<type>:<value> where the only current valid type is UTF8',
|
'The format is the same as OpenSSL: <oid>;<type>:<value> where the only current valid type is UTF8',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
ttl: attr({
|
ttl: attr({
|
||||||
label: 'TTL',
|
label: 'TTL',
|
||||||
editType: 'ttl',
|
editType: 'ttl',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
format: attr('string', {
|
format: attr('string', {
|
||||||
defaultValue: 'pem',
|
defaultValue: 'pem',
|
||||||
possibleValues: ['pem', 'der', 'pem_bundle'],
|
possibleValues: ['pem', 'der', 'pem_bundle'],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
excludeCnFromSans: attr('boolean', {
|
excludeCnFromSans: attr('boolean', {
|
||||||
label: 'Exclude Common Name from Subject Alternative Names (SANs)',
|
label: 'Exclude Common Name from Subject Alternative Names (SANs)',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
certificate: attr('string', {
|
certificate: attr('string', {
|
||||||
masked: true,
|
masked: true,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -2,6 +2,7 @@ import RESTSerializer from '@ember-data/serializer/rest';
|
||||||
import { isNone, isBlank } from '@ember/utils';
|
import { isNone, isBlank } from '@ember/utils';
|
||||||
import { assign } from '@ember/polyfills';
|
import { assign } from '@ember/polyfills';
|
||||||
import { decamelize } from '@ember/string';
|
import { decamelize } from '@ember/string';
|
||||||
|
import { parsePkiCert } from '../helpers/parse-pki-cert';
|
||||||
|
|
||||||
export default RESTSerializer.extend({
|
export default RESTSerializer.extend({
|
||||||
keyForAttribute: function(attr) {
|
keyForAttribute: function(attr) {
|
||||||
|
@ -41,7 +42,14 @@ export default RESTSerializer.extend({
|
||||||
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
|
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
|
||||||
const responseJSON = this.normalizeItems(payload);
|
const responseJSON = this.normalizeItems(payload);
|
||||||
const { modelName } = primaryModelClass;
|
const { modelName } = primaryModelClass;
|
||||||
let transformedPayload = { [modelName]: responseJSON };
|
let transformedPayload, certMetadata;
|
||||||
|
// hits cert/list endpoint first which returns an array, only want to parse if response is not an array
|
||||||
|
if (!Array.isArray(responseJSON)) {
|
||||||
|
certMetadata = parsePkiCert([responseJSON]);
|
||||||
|
transformedPayload = { [modelName]: { ...certMetadata, ...responseJSON } };
|
||||||
|
} else {
|
||||||
|
transformedPayload = { [modelName]: responseJSON };
|
||||||
|
}
|
||||||
return this._super(store, primaryModelClass, transformedPayload, id, requestType);
|
return this._super(store, primaryModelClass, transformedPayload, id, requestType);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
.column {
|
.column {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
|
padding: $spacing-m;
|
||||||
|
|
||||||
&.info-table-row-edit {
|
&.info-table-row-edit {
|
||||||
padding-bottom: 0.3rem;
|
padding-bottom: 0.3rem;
|
||||||
padding-top: 0.3rem;
|
padding-top: 0.3rem;
|
||||||
|
|
|
@ -10,25 +10,23 @@
|
||||||
{{#if (or model.certificate model.csr)}}
|
{{#if (or model.certificate model.csr)}}
|
||||||
{{#each model.attrs as |attr|}}
|
{{#each model.attrs as |attr|}}
|
||||||
{{#if attr.options.masked}}
|
{{#if attr.options.masked}}
|
||||||
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{get model attr.name}}>
|
<InfoTableRow data-test-table-row
|
||||||
|
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||||
|
@value={{get model attr.name}}>
|
||||||
<MaskedInput
|
<MaskedInput
|
||||||
@value={{get model attr.name}}
|
@value={{get model attr.name}}
|
||||||
@displayOnly={{true}}
|
@displayOnly={{true}}
|
||||||
@allowCopy={{true}}
|
@allowCopy={{true}}
|
||||||
/>
|
/>
|
||||||
</InfoTableRow>
|
</InfoTableRow>
|
||||||
{{else if (eq attr.name "expiration")}}
|
{{else if (and (get model attr.name) (or (eq attr.name "issueDate") (eq attr.name "expiryDate")))}}
|
||||||
{{info-table-row
|
<InfoTableRow data-test-table-row={{value}}
|
||||||
data-test-table-row
|
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||||
label=(capitalize (or attr.options.label (humanize (dasherize attr.name))))
|
@value={{date-format (get model attr.name) 'MMM dd, yyyy hh:mm:ss a' isFormatted=true}}/>
|
||||||
value=(date-format (get model attr.name) 'MMM dd, yyyy hh:mm:ss a')
|
|
||||||
}}
|
|
||||||
{{else}}
|
{{else}}
|
||||||
{{info-table-row
|
<InfoTableRow data-test-table-row={{value}}
|
||||||
data-test-table-row
|
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||||
label=(capitalize (or attr.options.label (humanize (dasherize attr.name))))
|
@value={{get model attr.name}}/>
|
||||||
value=(get model attr.name)
|
|
||||||
}}
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||||
|
@ -94,15 +92,24 @@
|
||||||
/>
|
/>
|
||||||
{{#each model.attrs as |attr|}}
|
{{#each model.attrs as |attr|}}
|
||||||
{{#if attr.options.masked}}
|
{{#if attr.options.masked}}
|
||||||
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{get model attr.name}}>
|
<InfoTableRow
|
||||||
|
data-test-table-row={{value}}
|
||||||
|
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||||
|
@value={{get model attr.name}}>
|
||||||
<MaskedInput
|
<MaskedInput
|
||||||
@value={{get model attr.name}}
|
@value={{get model attr.name}}
|
||||||
@displayOnly={{true}}
|
@displayOnly={{true}}
|
||||||
@allowCopy={{true}}
|
@allowCopy={{true}}
|
||||||
/>
|
/>
|
||||||
</InfoTableRow>
|
</InfoTableRow>
|
||||||
|
{{else if (and (get model attr.name) (or (eq attr.name "issueDate") (eq attr.name "expiryDate")))}}
|
||||||
|
<InfoTableRow data-test-table-row={{value}}
|
||||||
|
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||||
|
@value={{date-format (get model attr.name) 'MMM dd, yyyy hh:mm:ss a' isFormatted=true}}/>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{info-table-row data-test-table-row label=(capitalize (or attr.options.label (humanize (dasherize attr.name)))) value=(get model attr.name)}}
|
<InfoTableRow data-test-table-row={{value}}
|
||||||
|
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||||
|
@value={{get model attr.name}}/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||||
|
|
|
@ -13,22 +13,33 @@
|
||||||
<MessageError @model={{model}} />
|
<MessageError @model={{model}} />
|
||||||
{{#each model.attrs as |attr|}}
|
{{#each model.attrs as |attr|}}
|
||||||
{{#if (eq attr.type "object")}}
|
{{#if (eq attr.type "object")}}
|
||||||
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{stringify (get model attr.name)}} />
|
<InfoTableRow data-test-table-row
|
||||||
|
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||||
|
@value={{stringify (get model attr.name)}} />
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if attr.options.masked}}
|
{{#if attr.options.masked}}
|
||||||
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{get model attr.name}}>
|
<InfoTableRow data-test-table-row
|
||||||
|
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||||
|
@value={{get model attr.name}}>
|
||||||
<MaskedInput
|
<MaskedInput
|
||||||
@value={{get model attr.name}}
|
@value={{get model attr.name}}
|
||||||
@displayOnly={{true}}
|
@displayOnly={{true}}
|
||||||
@allowCopy={{true}}
|
@allowCopy={{true}}
|
||||||
/>
|
/>
|
||||||
</InfoTableRow>
|
</InfoTableRow>
|
||||||
|
{{else if (and (get model attr.name) (or (eq attr.name "issueDate") (eq attr.name "expiryDate")))}}
|
||||||
|
<InfoTableRow data-test-table-row
|
||||||
|
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||||
|
@value={{date-format (get model attr.name) 'MMM dd, yyyy hh:mm:ss a' isFormatted=true}} />
|
||||||
{{else}}
|
{{else}}
|
||||||
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{get model attr.name}} />
|
<InfoTableRow data-test-table-row
|
||||||
|
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||||
|
@value={{get model attr.name}} />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field is-grouped is-grouped-split box is-fullwidth is-bottomless">
|
<div class="field is-grouped is-grouped-split box is-fullwidth is-bottomless">
|
||||||
<div class="field is-grouped">
|
<div class="field is-grouped">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import { helper } from '@ember/component/helper';
|
import { helper } from '@ember/component/helper';
|
||||||
import { format, parseISO } from 'date-fns';
|
import { format, parseISO } from 'date-fns';
|
||||||
|
|
||||||
export function dateFormat([date, style]) {
|
export function dateFormat([date, style], { isFormatted = false }) {
|
||||||
// see format breaking in upgrade to date-fns 2.x https://github.com/date-fns/date-fns/blob/master/CHANGELOG.md#changed-5
|
// see format breaking in upgrade to date-fns 2.x https://github.com/date-fns/date-fns/blob/master/CHANGELOG.md#changed-5
|
||||||
|
if (isFormatted) {
|
||||||
|
return format(new Date(date), style);
|
||||||
|
}
|
||||||
let number = typeof date === 'string' ? parseISO(date) : date;
|
let number = typeof date === 'string' ? parseISO(date) : date;
|
||||||
if (!number) {
|
if (!number) {
|
||||||
return;
|
return;
|
||||||
|
|
35326
ui/package-lock.json
generated
Normal file
35326
ui/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -134,6 +134,7 @@
|
||||||
"ivy-codemirror": "IvyApp/ivy-codemirror#fb09333c5144da47e14a9e6260f80577d5408374",
|
"ivy-codemirror": "IvyApp/ivy-codemirror#fb09333c5144da47e14a9e6260f80577d5408374",
|
||||||
"jsonlint": "^1.6.3",
|
"jsonlint": "^1.6.3",
|
||||||
"loader.js": "^4.7.0",
|
"loader.js": "^4.7.0",
|
||||||
|
"node-forge": "^0.10.0",
|
||||||
"node-sass": "^4.10.0",
|
"node-sass": "^4.10.0",
|
||||||
"normalize.css": "4.1.1",
|
"normalize.css": "4.1.1",
|
||||||
"pretender": "^3.4.3",
|
"pretender": "^3.4.3",
|
||||||
|
|
|
@ -105,7 +105,9 @@ module('Acceptance | Enterprise | Transform secrets', function(hooks) {
|
||||||
await clickTrigger('#allowed_roles');
|
await clickTrigger('#allowed_roles');
|
||||||
await settled();
|
await settled();
|
||||||
await typeInSearch(roleName);
|
await typeInSearch(roleName);
|
||||||
|
await settled();
|
||||||
await selectChoose('#allowed_roles', '.ember-power-select-option', 0);
|
await selectChoose('#allowed_roles', '.ember-power-select-option', 0);
|
||||||
|
await settled();
|
||||||
await transformationsPage.submit();
|
await transformationsPage.submit();
|
||||||
await settled();
|
await settled();
|
||||||
assert.equal(
|
assert.equal(
|
||||||
|
|
|
@ -76,14 +76,18 @@ BXUV2Uwtxf+QCphnlht9muX2fsLIzDJea0JipWj1uf2H8OZsjE8=
|
||||||
|
|
||||||
await page.form.generateCA();
|
await page.form.generateCA();
|
||||||
await settled();
|
await settled();
|
||||||
assert.ok(page.form.rows.length > 0, 'shows all of the rows');
|
|
||||||
// TODO come back and figure out why not working after upgrade. I see it, it's a timing issue.
|
assert.ok(page.form.commonNameIsPresent, 'the common name displays');
|
||||||
// assert.ok(page.form.certificateIsPresent, 'the certificate is included');
|
assert.ok(page.form.issueDateIsPresent, 'the issue date displays');
|
||||||
|
assert.ok(page.form.expiryDateIsPresent, 'the expiration date displays');
|
||||||
|
assert
|
||||||
|
.dom('[data-test-value-div="Certificate"] [data-test-masked-input]')
|
||||||
|
.exists('certificate is present');
|
||||||
|
|
||||||
await page.form.back();
|
await page.form.back();
|
||||||
await settled();
|
|
||||||
await page.form.generateCA();
|
await page.form.generateCA();
|
||||||
await settled();
|
await settled();
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
page.flash.latestMessage.includes('You tried to generate a new root CA'),
|
page.flash.latestMessage.includes('You tried to generate a new root CA'),
|
||||||
'shows warning message'
|
'shows warning message'
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
import { setupRenderingTest } from 'ember-qunit';
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
import { render } from '@ember/test-helpers';
|
import { render } from '@ember/test-helpers';
|
||||||
|
import { format } from 'date-fns';
|
||||||
import hbs from 'htmlbars-inline-precompile';
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
|
||||||
module('Integration | Helper | date-format', function(hooks) {
|
module('Integration | Helper | date-format', function(hooks) {
|
||||||
|
@ -42,4 +43,14 @@ module('Integration | Helper | date-format', function(hooks) {
|
||||||
await render(hbs`<p data-test-date-format>Date: {{date-format tenDigitDate "MM/dd/yyyy"}}</p>`);
|
await render(hbs`<p data-test-date-format>Date: {{date-format tenDigitDate "MM/dd/yyyy"}}</p>`);
|
||||||
assert.dom('[data-test-date-format]').includesText('05/23/2021');
|
assert.dom('[data-test-date-format]').includesText('05/23/2021');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('it supports already formatted dates', async function(assert) {
|
||||||
|
let formattedDate = new Date();
|
||||||
|
this.set('formattedDate', formattedDate);
|
||||||
|
|
||||||
|
await render(
|
||||||
|
hbs`<p data-test-date-format>Date: {{date-format formattedDate 'MMMM dd, yyyy hh:mm:ss a' isFormatted=true}}</p>`
|
||||||
|
);
|
||||||
|
assert.dom('[data-test-date-format]').includesText(format(formattedDate, 'MMMM dd, yyyy hh:mm:ss a'));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,12 +27,15 @@ export default {
|
||||||
csr: text('[data-test-row-value="CSR"]', { normalize: false }),
|
csr: text('[data-test-row-value="CSR"]', { normalize: false }),
|
||||||
csrField: fillable('[data-test-input="csr"]'),
|
csrField: fillable('[data-test-input="csr"]'),
|
||||||
certificate: text('[data-test-row-value="Certificate"]', { normalize: false }),
|
certificate: text('[data-test-row-value="Certificate"]', { normalize: false }),
|
||||||
certificateIsPresent: isPresent('[data-test-row-value="Certificate"]'),
|
commonNameIsPresent: isPresent('[data-test-row-value="Common name"]'),
|
||||||
uploadCert: clickable('[data-test-input="uploadPemBundle"]'),
|
uploadCert: clickable('[data-test-input="uploadPemBundle"]'),
|
||||||
enterCertAsText: clickable('[data-test-text-toggle]'),
|
enterCertAsText: clickable('[data-test-text-toggle]'),
|
||||||
pemBundle: fillable('[data-test-text-file-textarea="true"]'),
|
pemBundle: fillable('[data-test-text-file-textarea="true"]'),
|
||||||
commonName: fillable('[data-test-input="commonName"]'),
|
commonName: fillable('[data-test-input="commonName"]'),
|
||||||
|
|
||||||
|
issueDateIsPresent: text('[data-test-row-value="Issue date"]'),
|
||||||
|
expiryDateIsPresent: text('[data-test-row-value="Expiration date"]'),
|
||||||
|
|
||||||
async generateCA(commonName = 'PKI CA', type = 'root') {
|
async generateCA(commonName = 'PKI CA', type = 'root') {
|
||||||
if (type === 'intermediate') {
|
if (type === 'intermediate') {
|
||||||
return await this.replaceCA()
|
return await this.replaceCA()
|
||||||
|
|
|
@ -13701,6 +13701,11 @@ node-fetch@^2.6.1:
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||||
|
|
||||||
|
node-forge@^0.10.0:
|
||||||
|
version "0.10.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
|
||||||
|
integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==
|
||||||
|
|
||||||
node-gyp@^3.8.0:
|
node-gyp@^3.8.0:
|
||||||
version "3.8.0"
|
version "3.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
|
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
|
||||||
|
|
Loading…
Reference in a new issue