Skip to content

Commit

Permalink
Call metadata and get user keys right before license server call (#2634)
Browse files Browse the repository at this point in the history
  • Loading branch information
tzjames committed Jun 12, 2024
1 parent 13cd6f8 commit f8c8288
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 148 deletions.
24 changes: 20 additions & 4 deletions packages/back-end/src/controllers/license.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import crypto from "crypto";
import { Response } from "express";
import {
AccountPlan,
licenseInit,
LicenseServerError,
postCreateTrialEnterpriseLicenseToLicenseServer,
postResendEmailVerificationEmailToLicenseServer,
Expand All @@ -10,7 +11,7 @@ import {
import md5 from "md5";
import {
getLicenseMetaData,
initializeLicenseForOrg,
getUserCodesForOrg,
} from "../services/licenseData";
import { getUserLicenseCodes } from "../services/users";
import { AuthRequest } from "../types/AuthRequest";
Expand Down Expand Up @@ -39,7 +40,12 @@ export async function getLicenseData(req: AuthRequest, res: Response) {

if (req.organization?.licenseKey || process.env.LICENSE_KEY) {
// Force refresh the license data
licenseData = await initializeLicenseForOrg(req.organization, true);
licenseData = await licenseInit(
req.organization,
getUserCodesForOrg,
getLicenseMetaData,
true
);
} else if (req.organization?.subscription) {
// TODO: Get rid of updateSubscriptionInDb one we have moved the license off the organizations
// This is to update the subscription data in the organization from stripe if they have it
Expand Down Expand Up @@ -133,7 +139,12 @@ export async function postCreateTrialEnterpriseLicense(
if (!org.licenseKey) {
await updateOrganization(org.id, { licenseKey: results.licenseId });
} else {
await initializeLicenseForOrg(req.organization, true);
await licenseInit(
req.organization,
getUserCodesForOrg,
getLicenseMetaData,
true
);
}
return res.status(200).json({ status: 200 });
} catch (e) {
Expand Down Expand Up @@ -176,7 +187,12 @@ export async function postVerifyEmail(
await postVerifyEmailToLicenseServer(emailVerificationToken);

// update license info from the license server as if the email was verified then the license data will be changed
await initializeLicenseForOrg(req.organization, true);
await licenseInit(
req.organization,
getUserCodesForOrg,
getLicenseMetaData,
true
);

return res.status(200).json({ status: 200 });
} catch (e) {
Expand Down
10 changes: 7 additions & 3 deletions packages/back-end/src/controllers/stripe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Stripe } from "stripe";
import {
LicenseServerError,
getLicense,
licenseInit,
postCreateBillingSessionToLicenseServer,
postNewProSubscriptionToLicenseServer,
postNewProTrialSubscriptionToLicenseServer,
Expand All @@ -28,7 +29,10 @@ import { SubscriptionQuote } from "../../types/organization";
import { sendStripeTrialWillEndEmail } from "../services/email";
import { logger } from "../util/logger";
import { updateOrganization } from "../models/OrganizationModel";
import { initializeLicenseForOrg } from "../services/licenseData";
import {
getLicenseMetaData,
getUserCodesForOrg,
} from "../services/licenseData";

function withLicenseServerErrorHandling<T>(
fn: (req: AuthRequest<T>, res: Response) => Promise<void>
Expand Down Expand Up @@ -79,7 +83,7 @@ export const postNewProTrialSubscription = withLicenseServerErrorHandling(
if (org.licenseKey !== result.license.id) {
throw new Error("Your organization already has a license key.");
}
await initializeLicenseForOrg(org, true);
await licenseInit(org, getUserCodesForOrg, getLicenseMetaData, true);
}

res.status(200).json(result);
Expand Down Expand Up @@ -228,7 +232,7 @@ export const postSubscriptionSuccess = withLicenseServerErrorHandling(
await updateOrganization(org.id, { licenseKey: result.id });

// update license info from the license server as it will have changed.
await initializeLicenseForOrg(req.organization, true);
await licenseInit(org, getUserCodesForOrg, getLicenseMetaData, true);

res.status(200).json({
status: 200,
Expand Down
8 changes: 6 additions & 2 deletions packages/back-end/src/jobs/updateLicense.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
* void within a week if something is not done to unblock the connection.
*/
import Agenda from "agenda";
import { licenseInit } from "enterprise";
import { getSelfHostedOrganization } from "../models/OrganizationModel";
import { trackJob } from "../services/otel";
import { IS_CLOUD } from "../util/secrets";
import { initializeLicenseForOrg } from "../services/licenseData";
import {
getLicenseMetaData,
getUserCodesForOrg,
} from "../services/licenseData";

const UPDATE_LICENSES_JOB_NAME = "updateLicenses";

Expand All @@ -19,7 +23,7 @@ const updateLicense = trackJob(UPDATE_LICENSES_JOB_NAME, async () => {

const org = await getSelfHostedOrganization();
if (org) {
initializeLicenseForOrg(org);
licenseInit(org, getUserCodesForOrg, getLicenseMetaData);
}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Request, Response, NextFunction } from "express";
import { hasPermission } from "shared/permissions";
import { licenseInit } from "enterprise";
import { ApiRequestLocals } from "../../types/api";
import { lookupOrganizationByApiKey } from "../models/ApiKeyModel";
import { getOrganizationById } from "../services/organizations";
Expand All @@ -15,7 +16,10 @@ import { ApiKeyInterface } from "../../types/apikey";
import { getTeamsForOrganization } from "../models/TeamModel";
import { TeamInterface } from "../../types/team";
import { getUserById } from "../services/users";
import { initializeLicenseForOrg } from "../services/licenseData";
import {
getLicenseMetaData,
getUserCodesForOrg,
} from "../services/licenseData";
import { ReqContextClass } from "../services/context";

export default function authenticateApiRequestMiddleware(
Expand Down Expand Up @@ -167,7 +171,7 @@ export default function authenticateApiRequestMiddleware(
};

// init license for org if it exists
await initializeLicenseForOrg(req.organization);
await licenseInit(org, getUserCodesForOrg, getLicenseMetaData);

// Continue to the actual request handler
next();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getEffectiveAccountPlan,
getLicense,
getLicenseError,
licenseInit,
} from "enterprise";
import { experimentHasLinkedChanges } from "shared/util";
import {
Expand Down Expand Up @@ -123,7 +124,10 @@ import { getTeamsForOrganization } from "../../models/TeamModel";
import { getAllFactTablesForOrganization } from "../../models/FactTableModel";
import { TeamInterface } from "../../../types/team";
import { fireSdkWebhook } from "../../jobs/sdkWebhooks";
import { initializeLicenseForOrg } from "../../services/licenseData";
import {
getLicenseMetaData,
getUserCodesForOrg,
} from "../../services/licenseData";
import { findSDKConnectionsByIds } from "../../models/SdkConnectionModel";

export async function getDefinitions(req: AuthRequest, res: Response) {
Expand Down Expand Up @@ -664,7 +668,11 @@ export async function getOrganization(req: AuthRequest, res: Response) {
license = getLicense(licenseKey || process.env.LICENSE_KEY);
if (!license || (license.organizationId && license.organizationId !== id)) {
try {
license = await initializeLicenseForOrg(org);
license = await licenseInit(
org,
getUserCodesForOrg,
getLicenseMetaData
);
} catch (e) {
// eslint-disable-next-line no-console
console.error("setting license failed", e);
Expand Down Expand Up @@ -1938,7 +1946,7 @@ export async function setLicenseKey(
}

org.licenseKey = licenseKey;
await initializeLicenseForOrg(org, true);
await licenseInit(org, getUserCodesForOrg, getLicenseMetaData, true);
}

export async function putLicenseKey(
Expand Down
10 changes: 7 additions & 3 deletions packages/back-end/src/services/auth/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NextFunction, Request, Response } from "express";
import { SSO_CONFIG } from "enterprise";
import { licenseInit, SSO_CONFIG } from "enterprise";
import { userHasPermission } from "shared/permissions";
import { logger } from "../../util/logger";
import { IS_CLOUD } from "../../util/secrets";
Expand All @@ -24,7 +24,7 @@ import {
} from "../../events/event-types";
import { insertAudit } from "../../models/AuditModel";
import { getTeamsForOrganization } from "../../models/TeamModel";
import { initializeLicenseForOrg } from "../licenseData";
import { getLicenseMetaData, getUserCodesForOrg } from "../licenseData";
import { AuthConnection } from "./AuthConnection";
import { OpenIdAuthConnection } from "./OpenIdAuthConnection";
import { LocalAuthConnection } from "./LocalAuthConnection";
Expand Down Expand Up @@ -194,7 +194,11 @@ export async function processJWT(
}

// init license for org if it exists
await initializeLicenseForOrg(req.organization);
await licenseInit(
req.organization,
getUserCodesForOrg,
getLicenseMetaData
);
} else {
res.status(404).json({
status: 404,
Expand Down
102 changes: 43 additions & 59 deletions packages/back-end/src/services/licenseData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import path from "path";
import fs from "fs";
import { licenseInit } from "enterprise";
import md5 from "md5";
import { findAllSDKConnectionsAcrossAllOrgs } from "../models/SdkConnectionModel";
import { getInstallationId } from "../models/InstallationModel";
Expand Down Expand Up @@ -65,68 +64,53 @@ export async function getLicenseMetaData() {
};
}

export async function initializeLicenseForOrg(
org?: OrganizationInterface,
forceRefresh = false
) {
const key = org?.licenseKey || process.env.LICENSE_KEY;

if (!key) {
return;
}

if (key.startsWith("license_")) {
let userLicenseCodes: string[] = [];
if (IS_CLOUD && org) {
const memberIds = org.members.map((member) => member.id);
const memberEmails = (await getUsersByIds(memberIds)).map(
(user) => user.email
);
const inviteEmails = org.invites.map((invite) => invite.email);
const membersAndInviteEmails = memberEmails.concat(inviteEmails);
userLicenseCodes = membersAndInviteEmails.map((email) => {
return md5(email).slice(0, 8);
});
} else {
// Self-Host logic
// get all users and invites codes across all orgs in the db
// that are part of at least one organization
// there may be multiple orgs in case it is a MULTI_ORG site
const users = await UserModel.aggregate([
{
$lookup: {
from: "organizations",
localField: "id",
foreignField: "members.id",
as: "orgs",
},
export async function getUserCodesForOrg(org: OrganizationInterface) {
let userLicenseCodes: string[] = [];
if (IS_CLOUD && org) {
const memberIds = org.members.map((member) => member.id);
const memberEmails = (await getUsersByIds(memberIds)).map(
(user) => user.email
);
const inviteEmails = org.invites.map((invite) => invite.email);
const membersAndInviteEmails = memberEmails.concat(inviteEmails);
userLicenseCodes = membersAndInviteEmails.map((email) => {
return md5(email).slice(0, 8);
});
} else {
// Self-Host logic
// get all users and invites codes across all orgs in the db
// that are part of at least one organization
// there may be multiple orgs in case it is a MULTI_ORG site
const users = await UserModel.aggregate([
{
$lookup: {
from: "organizations",
localField: "id",
foreignField: "members.id",
as: "orgs",
},
{
$match: {
"orgs.0": { $exists: true },
},
},
{
$match: {
"orgs.0": { $exists: true },
},
]);
},
]);

const userEmailCodes = await Promise.all(
users.map(async (user) => {
return md5(user.email).slice(0, 8);
})
);

const inviteEmails = await getAllInviteEmailsInDb();
const inviteEmailCodes: string[] = inviteEmails.map((email) => {
return md5(email).slice(0, 8);
});

userLicenseCodes = Array.from(
new Set(userEmailCodes.concat(inviteEmailCodes))
);
}
const userEmailCodes = await Promise.all(
users.map(async (user) => {
return md5(user.email).slice(0, 8);
})
);

const metaData = await getLicenseMetaData();
const inviteEmails = await getAllInviteEmailsInDb();
const inviteEmailCodes: string[] = inviteEmails.map((email) => {
return md5(email).slice(0, 8);
});

return await licenseInit(key, userLicenseCodes, metaData, forceRefresh);
userLicenseCodes = Array.from(
new Set(userEmailCodes.concat(inviteEmailCodes))
);
}
return await licenseInit(key);
return userLicenseCodes;
}
Loading

0 comments on commit f8c8288

Please sign in to comment.