mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-16 01:05:40 +00:00
Add org-scoped auth to org-level endpoints, add migration file for org enableAuth field
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import axios, { AxiosError } from "axios";
|
||||
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { request } from "@app/lib/config/request";
|
||||
|
||||
import { TFeatureSet } from "./license-types";
|
||||
|
||||
export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
||||
_id: null,
|
||||
slug: null,
|
||||
tier: -1,
|
||||
workspaceLimit: null,
|
||||
workspacesUsed: 0,
|
||||
memberLimit: null,
|
||||
membersUsed: 0,
|
||||
environmentLimit: null,
|
||||
environmentsUsed: 0,
|
||||
secretVersioning: true,
|
||||
pitRecovery: false,
|
||||
ipAllowlisting: false,
|
||||
rbac: false,
|
||||
customRateLimits: false,
|
||||
customAlerts: false,
|
||||
auditLogs: false,
|
||||
auditLogsRetentionDays: 0,
|
||||
samlSSO: false,
|
||||
status: null,
|
||||
trial_end: null,
|
||||
has_used_trial: true,
|
||||
secretApproval: false,
|
||||
secretRotation: true
|
||||
});
|
||||
|
||||
export const setupLicenceRequestWithStore = (baseURL: string, refreshUrl: string, licenseKey: string) => {
|
||||
let token: string;
|
||||
const licenceReq = axios.create({
|
||||
baseURL,
|
||||
timeout: 35 * 1000
|
||||
// signal: AbortSignal.timeout(60 * 1000)
|
||||
});
|
||||
|
||||
const refreshLicence = async () => {
|
||||
const appCfg = getConfig();
|
||||
const {
|
||||
data: { token: authToken }
|
||||
} = await request.post<{ token: string }>(
|
||||
refreshUrl,
|
||||
{},
|
||||
{
|
||||
baseURL: appCfg.LICENSE_SERVER_URL,
|
||||
headers: {
|
||||
"X-API-KEY": licenseKey
|
||||
}
|
||||
}
|
||||
);
|
||||
token = authToken;
|
||||
return token;
|
||||
};
|
||||
|
||||
licenceReq.interceptors.request.use(
|
||||
(config) => {
|
||||
if (token && config.headers) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(err) => Promise.reject(err)
|
||||
);
|
||||
|
||||
licenceReq.interceptors.response.use(
|
||||
(response) => response,
|
||||
async (err) => {
|
||||
const originalRequest = (err as AxiosError).config;
|
||||
|
||||
// eslint-disable-next-line
|
||||
if ((err as AxiosError)?.response?.status === 401 && !(originalRequest as any)._retry) {
|
||||
// eslint-disable-next-line
|
||||
(originalRequest as any)._retry = true; // injected
|
||||
|
||||
// refresh
|
||||
await refreshLicence();
|
||||
|
||||
licenceReq.defaults.headers.common.Authorization = `Bearer ${token}`;
|
||||
return licenceReq(originalRequest!);
|
||||
}
|
||||
|
||||
return Promise.reject(err);
|
||||
}
|
||||
);
|
||||
|
||||
return { request: licenceReq, refreshLicence };
|
||||
};
|
||||
@@ -0,0 +1,508 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
// eslint-disable @typescript-eslint/no-unsafe-assignment
|
||||
|
||||
// TODO(akhilmhdh): With tony find out the api structure and fill it here
|
||||
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
import NodeCache from "node-cache";
|
||||
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
||||
|
||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
||||
import { getDefaultOnPremFeatures, setupLicenceRequestWithStore } from "./licence-fns";
|
||||
import { TLicenseDALFactory } from "./license-dal";
|
||||
import {
|
||||
InstanceType,
|
||||
TAddOrgPmtMethodDTO,
|
||||
TAddOrgTaxIdDTO,
|
||||
TCreateOrgPortalSession,
|
||||
TDelOrgPmtMethodDTO,
|
||||
TDelOrgTaxIdDTO,
|
||||
TFeatureSet,
|
||||
TGetOrgBillInfoDTO,
|
||||
TGetOrgTaxIdDTO,
|
||||
TOrgInvoiceDTO,
|
||||
TOrgLicensesDTO,
|
||||
TOrgPlanDTO,
|
||||
TOrgPlansTableDTO,
|
||||
TOrgPmtMethodsDTO,
|
||||
TStartOrgTrialDTO,
|
||||
TUpdateOrgBillingDetailsDTO
|
||||
} from "./license-types";
|
||||
|
||||
type TLicenseServiceFactoryDep = {
|
||||
orgDAL: Pick<TOrgDALFactory, "findOrgById">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||
licenseDAL: TLicenseDALFactory;
|
||||
};
|
||||
|
||||
export type TLicenseServiceFactory = ReturnType<typeof licenseServiceFactory>;
|
||||
|
||||
const LICENSE_SERVER_CLOUD_LOGIN = "/api/auth/v1/license-server-login";
|
||||
const LICENSE_SERVER_ON_PREM_LOGIN = "/api/auth/v1/licence-login";
|
||||
|
||||
const FEATURE_CACHE_KEY = (orgId: string, projectId?: string) => `${orgId}-${projectId || ""}`;
|
||||
export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }: TLicenseServiceFactoryDep) => {
|
||||
let isValidLicense = false;
|
||||
let instanceType = InstanceType.OnPrem;
|
||||
let onPremFeatures: TFeatureSet = getDefaultOnPremFeatures();
|
||||
const featureStore = new NodeCache({ stdTTL: 60 });
|
||||
|
||||
const appCfg = getConfig();
|
||||
const licenseServerCloudApi = setupLicenceRequestWithStore(
|
||||
appCfg.LICENSE_SERVER_URL || "",
|
||||
LICENSE_SERVER_CLOUD_LOGIN,
|
||||
appCfg.LICENSE_SERVER_KEY || ""
|
||||
);
|
||||
|
||||
const licenseServerOnPremApi = setupLicenceRequestWithStore(
|
||||
appCfg.LICENSE_SERVER_URL || "",
|
||||
LICENSE_SERVER_ON_PREM_LOGIN,
|
||||
appCfg.LICENSE_KEY || ""
|
||||
);
|
||||
|
||||
const init = async () => {
|
||||
try {
|
||||
if (appCfg.LICENSE_SERVER_KEY) {
|
||||
const token = await licenseServerCloudApi.refreshLicence();
|
||||
if (token) instanceType = InstanceType.Cloud;
|
||||
logger.info(`Instance type: ${InstanceType.Cloud}`);
|
||||
isValidLicense = true;
|
||||
return;
|
||||
}
|
||||
if (appCfg.LICENSE_KEY) {
|
||||
const token = await licenseServerOnPremApi.refreshLicence();
|
||||
if (token) {
|
||||
const {
|
||||
data: { currentPlan }
|
||||
} = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>("/api/license/v1/plan");
|
||||
onPremFeatures = currentPlan;
|
||||
instanceType = InstanceType.EnterpriseOnPrem;
|
||||
logger.info(`Instance type: ${InstanceType.EnterpriseOnPrem}`);
|
||||
isValidLicense = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// this means this is self hosted oss version
|
||||
// else it would reach catch statement
|
||||
isValidLicense = true;
|
||||
} catch (error) {
|
||||
logger.error(`init-license: encountered an error when init license [error]`, error);
|
||||
}
|
||||
};
|
||||
|
||||
const getPlan = async (orgId: string, projectId?: string) => {
|
||||
logger.info(`getPlan: attempting to fetch plan for [orgId=${orgId}] [projectId=${projectId}]`);
|
||||
try {
|
||||
if (instanceType === InstanceType.Cloud) {
|
||||
const cachedPlan = featureStore.get<TFeatureSet>(FEATURE_CACHE_KEY(orgId, projectId));
|
||||
if (cachedPlan) return cachedPlan;
|
||||
|
||||
const org = await orgDAL.findOrgById(orgId);
|
||||
if (!org) throw new BadRequestError({ message: "Org not found" });
|
||||
const {
|
||||
data: { currentPlan }
|
||||
} = await licenseServerCloudApi.request.get<{ currentPlan: TFeatureSet }>(
|
||||
`/api/license-server/v1/customers/${org.customerId}/cloud-plan`,
|
||||
{
|
||||
params: {
|
||||
workspaceId: projectId
|
||||
}
|
||||
}
|
||||
);
|
||||
featureStore.set(FEATURE_CACHE_KEY(org.id, projectId), currentPlan);
|
||||
return currentPlan;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`getPlan: encountered an error when fetching pan [orgId=${orgId}] [projectId=${projectId}] [error]`,
|
||||
error
|
||||
);
|
||||
return onPremFeatures;
|
||||
}
|
||||
return onPremFeatures;
|
||||
};
|
||||
|
||||
const refreshPlan = async (orgId: string, projectId?: string) => {
|
||||
if (instanceType === InstanceType.Cloud) {
|
||||
featureStore.del(FEATURE_CACHE_KEY(orgId, projectId));
|
||||
await getPlan(orgId, projectId);
|
||||
}
|
||||
};
|
||||
|
||||
const generateOrgCustomerId = async (orgName: string, email: string) => {
|
||||
if (instanceType === InstanceType.Cloud) {
|
||||
const {
|
||||
data: { customerId }
|
||||
} = await licenseServerCloudApi.request.post<{ customerId: string }>(
|
||||
"/api/license-server/v1/customers",
|
||||
{
|
||||
email,
|
||||
name: orgName
|
||||
},
|
||||
{ timeout: 5000, signal: AbortSignal.timeout(5000) }
|
||||
);
|
||||
return customerId;
|
||||
}
|
||||
};
|
||||
|
||||
const removeOrgCustomer = async (customerId: string) => {
|
||||
await licenseServerCloudApi.request.delete(`/api/license-server/v1/customers/${customerId}`);
|
||||
};
|
||||
|
||||
const updateSubscriptionOrgMemberCount = async (orgId: string) => {
|
||||
if (instanceType === InstanceType.Cloud) {
|
||||
const org = await orgDAL.findOrgById(orgId);
|
||||
if (!org) throw new BadRequestError({ message: "Org not found" });
|
||||
|
||||
const count = await licenseDAL.countOfOrgMembers(orgId);
|
||||
if (org?.customerId) {
|
||||
await licenseServerCloudApi.request.patch(`/api/license-server/v1/customers/${org.customerId}/cloud-plan`, {
|
||||
quantity: count
|
||||
});
|
||||
}
|
||||
featureStore.del(orgId);
|
||||
} else if (instanceType === InstanceType.EnterpriseOnPrem) {
|
||||
const usedSeats = await licenseDAL.countOfOrgMembers(null);
|
||||
await licenseServerOnPremApi.request.patch(`/api/license/v1/license`, { usedSeats });
|
||||
}
|
||||
await refreshPlan(orgId);
|
||||
};
|
||||
|
||||
// below all are api calls
|
||||
const getOrgPlansTableByBillCycle = async ({ orgId, actor, actorId, actorOrgScope, billingCycle }: TOrgPlansTableDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
const { data } = await licenseServerCloudApi.request.get(
|
||||
`/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
const getOrgPlan = async ({ orgId, actor, actorId, actorOrgScope, projectId }: TOrgPlanDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
const plan = await getPlan(orgId, projectId);
|
||||
return plan;
|
||||
};
|
||||
|
||||
const startOrgTrial = async ({ orgId, actorId, actor, actorOrgScope, success_url }: TStartOrgTrialDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
|
||||
const {
|
||||
data: { url }
|
||||
} = await licenseServerCloudApi.request.post(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/session/trial`,
|
||||
{ success_url }
|
||||
);
|
||||
featureStore.del(FEATURE_CACHE_KEY(orgId));
|
||||
return { url };
|
||||
};
|
||||
|
||||
const createOrganizationPortalSession = async ({ orgId, actorId, actor, actorOrgScope }: TCreateOrgPortalSession) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
|
||||
const {
|
||||
data: { pmtMethods }
|
||||
} = await licenseServerCloudApi.request.get<{ pmtMethods: string[] }>(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods`
|
||||
);
|
||||
|
||||
if (pmtMethods.length < 1) {
|
||||
// case: organization has no payment method on file
|
||||
// -> redirect to add payment method portal
|
||||
const {
|
||||
data: { url }
|
||||
} = await licenseServerCloudApi.request.post(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods`,
|
||||
{
|
||||
success_url: `${appCfg.SITE_URL}/dashboard`,
|
||||
cancel_url: `${appCfg.SITE_URL}/dashboard`
|
||||
}
|
||||
);
|
||||
|
||||
return { url };
|
||||
}
|
||||
// case: organization has payment method on file
|
||||
// -> redirect to billing portal
|
||||
const {
|
||||
data: { url }
|
||||
} = await licenseServerCloudApi.request.post(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/billing-portal`,
|
||||
{
|
||||
return_url: `${appCfg.SITE_URL}/dashboard`
|
||||
}
|
||||
);
|
||||
|
||||
return { url };
|
||||
};
|
||||
|
||||
const getOrgBillingInfo = async ({ orgId, actor, actorId, actorOrgScope }: TGetOrgBillInfoDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
const { data } = await licenseServerCloudApi.request.get(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/cloud-plan/billing`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
// returns org current plan feature table
|
||||
const getOrgPlanTable = async ({ orgId, actor, actorId, actorOrgScope }: TGetOrgBillInfoDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
const { data } = await licenseServerCloudApi.request.get(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/cloud-plan/table`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
const getOrgBillingDetails = async ({ orgId, actor, actorId, actorOrgScope }: TGetOrgBillInfoDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
|
||||
const { data } = await licenseServerCloudApi.request.get(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
const updateOrgBillingDetails = async ({ actorId, actor, actorOrgScope, orgId, name, email }: TUpdateOrgBillingDetailsDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
const { data } = await licenseServerCloudApi.request.patch(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details`,
|
||||
{
|
||||
name,
|
||||
email
|
||||
}
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
const getOrgPmtMethods = async ({ orgId, actor, actorId, actorOrgScope }: TOrgPmtMethodsDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
|
||||
const {
|
||||
data: { pmtMethods }
|
||||
} = await licenseServerCloudApi.request.get(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods`
|
||||
);
|
||||
return pmtMethods;
|
||||
};
|
||||
|
||||
const addOrgPmtMethods = async ({ orgId, actor, actorId, actorOrgScope, success_url, cancel_url }: TAddOrgPmtMethodDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
const {
|
||||
data: { url }
|
||||
} = await licenseServerCloudApi.request.post(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods`,
|
||||
{
|
||||
success_url,
|
||||
cancel_url
|
||||
}
|
||||
);
|
||||
return { url };
|
||||
};
|
||||
|
||||
const delOrgPmtMethods = async ({ actorId, actor, actorOrgScope, orgId, pmtMethodId }: TDelOrgPmtMethodDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
|
||||
const { data } = await licenseServerCloudApi.request.delete(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods/${pmtMethodId}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
const getOrgTaxIds = async ({ orgId, actor, actorId, actorOrgScope }: TGetOrgTaxIdDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
const {
|
||||
data: { tax_ids: taxIds }
|
||||
} = await licenseServerCloudApi.request.get(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/tax-ids`
|
||||
);
|
||||
return taxIds;
|
||||
};
|
||||
|
||||
const addOrgTaxId = async ({ actorId, actor, actorOrgScope, orgId, type, value }: TAddOrgTaxIdDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
|
||||
const { data } = await licenseServerCloudApi.request.post(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/tax-ids`,
|
||||
{
|
||||
type,
|
||||
value
|
||||
}
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
const delOrgTaxId = async ({ orgId, actor, actorId, actorOrgScope, taxId }: TDelOrgTaxIdDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
|
||||
const { data } = await licenseServerCloudApi.request.delete(
|
||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/tax-ids/${taxId}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
const getOrgTaxInvoices = async ({ actorId, actor, actorOrgScope, orgId }: TOrgInvoiceDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
|
||||
const {
|
||||
data: { invoices }
|
||||
} = await licenseServerCloudApi.request.get(`/api/license-server/v1/customers/${organization.customerId}/invoices`);
|
||||
return invoices;
|
||||
};
|
||||
|
||||
const getOrgLicenses = async ({ orgId, actor, actorId, actorOrgScope }: TOrgLicensesDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) {
|
||||
throw new BadRequestError({
|
||||
message: "Failed to find organization"
|
||||
});
|
||||
}
|
||||
|
||||
const {
|
||||
data: { licenses }
|
||||
} = await licenseServerCloudApi.request.get(`/api/license-server/v1/customers/${organization.customerId}/licenses`);
|
||||
return licenses;
|
||||
};
|
||||
|
||||
return {
|
||||
generateOrgCustomerId,
|
||||
removeOrgCustomer,
|
||||
init,
|
||||
get isValidLicense() {
|
||||
return isValidLicense;
|
||||
},
|
||||
getPlan,
|
||||
updateSubscriptionOrgMemberCount,
|
||||
refreshPlan,
|
||||
getOrgPlan,
|
||||
getOrgPlansTableByBillCycle,
|
||||
startOrgTrial,
|
||||
createOrganizationPortalSession,
|
||||
getOrgBillingInfo,
|
||||
getOrgPlanTable,
|
||||
getOrgBillingDetails,
|
||||
updateOrgBillingDetails,
|
||||
addOrgPmtMethods,
|
||||
delOrgPmtMethods,
|
||||
getOrgPmtMethods,
|
||||
getOrgLicenses,
|
||||
getOrgTaxInvoices,
|
||||
getOrgTaxIds,
|
||||
addOrgTaxId,
|
||||
delOrgTaxId
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
import { TOrgPermission } from "@app/lib/types";
|
||||
|
||||
export enum InstanceType {
|
||||
OnPrem = "self-hosted",
|
||||
EnterpriseOnPrem = "enterprise-self-hosted",
|
||||
Cloud = "cloud"
|
||||
}
|
||||
|
||||
export type TFeatureSet = {
|
||||
_id: null;
|
||||
slug: null;
|
||||
tier: -1;
|
||||
workspaceLimit: null;
|
||||
workspacesUsed: 0;
|
||||
memberLimit: null;
|
||||
membersUsed: 0;
|
||||
environmentLimit: null;
|
||||
environmentsUsed: 0;
|
||||
secretVersioning: true;
|
||||
pitRecovery: false;
|
||||
ipAllowlisting: false;
|
||||
rbac: false;
|
||||
customRateLimits: false;
|
||||
customAlerts: false;
|
||||
auditLogs: false;
|
||||
auditLogsRetentionDays: 0;
|
||||
samlSSO: false;
|
||||
status: null;
|
||||
trial_end: null;
|
||||
has_used_trial: true;
|
||||
secretApproval: false;
|
||||
secretRotation: true;
|
||||
};
|
||||
|
||||
export type TOrgPlansTableDTO = {
|
||||
billingCycle: string;
|
||||
} & TOrgPermission;
|
||||
|
||||
export type TOrgPlanDTO = {
|
||||
projectId?: string;
|
||||
} & TOrgPermission;
|
||||
|
||||
export type TStartOrgTrialDTO = {
|
||||
success_url: string;
|
||||
} & TOrgPermission;
|
||||
|
||||
export type TCreateOrgPortalSession = TOrgPermission;
|
||||
|
||||
export type TGetOrgBillInfoDTO = TOrgPermission;
|
||||
|
||||
export type TOrgPlanTableDTO = TOrgPermission;
|
||||
|
||||
export type TOrgBillingDetailsDTO = TOrgPermission;
|
||||
|
||||
export type TUpdateOrgBillingDetailsDTO = TOrgPermission & {
|
||||
name?: string;
|
||||
email?: string;
|
||||
};
|
||||
|
||||
export type TOrgPmtMethodsDTO = TOrgPermission;
|
||||
|
||||
export type TAddOrgPmtMethodDTO = TOrgPermission & { success_url: string; cancel_url: string };
|
||||
|
||||
export type TDelOrgPmtMethodDTO = TOrgPermission & { pmtMethodId: string };
|
||||
|
||||
export type TGetOrgTaxIdDTO = TOrgPermission;
|
||||
|
||||
export type TAddOrgTaxIdDTO = TOrgPermission & { type: string; value: string };
|
||||
|
||||
export type TDelOrgTaxIdDTO = TOrgPermission & { taxId: string };
|
||||
|
||||
export type TOrgInvoiceDTO = TOrgPermission;
|
||||
|
||||
export type TOrgLicensesDTO = TOrgPermission;
|
||||
Reference in New Issue
Block a user