diff --git a/.env.example b/.env.example index b662b7961..989a285e3 100644 --- a/.env.example +++ b/.env.example @@ -47,7 +47,12 @@ SMTP_PASSWORD= # Integration # Optional only if integration is used -OAUTH_CLIENT_SECRET_HEROKU= +CLIENT_ID_HEROKU= +CLIENT_ID_VERCEL= +CLIENT_ID_NETLIFY= +CLIENT_SECRET_HEROKU= +CLIENT_SECRET_VERCEL= +CLIENT_SECRET_NETLIFY= # Sentry (optional) for monitoring errors SENTRY_DSN= diff --git a/backend/environment.d.ts b/backend/environment.d.ts index 33827fb2b..853f52e5b 100644 --- a/backend/environment.d.ts +++ b/backend/environment.d.ts @@ -14,8 +14,12 @@ declare global { JWT_SIGNUP_SECRET: string; MONGO_URL: string; NODE_ENV: 'development' | 'staging' | 'testing' | 'production'; - OAUTH_CLIENT_SECRET_HEROKU: string; - OAUTH_TOKEN_URL_HEROKU: string; + CLIENT_ID_HEROKU: string; + CLIENT_ID_VERCEL: string; + CLIENT_ID_NETLIFY: string; + CLIENT_SECRET_HEROKU: string; + CLIENT_SECRET_VERCEL: string; + CLIENT_SECRET_NETLIFY: string; POSTHOG_HOST: string; POSTHOG_PROJECT_API_KEY: string; PRIVATE_KEY: string; diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index ea5f653a3..7c23bee4a 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,7 +10,7 @@ const JWT_SIGNUP_LIFETIME = process.env.JWT_SIGNUP_LIFETIME! || '15m'; const JWT_SIGNUP_SECRET = process.env.JWT_SIGNUP_SECRET!; const MONGO_URL = process.env.MONGO_URL!; const NODE_ENV = process.env.NODE_ENV! || 'production'; -const OAUTH_CLIENT_SECRET_HEROKU = process.env.OAUTH_CLIENT_SECRET_HEROKU!; +const CLIENT_SECRET_HEROKU = process.env.CLIENT_SECRET_HEROKU!; const CLIENT_ID_VERCEL = process.env.CLIENT_ID_VERCEL!; const CLIENT_ID_NETLIFY = process.env.CLIENT_ID_NETLIFY!; const CLIENT_SECRET_VERCEL = process.env.CLIENT_SECRET_VERCEL!; @@ -49,9 +49,9 @@ export { JWT_SIGNUP_SECRET, MONGO_URL, NODE_ENV, - OAUTH_CLIENT_SECRET_HEROKU, CLIENT_ID_VERCEL, CLIENT_ID_NETLIFY, + CLIENT_SECRET_HEROKU, CLIENT_SECRET_VERCEL, CLIENT_SECRET_NETLIFY, POSTHOG_HOST, diff --git a/backend/src/integrations/exchange.ts b/backend/src/integrations/exchange.ts index 5b7bc71ae..26e6521a1 100644 --- a/backend/src/integrations/exchange.ts +++ b/backend/src/integrations/exchange.ts @@ -11,7 +11,7 @@ import { } from '../variables'; import { SITE_URL, - OAUTH_CLIENT_SECRET_HEROKU, + CLIENT_SECRET_HEROKU, CLIENT_ID_VERCEL, CLIENT_ID_NETLIFY, CLIENT_SECRET_VERCEL, @@ -114,7 +114,7 @@ const exchangeCodeHeroku = async ({ new URLSearchParams({ grant_type: 'authorization_code', code: code, - client_secret: OAUTH_CLIENT_SECRET_HEROKU + client_secret: CLIENT_SECRET_HEROKU } as any) )).data; diff --git a/backend/src/integrations/refresh.ts b/backend/src/integrations/refresh.ts index b19a6a663..16870944d 100644 --- a/backend/src/integrations/refresh.ts +++ b/backend/src/integrations/refresh.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import * as Sentry from '@sentry/node'; import { INTEGRATION_HEROKU } from '../variables'; import { - OAUTH_CLIENT_SECRET_HEROKU + CLIENT_SECRET_HEROKU } from '../config'; import { INTEGRATION_HEROKU_TOKEN_URL @@ -59,7 +59,7 @@ const exchangeRefreshHeroku = async ({ new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken, - client_secret: OAUTH_CLIENT_SECRET_HEROKU + client_secret: CLIENT_SECRET_HEROKU } as any) ); diff --git a/backend/src/middleware/requireIntegrationAuthorizationAuth.ts b/backend/src/middleware/requireIntegrationAuthorizationAuth.ts index 0bf552654..ed44ffec5 100644 --- a/backend/src/middleware/requireIntegrationAuthorizationAuth.ts +++ b/backend/src/middleware/requireIntegrationAuthorizationAuth.ts @@ -10,14 +10,16 @@ import { validateMembership } from '../helpers/membership'; * @param {Object} obj * @param {String[]} obj.acceptedRoles - accepted workspace roles * @param {String[]} obj.acceptedStatuses - accepted workspace statuses - * @param {Boolean} obj.attachRefresh - whether or not to decrypt and attach integration authorization refresh token onto request + * @param {Boolean} obj.attachAccessToken - whether or not to decrypt and attach integration authorization access token onto request */ const requireIntegrationAuthorizationAuth = ({ acceptedRoles, - acceptedStatuses + acceptedStatuses, + attachAccessToken = true }: { acceptedRoles: string[]; acceptedStatuses: string[]; + attachAccessToken?: boolean; }) => { return async (req: Request, res: Response, next: NextFunction) => { try { @@ -41,9 +43,11 @@ const requireIntegrationAuthorizationAuth = ({ }); req.integrationAuth = integrationAuth; - req.accessToken = await IntegrationService.getIntegrationAuthAccess({ - integrationAuthId: integrationAuth._id.toString() - }); + if (attachAccessToken) { + req.accessToken = await IntegrationService.getIntegrationAuthAccess({ + integrationAuthId: integrationAuth._id.toString() + }); + } return next(); } catch (err) { diff --git a/backend/src/routes/integrationAuth.ts b/backend/src/routes/integrationAuth.ts index 650221f82..159d31934 100644 --- a/backend/src/routes/integrationAuth.ts +++ b/backend/src/routes/integrationAuth.ts @@ -42,7 +42,8 @@ router.delete( requireAuth, requireIntegrationAuthorizationAuth({ acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED] + acceptedStatuses: [GRANTED], + attachAccessToken: false }), param('integrationAuthId'), validateRequest, diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 623462d5b..4d6c3fe86 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -51,8 +51,12 @@ services: env_file: .env environment: - NEXT_PUBLIC_ENV=development + - INFISICAL_TELEMETRY_ENABLED=${TELEMETRY_ENABLED} + - NEXT_PUBLIC_SITE_URL=${SITE_URL} - NEXT_PUBLIC_STRIPE_PRODUCT_PRO=${STRIPE_PRODUCT_PRO} - NEXT_PUBLIC_STRIPE_PRODUCT_STARTER=${STRIPE_PRODUCT_STARTER} + - NEXT_PUBLIC_CLIENT_ID_HEROKU=${CLIENT_ID_HEROKU} + - NEXT_PUBLIC_CLIENT_ID_NETLIFY=${CLIENT_ID_NETLIFY} networks: - infisical-dev diff --git a/docker-compose.yml b/docker-compose.yml index bd9022cef..366b512db 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -41,6 +41,9 @@ services: - INFISICAL_TELEMETRY_ENABLED=${TELEMETRY_ENABLED} - NEXT_PUBLIC_STRIPE_PRODUCT_PRO=${STRIPE_PRODUCT_PRO} - NEXT_PUBLIC_STRIPE_PRODUCT_STARTER=${STRIPE_PRODUCT_STARTER} + - NEXT_PUBLIC_SITE_URL=${SITE_URL} + - NEXT_PUBLIC_CLIENT_ID_HEROKU=${CLIENT_ID_HEROKU} + - NEXT_PUBLIC_CLIENT_ID_NETLIFY=${CLIENT_ID_NETLIFY} networks: - infisical diff --git a/docs/self-hosting/configuration/envars.mdx b/docs/self-hosting/configuration/envars.mdx index a55efbebc..9c6697df5 100644 --- a/docs/self-hosting/configuration/envars.mdx +++ b/docs/self-hosting/configuration/envars.mdx @@ -28,6 +28,9 @@ Configuring Infisical requires setting some environment variables. There is a fi | `SMTP_USERNAME` | ❗️ Credential to connect to host (e.g. `team@infisical.com`) | `None` | | `SMTP_PASSWORD` | ❗️ Credential to connect to host | `None` | | `TELEMETRY_ENABLED` | `true` or `false`. [More](../overview). | `true` | -| `OAUTH_CLIENT_SECRET_HEROKU` | OAuth client secret for Heroku integration | `None` | -| `OAUTH_TOKEN_URL_HEROKU` | OAuth token URL for Heroku integration | `None` | +| `CLIENT_ID_VERCEL` | OAuth client id for Vercel integration | `None` | +| `CLIENT_ID_NETLIFY` | OAuth client id for Netlify integration | `None` | +| `CLIENT_SECRET_HEROKU` | OAuth client secret for Heroku integration | `None` | +| `CLIENT_SECRET_VERCEL` | OAuth client secret for Vercel integration | `None` | +| `CLIENT_SECRET_NETLIFY` | OAuth client secret for Netlify integration | `None` | | `SENTRY_DSN` | DSN for error-monitoring with Sentry | `None` | diff --git a/frontend/components/integrations/CloudIntegration.tsx b/frontend/components/integrations/CloudIntegration.tsx index b9bbb08c8..f64268dba 100644 --- a/frontend/components/integrations/CloudIntegration.tsx +++ b/frontend/components/integrations/CloudIntegration.tsx @@ -87,6 +87,7 @@ const CloudIntegration = ({ ) .map((authorization) => authorization._id)[0], }); + router.reload(); }} className="cursor-pointer w-max bg-red py-0.5 px-2 rounded-b-md text-xs flex flex-row items-center opacity-0 group-hover:opacity-100 duration-200" diff --git a/frontend/components/integrations/Integration.tsx b/frontend/components/integrations/Integration.tsx index 8a323336e..d3fe58d65 100644 --- a/frontend/components/integrations/Integration.tsx +++ b/frontend/components/integrations/Integration.tsx @@ -17,8 +17,6 @@ import getIntegrationApps from "../../pages/api/integrations/GetIntegrationApps" import Button from "~/components/basic/buttons/Button"; import ListBox from "~/components/basic/Listbox"; -// TODO: optimize laggy dropdown for app options - interface Integration { app?: string; environment: string; diff --git a/frontend/components/utilities/config/index.ts b/frontend/components/utilities/config/index.ts index d0ffed00c..256c350a8 100644 --- a/frontend/components/utilities/config/index.ts +++ b/frontend/components/utilities/config/index.ts @@ -4,6 +4,9 @@ const POSTHOG_HOST = process.env.NEXT_PUBLIC_POSTHOG_HOST! || "https://app.posthog.com"; const STRIPE_PRODUCT_PRO = process.env.NEXT_PUBLIC_STRIPE_PRODUCT_PRO!; const STRIPE_PRODUCT_STARTER = process.env.NEXT_PUBLIC_STRIPE_PRODUCT_STARTER!; +const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL!; +const CLIENT_ID_HEROKU = process.env.NEXT_PUBLIC_CLIENT_ID_HEROKU!; +const CLIENT_ID_NETLIFY = process.env.NEXT_PUBLIC_CLIENT_ID_NETLIFY!; export { ENV, @@ -11,4 +14,7 @@ export { POSTHOG_HOST, STRIPE_PRODUCT_PRO, STRIPE_PRODUCT_STARTER, -}; + SITE_URL, + CLIENT_ID_HEROKU, + CLIENT_ID_NETLIFY +}; \ No newline at end of file diff --git a/frontend/pages/integrations/[id].js b/frontend/pages/integrations/[id].js index 46aec2220..335fc4d40 100644 --- a/frontend/pages/integrations/[id].js +++ b/frontend/pages/integrations/[id].js @@ -8,7 +8,8 @@ import FrameworkIntegrationSection from "~/components/integrations/FrameworkInte import CloudIntegrationSection from "~/components/integrations/CloudIntegrationSection"; import IntegrationSection from "~/components/integrations/IntegrationSection"; import frameworkIntegrationOptions from "../../public/json/frameworkIntegrations.json"; -import cloudIntegrationOptions from "../../public/json/cloudIntegrations.json"; +// import cloudIntegrationOptions from "../../public/json/cloudIntegrations.json"; +import { cloudIntegrationOptions } from "../../public/data/cloudIntegrations"; import getWorkspaceAuthorizations from "../api/integrations/getWorkspaceAuthorizations"; import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations"; import getBot from "../api/bot/getBot"; @@ -29,7 +30,7 @@ export default function Integrations() { const [integrations, setIntegrations] = useState([]); const [bot, setBot] = useState(null); const [isActivateBotDialogOpen, setIsActivateBotDialogOpen] = useState(false); - const [isIntegrationAccessTokenDialogOpen, setIntegrationAccessTokenDialogOpen] = useState(true); + // const [isIntegrationAccessTokenDialogOpen, setIntegrationAccessTokenDialogOpen] = useState(true); const [selectedIntegrationOption, setSelectedIntegrationOption] = useState(null); const router = useRouter(); @@ -122,22 +123,20 @@ export default function Integrations() { const state = crypto.randomBytes(16).toString("hex"); localStorage.setItem('latestCSRFToken', state); - // TODO: Add CircleCI, Render, Fly.io - switch (integrationOption.name) { case 'Heroku': window.location = `https://id.heroku.com/oauth/authorize?client_id=${integrationOption.clientId}&response_type=code&scope=write-protected&state=${state}`; break; case 'Vercel': - window.location = `https://vercel.com/integrations/infisical/new?state=${state}`; + window.location = `https://vercel.com/integrations/infisical-dev/new?state=${state}`; break; case 'Netlify': - window.location = `https://app.netlify.com/authorize?client_id=${integrationOption.clientId}&response_type=code&redirect_uri=${integrationOption.redirectURL}&state=${state}`; - break; - case 'Fly.io': - console.log('fly.io'); - setIntegrationAccessTokenDialogOpen(true); + window.location = `https://app.netlify.com/authorize?client_id=${integrationOption.clientId}&response_type=code&state=${state}&redirect_uri=${integrationOption.redirectURL}`; break; + // case 'Fly.io': + // console.log('fly.io'); + // setIntegrationAccessTokenDialogOpen(true); + // break; } } catch (err) { console.log(err); @@ -163,7 +162,7 @@ export default function Integrations() { } // case: bot is not active -> open modal to activate bot - setIsActivateBotOpen(true); + setIsActivateBotDialogOpen(true); } catch (err) { console.error(err); } @@ -193,13 +192,13 @@ export default function Integrations() { handleBotActivate={handleBotActivate} handleIntegrationOption={handleIntegrationOption} /> - setIntegrationAccessTokenDialogOpen(false)} selectedIntegrationOption={selectedIntegrationOption} handleBotActivate={handleBotActivate} handleIntegrationOption={handleIntegrationOption} - /> + /> */}