From 075a3f3bf9915216bba6c83428d3dd5f1a571376 Mon Sep 17 00:00:00 2001 From: Julius Knorr Date: Thu, 18 Jun 2026 15:57:24 +0200 Subject: [PATCH] feat: remove edition/license feature gates Unlock branding, customization and the advanced API, always allow Visio over WOPI, and stop enforcing connection/user limits so the open-source build has no edition-based limitations. Assisted-by: ClaudeCode:claude-opus-4-8 Signed-off-by: Julius Knorr --- Common/sources/license.js | 6 +- Common/sources/tenantManager.js | 47 ++------------- DocService/sources/DocsCoServer.js | 93 ++---------------------------- DocService/sources/wopiClient.js | 5 +- 4 files changed, 12 insertions(+), 139 deletions(-) diff --git a/Common/sources/license.js b/Common/sources/license.js index a985ef555..44e2dbf98 100644 --- a/Common/sources/license.js +++ b/Common/sources/license.js @@ -40,11 +40,11 @@ exports.readLicense = async function () { type: c_LR.Success, packageType: constants.PACKAGE_TYPE_OS, mode: constants.LICENSE_MODE.None, - branding: false, + branding: true, connections: constants.LICENSE_CONNECTIONS, connectionsView: constants.LICENSE_CONNECTIONS, - customization: false, - advancedApi: false, + customization: true, + advancedApi: true, usersCount: 0, usersViewCount: 0, usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY, diff --git a/Common/sources/tenantManager.js b/Common/sources/tenantManager.js index 004b2e744..1b6a38532 100644 --- a/Common/sources/tenantManager.js +++ b/Common/sources/tenantManager.js @@ -394,37 +394,14 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) { res.graceDays = Math.max(0, oLicense['grace_days'] >> 0); } - const timeLimited = 0 !== (res.mode & c_LM.Limited); - - const checkDate = res.mode & c_LM.Trial || timeLimited ? new Date() : licenseInfo.buildDate; - //Calendar check of start_date allows to issue a license for old versions + //fully open-source build: a supplied license file is never expired or limited; + //only honor a future start_date as "not yet active" const checkStartDate = new Date(); - if (startDate <= checkStartDate && checkDate <= res.endDate) { - res.type = c_LR.Success; - } else if (startDate > checkStartDate) { + if (startDate > checkStartDate) { res.type = c_LR.NotBefore; ctx.logger.warn('License: License not active before start_date:%s.', startDate.toISOString()); - } else if (timeLimited) { - // Grace period after end license = limited mode with limited connections - if (res.endDate.setUTCDate(res.endDate.getUTCDate() + res.graceDays) >= checkDate) { - res.type = c_LR.SuccessLimit; - res.connections = Math.min(res.connections, constants.LICENSE_CONNECTIONS); - res.connectionsView = Math.min(res.connectionsView, constants.LICENSE_CONNECTIONS); - res.usersCount = Math.min(res.usersCount, constants.LICENSE_USERS); - res.usersViewCount = Math.min(res.usersViewCount, constants.LICENSE_USERS); - const errStr = res.usersCount ? `${res.usersCount} unique users` : `${res.connections} concurrent connections`; - ctx.logger.error( - `License: License needs to be renewed.\nYour users have only ${errStr} ` + - `available for document editing for the next ${res.graceDays} days.\nPlease renew the ` + - 'license to restore the full access' - ); - } else { - res.type = c_LR.ExpiredLimited; - } - } else if (0 !== (res.mode & c_LM.Trial)) { - res.type = c_LR.ExpiredTrial; } else { - res.type = c_LR.Expired; + res.type = c_LR.Success; } } catch (e) { ctx.logger.warn(e); @@ -435,22 +412,6 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) { res.usersViewCount = 0; res.type = c_LR.Error; } - if (res.type === c_LR.Expired || res.type === c_LR.ExpiredLimited || res.type === c_LR.ExpiredTrial) { - res.count = 1; - - let errorMessage; - if (res.type === c_LR.Expired) { - errorMessage = - 'Your access to updates and support has expired.\n' + - 'Your license key can not be applied to new versions.\n' + - 'Please extend the license to get updates and support.'; - } else if (res.type === c_LR.ExpiredLimited) { - errorMessage = 'License expired.\nYour users can not edit or view document anymore.\n' + 'Please renew the license.'; - } else { - errorMessage = 'License Expired!!!'; - } - ctx.logger.warn('License: ' + errorMessage); - } return [res, oLicense]; } diff --git a/DocService/sources/DocsCoServer.js b/DocService/sources/DocsCoServer.js index 84f9ba1bf..ca9140c41 100644 --- a/DocService/sources/DocsCoServer.js +++ b/DocService/sources/DocsCoServer.js @@ -93,14 +93,12 @@ const wopiClient = require('./wopiClient'); const queueService = require('./../../Common/sources/taskqueueRabbitMQ'); const operationContext = require('./../../Common/sources/operationContext'); const tenantManager = require('./../../Common/sources/tenantManager'); -const {notificationTypes, ...notificationService} = require('../../Common/sources/notificationService'); const aiProxyHandler = require('./ai/aiProxyHandler'); const cfgEditorDataStorage = config.get('services.CoAuthoring.server.editorDataStorage'); const cfgEditorStatStorage = config.get('services.CoAuthoring.server.editorStatStorage'); const editorDataStorage = require('./' + cfgEditorDataStorage); const editorStatStorage = require('./' + (cfgEditorStatStorage || cfgEditorDataStorage)); -const util = require('util'); const cfgEditSingleton = config.get('services.CoAuthoring.server.edit_singleton'); const cfgEditor = config.get('services.CoAuthoring.editor'); @@ -129,9 +127,6 @@ const cfgQueueRetentionPeriod = config.get('queue.retentionPeriod'); const cfgForgottenFiles = config.get('services.CoAuthoring.server.forgottenfiles'); const cfgForgottenFilesName = config.get('services.CoAuthoring.server.forgottenfilesname'); const cfgMaxRequestChanges = config.get('services.CoAuthoring.server.maxRequestChanges'); -const cfgWarningLimitPercents = config.get('license.warning_limit_percents'); -const cfgNotificationRuleLicenseLimitEdit = config.get('notification.rules.licenseLimitEdit.template'); -const cfgNotificationRuleLicenseLimitLiveViewer = config.get('notification.rules.licenseLimitLiveViewer.template'); const cfgErrorFiles = config.get('FileConverter.converter.errorfiles'); const cfgOpenProtectedFile = config.get('services.CoAuthoring.server.openProtectedFile'); const cfgIsAnonymousSupport = config.get('services.CoAuthoring.server.isAnonymousSupport'); @@ -3895,90 +3890,10 @@ exports.install = function (server, app, callbackFunction) { }); } - function* _checkLicenseAuth(ctx, licenseInfo, userId, isLiveViewer) { - const tenWarningLimitPercents = ctx.getCfg('license.warning_limit_percents', cfgWarningLimitPercents) / 100; - const tenNotificationRuleLicenseLimitEdit = ctx.getCfg(`notification.rules.licenseLimitEdit.template`, cfgNotificationRuleLicenseLimitEdit); - const tenNotificationRuleLicenseLimitLiveViewer = ctx.getCfg( - `notification.rules.licenseLimitLiveViewer.template`, - cfgNotificationRuleLicenseLimitLiveViewer - ); - const c_LR = constants.LICENSE_RESULT; - let licenseType = licenseInfo.type; - if (c_LR.Success === licenseType || c_LR.SuccessLimit === licenseType) { - let notificationLimit, notificationLimitTitle; - let notificationTemplate = tenNotificationRuleLicenseLimitEdit; - let notificationType = notificationTypes.LICENSE_LIMIT_EDIT; - let notificationPercent = 100; - if (licenseInfo.usersCount) { - const nowUTC = getLicenseNowUtc(); - notificationLimitTitle = 'user'; - notificationLimit = 'users'; - if (isLiveViewer) { - notificationTemplate = tenNotificationRuleLicenseLimitLiveViewer; - notificationType = notificationTypes.LICENSE_LIMIT_LIVE_VIEWER; - const arrUsers = yield editorStat.getPresenceUniqueViewUser(ctx, nowUTC); - if ( - arrUsers.length >= licenseInfo.usersViewCount && - -1 === - arrUsers.findIndex(element => { - return element.userid === userId; - }) - ) { - licenseType = licenseInfo.hasLicense ? c_LR.UsersViewCount : c_LR.UsersViewCountOS; - } else if (licenseInfo.usersViewCount * tenWarningLimitPercents <= arrUsers.length) { - notificationPercent = tenWarningLimitPercents * 100; - } - } else { - const arrUsers = yield editorStat.getPresenceUniqueUser(ctx, nowUTC); - if ( - arrUsers.length >= licenseInfo.usersCount && - -1 === - arrUsers.findIndex(element => { - return element.userid === userId; - }) - ) { - licenseType = licenseInfo.hasLicense ? c_LR.UsersCount : c_LR.UsersCountOS; - } else if (licenseInfo.usersCount * tenWarningLimitPercents <= arrUsers.length) { - notificationPercent = tenWarningLimitPercents * 100; - } - } - } else { - notificationLimitTitle = 'connection'; - notificationLimit = 'connections'; - if (isLiveViewer) { - notificationTemplate = tenNotificationRuleLicenseLimitLiveViewer; - notificationType = notificationTypes.LICENSE_LIMIT_LIVE_VIEWER; - const connectionsLiveCount = licenseInfo.connectionsView; - const liveViewerConnectionsCount = yield editorStat.getLiveViewerConnectionsCount(ctx, connections); - if (liveViewerConnectionsCount >= connectionsLiveCount) { - licenseType = licenseInfo.hasLicense ? c_LR.ConnectionsLive : c_LR.ConnectionsLiveOS; - } else if (connectionsLiveCount * tenWarningLimitPercents <= liveViewerConnectionsCount) { - notificationPercent = tenWarningLimitPercents * 100; - } - } else { - const connectionsCount = licenseInfo.connections; - const editConnectionsCount = yield editorStat.getEditorConnectionsCount(ctx, connections); - if (editConnectionsCount >= connectionsCount) { - licenseType = licenseInfo.hasLicense ? c_LR.Connections : c_LR.ConnectionsOS; - } else if (connectionsCount * tenWarningLimitPercents <= editConnectionsCount) { - notificationPercent = tenWarningLimitPercents * 100; - } - } - } - if ((c_LR.Success !== licenseType && c_LR.SuccessLimit !== licenseType) || 100 !== notificationPercent) { - const applicationName = (process.env.APPLICATION_NAME || '').toUpperCase(); - const title = util.format(notificationTemplate.title, applicationName, notificationLimitTitle); - const message = util.format(notificationTemplate.body, notificationPercent, notificationLimit); - if (100 !== notificationPercent) { - ctx.logger.warn(message); - } else { - ctx.logger.error(message); - } - //todo with yield service could throw error - void notificationService.notify(ctx, notificationType, title, message, notificationType + notificationPercent); - } - } - return licenseType; + // eslint-disable-next-line require-yield + function* _checkLicenseAuth(_ctx, _licenseInfo, _userId, _isLiveViewer) { + //fully open-source build: no connection/user limits are enforced + return constants.LICENSE_RESULT.Success; } //publish subscribe message brocker diff --git a/DocService/sources/wopiClient.js b/DocService/sources/wopiClient.js index 479bb462f..3a8edec2b 100644 --- a/DocService/sources/wopiClient.js +++ b/DocService/sources/wopiClient.js @@ -49,7 +49,6 @@ const taskResult = require('./taskresult'); const canvasService = require('./canvasservice'); const converterService = require('./converterservice'); const mime = require('mime'); -const license = require('./../../Common/sources/license'); const cfgTokenOutboxAlgorithm = config.get('services.CoAuthoring.token.outbox.algorithm'); const cfgTokenOutboxExpires = config.get('services.CoAuthoring.token.outbox.expires'); @@ -179,9 +178,7 @@ function discovery(req, res) { ]; const documentTypes = [`word`, `cell`, `slide`, `pdf`]; //todo check sdkjs-ooxml addon - const addVisio = - (tenWopiDiagramView.length > 0 || tenWopiDiagramEdit.length > 0) && - (constants.PACKAGE_TYPE_OS !== license.packageType || process.env?.NODE_ENV?.startsWith('development-')); + const addVisio = tenWopiDiagramView.length > 0 || tenWopiDiagramEdit.length > 0; if (addVisio) { names.push('Visio'); favIconUrls.push(tenWopiFavIconUrlDiagram);