mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 18:28:27 +00:00
Finish v1 Azure Key Vault integration
This commit is contained in:
@@ -199,13 +199,13 @@ const Layout = ({ children }: LayoutProps) => {
|
||||
.split('/')
|
||||
[router.asPath.split('/').length - 1].split('?')[0];
|
||||
|
||||
if (!['heroku', 'vercel', 'github', 'netlify'].includes(intendedWorkspaceId)) {
|
||||
if (!['heroku', 'vercel', 'github', 'netlify', 'azure-key-vault'].includes(intendedWorkspaceId)) {
|
||||
localStorage.setItem('projectData.id', intendedWorkspaceId);
|
||||
}
|
||||
|
||||
// If a user is not a member of a workspace they are trying to access, just push them to one of theirs
|
||||
if (
|
||||
!['heroku', 'vercel', 'github', 'netlify'].includes(intendedWorkspaceId) &&
|
||||
!['heroku', 'vercel', 'github', 'netlify', 'azure-key-vault'].includes(intendedWorkspaceId) &&
|
||||
!userWorkspaces
|
||||
.map((workspace: { _id: string }) => workspace._id)
|
||||
.includes(intendedWorkspaceId)
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useRouter } from 'next/router';
|
||||
import { faArrowRight, faRotate, faX } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
// TODO: This needs to be moved from public folder
|
||||
import { contextNetlifyMapping, reverseContextNetlifyMapping } from 'public/data/frequentConstants';
|
||||
import { contextNetlifyMapping, integrationSlugNameMapping, reverseContextNetlifyMapping } from 'public/data/frequentConstants';
|
||||
|
||||
import Button from '@app/components/basic/buttons/Button';
|
||||
import ListBox from '@app/components/basic/Listbox';
|
||||
@@ -52,6 +52,7 @@ const IntegrationTile = ({
|
||||
environments = [],
|
||||
handleDeleteIntegration
|
||||
}: Props) => {
|
||||
|
||||
// set initial environment. This find will only execute when component is mounting
|
||||
const [integrationEnvironment, setIntegrationEnvironment] = useState<Props['environments'][0]>(
|
||||
environments.find(({ slug }) => slug === integration.environment) || {
|
||||
@@ -72,7 +73,14 @@ const IntegrationTile = ({
|
||||
});
|
||||
|
||||
setApps(tempApps);
|
||||
setIntegrationApp(integration.app ? integration.app : tempApps[0].name);
|
||||
|
||||
if (integration?.app) {
|
||||
setIntegrationApp(integration.app);
|
||||
} else if (tempApps.length > 0) {
|
||||
setIntegrationApp(tempApps[0].name)
|
||||
} else {
|
||||
setIntegrationApp('');
|
||||
}
|
||||
|
||||
switch (integration.integration) {
|
||||
case 'vercel':
|
||||
@@ -174,7 +182,7 @@ const IntegrationTile = ({
|
||||
return <div />;
|
||||
};
|
||||
|
||||
if (!integrationApp || apps.length === 0) return <div />;
|
||||
if (!integrationApp) return <div />;
|
||||
|
||||
return (
|
||||
<div className="max-w-5xl p-6 mx-6 mb-8 rounded-md bg-white/5 flex justify-between">
|
||||
@@ -201,7 +209,8 @@ const IntegrationTile = ({
|
||||
<div className="mr-2">
|
||||
<p className="text-gray-400 text-xs font-semibold mb-2">INTEGRATION</p>
|
||||
<div className="py-2.5 bg-white/[.07] rounded-md pl-4 pr-10 text-sm font-semibold text-gray-300">
|
||||
{integration.integration.charAt(0).toUpperCase() + integration.integration.slice(1)}
|
||||
{/* {integration.integration.charAt(0).toUpperCase() + integration.integration.slice(1)} */}
|
||||
{integrationSlugNameMapping[integration.integration]}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mr-2">
|
||||
|
||||
@@ -35,7 +35,7 @@ export const WorkspaceProvider = ({ children }: Props): JSX.Element => {
|
||||
// ws empty means user has no access to the ws
|
||||
// push to the first workspace
|
||||
if (!isLoading && !value?.currentWorkspace?._id) {
|
||||
router.push(`/dashboard/${value.workspaces?.[0]?._id}`);
|
||||
// router.push(`/dashboard/${value.workspaces?.[0]?._id}`);
|
||||
}
|
||||
}, [value?.currentWorkspace?._id, isLoading, value.workspaces?.[0]?._id, router.pathname]);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ const AuthorizeIntegration = ({ workspaceId, code, integration }: Props) =>
|
||||
})
|
||||
}).then(async (res) => {
|
||||
if (res && res.status === 200) {
|
||||
return res;
|
||||
return (res.json());
|
||||
}
|
||||
console.log('Failed to authorize the integration');
|
||||
return undefined;
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../components/v2';
|
||||
import AuthorizeIntegration from './api/integrations/authorizeIntegration';
|
||||
import updateIntegration from './api/integrations/updateIntegration';
|
||||
import getAWorkspace from './api/workspace/getAWorkspace';
|
||||
|
||||
interface Integration {
|
||||
_id: string;
|
||||
isActive: boolean;
|
||||
app: string | null;
|
||||
appId: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
environment: string;
|
||||
integration: string;
|
||||
targetEnvironment: string;
|
||||
workspace: string;
|
||||
integrationAuth: string;
|
||||
}
|
||||
|
||||
export default function AzureKeyVault() {
|
||||
const router = useRouter();
|
||||
|
||||
// query-string variables
|
||||
const parsedUrl = queryString.parse(router.asPath.split('?')[1]);
|
||||
const {code} = parsedUrl;
|
||||
const {state} = parsedUrl;
|
||||
|
||||
const [integration, setIntegration] = useState<Integration | null>(null);
|
||||
const [environments, setEnvironments] = useState<
|
||||
{
|
||||
name: string;
|
||||
slug: string;
|
||||
}[]
|
||||
>([]);
|
||||
const [environment, setEnvironment] = useState('');
|
||||
const [vaultBaseUrl, setVaultBaseUrl] = useState('');
|
||||
const [vaultBaseUrlErrorText, setVaultBaseUrlErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
if (state === localStorage.getItem('latestCSRFToken')) {
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
|
||||
const integrationDetails = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'azure-key-vault',
|
||||
});
|
||||
|
||||
setIntegration(integrationDetails.integration);
|
||||
|
||||
const workspaceId = localStorage.getItem('projectData.id');
|
||||
if (!workspaceId) return;
|
||||
|
||||
const workspace = await getAWorkspace(workspaceId);
|
||||
setEnvironment(workspace.environments[0].slug);
|
||||
setEnvironments(workspace.environments);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Azure Key Vault integration error: ', error);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (vaultBaseUrl.length === 0) {
|
||||
setVaultBaseUrlErrorText('Vault URI cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!vaultBaseUrl.startsWith('https://')
|
||||
|| !vaultBaseUrl.endsWith('vault.azure.net')
|
||||
) {
|
||||
setVaultBaseUrlErrorText('Vault URI must be like https://<vault_name>.vault.azure.net');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!integration) return;
|
||||
|
||||
setIsLoading(true);
|
||||
await updateIntegration({
|
||||
integrationId: integration._id,
|
||||
isActive: true,
|
||||
environment,
|
||||
app: vaultBaseUrl,
|
||||
appId: null,
|
||||
targetEnvironment: null,
|
||||
owner: null
|
||||
});
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
return (integration && environments.length > 0) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Azure Key Vault Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
<Select
|
||||
value={environment}
|
||||
onValueChange={(val) => setEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
>
|
||||
{environments.map((e) => (
|
||||
<SelectItem value={e.slug} key={`azure-key-vault-environment-${e.slug}`}>
|
||||
{e.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Vault URI"
|
||||
errorText={vaultBaseUrlErrorText}
|
||||
isError={vaultBaseUrlErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder='https://example.vault.azure.net'
|
||||
value={vaultBaseUrl}
|
||||
onChange={(e) => setVaultBaseUrl(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
}
|
||||
|
||||
AzureKeyVault.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -25,7 +25,7 @@ export default function Github() {
|
||||
integration: 'github',
|
||||
});
|
||||
router.push(
|
||||
`/integrations/${ localStorage.getItem('projectData.id')}`
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -195,6 +195,11 @@ export default function Integrations() {
|
||||
localStorage.setItem('latestCSRFToken', state);
|
||||
|
||||
switch (integrationOption.slug) {
|
||||
case 'azure-key-vault':
|
||||
window.location.assign(
|
||||
`https://login.microsoftonline.com/${integrationOption.tenantId}/oauth2/v2.0/authorize?client_id=${integrationOption.clientId}&response_type=code&redirect_uri=${window.location.origin}/azure-key-vault&response_mode=query&scope=https://vault.azure.net/.default openid offline_access&state=${state}`
|
||||
);
|
||||
break;
|
||||
case 'heroku':
|
||||
window.location.assign(
|
||||
`https://id.heroku.com/oauth/authorize?client_id=${integrationOption.clientId}&response_type=code&scope=write-protected&state=${state}`
|
||||
@@ -275,10 +280,15 @@ export default function Integrations() {
|
||||
|
||||
// case: integration has been authorized before
|
||||
// -> create new integration
|
||||
const integration = await createIntegration({
|
||||
integrationAuthId: integrationAuthX._id
|
||||
});
|
||||
setIntegrations([...integrations, integration]);
|
||||
|
||||
if (!['azure-key-vault'].includes(integrationOption.slug)) {
|
||||
const integration = await createIntegration({
|
||||
integrationAuthId: integrationAuthX._id
|
||||
});
|
||||
setIntegrations([...integrations, integration]);
|
||||
} else {
|
||||
handleIntegrationOption({ integrationOption });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user