mirror of
https://github.com/Infisical/infisical.git
synced 2026-01-09 15:38:03 -05:00
Merge branch 'main' into fix/teamCityParametersHiddenConfig
This commit is contained in:
@@ -183,7 +183,7 @@ export const dynamicSecretLeaseServiceFactory = ({
|
||||
});
|
||||
|
||||
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
|
||||
if (!dynamicSecretLease) {
|
||||
if (!dynamicSecretLease || dynamicSecretLease.dynamicSecret.folderId !== folder.id) {
|
||||
throw new NotFoundError({ message: `Dynamic secret lease with ID '${leaseId}' not found` });
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ export const dynamicSecretLeaseServiceFactory = ({
|
||||
});
|
||||
|
||||
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
|
||||
if (!dynamicSecretLease)
|
||||
if (!dynamicSecretLease || dynamicSecretLease.dynamicSecret.folderId !== folder.id)
|
||||
throw new NotFoundError({ message: `Dynamic secret lease with ID '${leaseId}' not found` });
|
||||
|
||||
const dynamicSecretCfg = dynamicSecretLease.dynamicSecret;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { getDbConnectionHost } from "@app/lib/knex";
|
||||
|
||||
export const verifyHostInputValidity = async (host: string, isGateway = false) => {
|
||||
const appCfg = getConfig();
|
||||
// if (appCfg.NODE_ENV === "development") return; // incase you want to remove this check in dev
|
||||
// if (appCfg.NODE_ENV === "development") return ["host.docker.internal"]; // incase you want to remove this check in dev
|
||||
|
||||
const reservedHosts = [appCfg.DB_HOST || getDbConnectionHost(appCfg.DB_CONNECTION_URI)].concat(
|
||||
(appCfg.DB_READ_REPLICAS || []).map((el) => getDbConnectionHost(el.DB_CONNECTION_URI)),
|
||||
|
||||
@@ -42,6 +42,31 @@ type TIdentityAwsAuthServiceFactoryDep = {
|
||||
|
||||
export type TIdentityAwsAuthServiceFactory = ReturnType<typeof identityAwsAuthServiceFactory>;
|
||||
|
||||
const awsRegionFromHeader = (authorizationHeader: string): string | null => {
|
||||
// https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html
|
||||
// The Authorization header takes the following form.
|
||||
// Authorization: AWS4-HMAC-SHA256
|
||||
// Credential=AKIAIOSFODNN7EXAMPLE/20230719/us-east-1/sts/aws4_request,
|
||||
// SignedHeaders=content-length;content-type;host;x-amz-date,
|
||||
// Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024
|
||||
//
|
||||
// The credential is in the form of "<your-access-key-id>/<date>/<aws-region>/<aws-service>/aws4_request"
|
||||
try {
|
||||
const fields = authorizationHeader.split(" ");
|
||||
for (const field of fields) {
|
||||
if (field.startsWith("Credential=")) {
|
||||
const parts = field.split("/");
|
||||
if (parts.length >= 3) {
|
||||
return parts[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const identityAwsAuthServiceFactory = ({
|
||||
identityAccessTokenDAL,
|
||||
identityAwsAuthDAL,
|
||||
@@ -60,6 +85,9 @@ export const identityAwsAuthServiceFactory = ({
|
||||
const headers: TAwsGetCallerIdentityHeaders = JSON.parse(Buffer.from(iamRequestHeaders, "base64").toString());
|
||||
const body: string = Buffer.from(iamRequestBody, "base64").toString();
|
||||
|
||||
const region = headers.Authorization ? awsRegionFromHeader(headers.Authorization) : null;
|
||||
const url = region ? `https://sts.${region}.amazonaws.com` : identityAwsAuth.stsEndpoint;
|
||||
|
||||
const {
|
||||
data: {
|
||||
GetCallerIdentityResponse: {
|
||||
@@ -68,7 +96,7 @@ export const identityAwsAuthServiceFactory = ({
|
||||
}
|
||||
}: { data: TGetCallerIdentityResponse } = await axios({
|
||||
method: iamHttpRequestMethod,
|
||||
url: headers?.Host ? `https://${headers.Host}` : identityAwsAuth.stsEndpoint,
|
||||
url,
|
||||
headers,
|
||||
data: body
|
||||
});
|
||||
|
||||
@@ -471,6 +471,7 @@ export const identityUaServiceFactory = ({
|
||||
const clientSecretHash = await bcrypt.hash(clientSecret, appCfg.SALT_ROUNDS);
|
||||
|
||||
const identityUaAuth = await identityUaDAL.findOne({ identityId: identityMembershipOrg.identityId });
|
||||
if (!identityUaAuth) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||
|
||||
const identityUaClientSecret = await identityUaClientSecretDAL.create({
|
||||
identityUAId: identityUaAuth.id,
|
||||
@@ -567,6 +568,12 @@ export const identityUaServiceFactory = ({
|
||||
});
|
||||
}
|
||||
|
||||
const identityUa = await identityUaDAL.findOne({ identityId });
|
||||
if (!identityUa) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||
|
||||
const clientSecret = await identityUaClientSecretDAL.findOne({ id: clientSecretId, identityUAId: identityUa.id });
|
||||
if (!clientSecret) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||
|
||||
const { permission, membership } = await permissionService.getOrgPermission(
|
||||
actor,
|
||||
actorId,
|
||||
@@ -601,7 +608,6 @@ export const identityUaServiceFactory = ({
|
||||
details: { missingPermissions: permissionBoundary.missingPermissions }
|
||||
});
|
||||
|
||||
const clientSecret = await identityUaClientSecretDAL.findById(clientSecretId);
|
||||
return { ...clientSecret, identityId, orgId: identityMembershipOrg.orgId };
|
||||
};
|
||||
|
||||
@@ -622,6 +628,12 @@ export const identityUaServiceFactory = ({
|
||||
});
|
||||
}
|
||||
|
||||
const identityUa = await identityUaDAL.findOne({ identityId });
|
||||
if (!identityUa) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||
|
||||
const clientSecret = await identityUaClientSecretDAL.findOne({ id: clientSecretId, identityUAId: identityUa.id });
|
||||
if (!clientSecret) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||
|
||||
const { permission, membership } = await permissionService.getOrgPermission(
|
||||
actor,
|
||||
actorId,
|
||||
@@ -658,11 +670,11 @@ export const identityUaServiceFactory = ({
|
||||
});
|
||||
}
|
||||
|
||||
const clientSecret = await identityUaClientSecretDAL.updateById(clientSecretId, {
|
||||
const updatedClientSecret = await identityUaClientSecretDAL.updateById(clientSecretId, {
|
||||
isClientSecretRevoked: true
|
||||
});
|
||||
|
||||
return { ...clientSecret, identityId, orgId: identityMembershipOrg.orgId };
|
||||
return { ...updatedClientSecret, identityId, orgId: identityMembershipOrg.orgId };
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,81 +1,118 @@
|
||||
import Select, { Props } from "react-select";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { ClearIndicator, DropdownIndicator, MultiValueRemove, Option } from "../Select/components";
|
||||
import {
|
||||
ClearIndicator,
|
||||
DropdownIndicator,
|
||||
Group,
|
||||
MultiValueRemove,
|
||||
Option
|
||||
} from "../Select/components";
|
||||
|
||||
export const FilterableSelect = <T,>({
|
||||
isMulti,
|
||||
closeMenuOnSelect,
|
||||
tabSelectsValue = false,
|
||||
groupBy = null,
|
||||
getGroupHeaderLabel = null,
|
||||
options = [],
|
||||
...props
|
||||
}: Props<T>) => (
|
||||
<Select
|
||||
isMulti={isMulti}
|
||||
closeMenuOnSelect={closeMenuOnSelect ?? !isMulti}
|
||||
hideSelectedOptions={false}
|
||||
unstyled
|
||||
styles={{
|
||||
input: (base) => ({
|
||||
...base,
|
||||
"input:focus": {
|
||||
boxShadow: "none"
|
||||
}
|
||||
}),
|
||||
multiValueLabel: (base) => ({
|
||||
...base,
|
||||
whiteSpace: "normal",
|
||||
overflow: "visible"
|
||||
}),
|
||||
control: (base) => ({
|
||||
...base,
|
||||
transition: "none"
|
||||
})
|
||||
}}
|
||||
tabSelectsValue={tabSelectsValue}
|
||||
components={{
|
||||
DropdownIndicator,
|
||||
ClearIndicator,
|
||||
MultiValueRemove,
|
||||
Option,
|
||||
...props.components
|
||||
}}
|
||||
classNames={{
|
||||
container: ({ isDisabled }) =>
|
||||
twMerge("w-full font-inter text-sm", isDisabled && "!pointer-events-auto opacity-50"),
|
||||
control: ({ isFocused, isDisabled }) =>
|
||||
twMerge(
|
||||
isFocused ? "border-primary-400/50" : "border-mineshaft-600",
|
||||
`w-full rounded-md border bg-mineshaft-900 p-0.5 font-inter text-mineshaft-200 ${
|
||||
isDisabled ? "!cursor-not-allowed" : "hover:cursor-pointer hover:border-gray-400"
|
||||
} `
|
||||
),
|
||||
placeholder: () =>
|
||||
`${isMulti ? "py-[0.22rem]" : "leading-7"} text-mineshaft-400 text-sm pl-1`,
|
||||
input: () => "pl-1",
|
||||
valueContainer: () =>
|
||||
`px-1 max-h-[8.2rem] ${
|
||||
isMulti ? "!overflow-y-auto thin-scrollbar py-1" : "py-[0.1rem]"
|
||||
} gap-1`,
|
||||
singleValue: () => "leading-7 ml-1",
|
||||
multiValue: () => "bg-mineshaft-600 text-sm rounded items-center py-0.5 px-2 gap-1.5",
|
||||
multiValueLabel: () => "leading-6 text-sm",
|
||||
multiValueRemove: () => "hover:text-red text-bunker-400",
|
||||
indicatorsContainer: () => "p-1 gap-1",
|
||||
clearIndicator: () => "p-1 hover:text-red text-bunker-400",
|
||||
indicatorSeparator: () => "bg-bunker-400",
|
||||
dropdownIndicator: () => "text-bunker-200 p-1",
|
||||
menuList: () => "flex flex-col gap-1",
|
||||
menu: () =>
|
||||
"my-2 p-2 border text-sm text-mineshaft-200 thin-scrollbar bg-mineshaft-900 border-mineshaft-600 rounded-md",
|
||||
groupHeading: () => "ml-3 mt-2 mb-1 text-mineshaft-400 text-sm",
|
||||
option: ({ isFocused, isSelected }) =>
|
||||
twMerge(
|
||||
isFocused && "bg-mineshaft-700 active:bg-mineshaft-600",
|
||||
isSelected && "text-mineshaft-200",
|
||||
"rounded px-3 py-2 text-xs hover:cursor-pointer"
|
||||
),
|
||||
noOptionsMessage: () => "text-mineshaft-400 p-2 rounded-md"
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}: Props<T> & {
|
||||
groupBy?: string | null;
|
||||
getGroupHeaderLabel?: ((groupValue: any) => string) | null;
|
||||
}) => {
|
||||
let processedOptions = options;
|
||||
|
||||
if (groupBy && Array.isArray(options)) {
|
||||
const groupedOptions = options.reduce((acc, option) => {
|
||||
const groupValue = option[groupBy];
|
||||
const groupKey = groupValue?.toString() || "undefined";
|
||||
|
||||
if (!acc[groupKey]) {
|
||||
acc[groupKey] = {
|
||||
label: getGroupHeaderLabel ? getGroupHeaderLabel(groupValue) : groupValue,
|
||||
options: []
|
||||
};
|
||||
}
|
||||
|
||||
acc[groupKey].options.push(option);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
processedOptions = Object.values(groupedOptions);
|
||||
}
|
||||
|
||||
return (
|
||||
<Select
|
||||
isMulti={isMulti}
|
||||
closeMenuOnSelect={closeMenuOnSelect ?? !isMulti}
|
||||
hideSelectedOptions={false}
|
||||
unstyled
|
||||
options={processedOptions}
|
||||
styles={{
|
||||
input: (base) => ({
|
||||
...base,
|
||||
"input:focus": {
|
||||
boxShadow: "none"
|
||||
}
|
||||
}),
|
||||
multiValueLabel: (base) => ({
|
||||
...base,
|
||||
whiteSpace: "normal",
|
||||
overflow: "visible"
|
||||
}),
|
||||
control: (base) => ({
|
||||
...base,
|
||||
transition: "none"
|
||||
})
|
||||
}}
|
||||
tabSelectsValue={tabSelectsValue}
|
||||
components={{
|
||||
DropdownIndicator,
|
||||
ClearIndicator,
|
||||
MultiValueRemove,
|
||||
Option,
|
||||
Group,
|
||||
...props.components
|
||||
}}
|
||||
classNames={{
|
||||
container: ({ isDisabled }) =>
|
||||
twMerge("w-full font-inter text-sm", isDisabled && "!pointer-events-auto opacity-50"),
|
||||
control: ({ isFocused, isDisabled }) =>
|
||||
twMerge(
|
||||
isFocused ? "border-primary-400/50" : "border-mineshaft-600",
|
||||
`w-full rounded-md border bg-mineshaft-900 p-0.5 font-inter text-mineshaft-200 ${
|
||||
isDisabled ? "!cursor-not-allowed" : "hover:cursor-pointer hover:border-gray-400"
|
||||
} `
|
||||
),
|
||||
placeholder: () =>
|
||||
`${isMulti ? "py-[0.22rem]" : "leading-7"} text-mineshaft-400 text-sm pl-1`,
|
||||
input: () => "pl-1",
|
||||
valueContainer: () =>
|
||||
`px-1 max-h-[8.2rem] ${
|
||||
isMulti ? "!overflow-y-auto thin-scrollbar py-1" : "py-[0.1rem]"
|
||||
} gap-1`,
|
||||
singleValue: () => "leading-7 ml-1",
|
||||
multiValue: () => "bg-mineshaft-600 text-sm rounded items-center py-0.5 px-2 gap-1.5",
|
||||
multiValueLabel: () => "leading-6 text-sm",
|
||||
multiValueRemove: () => "hover:text-red text-bunker-400",
|
||||
indicatorsContainer: () => "p-1 gap-1",
|
||||
clearIndicator: () => "p-1 hover:text-red text-bunker-400",
|
||||
indicatorSeparator: () => "bg-bunker-400",
|
||||
dropdownIndicator: () => "text-bunker-200 p-1",
|
||||
menuList: () => "flex flex-col gap-1",
|
||||
menu: () =>
|
||||
"my-2 p-2 border text-sm text-mineshaft-200 thin-scrollbar bg-mineshaft-900 border-mineshaft-600 rounded-md",
|
||||
groupHeading: () => "ml-3 mt-2 mb-1 text-mineshaft-400 text-sm",
|
||||
option: ({ isFocused, isSelected }) =>
|
||||
twMerge(
|
||||
isFocused && "bg-mineshaft-700 active:bg-mineshaft-600",
|
||||
isSelected && "text-mineshaft-200",
|
||||
"rounded px-3 py-2 text-xs hover:cursor-pointer"
|
||||
),
|
||||
noOptionsMessage: () => "text-mineshaft-400 p-2 rounded-md"
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
ClearIndicatorProps,
|
||||
components,
|
||||
DropdownIndicatorProps,
|
||||
GroupProps,
|
||||
MultiValueRemoveProps,
|
||||
OptionProps
|
||||
} from "react-select";
|
||||
@@ -45,3 +46,7 @@ export const Option = <T,>({ isSelected, children, ...props }: OptionProps<T>) =
|
||||
</components.Option>
|
||||
);
|
||||
};
|
||||
|
||||
export const Group = <T,>(props: GroupProps<T>) => {
|
||||
return <components.Group {...props} />;
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
useGetUserWorkspaces
|
||||
} from "@app/hooks/api";
|
||||
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
||||
import { ProjectVersion } from "@app/hooks/api/workspace/types";
|
||||
import { ProjectType, ProjectVersion } from "@app/hooks/api/workspace/types";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
import { OrgInviteLink } from "./OrgInviteLink";
|
||||
@@ -168,6 +168,21 @@ export const AddOrgMemberModal = ({
|
||||
reset();
|
||||
};
|
||||
|
||||
const getGroupHeaderLabel = (type: ProjectType) => {
|
||||
switch (type) {
|
||||
case ProjectType.SecretManager:
|
||||
return "Secrets";
|
||||
case ProjectType.CertificateManager:
|
||||
return "PKI";
|
||||
case ProjectType.KMS:
|
||||
return "KMS";
|
||||
case ProjectType.SSH:
|
||||
return "SSH";
|
||||
default:
|
||||
return "Other";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.addMember?.isOpen}
|
||||
@@ -247,6 +262,8 @@ export const AddOrgMemberModal = ({
|
||||
getOptionLabel={(project) => project.name}
|
||||
getOptionValue={(project) => project.id}
|
||||
options={projects}
|
||||
groupBy="type"
|
||||
getGroupHeaderLabel={getGroupHeaderLabel}
|
||||
placeholder="Select projects..."
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
Reference in New Issue
Block a user