mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 00:27:30 +00:00
Add integration auth revocation
This commit is contained in:
@@ -5,7 +5,7 @@ import { readFileSync } from 'fs';
|
|||||||
import { IntegrationAuth, Integration } from '../models';
|
import { IntegrationAuth, Integration } from '../models';
|
||||||
import { INTEGRATION_SET, ENV_DEV } from '../variables';
|
import { INTEGRATION_SET, ENV_DEV } from '../variables';
|
||||||
import { IntegrationService } from '../services';
|
import { IntegrationService } from '../services';
|
||||||
import { getApps } from '../integrations';
|
import { getApps, revokeAccess } from '../integrations';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform OAuth2 code-token exchange as part of integration [integration] for workspace with id [workspaceId]
|
* Perform OAuth2 code-token exchange as part of integration [integration] for workspace with id [workspaceId]
|
||||||
@@ -74,46 +74,22 @@ export const getIntegrationAuthApps = async (req: Request, res: Response) => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const deleteIntegrationAuth = async (req: Request, res: Response) => {
|
export const deleteIntegrationAuth = async (req: Request, res: Response) => {
|
||||||
// TODO: unfinished - disable application via Heroku API and make compatible with other integration types
|
|
||||||
try {
|
try {
|
||||||
const { integrationAuthId } = req.params;
|
const { integrationAuthId } = req.params;
|
||||||
|
|
||||||
// TODO: disable application via Heroku API; figure out what authorization id is
|
await revokeAccess({
|
||||||
|
integrationAuth: req.integrationAuth,
|
||||||
const integrations = JSON.parse(
|
accessToken: req.accessToken
|
||||||
readFileSync('./src/json/integrations.json').toString()
|
|
||||||
);
|
|
||||||
|
|
||||||
let authorizationId;
|
|
||||||
switch (req.integrationAuth.integration) {
|
|
||||||
case 'heroku':
|
|
||||||
authorizationId = integrations.heroku.clientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// not sure what authorizationId is?
|
|
||||||
// // revoke authorization
|
|
||||||
// const res2 = await axios.delete(
|
|
||||||
// `https://api.heroku.com/oauth/authorizations/${authorizationId}`,
|
|
||||||
// {
|
|
||||||
// headers: {
|
|
||||||
// 'Accept': 'application/vnd.heroku+json; version=3',
|
|
||||||
// 'Authorization': 'Bearer ' + req.accessToken
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
const deletedIntegrationAuth = await IntegrationAuth.findOneAndDelete({
|
|
||||||
_id: integrationAuthId
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (deletedIntegrationAuth) {
|
|
||||||
await Integration.deleteMany({
|
|
||||||
integrationAuth: deletedIntegrationAuth._id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
Sentry.setUser(null);
|
||||||
|
Sentry.captureException(err);
|
||||||
return res.status(400).send({
|
return res.status(400).send({
|
||||||
message: 'Failed to delete integration authorization'
|
message: 'Failed to delete integration authorization'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
return res.status(200).send({
|
||||||
|
message: 'Successfully deleted integration authorization'
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -2,10 +2,12 @@ import { exchangeCode } from './exchange';
|
|||||||
import { exchangeRefresh } from './refresh';
|
import { exchangeRefresh } from './refresh';
|
||||||
import { getApps } from './apps';
|
import { getApps } from './apps';
|
||||||
import { syncSecrets } from './sync';
|
import { syncSecrets } from './sync';
|
||||||
|
import { revokeAccess } from './revoke';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
exchangeCode,
|
exchangeCode,
|
||||||
exchangeRefresh,
|
exchangeRefresh,
|
||||||
getApps,
|
getApps,
|
||||||
syncSecrets
|
syncSecrets,
|
||||||
|
revokeAccess
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import * as Sentry from '@sentry/node';
|
||||||
|
import {
|
||||||
|
IIntegrationAuth,
|
||||||
|
IntegrationAuth,
|
||||||
|
Integration
|
||||||
|
} from '../models';
|
||||||
|
import {
|
||||||
|
INTEGRATION_HEROKU,
|
||||||
|
INTEGRATION_VERCEL,
|
||||||
|
INTEGRATION_NETLIFY
|
||||||
|
} from '../variables';
|
||||||
|
|
||||||
|
const revokeAccess = async ({
|
||||||
|
integrationAuth,
|
||||||
|
accessToken
|
||||||
|
}: {
|
||||||
|
integrationAuth: IIntegrationAuth,
|
||||||
|
accessToken: String
|
||||||
|
}) => {
|
||||||
|
try {
|
||||||
|
// add any integration-specific revocation logic
|
||||||
|
switch (integrationAuth.integration) {
|
||||||
|
case INTEGRATION_HEROKU:
|
||||||
|
break;
|
||||||
|
case INTEGRATION_VERCEL:
|
||||||
|
break;
|
||||||
|
case INTEGRATION_NETLIFY:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deletedIntegrationAuth = await IntegrationAuth.findOneAndDelete({
|
||||||
|
_id: integrationAuth._id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (deletedIntegrationAuth) {
|
||||||
|
await Integration.deleteMany({
|
||||||
|
integrationAuth: deletedIntegrationAuth._id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
Sentry.setUser(null);
|
||||||
|
Sentry.captureException(err);
|
||||||
|
throw new Error('Failed to delete integration authorization');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
revokeAccess
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import {
|
import {
|
||||||
faCheck,
|
faCheck,
|
||||||
@@ -33,6 +34,7 @@ const CloudIntegration = ({
|
|||||||
integrationOptionPress,
|
integrationOptionPress,
|
||||||
integrationAuths
|
integrationAuths
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
|
const router = useRouter();
|
||||||
return integrationAuths ? (
|
return integrationAuths ? (
|
||||||
<div
|
<div
|
||||||
className={`relative ${
|
className={`relative ${
|
||||||
@@ -74,7 +76,8 @@ const CloudIntegration = ({
|
|||||||
.includes(cloudIntegrationOption.name.toLowerCase()) && (
|
.includes(cloudIntegrationOption.name.toLowerCase()) && (
|
||||||
<div className="absolute group z-50 top-0 right-0 flex flex-row">
|
<div className="absolute group z-50 top-0 right-0 flex flex-row">
|
||||||
<div
|
<div
|
||||||
onClick={() => {
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
deleteIntegrationAuth({
|
deleteIntegrationAuth({
|
||||||
integrationAuthId: integrationAuths
|
integrationAuthId: integrationAuths
|
||||||
.filter(
|
.filter(
|
||||||
|
|||||||
@@ -115,44 +115,24 @@ export default function Integrations() {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const handleIntegrationOption = async ({ integrationOption }) => {
|
const handleIntegrationOption = async ({ integrationOption }) => {
|
||||||
// TODO: modularize and handle switch by slug
|
try {
|
||||||
|
// generate CSRF token for OAuth2 code-token exchange integrations
|
||||||
console.log('handle', integrationOption);
|
const state = crypto.randomBytes(16).toString("hex");
|
||||||
|
localStorage.setItem('latestCSRFToken', state);
|
||||||
// generate CSRF token for OAuth2 code-token exchange integrations
|
|
||||||
const state = crypto.randomBytes(16).toString("hex");
|
switch (integrationOption.name) {
|
||||||
localStorage.setItem('latestCSRFToken', state);
|
case 'Heroku':
|
||||||
|
window.location = `https://id.heroku.com/oauth/authorize?client_id=${integrationOption.clientId}&response_type=code&scope=write-protected&state=${state}`;
|
||||||
switch (integrationOption.name) {
|
break;
|
||||||
case 'Heroku':
|
case 'Vercel':
|
||||||
// console.log('Heroku integration ', integrationOption);
|
window.location = `https://vercel.com/integrations/infisical/new?state=${state}`;
|
||||||
window.location = `https://id.heroku.com/oauth/authorize?client_id=${integrationOption.clientId}&response_type=code&scope=write-protected&state=${state}`;
|
break;
|
||||||
break;
|
case 'Netlify':
|
||||||
case 'Vercel':
|
window.location = `https://app.netlify.com/authorize?client_id=${integrationOption.clientId}&response_type=code&redirect_uri=${integrationOption.redirectURL}&state=${state}`;
|
||||||
window.location = `https://vercel.com/integrations/infisical/new?state=${state}`;
|
break;
|
||||||
break;
|
}
|
||||||
case 'Netlify':
|
} catch (err) {
|
||||||
// window.location = `https://app.netlify.com/authorize?client_id=${integrationOption.clientId}&response_type=token&redirect_uri=${integrationOption.redirectURL}&state=${state}`;
|
console.log(err);
|
||||||
window.location = `https://app.netlify.com/authorize?client_id=${integrationOption.clientId}&response_type=code&redirect_uri=${integrationOption.redirectURL}&state=${state}`;
|
|
||||||
// const res = await axios.post('https://api.netlify.com/api/v1/oauth/tickets' + '?client_id=' + integrationOption.clientId);
|
|
||||||
|
|
||||||
// window.location = `https://app.netlify.com/authorize?client_id=${integrationOption.clientId}&response_type=ticket&redirect_uri=${integrationOption.redirectURL}&state=${state}&ticket=${res.data.id}`;
|
|
||||||
// `https://app.netlify.com/authorize?response_type=ticket&ticket=${ticket.id}`
|
|
||||||
try {
|
|
||||||
// const res = await axios.post('https://api.netlify.com/api/v1/oauth/tickets' + '?client_id=' + integrationOption.clientId);
|
|
||||||
// console.log('res response', res);
|
|
||||||
// const res2 = await axios.get('https://api.netlify.com/api/v1/oauth/tickets/' + res.data.id);
|
|
||||||
// console.log('res2 response', res2);
|
|
||||||
// console.log('ticket_id', res.data.id);
|
|
||||||
// // exchange ticket:
|
|
||||||
// const res3 = await axios.get(`https://api.netlify.com/api/v1/oauth/tickets/${res.data.id}/exchange`);
|
|
||||||
// console.log('res3 response', res3);
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Netlify ', err);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user