diff --git a/integration/groups_test.go b/integration/groups_test.go index eba98ee82..9fd783083 100644 --- a/integration/groups_test.go +++ b/integration/groups_test.go @@ -18,6 +18,7 @@ package integration import ( "bytes" + "encoding/base64" "encoding/json" "fmt" "log" @@ -113,7 +114,7 @@ func Test_GetGroupAPI(t *testing.T) { { name: "Get Group - Valid", args: args{ - api: "?name=getgroup1", + api: base64.StdEncoding.EncodeToString([]byte("getgroup1")), }, expectedStatus: 200, expectedError: nil, @@ -121,7 +122,7 @@ func Test_GetGroupAPI(t *testing.T) { { name: "Get Group - Invalid", args: args{ - api: "?name=askfjalkd", + api: base64.StdEncoding.EncodeToString([]byte("askfjalkd")), }, expectedStatus: 500, expectedError: nil, @@ -139,7 +140,7 @@ func Test_GetGroupAPI(t *testing.T) { requestDataJSON, _ := json.Marshal(requestDataPolicy) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( - "GET", fmt.Sprintf("http://localhost:9090/api/v1/group%s", tt.args.api), requestDataBody) + "GET", fmt.Sprintf("http://localhost:9090/api/v1/group/%s", tt.args.api), requestDataBody) if err != nil { log.Println(err) return @@ -223,7 +224,7 @@ func Test_PutGroupsAPI(t *testing.T) { { name: "Put Group - Valid", args: args{ - api: "?name=putgroup1", + api: base64.StdEncoding.EncodeToString([]byte("putgroup1")), members: []string{"member3"}, status: "enabled", }, @@ -233,7 +234,7 @@ func Test_PutGroupsAPI(t *testing.T) { { name: "Put Group - Invalid", args: args{ - api: "?name=gdgfdfgd", + api: base64.StdEncoding.EncodeToString([]byte("gdgfdfgd")), members: []string{"member3"}, status: "enabled", }, @@ -256,7 +257,7 @@ func Test_PutGroupsAPI(t *testing.T) { requestDataJSON, _ := json.Marshal(requestDataPolicy) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( - "PUT", fmt.Sprintf("http://localhost:9090/api/v1/group%s", tt.args.api), requestDataBody) + "PUT", fmt.Sprintf("http://localhost:9090/api/v1/group/%s", tt.args.api), requestDataBody) if err != nil { log.Println(err) return @@ -293,7 +294,7 @@ func Test_DeleteGroupAPI(t *testing.T) { { name: "Delete Group - Valid", args: args{ - api: "?name=grouptests1", + api: base64.StdEncoding.EncodeToString([]byte("grouptests1")), }, verb: "DELETE", expectedStatus: 204, @@ -302,7 +303,7 @@ func Test_DeleteGroupAPI(t *testing.T) { { name: "Delete Group - Invalid", args: args{ - api: "?name=grouptests12345", + api: base64.StdEncoding.EncodeToString([]byte("grouptests12345")), }, verb: "DELETE", expectedStatus: 404, @@ -311,7 +312,7 @@ func Test_DeleteGroupAPI(t *testing.T) { { name: "Access Group After Delete - Invalid", args: args{ - api: "?name=grouptests1", + api: base64.StdEncoding.EncodeToString([]byte("grouptests1")), }, verb: "GET", expectedStatus: 500, @@ -330,7 +331,7 @@ func Test_DeleteGroupAPI(t *testing.T) { requestDataJSON, _ := json.Marshal(requestDataPolicy) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( - tt.verb, fmt.Sprintf("http://localhost:9090/api/v1/group%s", tt.args.api), requestDataBody) + tt.verb, fmt.Sprintf("http://localhost:9090/api/v1/group/%s", tt.args.api), requestDataBody) if err != nil { log.Println(err) return diff --git a/integration/policy_test.go b/integration/policy_test.go index fab72f078..dc00ae9ca 100644 --- a/integration/policy_test.go +++ b/integration/policy_test.go @@ -18,6 +18,7 @@ package integration import ( "bytes" + "encoding/base64" "encoding/json" "fmt" "io/ioutil" @@ -519,7 +520,7 @@ func Test_GetPolicyAPI(t *testing.T) { { name: "Get Policies - Invalid", args: args{ - api: "/policy?name=test3", + api: base64.StdEncoding.EncodeToString([]byte("test3")), }, expectedStatus: 500, expectedError: nil, @@ -527,7 +528,7 @@ func Test_GetPolicyAPI(t *testing.T) { { name: "Get Policies - Valid", args: args{ - api: "/policy?name=getpolicytest", + api: base64.StdEncoding.EncodeToString([]byte("getpolicytest")), }, expectedStatus: 200, expectedError: nil, @@ -541,7 +542,7 @@ func Test_GetPolicyAPI(t *testing.T) { } request, err := http.NewRequest( - "GET", fmt.Sprintf("http://localhost:9090/api/v1%s", tt.args.api), nil) + "GET", fmt.Sprintf("http://localhost:9090/api/v1/policy/%s", tt.args.api), nil) if err != nil { log.Println(err) return @@ -594,7 +595,7 @@ func Test_PolicyListUsersAPI(t *testing.T) { { name: "List Users for Policy - Valid", args: args{ - api: "/policies/policylistusers/users", + api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("policylistusers")) + "/users", }, expectedStatus: 200, expectedError: nil, @@ -602,7 +603,7 @@ func Test_PolicyListUsersAPI(t *testing.T) { { name: "List Users for Policy - Invalid", args: args{ - api: "/policies/test2/users", + api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("test2")) + "/users", }, expectedStatus: 404, expectedError: nil, @@ -673,7 +674,8 @@ func Test_PolicyListGroupsAPI(t *testing.T) { { name: "List Users for Policy - Valid", args: args{ - api: "/policies/policylistgroups/groups", + + api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("policylistgroups")) + "/groups", }, expectedStatus: 200, expectedError: nil, @@ -681,7 +683,7 @@ func Test_PolicyListGroupsAPI(t *testing.T) { { name: "List Users for Policy - Invalid", args: args{ - api: "/policies/test3/groups", + api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("test3")) + "/groups", }, expectedStatus: 404, expectedError: nil, @@ -750,7 +752,7 @@ func Test_DeletePolicyAPI(t *testing.T) { { name: "Delete Policies - Valid", args: args{ - api: "/policy?name=testdelete", + api: base64.StdEncoding.EncodeToString([]byte("testdelete")), method: "DELETE", }, expectedStatus: 204, @@ -759,7 +761,7 @@ func Test_DeletePolicyAPI(t *testing.T) { { name: "Get Policy After Delete - Invalid", args: args{ - api: "/policy?name=testdelete", + api: base64.StdEncoding.EncodeToString([]byte("testdelete")), method: "GET", }, expectedStatus: 500, @@ -774,7 +776,7 @@ func Test_DeletePolicyAPI(t *testing.T) { } request, err := http.NewRequest( - tt.args.method, fmt.Sprintf("http://localhost:9090/api/v1%s", tt.args.api), nil) + tt.args.method, fmt.Sprintf("http://localhost:9090/api/v1/policy/%s", tt.args.api), nil) if err != nil { log.Println(err) return diff --git a/integration/service_account_test.go b/integration/service_account_test.go index 60f6610fd..8388dbe46 100644 --- a/integration/service_account_test.go +++ b/integration/service_account_test.go @@ -18,6 +18,7 @@ package integration import ( "bytes" + "encoding/base64" "encoding/json" "fmt" "log" @@ -95,7 +96,7 @@ func TestAddServiceAccount(t *testing.T) { requestDataJSON, _ = json.Marshal(requestDataPolicy) requestDataBody = bytes.NewReader(requestDataJSON) request, err = http.NewRequest( - "PUT", "http://localhost:9090/api/v1/service-accounts/testuser1/policy", requestDataBody) + "PUT", "http://localhost:9090/api/v1/service-accounts/"+base64.StdEncoding.EncodeToString([]byte("testuser1"))+"/policy", requestDataBody) if err != nil { log.Println(err) return @@ -114,7 +115,7 @@ func TestAddServiceAccount(t *testing.T) { // Test policy request, err = http.NewRequest( - "GET", "http://localhost:9090/api/v1/service-accounts/testuser1/policy", nil) + "GET", "http://localhost:9090/api/v1/service-accounts/"+base64.StdEncoding.EncodeToString([]byte("testuser1"))+"/policy", nil) if err != nil { log.Println(err) return @@ -146,7 +147,7 @@ func TestAddServiceAccount(t *testing.T) { // {{baseUrl}}/user?name=proident velit // Investiga como se borra en el browser. request, err = http.NewRequest( - "DELETE", "http://localhost:9090/api/v1/service-accounts/testuser1", nil) + "DELETE", "http://localhost:9090/api/v1/service-accounts/"+base64.StdEncoding.EncodeToString([]byte("testuser1")), nil) if err != nil { log.Println(err) return diff --git a/integration/users_test.go b/integration/users_test.go index 3d89c26be..0e6c9bd39 100644 --- a/integration/users_test.go +++ b/integration/users_test.go @@ -18,6 +18,7 @@ package integration import ( "bytes" + "encoding/base64" "encoding/json" "fmt" "io" @@ -62,6 +63,7 @@ func AddUser(accessKey, secretKey string, groups, policies []string) (*http.Resp } func DeleteUser(userName string) (*http.Response, error) { + userName = base64.StdEncoding.EncodeToString([]byte(userName)) /* This is an atomic function to delete user and can be reused across different functions. @@ -70,7 +72,7 @@ func DeleteUser(userName string) (*http.Response, error) { Timeout: 3 * time.Second, } request, err := http.NewRequest( - "DELETE", "http://localhost:9090/api/v1/user?name="+userName, nil) + "DELETE", "http://localhost:9090/api/v1/user/"+userName, nil) if err != nil { log.Println(err) } @@ -102,6 +104,7 @@ func ListUsers(offset, limit string) (*http.Response, error) { } func GetUserInformation(userName string) (*http.Response, error) { + userName = base64.StdEncoding.EncodeToString([]byte(userName)) /* Helper function to get user information via API: {{baseUrl}}/user?name=proident velit @@ -111,7 +114,7 @@ func GetUserInformation(userName string) (*http.Response, error) { } request, err := http.NewRequest( "GET", - "http://localhost:9090/api/v1/user?name="+userName, + "http://localhost:9090/api/v1/user/"+userName, nil) if err != nil { log.Println(err) @@ -123,6 +126,7 @@ func GetUserInformation(userName string) (*http.Response, error) { } func UpdateUserInformation(name, status string, groups []string) (*http.Response, error) { + name = base64.StdEncoding.EncodeToString([]byte(name)) /* Helper function to update user information: PUT: {{baseUrl}}/user?name=proident velit @@ -145,7 +149,7 @@ func UpdateUserInformation(name, status string, groups []string) (*http.Response requestDataJSON, _ := json.Marshal(requestDataAdd) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( - "PUT", "http://localhost:9090/api/v1/user?name="+name, requestDataBody) + "PUT", "http://localhost:9090/api/v1/user/"+name, requestDataBody) if err != nil { log.Println(err) } @@ -156,6 +160,7 @@ func UpdateUserInformation(name, status string, groups []string) (*http.Response } func RemoveUser(name string) (*http.Response, error) { + name = base64.StdEncoding.EncodeToString([]byte(name)) /* Helper function to remove user. DELETE: {{baseUrl}}/user?name=proident velit @@ -164,7 +169,7 @@ func RemoveUser(name string) (*http.Response, error) { Timeout: 3 * time.Second, } request, err := http.NewRequest( - "DELETE", "http://localhost:9090/api/v1/user?name="+name, nil) + "DELETE", "http://localhost:9090/api/v1/user/"+name, nil) if err != nil { log.Println(err) } @@ -175,6 +180,7 @@ func RemoveUser(name string) (*http.Response, error) { } func UpdateGroupsForAUser(userName string, groups []string) (*http.Response, error) { + userName = base64.StdEncoding.EncodeToString([]byte(userName)) /* Helper function to update groups for a user PUT: {{baseUrl}}/user/groups?name=username @@ -195,7 +201,7 @@ func UpdateGroupsForAUser(userName string, groups []string) (*http.Response, err requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( "PUT", - "http://localhost:9090/api/v1/user/groups?name="+userName, + "http://localhost:9090/api/v1/user/"+userName+"/groups", requestDataBody, ) if err != nil { @@ -208,6 +214,7 @@ func UpdateGroupsForAUser(userName string, groups []string) (*http.Response, err } func CreateServiceAccountForUser(userName, policy string) (*http.Response, error) { + userName = base64.StdEncoding.EncodeToString([]byte(userName)) /* Helper function to Create Service Account for user POST: api/v1/user/username/service-accounts @@ -238,6 +245,7 @@ func CreateServiceAccountForUser(userName, policy string) (*http.Response, error } func CreateServiceAccountForUserWithCredentials(userName, policy, accessKey, secretKey string) (*http.Response, error) { + userName = base64.StdEncoding.EncodeToString([]byte(userName)) // Helper function to test "Create Service Account for User With Credentials" end point. client := &http.Client{ Timeout: 3 * time.Second, @@ -264,6 +272,7 @@ func CreateServiceAccountForUserWithCredentials(userName, policy, accessKey, sec } func ReturnsAListOfServiceAccountsForAUser(userName string) (*http.Response, error) { + userName = base64.StdEncoding.EncodeToString([]byte(userName)) /* Helper function to return a list of service accounts for a user. GET: {{baseUrl}}/user/:name/service-accounts @@ -740,8 +749,10 @@ func TestCreateServiceAccountForUser(t *testing.T) { } // 3. Verify the service account for the user - listOfAccountsResponse, - listOfAccountsError := ReturnsAListOfServiceAccountsForAUser(userName) + listOfAccountsResponse, listOfAccountsError := ReturnsAListOfServiceAccountsForAUser(userName) + + fmt.Println(listOfAccountsResponse, listOfAccountsError) + if listOfAccountsError != nil { log.Println(listOfAccountsError) assert.Fail("Error in listOfAccountsError") @@ -754,6 +765,7 @@ func TestCreateServiceAccountForUser(t *testing.T) { finalResponse, ) } + assert.Equal(len(finalResponse), serviceAccountLengthInBytes, finalResponse) } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index ea072bac5..c4dabdc45 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -16,7 +16,11 @@ package utils -import "github.com/google/uuid" +import ( + "encoding/base64" + + "github.com/google/uuid" +) // NewUUID - get a random UUID. func NewUUID() (string, error) { @@ -27,6 +31,15 @@ func NewUUID() (string, error) { return u.String(), nil } +// DecodeBase64 : decoded base64 input into utf-8 text +func DecodeBase64(s string) (string, error) { + decodedInput, err := base64.StdEncoding.DecodeString(s) + if err != nil { + return "", err + } + return string(decodedInput), nil +} + // Key used for Get/SetReqInfo type key string diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go new file mode 100644 index 000000000..fa5a20943 --- /dev/null +++ b/pkg/utils/utils_test.go @@ -0,0 +1,92 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2022 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package utils + +import "testing" + +func TestDecodeInput(t *testing.T) { + type args struct { + s string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "chinese characters", + args: args{ + s: "5bCP6aO85by+5bCP6aO85by+5bCP6aO85by+L+Wwj+mjvOW8vuWwj+mjvOW8vuWwj+mjvOW8vg==", + }, + want: "小飼弾小飼弾小飼弾/小飼弾小飼弾小飼弾", + wantErr: false, + }, + { + name: "spaces and & symbol", + args: args{ + s: "YSBhIC0gYSBhICYgYSBhIC0gYSBhIGE=", + }, + want: "a a - a a & a a - a a a", + wantErr: false, + }, + { + name: "the infamous fly me to the moon", + args: args{ + s: "MDIlMjAtJTIwRkxZJTIwTUUlMjBUTyUyMFRIRSUyME1PT04lMjA=", + }, + want: "02%20-%20FLY%20ME%20TO%20THE%20MOON%20", + wantErr: false, + }, + { + name: "random symbols", + args: args{ + s: "IUAjJCVeJiooKV8r", + }, + want: "!@#$%^&*()_+", + wantErr: false, + }, + { + name: "name with / symbols", + args: args{ + s: "dGVzdC90ZXN0Mi/lsI/po7zlvL7lsI/po7zlvL7lsI/po7zlvL4uanBn", + }, + want: "test/test2/小飼弾小飼弾小飼弾.jpg", + wantErr: false, + }, + { + name: "decoding fails", + args: args{ + s: "this should fail", + }, + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := DecodeBase64(tt.args.s) + if (err != nil) != tt.wantErr { + t.Errorf("DecodeBase64() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("DecodeBase64() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/portal-ui/src/common/SecureComponent/permissions.ts b/portal-ui/src/common/SecureComponent/permissions.ts index 4178e05df..c070ae859 100644 --- a/portal-ui/src/common/SecureComponent/permissions.ts +++ b/portal-ui/src/common/SecureComponent/permissions.ts @@ -126,7 +126,7 @@ export const IAM_PAGES = { GROUPS_VIEW: "/identity/groups/:groupName+", ACCOUNT: "/identity/account", ACCOUNT_ADD: "/identity/account/new-account", - USER_SA_ACCOUNT_ADD: "/identity/users/new-user-sa/:userName", + USER_SA_ACCOUNT_ADD: "/identity/users/new-user-sa/:userName+", /* Access */ POLICIES: "/access/policies", diff --git a/portal-ui/src/common/utils.ts b/portal-ui/src/common/utils.ts index 889330971..f4b77f332 100644 --- a/portal-ui/src/common/utils.ts +++ b/portal-ui/src/common/utils.ts @@ -674,7 +674,10 @@ export const representationNumber = (number: number | undefined) => { return `${returnValue}${unit}`; }; -export const encodeFileName = (name: string) => { +export const encodeURLString = (name: string | null) => { + if (!name) { + return ""; + } try { return btoa(unescape(encodeURIComponent(name))); } catch (err) { @@ -682,7 +685,7 @@ export const encodeFileName = (name: string) => { } }; -export const decodeFileName = (text: string) => { +export const decodeURLString = (text: string) => { try { return decodeURIComponent(escape(window.atob(text))); } catch (err) { diff --git a/portal-ui/src/screens/Console/Account/ChangePasswordModal.tsx b/portal-ui/src/screens/Console/Account/ChangePasswordModal.tsx index c5c9d3f8c..d9048fbec 100644 --- a/portal-ui/src/screens/Console/Account/ChangePasswordModal.tsx +++ b/portal-ui/src/screens/Console/Account/ChangePasswordModal.tsx @@ -34,7 +34,6 @@ import { setModalErrorSnackMessage } from "../../../actions"; import { ErrorResponseHandler } from "../../../common/types"; import api from "../../../common/api"; import { ChangePasswordIcon } from "../../../icons"; -import { decodeFileName } from "../../../common/utils"; import RemoveRedEyeIcon from "@mui/icons-material/RemoveRedEye"; import VisibilityOffIcon from "@mui/icons-material/VisibilityOff"; @@ -65,9 +64,7 @@ const ChangePassword = ({ const [loading, setLoading] = useState(false); const [showPassword, setShowPassword] = useState(false); - const userLoggedIn = decodeFileName( - localStorage.getItem("userLoggedIn") || "" - ); + const userLoggedIn = localStorage.getItem("userLoggedIn") || ""; const changePassword = (event: React.FormEvent) => { event.preventDefault(); @@ -129,7 +126,8 @@ const ChangePassword = ({ titleIcon={} >
- This will change your Console password. Please note your new password down, as it will be required to log into Console after this session. + This will change your Console password. Please note your new password + down, as it will be required to log into Console after this session.
- setShowPassword(!showPassword) - } + overlayAction={() => setShowPassword(!showPassword)} overlayIcon={ - showPassword ? ( - - ) : ( - - ) + showPassword ? : } /> @@ -172,15 +164,9 @@ const ChangePassword = ({ label="New Password" type={showPassword ? "text" : "password"} value={newPassword} - overlayAction={() => - setShowPassword(!showPassword) - } + overlayAction={() => setShowPassword(!showPassword)} overlayIcon={ - showPassword ? ( - - ) : ( - - ) + showPassword ? : } /> @@ -194,15 +180,9 @@ const ChangePassword = ({ label="Type New Password Again" type={showPassword ? "text" : "password"} value={reNewPassword} - overlayAction={() => - setShowPassword(!showPassword) - } + overlayAction={() => setShowPassword(!showPassword)} overlayIcon={ - showPassword ? ( - - ) : ( - - ) + showPassword ? : } /> diff --git a/portal-ui/src/screens/Console/Account/DeleteServiceAccount.tsx b/portal-ui/src/screens/Console/Account/DeleteServiceAccount.tsx index 9ef92e7bd..da05eb584 100644 --- a/portal-ui/src/screens/Console/Account/DeleteServiceAccount.tsx +++ b/portal-ui/src/screens/Console/Account/DeleteServiceAccount.tsx @@ -25,6 +25,7 @@ import { ErrorResponseHandler } from "../../../common/types"; import useApi from "../Common/Hooks/useApi"; import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog"; import { ConfirmDeleteIcon } from "../../../icons"; +import { encodeURLString } from "../../../common/utils"; const styles = (theme: Theme) => createStyles({ @@ -63,7 +64,7 @@ const DeleteServiceAccount = ({ const onConfirmDelete = () => { invokeDeleteApi( "DELETE", - `/api/v1/service-accounts/${selectedServiceAccount}` + `/api/v1/service-accounts/${encodeURLString(selectedServiceAccount)}` ); }; diff --git a/portal-ui/src/screens/Console/Account/ServiceAccountPolicy.tsx b/portal-ui/src/screens/Console/Account/ServiceAccountPolicy.tsx index b1164ed83..446269ac6 100644 --- a/portal-ui/src/screens/Console/Account/ServiceAccountPolicy.tsx +++ b/portal-ui/src/screens/Console/Account/ServiceAccountPolicy.tsx @@ -32,6 +32,7 @@ import api from "../../../common/api"; import ModalWrapper from "../Common/ModalWrapper/ModalWrapper"; import { ChangeAccessPolicyIcon } from "../../../icons"; import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper"; +import { encodeURLString } from "../../../common/utils"; const styles = (theme: Theme) => createStyles({ @@ -73,7 +74,12 @@ const ServiceAccountPolicy = ({ useEffect(() => { if (loading) { api - .invoke("GET", `/api/v1/service-accounts/${selectedAccessKey}/policy`) + .invoke( + "GET", + `/api/v1/service-accounts/${encodeURLString( + selectedAccessKey + )}/policy` + ) .then((res) => { setLoading(false); setPolicyDefinition(res); @@ -88,9 +94,13 @@ const ServiceAccountPolicy = ({ const setPolicy = (event: React.FormEvent, newPolicy: string) => { event.preventDefault(); api - .invoke("PUT", `/api/v1/service-accounts/${selectedAccessKey}/policy`, { - policy: newPolicy, - }) + .invoke( + "PUT", + `/api/v1/service-accounts/${encodeURLString(selectedAccessKey)}/policy`, + { + policy: newPolicy, + } + ) .then((res) => { closeModalAndRefresh(); }) diff --git a/portal-ui/src/screens/Console/Buckets/BucketDetails/AccessDetailsPanel.tsx b/portal-ui/src/screens/Console/Buckets/BucketDetails/AccessDetailsPanel.tsx index 123003e46..e7b72101c 100644 --- a/portal-ui/src/screens/Console/Buckets/BucketDetails/AccessDetailsPanel.tsx +++ b/portal-ui/src/screens/Console/Buckets/BucketDetails/AccessDetailsPanel.tsx @@ -44,6 +44,7 @@ import { Theme } from "@mui/material/styles"; import createStyles from "@mui/styles/createStyles"; import { tableStyles } from "../../Common/FormComponents/common/styleLibrary"; import withStyles from "@mui/styles/withStyles"; +import { encodeURLString } from "../../../../common/utils"; const mapState = (state: AppState) => ({ session: state.console.session, @@ -122,7 +123,7 @@ const AccessDetails = ({ type: "view", disableButtonFunction: () => !viewPolicy, onClick: (policy: any) => { - history.push(`${IAM_PAGES.POLICIES}/${policy.name}`); + history.push(`${IAM_PAGES.POLICIES}/${encodeURLString(policy.name)}`); }, }, ]; @@ -132,7 +133,7 @@ const AccessDetails = ({ type: "view", disableButtonFunction: () => !viewUser, onClick: (user: any) => { - history.push(`${IAM_PAGES.USERS}/${user}`); + history.push(`${IAM_PAGES.USERS}/${encodeURLString(user)}`); }, }, ]; diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreatePathModal.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreatePathModal.tsx index a716ac254..4a9819e55 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreatePathModal.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreatePathModal.tsx @@ -27,7 +27,7 @@ import { } from "../../../../Common/FormComponents/common/styleLibrary"; import { connect } from "react-redux"; import history from "../../../../../../history"; -import { encodeFileName } from "../../../../../../common/utils"; +import { encodeURLString } from "../../../../../../common/utils"; import { setModalErrorSnackMessage } from "../../../../../../actions"; import { BucketObjectItem } from "./types"; import { CreateNewPathIcon } from "../../../../../../icons"; @@ -101,7 +101,7 @@ const CreatePathModal = ({ .filter((splitItem) => splitItem.trim() !== "") .join("/"); - const newPath = `/buckets/${bucketName}/browse/${encodeFileName( + const newPath = `/buckets/${bucketName}/browse/${encodeURLString( `${folderPath}${cleanPathURL}/` )}`; history.push(newPath); diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteNonCurrent.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteNonCurrent.tsx index 45832b4f3..3a69fd07b 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteNonCurrent.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteNonCurrent.tsx @@ -20,7 +20,7 @@ import { DialogContentText } from "@mui/material"; import Grid from "@mui/material/Grid"; import { setErrorSnackMessage } from "../../../../../../actions"; import { ErrorResponseHandler } from "../../../../../../common/types"; -import { decodeFileName } from "../../../../../../common/utils"; +import { decodeURLString } from "../../../../../../common/utils"; import { ConfirmDeleteIcon } from "../../../../../../icons"; import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog"; import api from "../../../../../../common/api"; @@ -89,7 +89,7 @@ const DeleteNonCurrentVersions = ({ confirmationContent={ Are you sure you want to delete all the non-current versions for:{" "} - {decodeFileName(selectedObject)}?
+ {decodeURLString(selectedObject)}?

To continue please type YES, PROCEED in the box. diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx index 7eba0483d..0454d8bfb 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx @@ -19,7 +19,7 @@ import { connect } from "react-redux"; import { DialogContentText } from "@mui/material"; import { setErrorSnackMessage } from "../../../../../../actions"; import { ErrorResponseHandler } from "../../../../../../common/types"; -import { decodeFileName } from "../../../../../../common/utils"; +import { decodeURLString } from "../../../../../../common/utils"; import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog"; import useApi from "../../../../Common/Hooks/useApi"; import { ConfirmDeleteIcon } from "../../../../../../icons"; @@ -55,7 +55,7 @@ const DeleteObject = ({ return null; } const onConfirmDelete = () => { - const decodedSelectedObject = decodeFileName(selectedObject); + const decodedSelectedObject = decodeURLString(selectedObject); const recursive = decodedSelectedObject.endsWith("/"); invokeDeleteApi( "DELETE", @@ -79,7 +79,7 @@ const DeleteObject = ({ confirmationContent={ Are you sure you want to delete:
- {decodeFileName(selectedObject)}{" "} + {decodeURLString(selectedObject)}{" "} {selectedVersion !== "" ? (
diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/InspectObject.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/InspectObject.tsx index 702160946..ca6e79141 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/InspectObject.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/InspectObject.tsx @@ -19,8 +19,9 @@ import { connect } from "react-redux"; import withStyles from "@mui/styles/withStyles"; import { setErrorSnackMessage } from "../../../../../../actions"; import { - decodeFileName, + decodeURLString, deleteCookie, + encodeURLString, getCookieValue, performDownload, } from "../../../../../../common/utils"; @@ -77,8 +78,8 @@ const InspectObject = ({ }; const performInspect = async () => { - const file = encodeURIComponent(inspectPath + "/xl.meta"); - const volume = encodeURIComponent(volumeName); + const file = encodeURLString(inspectPath + "/xl.meta"); + const volume = encodeURLString(volumeName); const urlOfInspectApi = `/api/v1/admin/inspect?volume=${volume}&file=${file}&encrypt=${isEncrypt}`; @@ -137,7 +138,7 @@ const InspectObject = ({ onSubmit(e); }} > - Would you like to encrypt {decodeFileName(inspectPath)}?{" "} + Would you like to encrypt {decodeURLString(inspectPath)}?{" "}
{ - const decodedIPaths = decodeFileName(internalPaths); + const decodedIPaths = decodeURLString(internalPaths); if (decodedIPaths.endsWith("/") || decodedIPaths === "") { setObjectDetailsView(false); @@ -520,7 +520,7 @@ const ListObjects = ({ setObjectDetailsView(true); setLoadingVersions(true); setSelectedObjectView( - `${decodedIPaths ? `${encodeFileName(decodedIPaths)}` : ``}` + `${decodedIPaths ? `${encodeURLString(decodedIPaths)}` : ``}` ); setSimplePathHandler( `${decodedIPaths.split("/").slice(0, -1).join("/")}/` @@ -548,7 +548,7 @@ const ListObjects = ({ if (displayListObjects) { let pathPrefix = ""; if (internalPaths) { - const decodedPath = decodeFileName(internalPaths); + const decodedPath = decodeURLString(internalPaths); pathPrefix = decodedPath.endsWith("/") ? decodedPath : decodedPath + "/"; @@ -585,7 +585,7 @@ const ListObjects = ({ .invoke( "GET", `${urlTake}${ - pathPrefix ? `?prefix=${encodeFileName(pathPrefix)}` : `` + pathPrefix ? `?prefix=${encodeURLString(pathPrefix)}` : `` }` ) .then((res: BucketObjectItemsList) => { @@ -596,7 +596,7 @@ const ListObjects = ({ // We separate items between folders or files to display folders at the beginning always. records.forEach((record) => { // We omit files from the same path - if (record.name !== decodeFileName(internalPaths)) { + if (record.name !== decodeURLString(internalPaths)) { // this is a folder if (record.name.endsWith("/")) { folders.push(record); @@ -619,14 +619,14 @@ const ListObjects = ({ let pathPrefix = ""; if (internalPaths) { - const decodedPath = decodeFileName(internalPaths); + const decodedPath = decodeURLString(internalPaths); pathPrefix = decodedPath.endsWith("/") ? decodedPath : decodedPath + "/"; } pathTest = `/api/v1/buckets/${bucketName}/rewind/${rewindParsed}${ - pathPrefix ? `?prefix=${encodeFileName(pathPrefix)}` : `` + pathPrefix ? `?prefix=${encodeURLString(pathPrefix)}` : `` }`; } @@ -665,7 +665,7 @@ const ListObjects = ({ setSelectedObjectView(internalPaths); // We split the selected object URL & remove the last item to fetch the files list for the parent folder - const parentPath = `${decodeFileName(internalPaths) + const parentPath = `${decodeURLString(internalPaths) .split("/") .slice(0, -1) .join("/")}/`; @@ -675,7 +675,7 @@ const ListObjects = ({ "GET", `${urlTake}${ pathPrefix - ? `?prefix=${encodeFileName(parentPath)}` + ? `?prefix=${encodeURLString(parentPath)}` : `` }` ) @@ -778,13 +778,13 @@ const ListObjects = ({ }; const downloadObject = (object: BucketObjectItem) => { - const identityDownload = encodeFileName( + const identityDownload = encodeURLString( `${bucketName}-${object.name}-${new Date().getTime()}-${Math.random()}` ); const downloadCall = download( bucketName, - encodeFileName(object.name), + encodeURLString(object.name), object.version_id, object.size, (progress) => { @@ -821,13 +821,15 @@ const ListObjects = ({ setSelectedObjects([]); const newPath = `/buckets/${bucketName}/browse${ - idElement ? `/${encodeFileName(idElement)}` : `` + idElement ? `/${encodeURLString(idElement)}` : `` }`; history.push(newPath); setObjectDetailsView(true); setLoadingVersions(true); - setSelectedObjectView(`${idElement ? `${encodeFileName(idElement)}` : ``}`); + setSelectedObjectView( + `${idElement ? `${encodeURLString(idElement)}` : ``}` + ); }; const uploadObject = useCallback( @@ -873,7 +875,7 @@ const ListObjects = ({ const pathClean = path.endsWith("/") ? path.slice(0, -1) : path; - encodedPath = encodeFileName( + encodedPath = encodeURLString( `${pathClean}${ !pathClean.endsWith("/") && finalFolderPath !== "" && @@ -893,7 +895,7 @@ const ListObjects = ({ uploadUrl = `${uploadUrl}?prefix=${encodedPath}`; } - const identity = encodeFileName( + const identity = encodeURLString( `${bucketName}-${encodedPath}-${new Date().getTime()}-${Math.random()}` ); @@ -967,7 +969,7 @@ const ListObjects = ({ done: false, instanceID: identity, percentage: 0, - prefix: `${decodeFileName(encodedPath)}${fileName}`, + prefix: `${decodeURLString(encodedPath)}${fileName}`, type: "upload", waitingForFile: false, failed: false, @@ -1134,7 +1136,7 @@ const ListObjects = ({ setLoadingObjectsList(true); }; - const pageTitle = decodeFileName(internalPaths); + const pageTitle = decodeURLString(internalPaths); const currentPath = pageTitle.split("/").filter((i: string) => i !== ""); const plSelect = filteredRecords; @@ -1187,7 +1189,7 @@ const ListObjects = ({ setVersionsModeEnabled(false); // We change URL to be the contained folder - const decodedPath = decodeFileName(internalPaths); + const decodedPath = decodeURLString(internalPaths); const splitURLS = decodedPath.split("/"); // We remove the last section of the URL as it should be a file @@ -1199,7 +1201,7 @@ const ListObjects = ({ URLItem = `${splitURLS.join("/")}/`; } - history.push(`/buckets/${bucketName}/browse/${encodeFileName(URLItem)}`); + history.push(`/buckets/${bucketName}/browse/${encodeURLString(URLItem)}`); } setObjectDetailsView(false); diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx index fbabe8bb2..77081ce65 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx @@ -36,8 +36,8 @@ import { setSnackBarMessage, } from "../../../../../../actions"; import { - decodeFileName, - encodeFileName, + decodeURLString, + encodeURLString, niceBytes, niceBytesInt, niceDaysInt, @@ -191,7 +191,7 @@ const ObjectDetailPanel = ({ const [previewOpen, setPreviewOpen] = useState(false); const [totalVersionsSize, setTotalVersionsSize] = useState(0); - const internalPathsDecoded = decodeFileName(internalPaths) || ""; + const internalPathsDecoded = decodeURLString(internalPaths) || ""; const allPathData = internalPathsDecoded.split("/"); const currentItem = allPathData.pop() || ""; @@ -291,7 +291,7 @@ const ObjectDetailPanel = ({ }; const downloadObject = (object: IFileInfo) => { - const identityDownload = encodeFileName( + const identityDownload = encodeURLString( `${bucketName}-${object.name}-${new Date().getTime()}-${Math.random()}` ); diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/RestoreFileVersion.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/RestoreFileVersion.tsx index f9d4919c4..e65d258dd 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/RestoreFileVersion.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/RestoreFileVersion.tsx @@ -23,7 +23,7 @@ import withStyles from "@mui/styles/withStyles"; import { modalBasic } from "../../../../Common/FormComponents/common/styleLibrary"; import { setErrorSnackMessage } from "../../../../../../actions"; import { ErrorResponseHandler } from "../../../../../../common/types"; -import { encodeFileName } from "../../../../../../common/utils"; +import { encodeURLString } from "../../../../../../common/utils"; import api from "../../../../../../common/api"; import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog"; import RecoverIcon from "../../../../../../icons/RecoverIcon"; @@ -59,7 +59,7 @@ const RestoreFileVersion = ({ api .invoke( "PUT", - `/api/v1/buckets/${bucketName}/objects/restore?prefix=${encodeFileName( + `/api/v1/buckets/${bucketName}/objects/restore?prefix=${encodeURLString( objectPath )}&version_id=${versionID}` ) diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetLegalHoldModal.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetLegalHoldModal.tsx index 85f19b2db..3345b4d15 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetLegalHoldModal.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetLegalHoldModal.tsx @@ -33,7 +33,7 @@ import { ErrorResponseHandler } from "../../../../../../common/types"; import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper"; import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper"; import api from "../../../../../../common/api"; -import { encodeFileName } from "../../../../../../common/utils"; +import { encodeURLString } from "../../../../../../common/utils"; const styles = (theme: Theme) => createStyles({ @@ -77,7 +77,7 @@ const SetLegalHoldModal = ({ api .invoke( "PUT", - `/api/v1/buckets/${bucketName}/objects/legalhold?prefix=${encodeFileName( + `/api/v1/buckets/${bucketName}/objects/legalhold?prefix=${encodeURLString( objectName )}&version_id=${versionId}`, { status: legalHoldEnabled ? "enabled" : "disabled" } diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetRetention.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetRetention.tsx index 37f2a6d0f..6feac51e7 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetRetention.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetRetention.tsx @@ -35,7 +35,7 @@ import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapp import RadioGroupSelector from "../../../../Common/FormComponents/RadioGroupSelector/RadioGroupSelector"; import DateSelector from "../../../../Common/FormComponents/DateSelector/DateSelector"; import api from "../../../../../../common/api"; -import { encodeFileName } from "../../../../../../common/utils"; +import { encodeURLString } from "../../../../../../common/utils"; const styles = (theme: Theme) => createStyles({ @@ -135,7 +135,7 @@ const SetRetention = ({ api .invoke( "PUT", - `/api/v1/buckets/${bucketName}/objects/retention?prefix=${encodeFileName( + `/api/v1/buckets/${bucketName}/objects/retention?prefix=${encodeURLString( selectedObject )}&version_id=${versionId}`, { @@ -160,7 +160,7 @@ const SetRetention = ({ api .invoke( "DELETE", - `/api/v1/buckets/${bucketName}/objects/retention?prefix=${encodeFileName( + `/api/v1/buckets/${bucketName}/objects/retention?prefix=${encodeURLString( selectedObject )}&version_id=${versionId}` ) diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ShareFile.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ShareFile.tsx index beadc472e..48bac8cae 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ShareFile.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ShareFile.tsx @@ -39,7 +39,7 @@ import api from "../../../../../../common/api"; import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper"; import PredefinedList from "../../../../Common/FormComponents/PredefinedList/PredefinedList"; import DaysSelector from "../../../../Common/FormComponents/DaysSelector/DaysSelector"; -import { encodeFileName } from "../../../../../../common/utils"; +import { encodeURLString } from "../../../../../../common/utils"; import { ShareIcon } from "../../../../../../icons"; import BoxIconButton from "../../../../Common/BoxIconButton/BoxIconButton"; @@ -127,7 +127,7 @@ const ShareFile = ({ api .invoke( "GET", - `/api/v1/buckets/${bucketName}/objects?prefix=${encodeFileName( + `/api/v1/buckets/${bucketName}/objects?prefix=${encodeURLString( dataObject.name )}${distributedSetup ? "&with_versions=true" : ""}` ) @@ -177,7 +177,7 @@ const ShareFile = ({ api .invoke( "GET", - `/api/v1/buckets/${bucketName}/objects/share?prefix=${encodeFileName( + `/api/v1/buckets/${bucketName}/objects/share?prefix=${encodeURLString( dataObject.name )}&version_id=${versionID}${ selectedDate !== "" ? `&expires=${diffDate}s` : "" diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/TagsModal.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/TagsModal.tsx index 8caf7e54c..6df5167bb 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/TagsModal.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/TagsModal.tsx @@ -27,7 +27,7 @@ import { ErrorResponseHandler } from "../../../../../../common/types"; import InputBoxWrapper from "../../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper"; import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper"; import api from "../../../../../../common/api"; -import { encodeFileName } from "../../../../../../common/utils"; +import { encodeURLString } from "../../../../../../common/utils"; import { formFieldStyles, modalStyleUtils, @@ -108,7 +108,7 @@ const AddTagModal = ({ const [deleteKey, setDeleteKey] = useState(""); const [deleteLabel, setDeleteLabel] = useState(""); - const selectedObject = encodeFileName(actualInfo.name); + const selectedObject = encodeURLString(actualInfo.name); const currentTags = actualInfo.tags; const currTagKeys = Object.keys(currentTags || {}); diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx index 76539d1a2..f2c4f88a4 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx @@ -43,8 +43,8 @@ import { setSnackBarMessage, } from "../../../../../../actions"; import { - decodeFileName, - encodeFileName, + decodeURLString, + encodeURLString, niceBytesInt, } from "../../../../../../common/utils"; import ScreenTitle from "../../../../Common/ScreenTitle/ScreenTitle"; @@ -258,7 +258,7 @@ const VersionsNavigator = ({ }; const downloadObject = (object: IFileInfo) => { - const identityDownload = encodeFileName( + const identityDownload = encodeURLString( `${bucketName}-${object.name}-${new Date().getTime()}-${Math.random()}` ); @@ -482,7 +482,7 @@ const VersionsNavigator = ({ {delSelectedVOpen && ( diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/Preview/PreviewFileContent.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/Preview/PreviewFileContent.tsx index f0c8169b1..d853b135e 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/Preview/PreviewFileContent.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/Preview/PreviewFileContent.tsx @@ -20,7 +20,7 @@ import withStyles from "@mui/styles/withStyles"; import { Grid, LinearProgress } from "@mui/material"; import { BucketObjectItem } from "../ListObjects/types"; import { extensionPreview } from "../utils"; -import { encodeFileName } from "../../../../../../common/utils"; +import { encodeURLString } from "../../../../../../common/utils"; import clsx from "clsx"; const styles = () => @@ -75,7 +75,7 @@ const PreviewFile = ({ let path = ""; if (object) { - const encodedPath = encodeFileName(object.name); + const encodedPath = encodeURLString(object.name); let basename = document.baseURI.replace(window.location.origin, ""); path = `${window.location.origin}${basename}api/v1/buckets/${bucketName}/objects/download?preview=true&prefix=${encodedPath}`; if (object.version_id) { diff --git a/portal-ui/src/screens/Console/Common/CredentialsPrompt/CredentialsPrompt.tsx b/portal-ui/src/screens/Console/Common/CredentialsPrompt/CredentialsPrompt.tsx index 12efef5a0..d70b46e28 100644 --- a/portal-ui/src/screens/Console/Common/CredentialsPrompt/CredentialsPrompt.tsx +++ b/portal-ui/src/screens/Console/Common/CredentialsPrompt/CredentialsPrompt.tsx @@ -27,6 +27,7 @@ import WarnIcon from "../../../../icons/WarnIcon"; import { DownloadIcon, ServiceAccountCredentialsIcon } from "../../../../icons"; import RBIconButton from "../../Buckets/BucketDetails/SummaryItems/RBIconButton"; +import { encodeURLString } from "../../../../common/utils"; const styles = (theme: Theme) => createStyles({ @@ -76,7 +77,7 @@ const download = (filename: string, text: string) => { let element = document.createElement("a"); element.setAttribute( "href", - "data:text/plain;charset=utf-8," + encodeURIComponent(text) + "data:text/plain;charset=utf-8," + encodeURLString(text) ); element.setAttribute("download", filename); diff --git a/portal-ui/src/screens/Console/DirectCSI/FormatErrorsResult.tsx b/portal-ui/src/screens/Console/DirectCSI/FormatErrorsResult.tsx index 356be92eb..79deee248 100644 --- a/portal-ui/src/screens/Console/DirectCSI/FormatErrorsResult.tsx +++ b/portal-ui/src/screens/Console/DirectCSI/FormatErrorsResult.tsx @@ -23,6 +23,7 @@ import TableWrapper from "../Common/TableWrapper/TableWrapper"; import { IDirectCSIFormatResItem } from "./types"; import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary"; import { DriveFormatErrorsIcon } from "../../../icons"; +import { encodeURLString } from "../../../common/utils"; interface IFormatErrorsProps { open: boolean; @@ -43,7 +44,7 @@ const download = (filename: string, text: string) => { let element = document.createElement("a"); element.setAttribute( "href", - "data:application/json;charset=utf-8," + encodeURIComponent(text) + "data:application/json;charset=utf-8," + encodeURLString(text) ); element.setAttribute("download", filename); diff --git a/portal-ui/src/screens/Console/Groups/AddGroupMember.tsx b/portal-ui/src/screens/Console/Groups/AddGroupMember.tsx index 9692d320b..6f8fb2f04 100644 --- a/portal-ui/src/screens/Console/Groups/AddGroupMember.tsx +++ b/portal-ui/src/screens/Console/Groups/AddGroupMember.tsx @@ -17,6 +17,7 @@ import { } from "../Common/FormComponents/common/styleLibrary"; import withStyles from "@mui/styles/withStyles"; import { AddMembersToGroupIcon } from "../../../icons"; +import { encodeURLString } from "../../../common/utils"; type UserPickerModalProps = { classes?: any; @@ -55,7 +56,7 @@ const AddGroupMember = ({ function addMembersToGroup() { return api - .invoke("PUT", `/api/v1/group?name=${encodeURI(selectedGroup)}`, { + .invoke("PUT", `/api/v1/group/${encodeURLString(selectedGroup)}`, { group: selectedGroup, members: selectedUsers, status: groupStatus, diff --git a/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx b/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx index fc0eaeb49..31b496f18 100644 --- a/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx +++ b/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx @@ -22,6 +22,7 @@ import { ErrorResponseHandler } from "../../../common/types"; import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog"; import useApi from "../Common/Hooks/useApi"; import { ConfirmDeleteIcon } from "../../../icons"; +import { encodeURLString } from "../../../common/utils"; interface IDeleteGroup { selectedGroups: string[]; @@ -39,7 +40,7 @@ const DeleteGroup = ({ const onDelSuccess = () => closeDeleteModalAndRefresh(true); const onDelError = (err: ErrorResponseHandler) => { setErrorSnackMessage(err); - closeDeleteModalAndRefresh(true); + closeDeleteModalAndRefresh(false); }; const onClose = () => closeDeleteModalAndRefresh(false); @@ -50,7 +51,7 @@ const DeleteGroup = ({ } const onDeleteGroups = () => { for (let group of selectedGroups) { - invokeDeleteApi("DELETE", `/api/v1/group?name=${encodeURI(group)}`); + invokeDeleteApi("DELETE", `/api/v1/group/${encodeURLString(group)}`); } }; diff --git a/portal-ui/src/screens/Console/Groups/Groups.tsx b/portal-ui/src/screens/Console/Groups/Groups.tsx index f84de478e..a7a2cb27f 100644 --- a/portal-ui/src/screens/Console/Groups/Groups.tsx +++ b/portal-ui/src/screens/Console/Groups/Groups.tsx @@ -57,6 +57,7 @@ import { import withSuspense from "../Common/Components/withSuspense"; import RBIconButton from "../Buckets/BucketDetails/SummaryItems/RBIconButton"; +import { encodeURLString } from "../../../common/utils"; const DeleteGroup = withSuspense(React.lazy(() => import("./DeleteGroup"))); const SetPolicy = withSuspense( @@ -169,7 +170,7 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => { ); const viewAction = (group: any) => { - history.push(`${IAM_PAGES.GROUPS}/${group}`); + history.push(`${IAM_PAGES.GROUPS}/${encodeURLString(group)}`); }; const tableActions = [ @@ -225,7 +226,6 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => { display: "flex", }} > - {" "} createStyles({ @@ -110,11 +110,7 @@ export const formatPolicy = (policy: string = ""): string[] => { return policy.split(","); }; -export const getPoliciesAsString = (policies: string[]): string => { - return policies.join(", "); -}; - -const GroupsDetails = ({ classes }: IGroupDetailsProps) => { +const GroupsDetails = ({ classes, match }: IGroupDetailsProps) => { const [groupDetails, setGroupDetails] = useState({}); /*Modals*/ @@ -123,9 +119,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => { const [deleteOpen, setDeleteOpen] = useState(false); const [memberFilter, setMemberFilter] = useState(""); - //const [policyFilter, setPolicyFilter] = useState(""); - - const { groupName = "" } = useParams>(); + const groupName = decodeURLString(match.params["groupName"]); const { members = [], policy = "", status: groupEnabled } = groupDetails; @@ -151,7 +145,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => { function fetchGroupInfo() { if (getGroupDetails) { api - .invoke("GET", `/api/v1/group?name=${encodeURI(groupName)}`) + .invoke("GET", `/api/v1/group/${encodeURLString(groupName)}`) .then((res: any) => { setGroupDetails(res); }) @@ -164,7 +158,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => { function toggleGroupStatus(nextStatus: boolean) { return api - .invoke("PUT", `/api/v1/group?name=${encodeURI(groupName)}`, { + .invoke("PUT", `/api/v1/group/${encodeURLString(groupName)}`, { group: groupName, members: members, status: nextStatus ? "enabled" : "disabled", @@ -218,7 +212,9 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => { { type: "view", onClick: (userName) => { - history.push(`${IAM_PAGES.USERS}/${userName}`); + history.push( + `${IAM_PAGES.USERS}/${encodeURLString(userName)}` + ); }, }, ]} @@ -256,7 +252,9 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => { { type: "view", onClick: (policy) => { - history.push(`${IAM_PAGES.POLICIES}/${policy}`); + history.push( + `${IAM_PAGES.POLICIES}/${encodeURLString(policy)}` + ); }, }, ]} diff --git a/portal-ui/src/screens/Console/ObjectBrowser/BrowserBreadcrumbs.tsx b/portal-ui/src/screens/Console/ObjectBrowser/BrowserBreadcrumbs.tsx index 6c169b66f..96da3d43b 100644 --- a/portal-ui/src/screens/Console/ObjectBrowser/BrowserBreadcrumbs.tsx +++ b/portal-ui/src/screens/Console/ObjectBrowser/BrowserBreadcrumbs.tsx @@ -26,8 +26,8 @@ import { Link } from "react-router-dom"; import { Button, IconButton, Tooltip } from "@mui/material"; import { ObjectBrowserState } from "./types"; import { objectBrowserCommon } from "../Common/FormComponents/common/styleLibrary"; -import { encodeFileName } from "../../../common/utils"; -import { BackCaretIcon, CopyIcon, NewPathIcon } from "../../../icons"; +import { encodeURLString } from "../../../common/utils"; +import { BackCaretIcon, CopyIcon, NewPathIcon } from "../../../icons"; import { hasPermission } from "../../../common/SecureComponent"; import { IAM_SCOPES } from "../../../common/SecureComponent/permissions"; import { BucketObjectItem } from "../Buckets/ListBuckets/Objects/ListObjects/types"; @@ -95,7 +95,7 @@ const BrowserBreadcrumbs = ({ let breadcrumbsMap = splitPaths.map((objectItem: string, index: number) => { const subSplit = `${splitPaths.slice(0, index + 1).join("/")}/`; const route = `/buckets/${bucketName}/browse/${ - subSplit ? `${encodeFileName(subSplit)}` : `` + subSplit ? `${encodeURLString(subSplit)}` : `` }`; if (index === lastBreadcrumbsIndex && objectItem === versionedFile) { diff --git a/portal-ui/src/screens/Console/Policies/DeletePolicy.tsx b/portal-ui/src/screens/Console/Policies/DeletePolicy.tsx index 2c8f74f1b..c53dfa19f 100644 --- a/portal-ui/src/screens/Console/Policies/DeletePolicy.tsx +++ b/portal-ui/src/screens/Console/Policies/DeletePolicy.tsx @@ -22,6 +22,7 @@ import { ErrorResponseHandler } from "../../../common/types"; import useApi from "../Common/Hooks/useApi"; import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog"; import { ConfirmDeleteIcon } from "../../../icons"; +import { encodeURLString } from "../../../common/utils"; interface IDeletePolicyProps { closeDeleteModalAndRefresh: (refresh: boolean) => void; @@ -47,7 +48,10 @@ const DeletePolicy = ({ } const onConfirmDelete = () => { - invokeDeleteApi("DELETE", `/api/v1/policy?name=${selectedPolicy}`); + invokeDeleteApi( + "DELETE", + `/api/v1/policy/${encodeURLString(selectedPolicy)}` + ); }; return ( diff --git a/portal-ui/src/screens/Console/Policies/ListPolicies.tsx b/portal-ui/src/screens/Console/Policies/ListPolicies.tsx index cf2d510cc..c434f423a 100644 --- a/portal-ui/src/screens/Console/Policies/ListPolicies.tsx +++ b/portal-ui/src/screens/Console/Policies/ListPolicies.tsx @@ -50,6 +50,7 @@ import SearchBox from "../Common/SearchBox"; import withSuspense from "../Common/Components/withSuspense"; import RBIconButton from "../Buckets/BucketDetails/SummaryItems/RBIconButton"; +import { encodeURLString } from "../../../common/utils"; const DeletePolicy = withSuspense(React.lazy(() => import("./DeletePolicy"))); @@ -142,7 +143,7 @@ const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => { }; const viewAction = (policy: any) => { - history.push(`${IAM_PAGES.POLICIES}/${policy.name}`); + history.push(`${IAM_PAGES.POLICIES}/${encodeURLString(policy.name)}`); }; const tableActions = [ diff --git a/portal-ui/src/screens/Console/Policies/Policies.tsx b/portal-ui/src/screens/Console/Policies/Policies.tsx index 5cba88267..8a1a9579f 100644 --- a/portal-ui/src/screens/Console/Policies/Policies.tsx +++ b/portal-ui/src/screens/Console/Policies/Policies.tsx @@ -28,7 +28,10 @@ const Policies = () => { exact={true} component={ListPolicies} /> - + diff --git a/portal-ui/src/screens/Console/Policies/PolicyDetails.tsx b/portal-ui/src/screens/Console/Policies/PolicyDetails.tsx index 97ce0a93a..35d3997f5 100644 --- a/portal-ui/src/screens/Console/Policies/PolicyDetails.tsx +++ b/portal-ui/src/screens/Console/Policies/PolicyDetails.tsx @@ -59,6 +59,7 @@ import withSuspense from "../Common/Components/withSuspense"; import { AppState } from "../../../store"; import RBIconButton from "../Buckets/BucketDetails/SummaryItems/RBIconButton"; import PolicyView from "./PolicyView"; +import { decodeURLString, encodeURLString } from "../../../common/utils"; const DeletePolicy = withSuspense(React.lazy(() => import("./DeletePolicy"))); @@ -110,7 +111,9 @@ const PolicyDetails = ({ const [userList, setUserList] = useState([]); const [groupList, setGroupList] = useState([]); const [addLoading, setAddLoading] = useState(false); - const [policyName, setPolicyName] = useState(match.params[0]); + + const policyName = decodeURLString(match.params["policyName"]); + const [policyDefinition, setPolicyDefinition] = useState(""); const [loadingPolicy, setLoadingPolicy] = useState(true); const [filterUsers, setFilterUsers] = useState(""); @@ -179,7 +182,7 @@ const PolicyDetails = ({ api .invoke( "GET", - `/api/v1/policies/${encodeURIComponent(policyName)}/users` + `/api/v1/policies/${encodeURLString(policyName)}/users` ) .then((result: any) => { setUserList(result); @@ -201,7 +204,7 @@ const PolicyDetails = ({ api .invoke( "GET", - `/api/v1/policies/${encodeURIComponent(policyName)}/groups` + `/api/v1/policies/${encodeURLString(policyName)}/groups` ) .then((result: any) => { setGroupList(result); @@ -220,10 +223,7 @@ const PolicyDetails = ({ if (loadingPolicy) { if (displayPolicy) { api - .invoke( - "GET", - `/api/v1/policy?name=${encodeURIComponent(policyName)}` - ) + .invoke("GET", `/api/v1/policy/${encodeURLString(policyName)}`) .then((result: any) => { if (result) { setPolicy(result); @@ -271,7 +271,6 @@ const PolicyDetails = ({ ]); const resetForm = () => { - setPolicyName(""); setPolicyDefinition(""); }; @@ -287,7 +286,7 @@ const PolicyDetails = ({ }; const userViewAction = (user: any) => { - history.push(`${IAM_PAGES.USERS}/${user}`); + history.push(`${IAM_PAGES.USERS}/${encodeURLString(user)}`); }; const userTableActions = [ { @@ -302,7 +301,7 @@ const PolicyDetails = ({ ); const groupViewAction = (group: any) => { - history.push(`${IAM_PAGES.GROUPS}/${group}`); + history.push(`${IAM_PAGES.GROUPS}/${encodeURLString(group)}`); }; const groupTableActions = [ diff --git a/portal-ui/src/screens/Console/Policies/SetPolicy.tsx b/portal-ui/src/screens/Console/Policies/SetPolicy.tsx index a2b78173f..8006a8b85 100644 --- a/portal-ui/src/screens/Console/Policies/SetPolicy.tsx +++ b/portal-ui/src/screens/Console/Policies/SetPolicy.tsx @@ -34,6 +34,7 @@ import ModalWrapper from "../Common/ModalWrapper/ModalWrapper"; import api from "../../../common/api"; import PolicySelectors from "./PolicySelectors"; import PredefinedList from "../Common/FormComponents/PredefinedList/PredefinedList"; +import { encodeURLString } from "../../../common/utils"; interface ISetPolicyProps { classes: any; @@ -104,7 +105,7 @@ const SetPolicy = ({ const fetchGroupInformation = () => { if (selectedGroup) { api - .invoke("GET", `/api/v1/group?name=${encodeURI(selectedGroup)}`) + .invoke("GET", `/api/v1/group/${encodeURLString(selectedGroup)}`) .then((res: any) => { const groupPolicy: String = get(res, "policy", ""); setActualPolicy(groupPolicy.split(",")); diff --git a/portal-ui/src/screens/Console/Tools/Inspect.tsx b/portal-ui/src/screens/Console/Tools/Inspect.tsx index c780793d6..9db3b153b 100644 --- a/portal-ui/src/screens/Console/Tools/Inspect.tsx +++ b/portal-ui/src/screens/Console/Tools/Inspect.tsx @@ -34,6 +34,7 @@ import { connect } from "react-redux"; import HelpBox from "../../../common/HelpBox"; import { deleteCookie, + encodeURLString, getCookieValue, performDownload, } from "../../../common/utils"; @@ -158,8 +159,8 @@ const Inspect = ({ }; const performInspect = async () => { - const file = encodeURIComponent(inspectPath); - const volume = encodeURIComponent(volumeName); + const file = encodeURLString(inspectPath); + const volume = encodeURLString(volumeName); const urlOfInspectApi = `/api/v1/admin/inspect?volume=${volume}&file=${file}&encrypt=${isEncrypt}`; diff --git a/portal-ui/src/screens/Console/Users/AddUserServiceAccountScreen.tsx b/portal-ui/src/screens/Console/Users/AddUserServiceAccountScreen.tsx index 924c67f74..209c3db0f 100644 --- a/portal-ui/src/screens/Console/Users/AddUserServiceAccountScreen.tsx +++ b/portal-ui/src/screens/Console/Users/AddUserServiceAccountScreen.tsx @@ -45,6 +45,7 @@ import { setErrorSnackMessage } from "../../../../src/actions"; import SectionTitle from "../Common/SectionTitle"; import { getRandomString } from "../../../screens/Console/Tenants/utils"; import AddUserServiceAccountHelpBox from "./AddUserServiceAccountHelpBox"; +import { decodeURLString, encodeURLString } from "../../../common/utils"; interface IAddServiceAccountProps { classes: any; @@ -86,14 +87,16 @@ const AddServiceAccount = ({ const [showPassword, setShowPassword] = useState(false); const [policyJSON, setPolicyJSON] = useState(""); - const userName = match.params["userName"]; + const userName = decodeURLString(match.params["userName"]); useEffect(() => { if (addSending) { api .invoke( "POST", - `/api/v1/user/${userName}/service-account-credentials`, + `/api/v1/user/${encodeURLString( + userName + )}/service-account-credentials`, { policy: policyJSON, accessKey: accessKey, @@ -137,15 +140,15 @@ const AddServiceAccount = ({ const closeCredentialsModal = () => { setNewServiceAccount(null); - history.push(`${IAM_PAGES.USERS}/${userName}`); + history.push(`${IAM_PAGES.USERS}/${encodeURLString(userName)}`); }; return ( - {newServiceAccount !== null && ( + {newServiceAccount && ( { closeCredentialsModal(); }} @@ -156,7 +159,7 @@ const AddServiceAccount = ({ } diff --git a/portal-ui/src/screens/Console/Users/ChangeUserGroups.tsx b/portal-ui/src/screens/Console/Users/ChangeUserGroups.tsx index 58b34756e..8b4d60eba 100644 --- a/portal-ui/src/screens/Console/Users/ChangeUserGroups.tsx +++ b/portal-ui/src/screens/Console/Users/ChangeUserGroups.tsx @@ -31,6 +31,7 @@ import api from "../../../common/api"; import GroupsSelectors from "./GroupsSelectors"; import ModalWrapper from "../Common/ModalWrapper/ModalWrapper"; import AddMembersToGroup from "../../../icons/AddMembersToGroupIcon"; +import { encodeURLString } from "../../../common/utils"; const styles = (theme: Theme) => createStyles({ @@ -68,7 +69,7 @@ const ChangeUserGroups = ({ } api - .invoke("GET", `/api/v1/user?name=${encodeURI(selectedUser)}`) + .invoke("GET", `/api/v1/user/${encodeURLString(selectedUser)}`) .then((res) => { setAddLoading(false); setAccessKey(res.accessKey); @@ -100,7 +101,7 @@ const ChangeUserGroups = ({ setAddLoading(true); if (selectedUser !== null) { api - .invoke("PUT", `/api/v1/user?name=${encodeURI(selectedUser)}`, { + .invoke("PUT", `/api/v1/user/${encodeURLString(selectedUser)}`, { status: enabled ? "enabled" : "disabled", groups: selectedGroups, }) diff --git a/portal-ui/src/screens/Console/Users/DeleteUser.tsx b/portal-ui/src/screens/Console/Users/DeleteUser.tsx index 233fa8a66..3bb88a964 100644 --- a/portal-ui/src/screens/Console/Users/DeleteUser.tsx +++ b/portal-ui/src/screens/Console/Users/DeleteUser.tsx @@ -23,6 +23,7 @@ import useApi from "../Common/Hooks/useApi"; import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog"; import { ErrorResponseHandler } from "../../../common/types"; import { ConfirmDeleteIcon } from "../../../icons"; +import { encodeURLString } from "../../../common/utils"; interface IDeleteUserProps { closeDeleteModalAndRefresh: (refresh: boolean) => void; @@ -50,7 +51,7 @@ const DeleteUser = ({ const onConfirmDelete = () => { invokeDeleteApi( "DELETE", - `/api/v1/user?name=${encodeURI(selectedUser.accessKey)}`, + `/api/v1/user/${encodeURLString(selectedUser.accessKey)}`, { id: selectedUser.id, } diff --git a/portal-ui/src/screens/Console/Users/DeleteUserString.tsx b/portal-ui/src/screens/Console/Users/DeleteUserModal.tsx similarity index 91% rename from portal-ui/src/screens/Console/Users/DeleteUserString.tsx rename to portal-ui/src/screens/Console/Users/DeleteUserModal.tsx index bc186f2bc..767edfb27 100644 --- a/portal-ui/src/screens/Console/Users/DeleteUserString.tsx +++ b/portal-ui/src/screens/Console/Users/DeleteUserModal.tsx @@ -24,6 +24,7 @@ import useApi from "../Common/Hooks/useApi"; import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog"; import { ConfirmDeleteIcon } from "../../../icons"; import { IAM_PAGES } from "../../../common/SecureComponent/permissions"; +import { encodeURLString } from "../../../common/utils"; interface IDeleteUserProps { closeDeleteModalAndRefresh: (refresh: boolean) => void; @@ -32,7 +33,7 @@ interface IDeleteUserProps { setErrorSnackMessage: typeof setErrorSnackMessage; } -const DeleteUserString = ({ +const DeleteUserModal = ({ closeDeleteModalAndRefresh, deleteOpen, userName, @@ -51,9 +52,11 @@ const DeleteUserString = ({ } const onConfirmDelete = () => { - invokeDeleteApi("DELETE", `/api/v1/user?name=${encodeURI(userName)}`, { - id: userName, - }); + invokeDeleteApi( + "DELETE", + `/api/v1/user/${encodeURLString(userName)}`, + null + ); }; return ( @@ -81,4 +84,4 @@ const mapDispatchToProps = { const connector = connect(null, mapDispatchToProps); -export default connector(DeleteUserString); +export default connector(DeleteUserModal); diff --git a/portal-ui/src/screens/Console/Users/ListUsers.tsx b/portal-ui/src/screens/Console/Users/ListUsers.tsx index dc87e8ed5..ab241bd88 100644 --- a/portal-ui/src/screens/Console/Users/ListUsers.tsx +++ b/portal-ui/src/screens/Console/Users/ListUsers.tsx @@ -35,7 +35,7 @@ import { ErrorResponseHandler } from "../../../common/types"; import TableWrapper from "../Common/TableWrapper/TableWrapper"; import PageHeader from "../Common/PageHeader/PageHeader"; -import { decodeFileName } from "../../../common/utils"; +import { decodeURLString, encodeURLString } from "../../../common/utils"; import HelpBox from "../../../common/HelpBox"; import AButton from "../Common/AButton/AButton"; import PageLayout from "../Common/Layout/PageLayout"; @@ -165,7 +165,9 @@ const ListUsers = ({ classes, setErrorSnackMessage, history }: IUsersProps) => { }; const viewAction = (selectionElement: any): void => { - history.push(`${IAM_PAGES.USERS}/${encodeURI(selectionElement.accessKey)}`); + history.push( + `${IAM_PAGES.USERS}/${encodeURLString(selectionElement.accessKey)}` + ); }; const deleteAction = (selectionElement: any): void => { @@ -173,7 +175,7 @@ const ListUsers = ({ classes, setErrorSnackMessage, history }: IUsersProps) => { setSelectedUser(selectionElement); }; - const userLoggedIn = decodeFileName( + const userLoggedIn = decodeURLString( localStorage.getItem("userLoggedIn") || "" ); diff --git a/portal-ui/src/screens/Console/Users/UserDetails.tsx b/portal-ui/src/screens/Console/Users/UserDetails.tsx index b5a36caa1..a448d718c 100644 --- a/portal-ui/src/screens/Console/Users/UserDetails.tsx +++ b/portal-ui/src/screens/Console/Users/UserDetails.tsx @@ -47,7 +47,7 @@ import SetUserPolicies from "./SetUserPolicies"; import history from "../../../history"; import UserServiceAccountsPanel from "./UserServiceAccountsPanel"; import ChangeUserPasswordModal from "../Account/ChangeUserPasswordModal"; -import DeleteUserString from "./DeleteUserString"; +import DeleteUserModal from "./DeleteUserModal"; import ScreenTitle from "../Common/ScreenTitle/ScreenTitle"; import PanelTitle from "../Common/PanelTitle/PanelTitle"; import PageLayout from "../Common/Layout/PageLayout"; @@ -56,6 +56,7 @@ import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSw import BackLink from "../../../common/BackLink"; import RBIconButton from "../Buckets/BucketDetails/SummaryItems/RBIconButton"; import { IAM_PAGES } from "../../../common/SecureComponent/permissions"; +import { decodeURLString, encodeURLString } from "../../../common/utils"; const styles = (theme: Theme) => createStyles({ @@ -101,8 +102,7 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => { useState(false); const [deleteOpen, setDeleteOpen] = useState(false); const [hasPolicy, setHasPolicy] = useState(false); - - const userName = match.params["userName"]; + const userName = decodeURLString(match.params["userName"]); const changeUserPassword = () => { setChangeUserPasswordModalOpen(true); @@ -118,7 +118,7 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => { } setLoading(true); api - .invoke("GET", `/api/v1/user?name=${encodeURIComponent(userName)}`) + .invoke("GET", `/api/v1/user/${encodeURLString(userName)}`) .then((res) => { setAddLoading(false); const memberOf = res.memberOf || []; @@ -154,7 +154,7 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => { } setAddLoading(true); api - .invoke("PUT", `/api/v1/user?name=${encodeURIComponent(userName)}`, { + .invoke("PUT", `/api/v1/user/${encodeURLString(userName)}`, { status: isEnabled ? "enabled" : "disabled", groups: selectedGroups, }) @@ -210,7 +210,7 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => { /> )} {deleteOpen && ( - { @@ -348,7 +348,9 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => { type: "view", onClick: (policy: IPolicyItem) => { history.push( - `${IAM_PAGES.POLICIES}/${policy.policy}` + `${IAM_PAGES.POLICIES}/${encodeURLString( + policy.policy + )}` ); }, }, diff --git a/portal-ui/src/screens/Console/Users/UserServiceAccountsPanel.tsx b/portal-ui/src/screens/Console/Users/UserServiceAccountsPanel.tsx index e96110d8a..dae1883f4 100644 --- a/portal-ui/src/screens/Console/Users/UserServiceAccountsPanel.tsx +++ b/portal-ui/src/screens/Console/Users/UserServiceAccountsPanel.tsx @@ -39,14 +39,14 @@ import { AddIcon, DeleteIcon } from "../../../icons"; import PanelTitle from "../Common/PanelTitle/PanelTitle"; import RBIconButton from "../Buckets/BucketDetails/SummaryItems/RBIconButton"; import DeleteMultipleServiceAccounts from "./DeleteMultipleServiceAccounts"; -import { selectSAs } from "../../Console/Configurations/utils"; +import { selectSAs } from "../Configurations/utils"; import ServiceAccountPolicy from "../Account/ServiceAccountPolicy"; import { - IAM_PAGES, CONSOLE_UI_RESOURCE, IAM_SCOPES, } from "../../../common/SecureComponent/permissions"; import { SecureComponent } from "../../../common/SecureComponent"; +import { encodeURLString } from "../../../common/utils"; interface IUserServiceAccountsProps { classes: any; @@ -94,7 +94,7 @@ const UserServiceAccountsPanel = ({ useEffect(() => { if (loading) { api - .invoke("GET", `/api/v1/user/${user}/service-accounts`) + .invoke("GET", `/api/v1/user/${encodeURLString(user)}/service-accounts`) .then((res: string[]) => { const serviceAccounts = res.sort(stringSort); setLoading(false); @@ -254,10 +254,9 @@ const UserServiceAccountsPanel = ({ color="primary" icon={} onClick={() => { - let newSAPath = `/identity/users/${user}/new-user-sa`; - newSAPath = `${IAM_PAGES.USER_SA_ACCOUNT_ADD}/${user}`; - newSAPath = `/identity/users/new-user-sa/${user}`; - history.push(newSAPath); + history.push( + `/identity/users/new-user-sa/${encodeURLString(user)}` + ); }} disabled={!hasPolicy} /> diff --git a/portal-ui/src/screens/LoginPage/LoginPage.tsx b/portal-ui/src/screens/LoginPage/LoginPage.tsx index f9fa57fd0..135e88d08 100644 --- a/portal-ui/src/screens/LoginPage/LoginPage.tsx +++ b/portal-ui/src/screens/LoginPage/LoginPage.tsx @@ -37,7 +37,6 @@ import api from "../../common/api"; import history from "../../history"; import RefreshIcon from "../../icons/RefreshIcon"; import MainError from "../Console/Common/MainError/MainError"; -import { encodeFileName } from "../../common/utils"; import { ConsoleLogo, DocumentationIcon, @@ -349,7 +348,7 @@ const Login = ({ // We set the state in redux userLoggedIn(true); if (loginStrategy.loginStrategy === loginStrategyType.form) { - localStorage.setItem("userLoggedIn", encodeFileName(accessKey)); + localStorage.setItem("userLoggedIn", accessKey); } let targetPath = "/"; if ( diff --git a/portal-ui/tests/constants/timestamp.txt b/portal-ui/tests/constants/timestamp.txt index 295e61667..7eeecdc6a 100644 --- a/portal-ui/tests/constants/timestamp.txt +++ b/portal-ui/tests/constants/timestamp.txt @@ -1 +1 @@ -1642917498 +1652244779 diff --git a/restapi/admin_groups.go b/restapi/admin_groups.go index b6d7ef7e6..1a72a849b 100644 --- a/restapi/admin_groups.go +++ b/restapi/admin_groups.go @@ -21,6 +21,7 @@ import ( "github.com/go-openapi/errors" "github.com/go-openapi/runtime/middleware" + "github.com/minio/console/pkg/utils" "github.com/minio/console/restapi/operations" "github.com/minio/madmin-go" @@ -117,7 +118,12 @@ func getGroupInfoResponse(session *models.Principal, params groupApi.GroupInfoPa // defining the client to be used adminClient := AdminClient{Client: mAdmin} - groupDesc, err := groupInfo(ctx, adminClient, params.Name) + groupName, err := utils.DecodeBase64(params.Name) + if err != nil { + return nil, ErrorWithContext(ctx, err) + } + + groupDesc, err := groupInfo(ctx, adminClient, groupName) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -202,10 +208,16 @@ func getRemoveGroupResponse(session *models.Principal, params groupApi.RemoveGro if err != nil { return ErrorWithContext(ctx, err) } - // createad a MinIO Admin Client interface implementation + // Create a MinIO Admin Client interface implementation // defining the client to be used adminClient := AdminClient{Client: mAdmin} - if err := removeGroup(ctx, adminClient, params.Name); err != nil { + + groupName, err := utils.DecodeBase64(params.Name) + if err != nil { + return ErrorWithContext(ctx, err) + } + + if err := removeGroup(ctx, adminClient, groupName); err != nil { minioError := madmin.ToErrorResponse(err) err2 := ErrorWithContext(ctx, err) if minioError.Code == "XMinioAdminNoSuchGroup" { @@ -280,7 +292,11 @@ func getUpdateGroupResponse(session *models.Principal, params groupApi.UpdateGro return nil, ErrorWithContext(ctx, ErrGroupBodyNotInRequest) } expectedGroupUpdate := params.Body - groupName := params.Name + + groupName, err := utils.DecodeBase64(params.Name) + if err != nil { + return nil, ErrorWithContext(ctx, err) + } mAdmin, err := NewMinioAdminClient(session) if err != nil { diff --git a/restapi/admin_policies.go b/restapi/admin_policies.go index c831d58e1..1201a79fd 100644 --- a/restapi/admin_policies.go +++ b/restapi/admin_policies.go @@ -24,6 +24,8 @@ import ( "sort" "strings" + "github.com/minio/console/pkg/utils" + bucketApi "github.com/minio/console/restapi/operations/bucket" policyApi "github.com/minio/console/restapi/operations/policy" @@ -293,7 +295,10 @@ func getListPoliciesResponse(session *models.Principal, params policyApi.ListPol func getListUsersForPolicyResponse(session *models.Principal, params policyApi.ListUsersForPolicyParams) ([]string, *models.Error) { ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) defer cancel() - policy := params.Policy + policy, err := utils.DecodeBase64(params.Policy) + if err != nil { + return nil, ErrorWithContext(ctx, err) + } mAdmin, err := NewMinioAdminClient(session) if err != nil { return nil, ErrorWithContext(ctx, err) @@ -371,7 +376,10 @@ func getListGroupsForPolicyResponse(session *models.Principal, params policyApi. } // create a minioClient interface implementation // defining the client to be used - policy := params.Policy + policy, err := utils.DecodeBase64(params.Policy) + if err != nil { + return nil, ErrorWithContext(ctx, err) + } adminClient := AdminClient{Client: mAdmin} policies, err := listPolicies(ctx, adminClient) if err != nil { @@ -398,8 +406,11 @@ func getListGroupsForPolicyResponse(session *models.Principal, params policyApi. if err != nil { return nil, ErrorWithContext(ctx, err) } - if info.Policy == policy { - filteredGroups = append(filteredGroups, group) + groupPolicies := strings.Split(info.Policy, ",") + for _, groupPolicy := range groupPolicies { + if groupPolicy == policy { + filteredGroups = append(filteredGroups, group) + } } } sort.Strings(filteredGroups) @@ -422,6 +433,10 @@ func getRemovePolicyResponse(session *models.Principal, params policyApi.RemoveP if params.Name == "" { return ErrorWithContext(ctx, ErrPolicyNameNotInRequest) } + policyName, err := utils.DecodeBase64(params.Name) + if err != nil { + return ErrorWithContext(ctx, err) + } mAdmin, err := NewMinioAdminClient(session) if err != nil { return ErrorWithContext(ctx, err) @@ -430,7 +445,7 @@ func getRemovePolicyResponse(session *models.Principal, params policyApi.RemoveP // defining the client to be used adminClient := AdminClient{Client: mAdmin} - if err := removePolicy(ctx, adminClient, params.Name); err != nil { + if err := removePolicy(ctx, adminClient, policyName); err != nil { return ErrorWithContext(ctx, err) } return nil @@ -506,7 +521,11 @@ func getPolicyInfoResponse(session *models.Principal, params policyApi.PolicyInf // create a MinIO Admin Client interface implementation // defining the client to be used adminClient := AdminClient{Client: mAdmin} - policy, err := policyInfo(ctx, adminClient, params.Name) + policyName, err := utils.DecodeBase64(params.Name) + if err != nil { + return nil, ErrorWithContext(ctx, err) + } + policy, err := policyInfo(ctx, adminClient, policyName) if err != nil { return nil, ErrorWithContext(ctx, err) } diff --git a/restapi/admin_users.go b/restapi/admin_users.go index 2da19b9c4..3c044c3cd 100644 --- a/restapi/admin_users.go +++ b/restapi/admin_users.go @@ -22,6 +22,8 @@ import ( "sort" "strings" + "github.com/minio/console/pkg/utils" + "github.com/go-openapi/swag" "github.com/go-openapi/errors" @@ -249,13 +251,17 @@ func getRemoveUserResponse(session *models.Principal, params userApi.RemoveUserP if err != nil { return ErrorWithContext(ctx, err) } - if session.AccountAccessKey == params.Name { + userName, err := utils.DecodeBase64(params.Name) + if err != nil { + return ErrorWithContext(ctx, err) + } + if session.AccountAccessKey == userName { return ErrorWithContext(ctx, ErrAvoidSelfAccountDelete) } // create a minioClient interface implementation // defining the client to be used adminClient := AdminClient{Client: mAdmin} - if err := removeUser(ctx, adminClient, params.Name); err != nil { + if err := removeUser(ctx, adminClient, userName); err != nil { return ErrorWithContext(ctx, err) } return nil @@ -283,7 +289,12 @@ func getUserInfoResponse(session *models.Principal, params userApi.GetUserInfoPa // defining the client to be used adminClient := AdminClient{Client: mAdmin} - user, err := getUserInfo(ctx, adminClient, params.Name) + userName, err := utils.DecodeBase64(params.Name) + if err != nil { + return nil, ErrorWithContext(ctx, err) + } + + user, err := getUserInfo(ctx, adminClient, userName) if err != nil { // User doesn't exist, return 404 if madmin.ToErrorResponse(err).Code == "XMinioAdminNoSuchUser" { @@ -318,7 +329,7 @@ func getUserInfoResponse(session *models.Principal, params userApi.GetUserInfoPa } userInformation := &models.User{ - AccessKey: params.Name, + AccessKey: userName, MemberOf: user.MemberOf, Policy: policies, Status: string(user.Status), @@ -429,7 +440,12 @@ func getUpdateUserGroupsResponse(session *models.Principal, params userApi.Updat // defining the client to be used adminClient := AdminClient{Client: mAdmin} - user, err := updateUserGroups(ctx, adminClient, params.Name, params.Body.Groups) + userName, err := utils.DecodeBase64(params.Name) + if err != nil { + return nil, ErrorWithContext(ctx, err) + } + + user, err := updateUserGroups(ctx, adminClient, userName, params.Body.Groups) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -464,16 +480,18 @@ func getUpdateUserResponse(session *models.Principal, params userApi.UpdateUserI // create a minioClient interface implementation // defining the client to be used adminClient := AdminClient{Client: mAdmin} - - name := params.Name + userName, err := utils.DecodeBase64(params.Name) + if err != nil { + return nil, ErrorWithContext(ctx, err) + } status := *params.Body.Status groups := params.Body.Groups - if err := setUserStatus(ctx, adminClient, name, status); err != nil { + if err := setUserStatus(ctx, adminClient, userName, status); err != nil { return nil, ErrorWithContext(ctx, err) } - userElem, errUG := updateUserGroups(ctx, adminClient, name, groups) + userElem, errUG := updateUserGroups(ctx, adminClient, userName, groups) if errUG != nil { return nil, ErrorWithContext(ctx, errUG) diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go index 612539982..f1ff2984a 100644 --- a/restapi/embedded_spec.go +++ b/restapi/embedded_spec.go @@ -2617,7 +2617,7 @@ func init() { } } }, - "/group": { + "/group/{name}": { "get": { "tags": [ "Group" @@ -2628,7 +2628,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -2657,7 +2657,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true }, { @@ -2694,7 +2694,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -3139,7 +3139,7 @@ func init() { } } }, - "/policy": { + "/policy/{name}": { "get": { "tags": [ "Policy" @@ -3150,7 +3150,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -3179,7 +3179,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -3843,7 +3843,30 @@ func init() { } } }, - "/user": { + "/user/policy": { + "get": { + "tags": [ + "Policy" + ], + "summary": "returns policies for logged in user", + "operationId": "GetUserPolicy", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "string" + } + }, + "default": { + "description": "Generic error response.", + "schema": { + "$ref": "#/definitions/error" + } + } + } + } + }, + "/user/{name}": { "get": { "tags": [ "User" @@ -3854,7 +3877,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -3883,7 +3906,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true }, { @@ -3920,7 +3943,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -3937,7 +3960,7 @@ func init() { } } }, - "/user/groups": { + "/user/{name}/groups": { "put": { "tags": [ "User" @@ -3948,7 +3971,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true }, { @@ -3976,29 +3999,6 @@ func init() { } } }, - "/user/policy": { - "get": { - "tags": [ - "Policy" - ], - "summary": "returns policies for logged in user", - "operationId": "GetUserPolicy", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "type": "string" - } - }, - "default": { - "description": "Generic error response.", - "schema": { - "$ref": "#/definitions/error" - } - } - } - } - }, "/user/{name}/service-account-credentials": { "post": { "tags": [ @@ -9565,7 +9565,7 @@ func init() { } } }, - "/group": { + "/group/{name}": { "get": { "tags": [ "Group" @@ -9576,7 +9576,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -9605,7 +9605,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true }, { @@ -9642,7 +9642,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -10087,7 +10087,7 @@ func init() { } } }, - "/policy": { + "/policy/{name}": { "get": { "tags": [ "Policy" @@ -10098,7 +10098,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -10127,7 +10127,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -10791,7 +10791,30 @@ func init() { } } }, - "/user": { + "/user/policy": { + "get": { + "tags": [ + "Policy" + ], + "summary": "returns policies for logged in user", + "operationId": "GetUserPolicy", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "string" + } + }, + "default": { + "description": "Generic error response.", + "schema": { + "$ref": "#/definitions/error" + } + } + } + } + }, + "/user/{name}": { "get": { "tags": [ "User" @@ -10802,7 +10825,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -10831,7 +10854,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true }, { @@ -10868,7 +10891,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true } ], @@ -10885,7 +10908,7 @@ func init() { } } }, - "/user/groups": { + "/user/{name}/groups": { "put": { "tags": [ "User" @@ -10896,7 +10919,7 @@ func init() { { "type": "string", "name": "name", - "in": "query", + "in": "path", "required": true }, { @@ -10924,29 +10947,6 @@ func init() { } } }, - "/user/policy": { - "get": { - "tags": [ - "Policy" - ], - "summary": "returns policies for logged in user", - "operationId": "GetUserPolicy", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "type": "string" - } - }, - "default": { - "description": "Generic error response.", - "schema": { - "$ref": "#/definitions/error" - } - } - } - } - }, "/user/{name}/service-account-credentials": { "post": { "tags": [ diff --git a/restapi/operations/console_api.go b/restapi/operations/console_api.go index 1f2c78cbb..16bd71092 100644 --- a/restapi/operations/console_api.go +++ b/restapi/operations/console_api.go @@ -1531,7 +1531,7 @@ func (o *ConsoleAPI) initHandlerCache() { if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } - o.handlers["GET"]["/user"] = user.NewGetUserInfo(o.context, o.UserGetUserInfoHandler) + o.handlers["GET"]["/user/{name}"] = user.NewGetUserInfo(o.context, o.UserGetUserInfoHandler) if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } @@ -1539,7 +1539,7 @@ func (o *ConsoleAPI) initHandlerCache() { if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } - o.handlers["GET"]["/group"] = group.NewGroupInfo(o.context, o.GroupGroupInfoHandler) + o.handlers["GET"]["/group/{name}"] = group.NewGroupInfo(o.context, o.GroupGroupInfoHandler) if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } @@ -1643,7 +1643,7 @@ func (o *ConsoleAPI) initHandlerCache() { if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } - o.handlers["GET"]["/policy"] = policy.NewPolicyInfo(o.context, o.PolicyPolicyInfoHandler) + o.handlers["GET"]["/policy/{name}"] = policy.NewPolicyInfo(o.context, o.PolicyPolicyInfoHandler) if o.handlers["POST"] == nil { o.handlers["POST"] = make(map[string]http.Handler) } @@ -1683,15 +1683,15 @@ func (o *ConsoleAPI) initHandlerCache() { if o.handlers["DELETE"] == nil { o.handlers["DELETE"] = make(map[string]http.Handler) } - o.handlers["DELETE"]["/group"] = group.NewRemoveGroup(o.context, o.GroupRemoveGroupHandler) + o.handlers["DELETE"]["/group/{name}"] = group.NewRemoveGroup(o.context, o.GroupRemoveGroupHandler) if o.handlers["DELETE"] == nil { o.handlers["DELETE"] = make(map[string]http.Handler) } - o.handlers["DELETE"]["/policy"] = policy.NewRemovePolicy(o.context, o.PolicyRemovePolicyHandler) + o.handlers["DELETE"]["/policy/{name}"] = policy.NewRemovePolicy(o.context, o.PolicyRemovePolicyHandler) if o.handlers["DELETE"] == nil { o.handlers["DELETE"] = make(map[string]http.Handler) } - o.handlers["DELETE"]["/user"] = user.NewRemoveUser(o.context, o.UserRemoveUserHandler) + o.handlers["DELETE"]["/user/{name}"] = user.NewRemoveUser(o.context, o.UserRemoveUserHandler) if o.handlers["POST"] == nil { o.handlers["POST"] = make(map[string]http.Handler) } @@ -1787,7 +1787,7 @@ func (o *ConsoleAPI) initHandlerCache() { if o.handlers["PUT"] == nil { o.handlers["PUT"] = make(map[string]http.Handler) } - o.handlers["PUT"]["/group"] = group.NewUpdateGroup(o.context, o.GroupUpdateGroupHandler) + o.handlers["PUT"]["/group/{name}"] = group.NewUpdateGroup(o.context, o.GroupUpdateGroupHandler) if o.handlers["PUT"] == nil { o.handlers["PUT"] = make(map[string]http.Handler) } @@ -1795,11 +1795,11 @@ func (o *ConsoleAPI) initHandlerCache() { if o.handlers["PUT"] == nil { o.handlers["PUT"] = make(map[string]http.Handler) } - o.handlers["PUT"]["/user/groups"] = user.NewUpdateUserGroups(o.context, o.UserUpdateUserGroupsHandler) + o.handlers["PUT"]["/user/{name}/groups"] = user.NewUpdateUserGroups(o.context, o.UserUpdateUserGroupsHandler) if o.handlers["PUT"] == nil { o.handlers["PUT"] = make(map[string]http.Handler) } - o.handlers["PUT"]["/user"] = user.NewUpdateUserInfo(o.context, o.UserUpdateUserInfoHandler) + o.handlers["PUT"]["/user/{name}"] = user.NewUpdateUserInfo(o.context, o.UserUpdateUserInfoHandler) } // Serve creates a http handler to serve the API over HTTP diff --git a/restapi/operations/group/group_info.go b/restapi/operations/group/group_info.go index 1b74d5190..9f7b8b685 100644 --- a/restapi/operations/group/group_info.go +++ b/restapi/operations/group/group_info.go @@ -48,7 +48,7 @@ func NewGroupInfo(ctx *middleware.Context, handler GroupInfoHandler) *GroupInfo return &GroupInfo{Context: ctx, Handler: handler} } -/* GroupInfo swagger:route GET /group Group groupInfo +/* GroupInfo swagger:route GET /group/{name} Group groupInfo Group info diff --git a/restapi/operations/group/group_info_parameters.go b/restapi/operations/group/group_info_parameters.go index 45e835ae6..b312b501f 100644 --- a/restapi/operations/group/group_info_parameters.go +++ b/restapi/operations/group/group_info_parameters.go @@ -26,10 +26,8 @@ import ( "net/http" "github.com/go-openapi/errors" - "github.com/go-openapi/runtime" "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/strfmt" - "github.com/go-openapi/validate" ) // NewGroupInfoParams creates a new GroupInfoParams object @@ -51,7 +49,7 @@ type GroupInfoParams struct { /* Required: true - In: query + In: path */ Name string } @@ -65,10 +63,8 @@ func (o *GroupInfoParams) BindRequest(r *http.Request, route *middleware.Matched o.HTTPRequest = r - qs := runtime.Values(r.URL.Query()) - - qName, qhkName, _ := qs.GetOK("name") - if err := o.bindName(qName, qhkName, route.Formats); err != nil { + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { res = append(res, err) } if len(res) > 0 { @@ -77,22 +73,15 @@ func (o *GroupInfoParams) BindRequest(r *http.Request, route *middleware.Matched return nil } -// bindName binds and validates parameter Name from query. +// bindName binds and validates parameter Name from path. func (o *GroupInfoParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { - if !hasKey { - return errors.Required("name", "query", rawData) - } var raw string if len(rawData) > 0 { raw = rawData[len(rawData)-1] } // Required: true - // AllowEmptyValue: false - - if err := validate.RequiredString("name", "query", raw); err != nil { - return err - } + // Parameter is provided by construction from the route o.Name = raw return nil diff --git a/restapi/operations/group/group_info_urlbuilder.go b/restapi/operations/group/group_info_urlbuilder.go index 78947a953..e3246e8f6 100644 --- a/restapi/operations/group/group_info_urlbuilder.go +++ b/restapi/operations/group/group_info_urlbuilder.go @@ -26,6 +26,7 @@ import ( "errors" "net/url" golangswaggerpaths "path" + "strings" ) // GroupInfoURL generates an URL for the group info operation @@ -56,7 +57,14 @@ func (o *GroupInfoURL) SetBasePath(bp string) { func (o *GroupInfoURL) Build() (*url.URL, error) { var _result url.URL - var _path = "/group" + var _path = "/group/{name}" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on GroupInfoURL") + } _basePath := o._basePath if _basePath == "" { @@ -64,15 +72,6 @@ func (o *GroupInfoURL) Build() (*url.URL, error) { } _result.Path = golangswaggerpaths.Join(_basePath, _path) - qs := make(url.Values) - - nameQ := o.Name - if nameQ != "" { - qs.Set("name", nameQ) - } - - _result.RawQuery = qs.Encode() - return &_result, nil } diff --git a/restapi/operations/group/remove_group.go b/restapi/operations/group/remove_group.go index a3da922ab..c3f6094e1 100644 --- a/restapi/operations/group/remove_group.go +++ b/restapi/operations/group/remove_group.go @@ -48,7 +48,7 @@ func NewRemoveGroup(ctx *middleware.Context, handler RemoveGroupHandler) *Remove return &RemoveGroup{Context: ctx, Handler: handler} } -/* RemoveGroup swagger:route DELETE /group Group removeGroup +/* RemoveGroup swagger:route DELETE /group/{name} Group removeGroup Remove group diff --git a/restapi/operations/group/remove_group_parameters.go b/restapi/operations/group/remove_group_parameters.go index 6cd16f061..5ada44596 100644 --- a/restapi/operations/group/remove_group_parameters.go +++ b/restapi/operations/group/remove_group_parameters.go @@ -26,10 +26,8 @@ import ( "net/http" "github.com/go-openapi/errors" - "github.com/go-openapi/runtime" "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/strfmt" - "github.com/go-openapi/validate" ) // NewRemoveGroupParams creates a new RemoveGroupParams object @@ -51,7 +49,7 @@ type RemoveGroupParams struct { /* Required: true - In: query + In: path */ Name string } @@ -65,10 +63,8 @@ func (o *RemoveGroupParams) BindRequest(r *http.Request, route *middleware.Match o.HTTPRequest = r - qs := runtime.Values(r.URL.Query()) - - qName, qhkName, _ := qs.GetOK("name") - if err := o.bindName(qName, qhkName, route.Formats); err != nil { + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { res = append(res, err) } if len(res) > 0 { @@ -77,22 +73,15 @@ func (o *RemoveGroupParams) BindRequest(r *http.Request, route *middleware.Match return nil } -// bindName binds and validates parameter Name from query. +// bindName binds and validates parameter Name from path. func (o *RemoveGroupParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { - if !hasKey { - return errors.Required("name", "query", rawData) - } var raw string if len(rawData) > 0 { raw = rawData[len(rawData)-1] } // Required: true - // AllowEmptyValue: false - - if err := validate.RequiredString("name", "query", raw); err != nil { - return err - } + // Parameter is provided by construction from the route o.Name = raw return nil diff --git a/restapi/operations/group/remove_group_urlbuilder.go b/restapi/operations/group/remove_group_urlbuilder.go index e949639f6..f16547071 100644 --- a/restapi/operations/group/remove_group_urlbuilder.go +++ b/restapi/operations/group/remove_group_urlbuilder.go @@ -26,6 +26,7 @@ import ( "errors" "net/url" golangswaggerpaths "path" + "strings" ) // RemoveGroupURL generates an URL for the remove group operation @@ -56,7 +57,14 @@ func (o *RemoveGroupURL) SetBasePath(bp string) { func (o *RemoveGroupURL) Build() (*url.URL, error) { var _result url.URL - var _path = "/group" + var _path = "/group/{name}" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on RemoveGroupURL") + } _basePath := o._basePath if _basePath == "" { @@ -64,15 +72,6 @@ func (o *RemoveGroupURL) Build() (*url.URL, error) { } _result.Path = golangswaggerpaths.Join(_basePath, _path) - qs := make(url.Values) - - nameQ := o.Name - if nameQ != "" { - qs.Set("name", nameQ) - } - - _result.RawQuery = qs.Encode() - return &_result, nil } diff --git a/restapi/operations/group/update_group.go b/restapi/operations/group/update_group.go index 9f082093a..a2846bc31 100644 --- a/restapi/operations/group/update_group.go +++ b/restapi/operations/group/update_group.go @@ -48,7 +48,7 @@ func NewUpdateGroup(ctx *middleware.Context, handler UpdateGroupHandler) *Update return &UpdateGroup{Context: ctx, Handler: handler} } -/* UpdateGroup swagger:route PUT /group Group updateGroup +/* UpdateGroup swagger:route PUT /group/{name} Group updateGroup Update Group Members or Status diff --git a/restapi/operations/group/update_group_parameters.go b/restapi/operations/group/update_group_parameters.go index d33da39ff..66af044fc 100644 --- a/restapi/operations/group/update_group_parameters.go +++ b/restapi/operations/group/update_group_parameters.go @@ -60,7 +60,7 @@ type UpdateGroupParams struct { Body *models.UpdateGroupRequest /* Required: true - In: query + In: path */ Name string } @@ -74,8 +74,6 @@ func (o *UpdateGroupParams) BindRequest(r *http.Request, route *middleware.Match o.HTTPRequest = r - qs := runtime.Values(r.URL.Query()) - if runtime.HasBody(r) { defer r.Body.Close() var body models.UpdateGroupRequest @@ -104,8 +102,8 @@ func (o *UpdateGroupParams) BindRequest(r *http.Request, route *middleware.Match res = append(res, errors.Required("body", "body", "")) } - qName, qhkName, _ := qs.GetOK("name") - if err := o.bindName(qName, qhkName, route.Formats); err != nil { + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { res = append(res, err) } if len(res) > 0 { @@ -114,22 +112,15 @@ func (o *UpdateGroupParams) BindRequest(r *http.Request, route *middleware.Match return nil } -// bindName binds and validates parameter Name from query. +// bindName binds and validates parameter Name from path. func (o *UpdateGroupParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { - if !hasKey { - return errors.Required("name", "query", rawData) - } var raw string if len(rawData) > 0 { raw = rawData[len(rawData)-1] } // Required: true - // AllowEmptyValue: false - - if err := validate.RequiredString("name", "query", raw); err != nil { - return err - } + // Parameter is provided by construction from the route o.Name = raw return nil diff --git a/restapi/operations/group/update_group_urlbuilder.go b/restapi/operations/group/update_group_urlbuilder.go index e3c1e64e3..685dd703a 100644 --- a/restapi/operations/group/update_group_urlbuilder.go +++ b/restapi/operations/group/update_group_urlbuilder.go @@ -26,6 +26,7 @@ import ( "errors" "net/url" golangswaggerpaths "path" + "strings" ) // UpdateGroupURL generates an URL for the update group operation @@ -56,7 +57,14 @@ func (o *UpdateGroupURL) SetBasePath(bp string) { func (o *UpdateGroupURL) Build() (*url.URL, error) { var _result url.URL - var _path = "/group" + var _path = "/group/{name}" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on UpdateGroupURL") + } _basePath := o._basePath if _basePath == "" { @@ -64,15 +72,6 @@ func (o *UpdateGroupURL) Build() (*url.URL, error) { } _result.Path = golangswaggerpaths.Join(_basePath, _path) - qs := make(url.Values) - - nameQ := o.Name - if nameQ != "" { - qs.Set("name", nameQ) - } - - _result.RawQuery = qs.Encode() - return &_result, nil } diff --git a/restapi/operations/policy/policy_info.go b/restapi/operations/policy/policy_info.go index 10e63b0f6..cafcf27a0 100644 --- a/restapi/operations/policy/policy_info.go +++ b/restapi/operations/policy/policy_info.go @@ -48,7 +48,7 @@ func NewPolicyInfo(ctx *middleware.Context, handler PolicyInfoHandler) *PolicyIn return &PolicyInfo{Context: ctx, Handler: handler} } -/* PolicyInfo swagger:route GET /policy Policy policyInfo +/* PolicyInfo swagger:route GET /policy/{name} Policy policyInfo Policy info diff --git a/restapi/operations/policy/policy_info_parameters.go b/restapi/operations/policy/policy_info_parameters.go index 2bf96ac34..49238bc5d 100644 --- a/restapi/operations/policy/policy_info_parameters.go +++ b/restapi/operations/policy/policy_info_parameters.go @@ -26,10 +26,8 @@ import ( "net/http" "github.com/go-openapi/errors" - "github.com/go-openapi/runtime" "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/strfmt" - "github.com/go-openapi/validate" ) // NewPolicyInfoParams creates a new PolicyInfoParams object @@ -51,7 +49,7 @@ type PolicyInfoParams struct { /* Required: true - In: query + In: path */ Name string } @@ -65,10 +63,8 @@ func (o *PolicyInfoParams) BindRequest(r *http.Request, route *middleware.Matche o.HTTPRequest = r - qs := runtime.Values(r.URL.Query()) - - qName, qhkName, _ := qs.GetOK("name") - if err := o.bindName(qName, qhkName, route.Formats); err != nil { + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { res = append(res, err) } if len(res) > 0 { @@ -77,22 +73,15 @@ func (o *PolicyInfoParams) BindRequest(r *http.Request, route *middleware.Matche return nil } -// bindName binds and validates parameter Name from query. +// bindName binds and validates parameter Name from path. func (o *PolicyInfoParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { - if !hasKey { - return errors.Required("name", "query", rawData) - } var raw string if len(rawData) > 0 { raw = rawData[len(rawData)-1] } // Required: true - // AllowEmptyValue: false - - if err := validate.RequiredString("name", "query", raw); err != nil { - return err - } + // Parameter is provided by construction from the route o.Name = raw return nil diff --git a/restapi/operations/policy/policy_info_urlbuilder.go b/restapi/operations/policy/policy_info_urlbuilder.go index 45f0526ce..6d6ea3bb5 100644 --- a/restapi/operations/policy/policy_info_urlbuilder.go +++ b/restapi/operations/policy/policy_info_urlbuilder.go @@ -26,6 +26,7 @@ import ( "errors" "net/url" golangswaggerpaths "path" + "strings" ) // PolicyInfoURL generates an URL for the policy info operation @@ -56,7 +57,14 @@ func (o *PolicyInfoURL) SetBasePath(bp string) { func (o *PolicyInfoURL) Build() (*url.URL, error) { var _result url.URL - var _path = "/policy" + var _path = "/policy/{name}" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on PolicyInfoURL") + } _basePath := o._basePath if _basePath == "" { @@ -64,15 +72,6 @@ func (o *PolicyInfoURL) Build() (*url.URL, error) { } _result.Path = golangswaggerpaths.Join(_basePath, _path) - qs := make(url.Values) - - nameQ := o.Name - if nameQ != "" { - qs.Set("name", nameQ) - } - - _result.RawQuery = qs.Encode() - return &_result, nil } diff --git a/restapi/operations/policy/remove_policy.go b/restapi/operations/policy/remove_policy.go index 8327a4275..e4663e000 100644 --- a/restapi/operations/policy/remove_policy.go +++ b/restapi/operations/policy/remove_policy.go @@ -48,7 +48,7 @@ func NewRemovePolicy(ctx *middleware.Context, handler RemovePolicyHandler) *Remo return &RemovePolicy{Context: ctx, Handler: handler} } -/* RemovePolicy swagger:route DELETE /policy Policy removePolicy +/* RemovePolicy swagger:route DELETE /policy/{name} Policy removePolicy Remove policy diff --git a/restapi/operations/policy/remove_policy_parameters.go b/restapi/operations/policy/remove_policy_parameters.go index d0e01ee59..4b2852773 100644 --- a/restapi/operations/policy/remove_policy_parameters.go +++ b/restapi/operations/policy/remove_policy_parameters.go @@ -26,10 +26,8 @@ import ( "net/http" "github.com/go-openapi/errors" - "github.com/go-openapi/runtime" "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/strfmt" - "github.com/go-openapi/validate" ) // NewRemovePolicyParams creates a new RemovePolicyParams object @@ -51,7 +49,7 @@ type RemovePolicyParams struct { /* Required: true - In: query + In: path */ Name string } @@ -65,10 +63,8 @@ func (o *RemovePolicyParams) BindRequest(r *http.Request, route *middleware.Matc o.HTTPRequest = r - qs := runtime.Values(r.URL.Query()) - - qName, qhkName, _ := qs.GetOK("name") - if err := o.bindName(qName, qhkName, route.Formats); err != nil { + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { res = append(res, err) } if len(res) > 0 { @@ -77,22 +73,15 @@ func (o *RemovePolicyParams) BindRequest(r *http.Request, route *middleware.Matc return nil } -// bindName binds and validates parameter Name from query. +// bindName binds and validates parameter Name from path. func (o *RemovePolicyParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { - if !hasKey { - return errors.Required("name", "query", rawData) - } var raw string if len(rawData) > 0 { raw = rawData[len(rawData)-1] } // Required: true - // AllowEmptyValue: false - - if err := validate.RequiredString("name", "query", raw); err != nil { - return err - } + // Parameter is provided by construction from the route o.Name = raw return nil diff --git a/restapi/operations/policy/remove_policy_urlbuilder.go b/restapi/operations/policy/remove_policy_urlbuilder.go index 75cab4c72..546752e62 100644 --- a/restapi/operations/policy/remove_policy_urlbuilder.go +++ b/restapi/operations/policy/remove_policy_urlbuilder.go @@ -26,6 +26,7 @@ import ( "errors" "net/url" golangswaggerpaths "path" + "strings" ) // RemovePolicyURL generates an URL for the remove policy operation @@ -56,7 +57,14 @@ func (o *RemovePolicyURL) SetBasePath(bp string) { func (o *RemovePolicyURL) Build() (*url.URL, error) { var _result url.URL - var _path = "/policy" + var _path = "/policy/{name}" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on RemovePolicyURL") + } _basePath := o._basePath if _basePath == "" { @@ -64,15 +72,6 @@ func (o *RemovePolicyURL) Build() (*url.URL, error) { } _result.Path = golangswaggerpaths.Join(_basePath, _path) - qs := make(url.Values) - - nameQ := o.Name - if nameQ != "" { - qs.Set("name", nameQ) - } - - _result.RawQuery = qs.Encode() - return &_result, nil } diff --git a/restapi/operations/user/get_user_info.go b/restapi/operations/user/get_user_info.go index b94a6bd7a..f523cbce7 100644 --- a/restapi/operations/user/get_user_info.go +++ b/restapi/operations/user/get_user_info.go @@ -48,7 +48,7 @@ func NewGetUserInfo(ctx *middleware.Context, handler GetUserInfoHandler) *GetUse return &GetUserInfo{Context: ctx, Handler: handler} } -/* GetUserInfo swagger:route GET /user User getUserInfo +/* GetUserInfo swagger:route GET /user/{name} User getUserInfo Get User Info diff --git a/restapi/operations/user/get_user_info_parameters.go b/restapi/operations/user/get_user_info_parameters.go index b5a0a41c6..7bb25cdf0 100644 --- a/restapi/operations/user/get_user_info_parameters.go +++ b/restapi/operations/user/get_user_info_parameters.go @@ -26,10 +26,8 @@ import ( "net/http" "github.com/go-openapi/errors" - "github.com/go-openapi/runtime" "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/strfmt" - "github.com/go-openapi/validate" ) // NewGetUserInfoParams creates a new GetUserInfoParams object @@ -51,7 +49,7 @@ type GetUserInfoParams struct { /* Required: true - In: query + In: path */ Name string } @@ -65,10 +63,8 @@ func (o *GetUserInfoParams) BindRequest(r *http.Request, route *middleware.Match o.HTTPRequest = r - qs := runtime.Values(r.URL.Query()) - - qName, qhkName, _ := qs.GetOK("name") - if err := o.bindName(qName, qhkName, route.Formats); err != nil { + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { res = append(res, err) } if len(res) > 0 { @@ -77,22 +73,15 @@ func (o *GetUserInfoParams) BindRequest(r *http.Request, route *middleware.Match return nil } -// bindName binds and validates parameter Name from query. +// bindName binds and validates parameter Name from path. func (o *GetUserInfoParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { - if !hasKey { - return errors.Required("name", "query", rawData) - } var raw string if len(rawData) > 0 { raw = rawData[len(rawData)-1] } // Required: true - // AllowEmptyValue: false - - if err := validate.RequiredString("name", "query", raw); err != nil { - return err - } + // Parameter is provided by construction from the route o.Name = raw return nil diff --git a/restapi/operations/user/get_user_info_urlbuilder.go b/restapi/operations/user/get_user_info_urlbuilder.go index 7191d8766..5512fb920 100644 --- a/restapi/operations/user/get_user_info_urlbuilder.go +++ b/restapi/operations/user/get_user_info_urlbuilder.go @@ -26,6 +26,7 @@ import ( "errors" "net/url" golangswaggerpaths "path" + "strings" ) // GetUserInfoURL generates an URL for the get user info operation @@ -56,7 +57,14 @@ func (o *GetUserInfoURL) SetBasePath(bp string) { func (o *GetUserInfoURL) Build() (*url.URL, error) { var _result url.URL - var _path = "/user" + var _path = "/user/{name}" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on GetUserInfoURL") + } _basePath := o._basePath if _basePath == "" { @@ -64,15 +72,6 @@ func (o *GetUserInfoURL) Build() (*url.URL, error) { } _result.Path = golangswaggerpaths.Join(_basePath, _path) - qs := make(url.Values) - - nameQ := o.Name - if nameQ != "" { - qs.Set("name", nameQ) - } - - _result.RawQuery = qs.Encode() - return &_result, nil } diff --git a/restapi/operations/user/remove_user.go b/restapi/operations/user/remove_user.go index fe469896a..ea0b3c30b 100644 --- a/restapi/operations/user/remove_user.go +++ b/restapi/operations/user/remove_user.go @@ -48,7 +48,7 @@ func NewRemoveUser(ctx *middleware.Context, handler RemoveUserHandler) *RemoveUs return &RemoveUser{Context: ctx, Handler: handler} } -/* RemoveUser swagger:route DELETE /user User removeUser +/* RemoveUser swagger:route DELETE /user/{name} User removeUser Remove user diff --git a/restapi/operations/user/remove_user_parameters.go b/restapi/operations/user/remove_user_parameters.go index e089208fe..d1b61b286 100644 --- a/restapi/operations/user/remove_user_parameters.go +++ b/restapi/operations/user/remove_user_parameters.go @@ -26,10 +26,8 @@ import ( "net/http" "github.com/go-openapi/errors" - "github.com/go-openapi/runtime" "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/strfmt" - "github.com/go-openapi/validate" ) // NewRemoveUserParams creates a new RemoveUserParams object @@ -51,7 +49,7 @@ type RemoveUserParams struct { /* Required: true - In: query + In: path */ Name string } @@ -65,10 +63,8 @@ func (o *RemoveUserParams) BindRequest(r *http.Request, route *middleware.Matche o.HTTPRequest = r - qs := runtime.Values(r.URL.Query()) - - qName, qhkName, _ := qs.GetOK("name") - if err := o.bindName(qName, qhkName, route.Formats); err != nil { + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { res = append(res, err) } if len(res) > 0 { @@ -77,22 +73,15 @@ func (o *RemoveUserParams) BindRequest(r *http.Request, route *middleware.Matche return nil } -// bindName binds and validates parameter Name from query. +// bindName binds and validates parameter Name from path. func (o *RemoveUserParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { - if !hasKey { - return errors.Required("name", "query", rawData) - } var raw string if len(rawData) > 0 { raw = rawData[len(rawData)-1] } // Required: true - // AllowEmptyValue: false - - if err := validate.RequiredString("name", "query", raw); err != nil { - return err - } + // Parameter is provided by construction from the route o.Name = raw return nil diff --git a/restapi/operations/user/remove_user_urlbuilder.go b/restapi/operations/user/remove_user_urlbuilder.go index d91b2eb73..6d863908b 100644 --- a/restapi/operations/user/remove_user_urlbuilder.go +++ b/restapi/operations/user/remove_user_urlbuilder.go @@ -26,6 +26,7 @@ import ( "errors" "net/url" golangswaggerpaths "path" + "strings" ) // RemoveUserURL generates an URL for the remove user operation @@ -56,7 +57,14 @@ func (o *RemoveUserURL) SetBasePath(bp string) { func (o *RemoveUserURL) Build() (*url.URL, error) { var _result url.URL - var _path = "/user" + var _path = "/user/{name}" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on RemoveUserURL") + } _basePath := o._basePath if _basePath == "" { @@ -64,15 +72,6 @@ func (o *RemoveUserURL) Build() (*url.URL, error) { } _result.Path = golangswaggerpaths.Join(_basePath, _path) - qs := make(url.Values) - - nameQ := o.Name - if nameQ != "" { - qs.Set("name", nameQ) - } - - _result.RawQuery = qs.Encode() - return &_result, nil } diff --git a/restapi/operations/user/update_user_groups.go b/restapi/operations/user/update_user_groups.go index d13add4d2..3515264d5 100644 --- a/restapi/operations/user/update_user_groups.go +++ b/restapi/operations/user/update_user_groups.go @@ -48,7 +48,7 @@ func NewUpdateUserGroups(ctx *middleware.Context, handler UpdateUserGroupsHandle return &UpdateUserGroups{Context: ctx, Handler: handler} } -/* UpdateUserGroups swagger:route PUT /user/groups User updateUserGroups +/* UpdateUserGroups swagger:route PUT /user/{name}/groups User updateUserGroups Update Groups for a user diff --git a/restapi/operations/user/update_user_groups_parameters.go b/restapi/operations/user/update_user_groups_parameters.go index f2cba57bd..d64f2c145 100644 --- a/restapi/operations/user/update_user_groups_parameters.go +++ b/restapi/operations/user/update_user_groups_parameters.go @@ -60,7 +60,7 @@ type UpdateUserGroupsParams struct { Body *models.UpdateUserGroups /* Required: true - In: query + In: path */ Name string } @@ -74,8 +74,6 @@ func (o *UpdateUserGroupsParams) BindRequest(r *http.Request, route *middleware. o.HTTPRequest = r - qs := runtime.Values(r.URL.Query()) - if runtime.HasBody(r) { defer r.Body.Close() var body models.UpdateUserGroups @@ -104,8 +102,8 @@ func (o *UpdateUserGroupsParams) BindRequest(r *http.Request, route *middleware. res = append(res, errors.Required("body", "body", "")) } - qName, qhkName, _ := qs.GetOK("name") - if err := o.bindName(qName, qhkName, route.Formats); err != nil { + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { res = append(res, err) } if len(res) > 0 { @@ -114,22 +112,15 @@ func (o *UpdateUserGroupsParams) BindRequest(r *http.Request, route *middleware. return nil } -// bindName binds and validates parameter Name from query. +// bindName binds and validates parameter Name from path. func (o *UpdateUserGroupsParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { - if !hasKey { - return errors.Required("name", "query", rawData) - } var raw string if len(rawData) > 0 { raw = rawData[len(rawData)-1] } // Required: true - // AllowEmptyValue: false - - if err := validate.RequiredString("name", "query", raw); err != nil { - return err - } + // Parameter is provided by construction from the route o.Name = raw return nil diff --git a/restapi/operations/user/update_user_groups_urlbuilder.go b/restapi/operations/user/update_user_groups_urlbuilder.go index 53f10c3e6..f9c297632 100644 --- a/restapi/operations/user/update_user_groups_urlbuilder.go +++ b/restapi/operations/user/update_user_groups_urlbuilder.go @@ -26,6 +26,7 @@ import ( "errors" "net/url" golangswaggerpaths "path" + "strings" ) // UpdateUserGroupsURL generates an URL for the update user groups operation @@ -56,7 +57,14 @@ func (o *UpdateUserGroupsURL) SetBasePath(bp string) { func (o *UpdateUserGroupsURL) Build() (*url.URL, error) { var _result url.URL - var _path = "/user/groups" + var _path = "/user/{name}/groups" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on UpdateUserGroupsURL") + } _basePath := o._basePath if _basePath == "" { @@ -64,15 +72,6 @@ func (o *UpdateUserGroupsURL) Build() (*url.URL, error) { } _result.Path = golangswaggerpaths.Join(_basePath, _path) - qs := make(url.Values) - - nameQ := o.Name - if nameQ != "" { - qs.Set("name", nameQ) - } - - _result.RawQuery = qs.Encode() - return &_result, nil } diff --git a/restapi/operations/user/update_user_info.go b/restapi/operations/user/update_user_info.go index 3b2963554..b770a21b8 100644 --- a/restapi/operations/user/update_user_info.go +++ b/restapi/operations/user/update_user_info.go @@ -48,7 +48,7 @@ func NewUpdateUserInfo(ctx *middleware.Context, handler UpdateUserInfoHandler) * return &UpdateUserInfo{Context: ctx, Handler: handler} } -/* UpdateUserInfo swagger:route PUT /user User updateUserInfo +/* UpdateUserInfo swagger:route PUT /user/{name} User updateUserInfo Update User Info diff --git a/restapi/operations/user/update_user_info_parameters.go b/restapi/operations/user/update_user_info_parameters.go index f7b024bab..5db1f028f 100644 --- a/restapi/operations/user/update_user_info_parameters.go +++ b/restapi/operations/user/update_user_info_parameters.go @@ -60,7 +60,7 @@ type UpdateUserInfoParams struct { Body *models.UpdateUser /* Required: true - In: query + In: path */ Name string } @@ -74,8 +74,6 @@ func (o *UpdateUserInfoParams) BindRequest(r *http.Request, route *middleware.Ma o.HTTPRequest = r - qs := runtime.Values(r.URL.Query()) - if runtime.HasBody(r) { defer r.Body.Close() var body models.UpdateUser @@ -104,8 +102,8 @@ func (o *UpdateUserInfoParams) BindRequest(r *http.Request, route *middleware.Ma res = append(res, errors.Required("body", "body", "")) } - qName, qhkName, _ := qs.GetOK("name") - if err := o.bindName(qName, qhkName, route.Formats); err != nil { + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { res = append(res, err) } if len(res) > 0 { @@ -114,22 +112,15 @@ func (o *UpdateUserInfoParams) BindRequest(r *http.Request, route *middleware.Ma return nil } -// bindName binds and validates parameter Name from query. +// bindName binds and validates parameter Name from path. func (o *UpdateUserInfoParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { - if !hasKey { - return errors.Required("name", "query", rawData) - } var raw string if len(rawData) > 0 { raw = rawData[len(rawData)-1] } // Required: true - // AllowEmptyValue: false - - if err := validate.RequiredString("name", "query", raw); err != nil { - return err - } + // Parameter is provided by construction from the route o.Name = raw return nil diff --git a/restapi/operations/user/update_user_info_urlbuilder.go b/restapi/operations/user/update_user_info_urlbuilder.go index d60273cf7..c7c56d006 100644 --- a/restapi/operations/user/update_user_info_urlbuilder.go +++ b/restapi/operations/user/update_user_info_urlbuilder.go @@ -26,6 +26,7 @@ import ( "errors" "net/url" golangswaggerpaths "path" + "strings" ) // UpdateUserInfoURL generates an URL for the update user info operation @@ -56,7 +57,14 @@ func (o *UpdateUserInfoURL) SetBasePath(bp string) { func (o *UpdateUserInfoURL) Build() (*url.URL, error) { var _result url.URL - var _path = "/user" + var _path = "/user/{name}" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on UpdateUserInfoURL") + } _basePath := o._basePath if _basePath == "" { @@ -64,15 +72,6 @@ func (o *UpdateUserInfoURL) Build() (*url.URL, error) { } _result.Path = golangswaggerpaths.Join(_basePath, _path) - qs := make(url.Values) - - nameQ := o.Name - if nameQ != "" { - qs.Set("name", nameQ) - } - - _result.RawQuery = qs.Encode() - return &_result, nil } diff --git a/restapi/user_service_accounts.go b/restapi/user_service_accounts.go index 78f810b7f..58a7499cf 100644 --- a/restapi/user_service_accounts.go +++ b/restapi/user_service_accounts.go @@ -23,6 +23,8 @@ import ( "errors" "strings" + "github.com/minio/console/pkg/utils" + userApi "github.com/minio/console/restapi/operations/user" "github.com/go-openapi/runtime/middleware" @@ -233,8 +235,11 @@ func getCreateAUserServiceAccountResponse(session *models.Principal, params user // create a MinIO user Admin Client interface implementation // defining the client to be used userAdminClient := AdminClient{Client: userAdmin} - - saCreds, err := createAUserServiceAccount(ctx, userAdminClient, params.Body.Policy, params.Name) + name, err := utils.DecodeBase64(params.Name) + if err != nil { + return nil, ErrorWithContext(ctx, err) + } + saCreds, err := createAUserServiceAccount(ctx, userAdminClient, params.Body.Policy, name) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -254,7 +259,10 @@ func getCreateAUserServiceAccountCredsResponse(session *models.Principal, params // defining the client to be used userAdminClient := AdminClient{Client: userAdmin} serviceAccount := params.Body - user := params.Name + user, err := utils.DecodeBase64(params.Name) + if err != nil { + return nil, ErrorWithContext(ctx, err) + } if user == serviceAccount.AccessKey { return nil, ErrorWithContext(ctx, errors.New("Access Key already in use")) } @@ -331,7 +339,10 @@ func getUserServiceAccountsResponse(ctx context.Context, session *models.Princip // create a MinIO user Admin Client interface implementation // defining the client to be used userAdminClient := AdminClient{Client: userAdmin} - + user, err = utils.DecodeBase64(user) + if err != nil { + return nil, ErrorWithContext(ctx, err) + } serviceAccounts, err := getUserServiceAccounts(ctx, userAdminClient, user) if err != nil { return nil, ErrorWithContext(ctx, err) @@ -348,7 +359,10 @@ func deleteServiceAccount(ctx context.Context, userClient MinioAdmin, accessKey func getDeleteServiceAccountResponse(session *models.Principal, params saApi.DeleteServiceAccountParams) *models.Error { ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) defer cancel() - accessKey := params.AccessKey + accessKey, err := utils.DecodeBase64(params.AccessKey) + if err != nil { + return ErrorWithContext(ctx, err) + } userAdmin, err := NewMinioAdminClient(session) if err != nil { return ErrorWithContext(ctx, err) @@ -381,7 +395,10 @@ func getServiceAccountPolicy(ctx context.Context, userClient MinioAdmin, accessK func getServiceAccountPolicyResponse(session *models.Principal, params saApi.GetServiceAccountPolicyParams) (string, *models.Error) { ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) defer cancel() - accessKey := params.AccessKey + accessKey, err := utils.DecodeBase64(params.AccessKey) + if err != nil { + return "", ErrorWithContext(ctx, err) + } userAdmin, err := NewMinioAdminClient(session) if err != nil { return "", ErrorWithContext(ctx, err) @@ -408,7 +425,10 @@ func setServiceAccountPolicy(ctx context.Context, userClient MinioAdmin, accessK func getSetServiceAccountPolicyResponse(session *models.Principal, params saApi.SetServiceAccountPolicyParams) *models.Error { ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) defer cancel() - accessKey := params.AccessKey + accessKey, err := utils.DecodeBase64(params.AccessKey) + if err != nil { + return ErrorWithContext(ctx, err) + } policy := *params.Policy.Policy userAdmin, err := NewMinioAdminClient(session) if err != nil { diff --git a/swagger-console.yml b/swagger-console.yml index 570f593eb..564b74da0 100644 --- a/swagger-console.yml +++ b/swagger-console.yml @@ -1481,13 +1481,13 @@ paths: tags: - User - /user: + /user/{name}: get: summary: Get User Info operationId: GetUserInfo parameters: - name: name - in: query + in: path required: true type: string responses: @@ -1506,7 +1506,7 @@ paths: operationId: UpdateUserInfo parameters: - name: name - in: query + in: path required: true type: string - name: body @@ -1530,7 +1530,7 @@ paths: operationId: RemoveUser parameters: - name: name - in: query + in: path required: true type: string responses: @@ -1543,13 +1543,13 @@ paths: tags: - User - /user/groups: + /user/{name}/groups: put: summary: Update Groups for a user operationId: UpdateUserGroups parameters: - name: name - in: query + in: path required: true type: string - name: body @@ -1719,13 +1719,13 @@ paths: tags: - Group - /group: + /group/{name}: get: summary: Group info operationId: GroupInfo parameters: - name: name - in: query + in: path required: true type: string responses: @@ -1744,7 +1744,7 @@ paths: operationId: RemoveGroup parameters: - name: name - in: query + in: path required: true type: string responses: @@ -1761,7 +1761,7 @@ paths: operationId: UpdateGroup parameters: - name: name - in: query + in: path required: true type: string - name: body @@ -2017,13 +2017,13 @@ paths: tags: - Bucket - /policy: + /policy/{name}: get: summary: Policy info operationId: PolicyInfo parameters: - name: name - in: query + in: path required: true type: string responses: @@ -2042,7 +2042,7 @@ paths: operationId: RemovePolicy parameters: - name: name - in: query + in: path required: true type: string responses: