github.com/minio/console@v1.4.1/web-app/src/screens/Console/Support/registerThunks.ts (about) 1 // This file is part of MinIO Console Server 2 // Copyright (c) 2023 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 { 18 resetRegisterForm, 19 setClusterRegistered, 20 setLicenseInfo, 21 setLoading, 22 setLoadingLicenseInfo, 23 setSelectedSubnetOrganization, 24 setSubnetAccessToken, 25 setSubnetMFAToken, 26 setSubnetOrganizations, 27 setSubnetOTP, 28 } from "./registerSlice"; 29 import api from "../../../common/api"; 30 import { 31 SubnetInfo, 32 SubnetLoginRequest, 33 SubnetLoginResponse, 34 SubnetLoginWithMFARequest, 35 SubnetRegisterRequest, 36 } from "../License/types"; 37 import { ErrorResponseHandler } from "../../../common/types"; 38 import { 39 setErrorSnackMessage, 40 setServerNeedsRestart, 41 } from "../../../systemSlice"; 42 import { createAsyncThunk } from "@reduxjs/toolkit"; 43 import { AppState } from "../../../store"; 44 import { hasPermission } from "../../../common/SecureComponent"; 45 import { 46 CONSOLE_UI_RESOURCE, 47 IAM_PAGES, 48 IAM_PAGES_PERMISSIONS, 49 } from "../../../common/SecureComponent/permissions"; 50 51 export const fetchLicenseInfo = createAsyncThunk( 52 "register/fetchLicenseInfo", 53 async (_, { getState, dispatch }) => { 54 const state = getState() as AppState; 55 56 const getSubnetInfo = hasPermission( 57 CONSOLE_UI_RESOURCE, 58 IAM_PAGES_PERMISSIONS[IAM_PAGES.LICENSE], 59 true, 60 ); 61 62 const loadingLicenseInfo = state.register.loadingLicenseInfo; 63 64 if (loadingLicenseInfo) { 65 return; 66 } 67 if (getSubnetInfo) { 68 dispatch(setLoadingLicenseInfo(true)); 69 api 70 .invoke("GET", `/api/v1/subnet/info`) 71 .then((res: SubnetInfo) => { 72 dispatch(setLicenseInfo(res)); 73 dispatch(setClusterRegistered(true)); 74 dispatch(setLoadingLicenseInfo(false)); 75 }) 76 .catch((err: ErrorResponseHandler) => { 77 if ( 78 err.detailedError.toLowerCase() !== 79 "License is not present".toLowerCase() && 80 err.detailedError.toLowerCase() !== 81 "license not found".toLowerCase() 82 ) { 83 dispatch(setErrorSnackMessage(err)); 84 } 85 dispatch(setClusterRegistered(false)); 86 dispatch(setLoadingLicenseInfo(false)); 87 }); 88 } else { 89 dispatch(setLoadingLicenseInfo(false)); 90 } 91 }, 92 ); 93 94 export interface ClassRegisterArgs { 95 token: string; 96 account_id: string; 97 } 98 99 export const callRegister = createAsyncThunk( 100 "register/callRegister", 101 async (args: ClassRegisterArgs, { dispatch }) => { 102 const request: SubnetRegisterRequest = { 103 token: args.token, 104 account_id: args.account_id, 105 }; 106 api 107 .invoke("POST", "/api/v1/subnet/register", request) 108 .then(() => { 109 dispatch(setLoading(false)); 110 dispatch(setServerNeedsRestart(true)); 111 dispatch(resetRegisterForm()); 112 dispatch(fetchLicenseInfo()); 113 }) 114 .catch((err: ErrorResponseHandler) => { 115 dispatch(setErrorSnackMessage(err)); 116 dispatch(setLoading(false)); 117 }); 118 }, 119 ); 120 121 export const subnetLoginWithMFA = createAsyncThunk( 122 "register/subnetLoginWithMFA", 123 async (_, { getState, rejectWithValue, dispatch }) => { 124 const state = getState() as AppState; 125 126 const subnetEmail = state.register.subnetEmail; 127 const subnetMFAToken = state.register.subnetMFAToken; 128 const subnetOTP = state.register.subnetOTP; 129 const loading = state.register.loading; 130 131 if (loading) { 132 return; 133 } 134 dispatch(setLoading(true)); 135 const request: SubnetLoginWithMFARequest = { 136 username: subnetEmail, 137 otp: subnetOTP, 138 mfa_token: subnetMFAToken, 139 }; 140 api 141 .invoke("POST", "/api/v1/subnet/login/mfa", request) 142 .then((resp: SubnetLoginResponse) => { 143 dispatch(setLoading(false)); 144 if (resp && resp.access_token && resp.organizations.length > 0) { 145 if (resp.organizations.length === 1) { 146 dispatch( 147 callRegister({ 148 token: resp.access_token, 149 account_id: resp.organizations[0].accountId.toString(), 150 }), 151 ); 152 } else { 153 dispatch(setSubnetAccessToken(resp.access_token)); 154 dispatch(setSubnetOrganizations(resp.organizations)); 155 dispatch( 156 setSelectedSubnetOrganization( 157 resp.organizations[0].accountId.toString(), 158 ), 159 ); 160 } 161 } 162 }) 163 .catch((err: ErrorResponseHandler) => { 164 dispatch(setErrorSnackMessage(err)); 165 dispatch(setLoading(false)); 166 dispatch(setSubnetOTP("")); 167 }); 168 }, 169 ); 170 171 export const subnetLogin = createAsyncThunk( 172 "register/subnetLogin", 173 async (_, { getState, rejectWithValue, dispatch }) => { 174 const state = getState() as AppState; 175 176 const license = state.register.license; 177 const subnetPassword = state.register.subnetPassword; 178 const subnetEmail = state.register.subnetEmail; 179 const loading = state.register.loading; 180 181 if (loading) { 182 return; 183 } 184 dispatch(setLoading(true)); 185 let request: SubnetLoginRequest = { 186 username: subnetEmail, 187 password: subnetPassword, 188 apiKey: license, 189 }; 190 api 191 .invoke("POST", "/api/v1/subnet/login", request) 192 .then((resp: SubnetLoginResponse) => { 193 dispatch(setLoading(false)); 194 if (resp && resp.registered) { 195 dispatch(resetRegisterForm()); 196 dispatch(fetchLicenseInfo()); 197 } else if (resp && resp.mfa_token) { 198 dispatch(setSubnetMFAToken(resp.mfa_token)); 199 } else if (resp && resp.access_token && resp.organizations.length > 0) { 200 dispatch(setSubnetAccessToken(resp.access_token)); 201 dispatch(setSubnetOrganizations(resp.organizations)); 202 dispatch( 203 setSelectedSubnetOrganization( 204 resp.organizations[0].accountId.toString(), 205 ), 206 ); 207 } 208 }) 209 .catch((err: ErrorResponseHandler) => { 210 dispatch(setErrorSnackMessage(err)); 211 dispatch(setLoading(false)); 212 dispatch(resetRegisterForm()); 213 }); 214 }, 215 );