{"version":3,"file":"license.mjs","sources":["../../src/ee/license.ts"],"sourcesContent":["import fs from 'fs';\nimport { join, resolve } from 'path';\nimport crypto from 'crypto';\nimport type { Core } from '@strapi/types';\n\nimport { generateInstallId } from '@strapi/utils';\n\ninterface LicenseInfo {\n  type: 'bronze' | 'silver' | 'gold';\n  isTrial: boolean;\n  expireAt?: string;\n  seats?: number;\n  features?: Array<{ name: string; options?: Record<string, unknown> }>;\n  subscriptionId?: string;\n  planPriceId?: string;\n}\n\nconst DEFAULT_FEATURES = {\n  bronze: [],\n  silver: [],\n  gold: [\n    { name: 'sso' },\n    // Set a null retention duration to allow the user to override it\n    // The default of 90 days is set in the audit logs service\n    { name: 'audit-logs', options: { retentionDays: null } },\n    { name: 'review-workflows' },\n    { name: 'cms-content-releases' },\n    { name: 'cms-content-history', options: { retentionDays: 99999 } },\n    { name: 'cms-advanced-preview' },\n  ],\n};\n\nconst LICENSE_REGISTRY_URI = 'https://license.strapi.io';\n\nconst publicKey = fs.readFileSync(resolve(__dirname, '../../resources/key.pub'));\n\nclass LicenseCheckError extends Error {\n  shouldFallback = false;\n\n  constructor(message: string, shouldFallback = false) {\n    super(message);\n\n    this.shouldFallback = shouldFallback;\n  }\n}\n\nconst readLicense = (directory: string) => {\n  try {\n    const path = join(directory, 'license.txt');\n    return fs.readFileSync(path).toString();\n  } catch (error) {\n    if (typeof error === 'object' && error !== null && 'code' in error && error.code !== 'ENOENT') {\n      throw Error('License file not readable, review its format and access rules.');\n    }\n  }\n};\n\nconst verifyLicense = (license: string) => {\n  const [signature, base64Content] = Buffer.from(license, 'base64').toString().split('\\n');\n\n  if (!signature || !base64Content) {\n    throw new Error('Invalid license.');\n  }\n\n  const stringifiedContent = Buffer.from(base64Content, 'base64').toString();\n\n  const verify = crypto.createVerify('RSA-SHA256');\n  verify.update(stringifiedContent);\n  verify.end();\n\n  const verified = verify.verify(publicKey, signature, 'base64');\n\n  if (!verified) {\n    throw new Error('Invalid license.');\n  }\n\n  const licenseInfo: LicenseInfo = JSON.parse(stringifiedContent);\n\n  if (!licenseInfo.features) {\n    licenseInfo.features = DEFAULT_FEATURES[licenseInfo.type];\n  }\n\n  if (!licenseInfo.isTrial) {\n    licenseInfo.isTrial = false;\n  }\n\n  Object.freeze(licenseInfo.features);\n  return licenseInfo;\n};\n\nconst throwError = () => {\n  throw new LicenseCheckError('Could not proceed to the online validation of your license.', true);\n};\n\nconst fetchLicense = async (\n  { strapi }: { strapi: Core.Strapi },\n  key: string,\n  projectId: string\n) => {\n  const { installId: installIdFromPackageJson } = strapi.config;\n\n  const response = await strapi\n    .fetch(`${LICENSE_REGISTRY_URI}/api/licenses/validate`, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({\n        key,\n        projectId,\n        deviceId: generateInstallId(projectId, installIdFromPackageJson),\n      }), // NOTE: Doing nothing on the LR with the installId\n    })\n    .catch(throwError);\n\n  const contentType = response.headers.get('Content-Type');\n\n  if (contentType?.includes('application/json')) {\n    const { data, error } = await response.json();\n\n    switch (response.status) {\n      case 200:\n        return data.license;\n      case 400:\n        throw new LicenseCheckError(error.message);\n      case 404:\n        throw new LicenseCheckError('The license used does not exists.');\n      default:\n        throwError();\n    }\n  } else {\n    throwError();\n  }\n};\n\nexport { readLicense, verifyLicense, fetchLicense, LicenseCheckError, LICENSE_REGISTRY_URI };\n"],"names":["DEFAULT_FEATURES","bronze","silver","gold","name","options","retentionDays","LICENSE_REGISTRY_URI","publicKey","fs","readFileSync","resolve","__dirname","LicenseCheckError","Error","message","shouldFallback","readLicense","directory","path","join","toString","error","code","verifyLicense","license","signature","base64Content","Buffer","from","split","stringifiedContent","verify","crypto","createVerify","update","end","verified","licenseInfo","JSON","parse","features","type","isTrial","Object","freeze","throwError","fetchLicense","strapi","key","projectId","installId","installIdFromPackageJson","config","response","fetch","method","headers","body","stringify","deviceId","generateInstallId","catch","contentType","get","includes","data","json","status"],"mappings":"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"}