Skip to content
Snippets Groups Projects
S3APIService.tsx 3.75 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { ReactNode, createContext, useContext, useState } from "react";
    import { useOAuth } from "./OAuth2";
    import STS from "aws-sdk/clients/sts";
    import S3 from "aws-sdk/clients/s3";
    import { Credentials } from "aws-sdk";
    import { useCallback } from "react";
    import { useEffect } from "react";
    import { AWSError, Endpoint } from "aws-sdk";
    
    // **** AWS Config ****
    export interface AWSConfig {
      endpoint: string | Endpoint;
      region: string;
    }
    
    // ***** State *****
    
    export interface IS3ServiceState {
      awsCredentials?: Credentials;
    }
    
    
    export const initialS3ServiceState: IS3ServiceState = {
      awsCredentials: undefined
    }
    
    // ***** Context *****
    
    export interface S3ContextProps {
      awsConfig: AWSConfig;
      listBuckets(): void;
      createBucket(bucketName: string): void;
    }
    
    export const S3ServiceContext = createContext<S3ContextProps | undefined>(undefined);
    
    // ***** S3Service *****
    
    interface S3ServiceProviderProps {
      awsConfig: AWSConfig;
      children?: ReactNode;
    }
    
    export const S3ServiceProvider = (props: S3ServiceProviderProps): JSX.Element => {
      const { children, awsConfig } = props;
    
      const [s3ServiceState, setS3ServiceState] = useState<IS3ServiceState>(
        initialS3ServiceState
      );
      const oAuth = useOAuth();
    
      const isAuthenticated = () => {
        return oAuth.isAuthenticated && !oAuth.user?.token?.expired;
      }
    
      const getS3Client = (): S3 => {
        return new S3({
          ...awsConfig,
          credentials: s3ServiceState.awsCredentials,
          s3ForcePathStyle: true
        });
      }
    
    
      useEffect(() => {
        if (!oAuth.isAuthenticated) {
          return;
        }
    
        const user = oAuth.user!;
        const token = user.token;
    
        if (!token) {
          console.log("Token missig or expired");
          return;
        }
    
        const sts = new STS({
          endpoint: awsConfig.endpoint,
          region: awsConfig.region
        });
    
        sts.assumeRoleWithWebIdentity(
          {
            DurationSeconds: 3600,
            RoleArn: "arn:aws:iam:::role/S3AccessIAM200",
            RoleSessionName: "app1",
            WebIdentityToken: token.access_token,
          }, (err: AWSError, data) => {
            if (err) {
              throw new Error(err.message);
            }
    
            const stsCredentials = data.Credentials;
            if (!stsCredentials) {
              throw new Error("Cannot retrieve AWS Credentials from STS");
            }
    
            setS3ServiceState({
              awsCredentials: new Credentials({
                accessKeyId: stsCredentials.AccessKeyId,
                secretAccessKey: stsCredentials.SecretAccessKey,
                sessionToken: stsCredentials.SessionToken,
              })
            });
          }
        )
      }, [oAuth.isAuthenticated]);
    
    
      const listBuckets = useCallback(() => {
        if (!s3ServiceState.awsCredentials) {
          console.warn("No AWS credentials");
          return;
        }
        const s3 = getS3Client();
        s3.listBuckets((err, data) => {
          if (err) {
            throw new Error(err.message);
          }
          console.log(data);
        })
      }, [s3ServiceState.awsCredentials]);
    
      const createBucket = useCallback((bucketName: string) => {
        const s3 = getS3Client();
        s3.createBucket({
          Bucket: bucketName
        }, ((err, data) => {
          if (err) {
            throw new Error(err.name + " " + err.message);
          }
          console.log(data);
        }));
      }, [s3ServiceState.awsCredentials])
    
      return (
        <S3ServiceContext.Provider value={{
          awsConfig: awsConfig,
          listBuckets: listBuckets,
          createBucket: createBucket
        }}>
          {children}
        </S3ServiceContext.Provider>
      );
    }
    
    // **** useS3Service *****
    
    export const useS3Service = (): S3ContextProps => {
      const context = useContext(S3ServiceContext);
      if (!context) {
        throw new Error(
          "S3ServiceProvider context is undefined, \
          please verify you are calling useS3Service as a child of \
          <S3ServicePrivder> comonent."
        );
      }
      return context;
    }