// Copyright 2021 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 Base from 'stores/base'; import client from 'client'; import { action } from 'mobx'; import { SecretsStore } from './secrets'; import globalListenerStore from '../octavia/listener'; export class ContainersStore extends Base { get client() { return client.barbican.containers; } get payloadClient() { return client.barbican.secrets.payload; } get fetchListByLimit() { return true; } get secretStore() { // Not globalSecretsStore here return new SecretsStore(); } updateMarkerParams = (limit, offset) => ({ limit, offset, }); get mapper() { return (data) => { const { container_ref, algorithm } = data; const [, uuid] = container_ref.split('/containers/'); const { domain, expiration } = algorithm ? JSON.parse(algorithm) : {}; return { ...data, id: uuid, domain, expiration, }; }; } async requestListAllByLimit(params, limit) { let hasNext = true; let data = []; while (hasNext) { const offset = data.length || ''; // eslint-disable-next-line no-await-in-loop const result = await this.requestListByMarker(params, limit, offset); const items = this.getListDataFromResult(result); data = [...data, ...items]; if (limit >= result.total || offset >= result.total) { hasNext = false; } } return data; } updateItem(item, listeners) { const { container_ref } = item; const enabledLs = listeners.filter((ls) => { const refs = [ ls.default_tls_container_ref, ls.client_ca_tls_container_ref, ...ls.sni_container_refs, ]; return refs.includes(container_ref); }); if (enabledLs.length) { item.listener = enabledLs.map((ls) => ({ id: ls.id, name: ls.name, lb: ls.lbIds[0], })); } return item; } async listDidFetch(items) { if (items.length === 0) return items; const [secrets, listeners] = await Promise.all([ this.secretStore.fetchList({ mode: 'SERVER' }), globalListenerStore.fetchList(), ]); const newItems = items.map((it) => { const { secret_refs = [] } = it; if (secret_refs.length === 0) { it.hidden = true; } else { // Filter available secrets secret_refs.forEach((secret) => { const { secret_ref = '' } = secret; const [, secretId] = secret_ref.split('/secrets/'); const theSecret = secrets.find((s) => s.id === secretId); if (theSecret) { Object.assign(secret, { secret_info: theSecret }); Object.assign(it, { algorithm: theSecret.algorithm, mode: theSecret.mode, }); } else { it.hidden = true; } }); // Determine if the certificate is used in the listener this.updateItem(it, listeners); } return { ...it, }; }); return newItems.filter((it) => it.hidden !== true); } async detailDidFetch(item) { const { secret_refs = [] } = item; const [secrets, listeners] = await Promise.all([ this.secretStore.fetchList({ mode: 'SERVER' }), globalListenerStore.fetchList(), ]); const secretIds = []; // Filter available secrets secret_refs.forEach(async (secret) => { const { secret_ref = '' } = secret; const [, secretId] = secret_ref.split('/secrets/'); const theSecret = secrets.find((s) => s.id === secretId); if (theSecret) { secretIds.push(theSecret.id); Object.assign(secret, { secret_info: theSecret }); Object.assign(item, { algorithm: theSecret.algorithm, mode: theSecret.mode, }); } }); // Determine if the certificate is used in the listener this.updateItem(item, listeners); // Fetch secrets payload const payloads = await Promise.all( secretIds.map((id) => this.payloadClient.list(id, {}, { headers: { Accept: 'text/plain' } }) ) ); (payloads || []).forEach((it, index) => { secret_refs[index].secret_info.payload = it; }); return item; } @action async create(values) { // Create Secret const commonData = { name: values.name, mode: values.mode, payload_content_type: 'text/plain', secret_type: 'certificate', algorithm: JSON.stringify({ domain: values.domain, expiration: values.expiration, }), }; const contentData = { ...commonData, payload: values.certificate, }; const createSecretArr = [this.secretStore.create(contentData)]; if (values.mode === 'SERVER') { const privateKeyData = { ...commonData, payload: values.private_key, }; createSecretArr.push(this.secretStore.create(privateKeyData)); } const [content, privateKey] = await Promise.all(createSecretArr); // Create Containers const secretRefs = [ { name: 'certificate', secret_ref: content.secret_ref, }, ]; if (privateKey) { secretRefs.push({ name: 'private_key', secret_ref: privateKey.secret_ref, }); } const data = { type: 'certificate', name: values.name, secret_refs: secretRefs, }; return this.client.create(data); } @action delete = async (data) => { const { id, secret_refs = [] } = data; await Promise.all( secret_refs.map((it) => { const { secret_ref = '' } = it; const [, secretId] = secret_ref.split('/secrets/'); return this.secretStore.delete({ id: secretId }); }) ); return this.submitting(this.client.delete(id)); }; } const globalContainersStore = new ContainersStore(); export default globalContainersStore;