Finish removing Stripe from codebase

pull/677/head
Tuan Dang 11 months ago
parent f3e84dc6eb
commit 28943f3b6f

@ -61,13 +61,6 @@ SENTRY_DSN=
# Ignore - Not applicable for self-hosted version
POSTHOG_HOST=
POSTHOG_PROJECT_API_KEY=
STRIPE_SECRET_KEY=
STRIPE_PUBLISHABLE_KEY=
STRIPE_WEBHOOK_SECRET=
STRIPE_PRODUCT_STARTER=
STRIPE_PRODUCT_TEAM=
STRIPE_PRODUCT_PRO=
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
CLIENT_ID_GOOGLE=
CLIENT_SECRET_GOOGLE=

1
.gitignore vendored

@ -2,6 +2,7 @@
node_modules
.env
.env.dev
.env.gamma
.env.prod
.env.infisical

@ -39,12 +39,6 @@ declare global {
SMTP_PASSWORD: string;
SMTP_FROM_ADDRESS: string;
SMTP_FROM_NAME: string;
STRIPE_PRODUCT_STARTER: string;
STRIPE_PRODUCT_TEAM: string;
STRIPE_PRODUCT_PRO: string;
STRIPE_PUBLISHABLE_KEY: string;
STRIPE_SECRET_KEY: string;
STRIPE_WEBHOOK_SECRET: string;
TELEMETRY_ENABLED: string;
LICENSE_KEY: string;
}

@ -50,7 +50,6 @@
"query-string": "^7.1.3",
"rate-limit-mongo": "^2.3.2",
"rimraf": "^3.0.2",
"stripe": "^10.7.0",
"swagger-autogen": "^2.22.0",
"swagger-ui-express": "^4.6.2",
"tweetnacl": "^1.0.3",
@ -11588,18 +11587,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/stripe": {
"version": "10.17.0",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-10.17.0.tgz",
"integrity": "sha512-JHV2KoL+nMQRXu3m9ervCZZvi4DDCJfzHUE6CmtJxR9TmizyYfrVuhGvnsZLLnheby9Qrnf4Hq6iOEcejGwnGQ==",
"dependencies": {
"@types/node": ">=8.1.0",
"qs": "^6.11.0"
},
"engines": {
"node": "^8.1 || >=10.*"
}
},
"node_modules/strnum": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
@ -21096,15 +21083,6 @@
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true
},
"stripe": {
"version": "10.17.0",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-10.17.0.tgz",
"integrity": "sha512-JHV2KoL+nMQRXu3m9ervCZZvi4DDCJfzHUE6CmtJxR9TmizyYfrVuhGvnsZLLnheby9Qrnf4Hq6iOEcejGwnGQ==",
"requires": {
"@types/node": ">=8.1.0",
"qs": "^6.11.0"
}
},
"strnum": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",

@ -41,7 +41,6 @@
"query-string": "^7.1.3",
"rate-limit-mongo": "^2.3.2",
"rimraf": "^3.0.2",
"stripe": "^10.7.0",
"swagger-autogen": "^2.22.0",
"swagger-ui-express": "^4.6.2",
"tweetnacl": "^1.0.3",

@ -67,14 +67,6 @@ export const getLicenseServerKey = async () => {
}
export const getLicenseServerUrl = async () => (await client.getSecret("LICENSE_SERVER_URL")).secretValue || "https://portal.infisical.com";
// TODO: deprecate from here
export const getStripeProductStarter = async () => (await client.getSecret("STRIPE_PRODUCT_STARTER")).secretValue;
export const getStripeProductPro = async () => (await client.getSecret("STRIPE_PRODUCT_PRO")).secretValue;
export const getStripeProductTeam = async () => (await client.getSecret("STRIPE_PRODUCT_TEAM")).secretValue;
export const getStripePublishableKey = async () => (await client.getSecret("STRIPE_PUBLISHABLE_KEY")).secretValue;
export const getStripeSecretKey = async () => (await client.getSecret("STRIPE_SECRET_KEY")).secretValue;
export const getStripeWebhookSecret = async () => (await client.getSecret("STRIPE_WEBHOOK_SECRET")).secretValue;
export const getTelemetryEnabled = async () => (await client.getSecret("TELEMETRY_ENABLED")).secretValue !== "false" && true;
export const getLoopsApiKey = async () => (await client.getSecret("LOOPS_API_KEY")).secretValue;
export const getSmtpConfigured = async () => (await client.getSecret("SMTP_HOST")).secretValue == "" || (await client.getSecret("SMTP_HOST")).secretValue == undefined ? false : true

@ -10,7 +10,6 @@ import * as passwordController from "./passwordController";
import * as secretController from "./secretController";
import * as serviceTokenController from "./serviceTokenController";
import * as signupController from "./signupController";
import * as stripeController from "./stripeController";
import * as userActionController from "./userActionController";
import * as userController from "./userController";
import * as workspaceController from "./workspaceController";
@ -28,7 +27,6 @@ export {
secretController,
serviceTokenController,
signupController,
stripeController,
userActionController,
userController,
workspaceController,

@ -1,5 +1,4 @@
import { Request, Response } from "express";
import Stripe from "stripe";
import {
IncidentContactOrg,
Membership,
@ -10,7 +9,8 @@ import {
import { createOrganization as create } from "../../helpers/organization";
import { addMembershipsOrg } from "../../helpers/membershipOrg";
import { ACCEPTED, OWNER } from "../../variables";
import { getSiteURL, getStripeSecretKey } from "../../config";
import { getSiteURL, getLicenseServerUrl } from "../../config";
import { licenseServerKeyRequest } from "../../config/request";
export const getOrganizations = async (req: Request, res: Response) => {
const organizations = (
@ -222,7 +222,7 @@ export const deleteOrganizationIncidentContact = async (
};
/**
* Redirect user to (stripe) billing portal or add card page depending on
* Redirect user to billing portal or add card page depending on
* if there is a card on file
* @param req
* @param res
@ -232,34 +232,32 @@ export const createOrganizationPortalSession = async (
req: Request,
res: Response
) => {
let session;
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: "2022-08-01",
});
// check if there is a payment method on file
const paymentMethods = await stripe.paymentMethods.list({
customer: req.organization.customerId,
type: "card",
});
const { data: { pmtMethods } } = await licenseServerKeyRequest.get(
`${await getLicenseServerUrl()}/api/license-server/v1/customers/${req.organization.customerId}/billing-details/payment-methods`,
);
if (paymentMethods.data.length < 1) {
// case: no payment method on file
session = await stripe.checkout.sessions.create({
customer: req.organization.customerId,
mode: "setup",
payment_method_types: ["card"],
success_url: (await getSiteURL()) + "/dashboard",
cancel_url: (await getSiteURL()) + "/dashboard",
});
if (pmtMethods.length < 1) {
// case: organization has no payment method on file
// -> redirect to add payment method portal
const { data: { url } } = await licenseServerKeyRequest.post(
`${await getLicenseServerUrl()}/api/license-server/v1/customers/${req.organization.customerId}/billing-details/payment-methods`,
{
success_url: (await getSiteURL()) + "/dashboard",
cancel_url: (await getSiteURL()) + "/dashboard"
}
);
return res.status(200).send({ url });
} else {
session = await stripe.billingPortal.sessions.create({
customer: req.organization.customerId,
return_url: (await getSiteURL()) + "/dashboard",
});
// case: organization has payment method on file
// -> redirect to billing portal
const { data: { url } } = await licenseServerKeyRequest.post(
`${await getLicenseServerUrl()}/api/license-server/v1/customers/${req.organization.customerId}/billing-details/billing-portal`,
{
return_url: (await getSiteURL()) + "/dashboard"
}
);
return res.status(200).send({ url });
}
return res.status(200).send({ url: session.url });
};
/**
@ -272,16 +270,8 @@ export const getOrganizationSubscriptions = async (
req: Request,
res: Response
) => {
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: "2022-08-01",
});
const subscriptions = await stripe.subscriptions.list({
customer: req.organization.customerId,
});
return res.status(200).send({
subscriptions,
subscriptions: []
});
};

@ -1,31 +0,0 @@
import { Request, Response } from "express";
import Stripe from "stripe";
import { getStripeSecretKey, getStripeWebhookSecret } from "../../config";
/**
* Handle service provisioning/un-provisioning via Stripe
* @param req
* @param res
* @returns
*/
export const handleWebhook = async (req: Request, res: Response) => {
// check request for valid stripe signature
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: "2022-08-01",
});
const sig = req.headers["stripe-signature"] as string;
const event = stripe.webhooks.constructEvent(
req.body,
sig,
await getStripeWebhookSecret()
);
switch (event.type) {
case "":
break;
default:
}
return res.json({ received: true });
};

@ -1,4 +1,3 @@
import * as stripeController from "./stripeController";
import * as secretController from "./secretController";
import * as secretSnapshotController from "./secretSnapshotController";
import * as organizationsController from "./organizationsController";
@ -8,7 +7,6 @@ import * as membershipController from "./membershipController";
import * as cloudProductsController from "./cloudProductsController";
export {
stripeController,
secretController,
secretSnapshotController,
organizationsController,

@ -52,7 +52,7 @@ export const getOrganizationPmtMethods = async (req: Request, res: Response) =>
}
/**
* Return a Stripe session URL to add payment method for organization
* Return URL to add payment method for organization
*/
export const addOrganizationPmtMethod = async (req: Request, res: Response) => {
const {

@ -1,31 +0,0 @@
import { Request, Response } from "express";
import Stripe from "stripe";
import { getStripeSecretKey, getStripeWebhookSecret } from "../../../config";
/**
* Handle service provisioning/un-provisioning via Stripe
* @param req
* @param res
* @returns
*/
export const handleWebhook = async (req: Request, res: Response) => {
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: "2022-08-01",
});
// check request for valid stripe signature
const sig = req.headers["stripe-signature"] as string;
const event = stripe.webhooks.constructEvent(
req.body,
sig,
await getStripeWebhookSecret()
);
switch (event.type) {
case "":
break;
default:
}
return res.json({ received: true });
};

@ -1,7 +0,0 @@
import express from "express";
const router = express.Router();
import { stripeController } from "../../controllers/v1";
router.post("/webhook", stripeController.handleWebhook);
export default router;

@ -83,7 +83,7 @@ class EELicenseService {
if (!organization) throw OrganizationNotFoundError();
let url = `${await getLicenseServerUrl()}/api/license-server/v1/customers/${organization.customerId}/cloud-plan`;
if (workspaceId) {
url += `?workspaceId=${workspaceId}`;
}

@ -1,19 +1,13 @@
import Stripe from "stripe";
import { Types } from "mongoose";
import { MembershipOrg, Organization } from "../models";
import {
ACCEPTED,
} from "../variables";
import {
getStripeProductPro,
getStripeProductStarter,
getStripeProductTeam,
getStripeSecretKey,
} from "../config";
import {
EELicenseService,
} from "../ee/services";
import {
getLicenseServerKey,
getLicenseServerUrl,
} from "../config";
import {
@ -35,21 +29,21 @@ export const createOrganization = async ({
name: string;
email: string;
}) => {
const licenseServerKey = await getLicenseServerKey();
let organization;
// register stripe account
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: "2022-08-01",
});
if (await getStripeSecretKey()) {
const customer = await stripe.customers.create({
email,
description: name,
});
if (licenseServerKey) {
const { data: { customerId } } = await licenseServerKeyRequest.post(
`${await getLicenseServerUrl()}/api/license-server/v1/customers`,
{
email,
name
}
);
organization = await new Organization({
name,
customerId: customer.id,
customerId
}).save();
} else {
organization = await new Organization({
@ -57,68 +51,9 @@ export const createOrganization = async ({
}).save();
}
await initSubscriptionOrg({ organizationId: organization._id });
return organization;
};
/**
* Initialize free-tier subscription for new organization
* @param {Object} obj
* @param {String} obj.organizationId - id of associated organization for subscription
* @return {Object} obj
* @return {Object} obj.stripeSubscription - new stripe subscription
* @return {Subscription} obj.subscription - new subscription
*/
export const initSubscriptionOrg = async ({
organizationId,
}: {
organizationId: Types.ObjectId;
}) => {
let stripeSubscription;
let subscription;
// find organization
const organization = await Organization.findOne({
_id: organizationId,
});
if (organization) {
if (organization.customerId) {
// initialize starter subscription with quantity of 0
const stripe = new Stripe(await getStripeSecretKey(), {
apiVersion: "2022-08-01",
});
const productToPriceMap = {
starter: await getStripeProductStarter(),
team: await getStripeProductTeam(),
pro: await getStripeProductPro(),
};
stripeSubscription = await stripe.subscriptions.create({
customer: organization.customerId,
items: [
{
price: productToPriceMap["starter"],
quantity: 1,
},
],
payment_behavior: "default_incomplete",
proration_behavior: "none",
expand: ["latest_invoice.payment_intent"],
});
}
} else {
throw new Error("Failed to initialize free organization subscription");
}
return {
stripeSubscription,
subscription,
};
};
/**
* Update organization subscription quantity to reflect number of members in
* the organization.
@ -130,7 +65,6 @@ export const updateSubscriptionOrgQuantity = async ({
}: {
organizationId: string;
}) => {
let stripeSubscription;
// find organization
const organization = await Organization.findOne({
_id: organizationId,
@ -171,6 +105,4 @@ export const updateSubscriptionOrgQuantity = async ({
}
await EELicenseService.refreshPlan(organizationId);
return stripeSubscription;
};

@ -37,7 +37,6 @@ import {
secretsFolder as v1SecretsFolder,
serviceToken as v1ServiceTokenRouter,
signup as v1SignupRouter,
stripe as v1StripeRouter,
userAction as v1UserActionRouter,
user as v1UserRouter,
workspace as v1WorkspaceRouter,
@ -123,7 +122,6 @@ const main = async () => {
app.use("/api/v1/secret", v1SecretRouter); // deprecate
app.use("/api/v1/service-token", v1ServiceTokenRouter); // deprecate
app.use("/api/v1/password", v1PasswordRouter);
app.use("/api/v1/stripe", v1StripeRouter);
app.use("/api/v1/integration", v1IntegrationRouter);
app.use("/api/v1/integration-auth", v1IntegrationAuthRouter);
app.use("/api/v1/folders", v1SecretsFolder);

@ -12,7 +12,6 @@ import inviteOrg from "./inviteOrg";
import secret from "./secret";
import serviceToken from "./serviceToken";
import password from "./password";
import stripe from "./stripe";
import integration from "./integration";
import integrationAuth from "./integrationAuth";
import secretsFolder from "./secretsFolder";
@ -32,7 +31,6 @@ export {
secret,
serviceToken,
password,
stripe,
integration,
integrationAuth,
secretsFolder,

@ -1,7 +0,0 @@
import express from "express";
const router = express.Router();
import { stripeController } from "../../controllers/v1";
router.post("/webhook", stripeController.handleWebhook);
export default router;

@ -8,6 +8,5 @@ export * from "./organization";
export * from "./permission";
export * from "./secret";
export * from "./smtp";
export * from "./stripe";
export * from "./token";
export * from "./user";

@ -1,2 +0,0 @@
export const PLAN_STARTER = "starter";
export const PLAN_PRO = "pro";

@ -55,9 +55,6 @@ services:
environment:
- NEXT_PUBLIC_ENV=development
- INFISICAL_TELEMETRY_ENABLED=${TELEMETRY_ENABLED}
- NEXT_PUBLIC_STRIPE_PRODUCT_PRO=${STRIPE_PRODUCT_PRO}
- NEXT_PUBLIC_STRIPE_PRODUCT_TEAM=${STRIPE_PRODUCT_TEAM}
- NEXT_PUBLIC_STRIPE_PRODUCT_STARTER=${STRIPE_PRODUCT_STARTER}
networks:
- infisical-dev

@ -38,9 +38,6 @@ services:
environment:
# - NEXT_PUBLIC_POSTHOG_API_KEY=${POSTHOG_PROJECT_API_KEY}
- INFISICAL_TELEMETRY_ENABLED=${TELEMETRY_ENABLED}
- NEXT_PUBLIC_STRIPE_PRODUCT_PRO=${STRIPE_PRODUCT_PRO}
- NEXT_PUBLIC_STRIPE_PRODUCT_TEAM=${STRIPE_PRODUCT_TEAM}
- NEXT_PUBLIC_STRIPE_PRODUCT_STARTER=${STRIPE_PRODUCT_STARTER}
networks:
- infisical

@ -2,14 +2,11 @@ const ENV = process.env.NEXT_PUBLIC_ENV! || "development"; // investigate
const POSTHOG_API_KEY = process.env.NEXT_PUBLIC_POSTHOG_API_KEY!;
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 INTERCOM_ID = process.env.NEXT_PUBLIC_INTERCOM_ID!;
export {
ENV,
INTERCOM_ID,
POSTHOG_API_KEY,
POSTHOG_HOST,
STRIPE_PRODUCT_PRO,
STRIPE_PRODUCT_STARTER};
POSTHOG_HOST
};

@ -1,16 +1,12 @@
import { useEffect, useState } from "react";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import Head from "next/head";
import Plan from "@app/components/billing/Plan";
import NavHeader from "@app/components/navigation/NavHeader";
import { plans as plansConstant } from "@app/const";
import getOrganizationSubscriptions from "../../api/organization/GetOrgSubscription";
import getOrganizationUsers from "../../api/organization/GetOrgUsers";
import { useSubscription } from "@app/context";
export default function SettingsBilling() {
const [currentPlan, setCurrentPlan] = useState("");
const { subscription } = useSubscription();
const [numUsers, setNumUsers] = useState(0);
const { t } = useTranslation();
@ -25,7 +21,7 @@ export default function SettingsBilling() {
subtext: t("billing.starter.subtext")!,
buttonTextMain: t("billing.downgrade")!,
buttonTextSecondary: t("billing.learn-more")!,
current: currentPlan === plansConstant.starter
current: subscription?.slug === "starter" // subscription.slug?
},
{
key: 2,
@ -35,7 +31,7 @@ export default function SettingsBilling() {
text: "Unlimited members, up to 10 projects. Additional developer experience features.",
buttonTextMain: t("billing.upgrade")!,
buttonTextSecondary: t("billing.learn-more")!,
current: currentPlan === plansConstant.team
current: subscription?.slug === "team" || subscription?.slug === "team-annual"
},
{
key: 3,
@ -46,7 +42,7 @@ export default function SettingsBilling() {
subtext: t("billing.professional.subtext")!,
buttonTextMain: t("billing.upgrade")!,
buttonTextSecondary: t("billing.learn-more")!,
current: currentPlan === plansConstant.professional
current: subscription?.slug === "pro" || subscription?.slug === "pro-annual"
},
{
key: 4,
@ -55,26 +51,10 @@ export default function SettingsBilling() {
text: "Boost the security and efficiency of your engineering teams.",
buttonTextMain: t("billing.schedule-demo")!,
buttonTextSecondary: t("billing.learn-more")!,
current: false
current: subscription?.slug === "enterprise"
}
];
useEffect(() => {
(async () => {
const orgId = localStorage.getItem("orgData.id") as string;
const subscriptions = await getOrganizationSubscriptions({
orgId
});
if (subscriptions) {
setCurrentPlan(subscriptions.data[0].plan.product);
}
const orgUsers = await getOrganizationUsers({
orgId
});
setNumUsers(orgUsers.length);
})();
}, []);
return (
<div className="flex flex-col justify-between bg-bunker-800 pb-4 text-white">
<Head>

@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { plans } from "public/data/frequentConstants";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import NavHeader from "@app/components/navigation/NavHeader";

Loading…
Cancel
Save