Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix multiorg license report #2315

Merged
merged 3 commits into from Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 12 additions & 3 deletions packages/back-end/src/controllers/license.ts
Expand Up @@ -7,14 +7,18 @@ import {
postResendEmailVerificationEmailToLicenseServer,
postVerifyEmailToLicenseServer,
} from "enterprise";
import md5 from "md5";
import {
getLicenseMetaData,
initializeLicenseForOrg,
} from "../services/licenseData";
import { getUserLicenseCodes } from "../services/users";
import { AuthRequest } from "../types/AuthRequest";
import { getContextFromReq } from "../services/organizations";
import { updateOrganization } from "../models/OrganizationModel";
import {
getAllInviteEmailsInDb,
updateOrganization,
} from "../models/OrganizationModel";
import { PrivateApiErrorResponse } from "../../types/api";
import { updateSubscriptionInDb } from "../services/stripe";

Expand Down Expand Up @@ -53,15 +57,20 @@ export async function getLicenseReport(req: AuthRequest, res: Response) {

const timestamp = new Date().toISOString();
const licenseMetaData = await getLicenseMetaData();
const userLicenseCodes = await getUserLicenseCodes();
const userEmailCodes = await getUserLicenseCodes();
const inviteEmails = await getAllInviteEmailsInDb();
const inviteEmailCodes: string[] = inviteEmails.map((email) => {
return md5(email).slice(0, 8);
});

// Create a hmac signature of the license data
const hmac = crypto.createHmac("sha256", licenseMetaData.installationId);

const report = {
timestamp,
licenseMetaData,
userLicenseCodes,
userEmailCodes,
inviteEmailCodes,
};

return res.status(200).json({
Expand Down
Expand Up @@ -621,9 +621,9 @@ export async function getOrganization(req: AuthRequest, res: Response) {
} = org;

let license;
if (licenseKey) {
if (licenseKey || process.env.LICENSE_KEY) {
// automatically set the license data based on org license key
license = getLicense(org.licenseKey);
license = getLicense(org.licenseKey || process.env.LICENSE_KEY);
tzjames marked this conversation as resolved.
Show resolved Hide resolved
if (!license || (license.organizationId && license.organizationId !== id)) {
try {
license = await initializeLicenseForOrg(org);
Expand Down
Expand Up @@ -15,7 +15,8 @@ const DownloadLicenseUsageButton: FC = () => {
const res = await apiCall<{
status: number;
licenseMetaData: LicenseMetaData;
userLicenseCodes: string[];
userEmailCodes: string[];
inviteEmailCodes: string[];
signature: string;
timestamp: string;
}>(`/license/report`, {
Expand All @@ -32,8 +33,12 @@ const DownloadLicenseUsageButton: FC = () => {
{
license: license,
licenseMetaData: res.licenseMetaData,
userLicenseCodes: res.userLicenseCodes,
seatsUsed: res.userLicenseCodes.length,
userEmailCodes: res.userEmailCodes,
inviteEmailCodes: res.inviteEmailCodes,
activeSeatsUsed: res.userEmailCodes.length,
seatsUsed: Array.from(
new Set(res.userEmailCodes.concat(res.inviteEmailCodes))
).length,
tzjames marked this conversation as resolved.
Show resolved Hide resolved
signature: res.signature,
timestamp: res.timestamp,
},
Expand Down
3 changes: 2 additions & 1 deletion packages/front-end/components/License/ShowLicenseInfo.tsx
Expand Up @@ -7,6 +7,7 @@ import EditLicenseModal from "@/components/Settings/EditLicenseModal";
import { GBPremiumBadge } from "@/components/Icons";
import UpgradeModal from "@/components/Settings/UpgradeModal";
import AccountPlanNotices from "@/components/Layout/AccountPlanNotices";
import { isCloud } from "@/services/env";
import RefreshLicenseButton from "./RefreshLicenseButton";
import DownloadLicenseUsageButton from "./DownloadLicenseUsageButton";

Expand Down Expand Up @@ -35,7 +36,7 @@ const ShowLicenseInfo: FC<{

// TODO: Remove this once we have migrated all organizations to use the license key
const usesLicenseInfoOnModel =
!showUpgradeButton && !organization?.licenseKey;
isCloud() && !showUpgradeButton && !organization?.licenseKey;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I understand why we need the isCloud() check. Do self-hosted Growthbook orgs not use the license info from the licenses collection?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because self hosted orgs can also specify the license in an environmental variable rather than on the mongo organization object. We want to show the license info for them too. Only on cloud and only on old organizations still keeping the license data itself as properties on the organization, do we want to hide the license info, because it would not display correctly. We will be migrating those organizations off in the coming week.


return (
<div>
Expand Down