github.com/minio/console@v1.4.1/web-app/src/screens/Console/Buckets/BucketDetails/EnableBucketEncryption.tsx (about) 1 // This file is part of MinIO Console Server 2 // Copyright (c) 2021 MinIO, Inc. 3 // 4 // This program is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Affero General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Affero General Public License for more details. 13 // 14 // You should have received a copy of the GNU Affero General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 import React, { Fragment, useEffect, useState } from "react"; 18 19 import { 20 AddIcon, 21 Box, 22 BucketEncryptionIcon, 23 Button, 24 FormLayout, 25 Grid, 26 ProgressBar, 27 Select, 28 } from "mds"; 29 import { 30 ApiError, 31 BucketEncryptionInfo, 32 BucketEncryptionType, 33 KmsKeyInfo, 34 } from "api/consoleApi"; 35 import { api } from "api"; 36 import { errorToHandler } from "api/errors"; 37 import { modalStyleUtils } from "../../Common/FormComponents/common/styleLibrary"; 38 import { setModalErrorSnackMessage } from "../../../../systemSlice"; 39 import { useAppDispatch } from "../../../../store"; 40 import { 41 CONSOLE_UI_RESOURCE, 42 IAM_SCOPES, 43 } from "../../../../common/SecureComponent/permissions"; 44 import { SecureComponent } from "../../../../common/SecureComponent"; 45 import TooltipWrapper from "../../Common/TooltipWrapper/TooltipWrapper"; 46 import AddKeyModal from "./AddKeyModal"; 47 import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper"; 48 49 interface IEnableBucketEncryptionProps { 50 open: boolean; 51 encryptionEnabled: boolean; 52 encryptionCfg: BucketEncryptionInfo | null; 53 selectedBucket: string; 54 closeModalAndRefresh: () => void; 55 } 56 57 const EnableBucketEncryption = ({ 58 open, 59 encryptionCfg, 60 selectedBucket, 61 closeModalAndRefresh, 62 }: IEnableBucketEncryptionProps) => { 63 const dispatch = useAppDispatch(); 64 const [loading, setLoading] = useState<boolean>(false); 65 const [kmsKeyID, setKmsKeyID] = useState<string>(""); 66 const [encryptionType, setEncryptionType] = useState< 67 BucketEncryptionType | "disabled" 68 >("disabled"); 69 const [keys, setKeys] = useState<KmsKeyInfo[] | undefined>([]); 70 const [loadingKeys, setLoadingKeys] = useState<boolean>(false); 71 const [addOpen, setAddOpen] = useState<boolean>(false); 72 73 useEffect(() => { 74 if (encryptionCfg) { 75 if (encryptionCfg.algorithm === "AES256") { 76 setEncryptionType(BucketEncryptionType.SseS3); 77 } else { 78 setEncryptionType(BucketEncryptionType.SseKms); 79 setKmsKeyID(encryptionCfg.kmsMasterKeyID || ""); 80 } 81 } 82 }, [encryptionCfg]); 83 84 useEffect(() => { 85 if (encryptionType === "sse-kms") { 86 api.kms 87 .kmsListKeys() 88 .then((res) => { 89 setKeys(res.data.results); 90 setLoadingKeys(false); 91 }) 92 .catch((err) => { 93 setLoadingKeys(false); 94 dispatch(setModalErrorSnackMessage(errorToHandler(err.error))); 95 }); 96 } 97 }, [encryptionType, loadingKeys, dispatch]); 98 99 const enableBucketEncryption = (event: React.FormEvent) => { 100 event.preventDefault(); 101 if (loading) { 102 return; 103 } 104 if (encryptionType === "disabled") { 105 api.buckets 106 .disableBucketEncryption(selectedBucket) 107 .then(() => { 108 setLoading(false); 109 closeModalAndRefresh(); 110 }) 111 .catch(async (res) => { 112 const err = (await res.json()) as ApiError; 113 setLoading(false); 114 dispatch(setModalErrorSnackMessage(errorToHandler(err))); 115 }); 116 } else { 117 api.buckets 118 .enableBucketEncryption(selectedBucket, { 119 encType: encryptionType, 120 kmsKeyID: kmsKeyID, 121 }) 122 .then(() => { 123 setLoading(false); 124 closeModalAndRefresh(); 125 }) 126 127 .catch(async (res) => { 128 const err = (await res.json()) as ApiError; 129 setLoading(false); 130 dispatch(setModalErrorSnackMessage(errorToHandler(err))); 131 }); 132 } 133 }; 134 135 return ( 136 <Fragment> 137 {addOpen && ( 138 <AddKeyModal 139 addOpen={addOpen} 140 closeAddModalAndRefresh={(refresh: boolean) => { 141 setAddOpen(false); 142 setLoadingKeys(true); 143 }} 144 /> 145 )} 146 147 <ModalWrapper 148 modalOpen={open} 149 onClose={() => { 150 closeModalAndRefresh(); 151 }} 152 title="Enable Bucket Encryption" 153 titleIcon={<BucketEncryptionIcon />} 154 > 155 <form 156 noValidate 157 autoComplete="off" 158 onSubmit={(e: React.FormEvent<HTMLFormElement>) => { 159 enableBucketEncryption(e); 160 }} 161 > 162 <FormLayout withBorders={false} containerPadding={false}> 163 <Select 164 onChange={(value) => { 165 setEncryptionType(value as BucketEncryptionType | "disabled"); 166 }} 167 id="select-encryption-type" 168 name="select-encryption-type" 169 label={"Encryption Type"} 170 value={encryptionType} 171 options={[ 172 { 173 label: "Disabled", 174 value: "disabled", 175 }, 176 { 177 label: "SSE-S3", 178 value: BucketEncryptionType.SseS3, 179 }, 180 { 181 label: "SSE-KMS", 182 value: BucketEncryptionType.SseKms, 183 }, 184 ]} 185 /> 186 {encryptionType === "sse-kms" && ( 187 <Box sx={{ display: "flex", gap: 10 }} className={"inputItem"}> 188 {keys && ( 189 <Select 190 onChange={(value) => { 191 setKmsKeyID(value); 192 }} 193 id="select-kms-key-id" 194 name="select-kms-key-id" 195 label={"KMS Key ID"} 196 value={kmsKeyID} 197 options={keys.map((key: KmsKeyInfo) => { 198 return { 199 label: key.name || "", 200 value: key.name || "", 201 }; 202 })} 203 /> 204 )} 205 <SecureComponent 206 scopes={[IAM_SCOPES.KMS_IMPORT_KEY]} 207 resource={CONSOLE_UI_RESOURCE} 208 errorProps={{ disabled: true }} 209 > 210 <TooltipWrapper tooltip={"Add key"}> 211 <Button 212 id={"import-key"} 213 variant={"regular"} 214 icon={<AddIcon />} 215 onClick={(e) => { 216 setAddOpen(true); 217 e.preventDefault(); 218 }} 219 /> 220 </TooltipWrapper> 221 </SecureComponent> 222 </Box> 223 )} 224 <Grid item xs={12} sx={modalStyleUtils.modalButtonBar}> 225 <Button 226 id={"cancel"} 227 type="submit" 228 variant="regular" 229 onClick={() => { 230 closeModalAndRefresh(); 231 }} 232 disabled={loading} 233 label={"Cancel"} 234 /> 235 <Button 236 id={"save"} 237 type="submit" 238 variant="callAction" 239 disabled={loading} 240 label={"Save"} 241 /> 242 </Grid> 243 {loading && ( 244 <Grid item xs={12}> 245 <ProgressBar /> 246 </Grid> 247 )} 248 </FormLayout> 249 </form> 250 </ModalWrapper> 251 </Fragment> 252 ); 253 }; 254 255 export default EnableBucketEncryption;