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;