Files
skyline-console/src/pages/barbican/containers/Secret/actions/Create.jsx
Reet Srivastava fa2959a2b6 feat:adds barbican panel(named Key-Manager)
This change adds barbican panel for secrets and  list similar to other panels and subpanel. Has Creation , Detail Secret Page included

Change-Id: I33a7c4a4845529c5a6d44060728956701f50dccf
Signed-off-by: Reet Srivastava <reet.srivastava@rackspace.com>
2025-09-29 10:20:25 +00:00

463 lines
11 KiB
JavaScript

// Copyright 2025 99cloud
//
// 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.
import { inject, observer } from 'mobx-react';
import { ModalAction } from 'containers/Action';
import globalSecretsStore from 'stores/barbican/secrets';
import globalOrdersStore from 'stores/barbican/orders';
import moment from 'moment';
// Constants for secret configuration
const SECRET_CONFIG = {
KEY: {
BIT_LENGTH: 256,
ALGORITHM: 'aes',
},
ASYMMETRIC: {
BIT_LENGTH: 2048,
ALGORITHM: 'rsa',
},
};
export class CreateSecret extends ModalAction {
static id = 'create-secret';
static title = t('Create Secret');
static policy = ['secrets:post', 'orders:post'];
static allowed = () => Promise.resolve(true);
static get modalSize() {
return 'large';
}
static CONTENT_TYPE_OPTIONS = [
{ label: 'text/plain', value: 'text/plain' },
{ label: 'application/octet-stream', value: 'application/octet-stream' },
{ label: 'application/x-pkcs12', value: 'application/x-pkcs12' },
{ label: 'application/x-pem-file', value: 'application/x-pem-file' },
];
static ALGORITHM_OPTIONS = [
{ label: 'AES', value: 'aes' },
{ label: 'DES', value: 'des' },
{ label: '3DES', value: '3des' },
{ label: 'RSA', value: 'rsa' },
{ label: 'DSA', value: 'dsa' },
{ label: 'EC', value: 'ec' },
];
static ASYMMETRIC_ALGORITHM_OPTIONS = [
{ label: 'RSA', value: 'rsa' },
{ label: 'DSA', value: 'dsa' },
];
static BIT_LENGTH_OPTIONS = [
{ label: '128', value: 128 },
{ label: '192', value: 192 },
{ label: '256', value: 256 },
{ label: '1024', value: 1024 },
{ label: '2048', value: 2048 },
{ label: '4096', value: 4096 },
];
static MODE_OPTIONS = [
{ label: 'CBC', value: 'cbc' },
{ label: 'CTR', value: 'ctr' },
];
init() {
this.secretsStore = globalSecretsStore;
this.ordersStore = globalOrdersStore;
}
get name() {
return t('Create Secret');
}
get nameForStateUpdate() {
return ['creationType', 'secret_type', 'request_type', 'algorithm'];
}
onSecretTypeChange = (value) => {
const { creationType } = this.state;
if (!this.formRef.current) {
return;
}
if (creationType === 'direct') {
this.formRef.current.setFieldsValue({
secret_type: value,
});
return;
}
const config =
value === 'key'
? SECRET_CONFIG.KEY
: value === 'asymmetric'
? SECRET_CONFIG.ASYMMETRIC
: { BIT_LENGTH: undefined, ALGORITHM: undefined };
this.formRef.current.setFieldsValue({
request_type: value,
bit_length: config.BIT_LENGTH,
algorithm: config.ALGORITHM,
});
};
get defaultValue() {
return {
creationType: 'direct',
name: '',
payload: '',
payload_content_type: 'text/plain',
payload_content_encoding: '',
algorithm: 'aes',
bit_length: 256,
mode: 'cbc',
secret_type: 'opaque',
request_type: 'key',
expiration: '',
};
}
get creationTypeOptions() {
return [
{
label: t('Create Secret Directly'),
value: 'direct',
tip: t('Create a secret with your own payload content'),
},
{
label: t('Create Secret via Order'),
value: 'order',
tip: t('Create a secret through order (for certificates, keys, etc.)'),
},
];
}
get requestTypeOptions() {
return [
{
label: t('Key'),
value: 'key',
tip: t('Symmetric keys, private keys, and passphrases'),
},
{
label: t('Asymmetric Key'),
value: 'asymmetric',
tip: t('Asymmetric key pairs (public/private)'),
},
];
}
get secretTypeOptionsForDirect() {
return [
{
label: t('Opaque'),
value: 'opaque',
tip: t('Default secret type for arbitrary data'),
},
{
label: t('Symmetric'),
value: 'symmetric',
tip: t('Symmetric keys'),
},
{
label: t('Public'),
value: 'public',
tip: t('Public keys'),
},
{
label: t('Private'),
value: 'private',
tip: t('Private keys'),
},
{
label: t('Certificate'),
value: 'certificate',
tip: t('Certificates'),
},
{
label: t('Passphrase'),
value: 'passphrase',
tip: t('Passphrases'),
},
];
}
get algorithmOptions() {
const { secret_type, request_type } = this.state;
const currentType = secret_type || request_type;
if (currentType === 'asymmetric') {
return CreateSecret.ASYMMETRIC_ALGORITHM_OPTIONS;
}
return CreateSecret.ALGORITHM_OPTIONS;
}
get bitLengthOptions() {
return CreateSecret.BIT_LENGTH_OPTIONS;
}
get modeOptions() {
return CreateSecret.MODE_OPTIONS;
}
get formItems() {
const { creationType } = this.state;
const isDirect = creationType === 'direct';
const isOrder = creationType === 'order';
const baseItems = this.getBaseFormItems();
if (isDirect) {
return [...baseItems, ...this.getDirectFormItems()];
}
if (isOrder) {
return [...baseItems, ...this.getOrderFormItems()];
}
return baseItems;
}
getBaseFormItems() {
const { creationType } = this.state;
const isDirect = creationType === 'direct';
const isOrder = creationType === 'order';
return [
{
name: 'creationType',
label: t('Creation Method'),
type: 'radio',
options: this.creationTypeOptions,
required: true,
},
{
name: 'name',
label: t('Secret Name'),
type: 'input-name',
required: false,
withoutChinese: true,
tip: isOrder
? t('Optional. If not provided, a name will be auto-generated')
: t('Required for direct creation'),
rules: isDirect
? [
{
required: true,
message: t('Secret name is required for direct creation'),
},
]
: [],
},
];
}
getDirectFormItems() {
return [
{
name: 'payload',
label: t('Secret Payload'),
type: 'textarea',
required: true,
rows: 6,
placeholder: t('Enter the secret content'),
tip: t('The actual secret data to be stored'),
},
{
name: 'payload_content_type',
label: t('Payload Content Type'),
type: 'select',
options: CreateSecret.CONTENT_TYPE_OPTIONS,
required: true,
tip: t('Required when payload is supplied'),
},
{
name: 'payload_content_encoding',
label: t('Payload Content Encoding'),
type: 'input',
required: false,
tip: t(
'Required if payload content type is "application/octet-stream"'
),
},
{
name: 'secret_type',
label: t('Secret Type'),
type: 'select',
options: [
{
label: t('Select Secret Type'),
value: '',
},
...this.secretTypeOptionsForDirect,
],
required: false,
tip: t('Optional. Type of secret being stored (default: opaque)'),
},
{
name: 'algorithm',
label: t('Algorithm'),
type: 'select',
options: [
{
label: t('Select Algorithm'),
value: '',
},
...this.algorithmOptions,
],
required: false,
tip: t('Optional. Algorithm used by the secret (default: aes)'),
},
{
name: 'bit_length',
label: t('Bit Length'),
type: 'select',
options: [
{
label: t('Select Bit Length'),
value: '',
},
...this.bitLengthOptions,
],
required: false,
tip: t('Optional. Bit length of the secret (default: 256)'),
},
{
name: 'mode',
label: t('Mode'),
type: 'select',
options: [
{
label: t('Select Mode'),
value: '',
},
...this.modeOptions,
],
required: false,
tip: t(
'Optional. Algorithm mode, used only for reference (default: cbc)'
),
},
{
name: 'expiration',
label: t('Expiration Date'),
type: 'date-picker',
showToday: false,
disabledDate: (current) => current && current <= moment().endOf('d'),
tip: t('Optional. When the secret should expire (ISO 8601 format)'),
},
];
}
getOrderFormItems() {
return [
{
name: 'request_type',
label: t('Request Type'),
type: 'select',
options: this.requestTypeOptions,
required: true,
onChange: this.onSecretTypeChange,
},
{
name: 'algorithm',
label: t('Algorithm'),
type: 'select',
options: this.algorithmOptions,
required: false,
tip: t(
'Optional. Algorithm to be used with the requested key (default: aes)'
),
},
{
name: 'bit_length',
label: t('Bit Length'),
type: 'select',
options: this.bitLengthOptions,
required: false,
tip: t(
'Optional. Bit length of the requested secret key (default: 256)'
),
},
{
name: 'mode',
label: t('Mode'),
type: 'select',
options: this.modeOptions,
required: false,
tip: t(
'Optional. Algorithm mode to be used with the requested key (default: cbc)'
),
},
{
name: 'payload_content_type',
label: t('Payload Content Type'),
type: 'select',
options: [
{
label: 'application/octet-stream',
value: 'application/octet-stream',
},
{ label: 'text/plain', value: 'text/plain' },
{ label: 'application/x-pkcs12', value: 'application/x-pkcs12' },
{
label: 'application/x-pem-file',
value: 'application/x-pem-file',
},
],
required: false,
tip: t(
'Optional. Type/format of the secret to be generated (default: application/octet-stream)'
),
},
{
name: 'expiration',
label: t('Expiration Date'),
type: 'date-picker',
showToday: false,
disabledDate: (current) => current && current <= moment().endOf('d'),
tip: t('Optional. Expiration time for the secret in ISO 8601 format'),
},
];
}
onClickCancel = () => {
this.onCancel();
};
onSubmit = (values) => {
const { creationType, ...rest } = values;
if (creationType === 'direct') {
return this.secretsStore.create(rest);
}
if (creationType === 'order') {
return this.ordersStore.create(rest);
}
return Promise.reject(new Error('Invalid creation type'));
};
}
export default inject('rootStore')(observer(CreateSecret));