mirror of
https://github.com/strapi/strapi.git
synced 2025-11-13 16:52:18 +00:00
Audit logs react to license updates (with logs)
This commit is contained in:
parent
0dcfbde89f
commit
43ceb02092
@ -1,15 +1,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { features } = require('@strapi/strapi/lib/utils/ee');
|
|
||||||
const executeCERegister = require('../../server/register');
|
const executeCERegister = require('../../server/register');
|
||||||
const migrateAuditLogsTable = require('./migrations/audit-logs-table');
|
const migrateAuditLogsTable = require('./migrations/audit-logs-table');
|
||||||
const createAuditLogsService = require('./services/audit-logs');
|
const createAuditLogsService = require('./services/audit-logs');
|
||||||
|
|
||||||
module.exports = async ({ strapi }) => {
|
module.exports = async ({ strapi }) => {
|
||||||
const auditLogsIsAllowed = features.isEnabled('audit-logs');
|
const auditLogsIsEnabled = strapi.config.get('admin.auditLogs.enabled', true);
|
||||||
const auditLogsIsEnabled = strapi.config.get('server.auditLogs.enabled', true);
|
|
||||||
|
|
||||||
if (auditLogsIsAllowed && auditLogsIsEnabled) {
|
if (auditLogsIsEnabled) {
|
||||||
strapi.hook('strapi::content-types.beforeSync').register(migrateAuditLogsTable);
|
strapi.hook('strapi::content-types.beforeSync').register(migrateAuditLogsTable);
|
||||||
const auditLogsService = createAuditLogsService(strapi);
|
const auditLogsService = createAuditLogsService(strapi);
|
||||||
strapi.container.register('audit-logs', auditLogsService);
|
strapi.container.register('audit-logs', auditLogsService);
|
||||||
|
|||||||
@ -53,6 +53,24 @@ const getEventMap = (defaultEvents) => {
|
|||||||
}, {});
|
}, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getRetentionDays = (strapi) => {
|
||||||
|
const licenseRetentionDays = features.get('audit-logs')?.options.retentionDays;
|
||||||
|
const userRetentionDays = strapi.config.get('admin.auditLogs.retentionDays');
|
||||||
|
|
||||||
|
// For enterprise plans, use 90 days by default, but allow users to override it
|
||||||
|
if (licenseRetentionDays == null) {
|
||||||
|
return userRetentionDays ?? DEFAULT_RETENTION_DAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow users to override the license retention days, but not to increase it
|
||||||
|
if (userRetentionDays && userRetentionDays < licenseRetentionDays) {
|
||||||
|
return userRetentionDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User didn't provide a retention days value, use the license one
|
||||||
|
return licenseRetentionDays;
|
||||||
|
};
|
||||||
|
|
||||||
const createAuditLogsService = (strapi) => {
|
const createAuditLogsService = (strapi) => {
|
||||||
// NOTE: providers should be able to replace getEventMap to add or remove events
|
// NOTE: providers should be able to replace getEventMap to add or remove events
|
||||||
const eventMap = getEventMap(defaultEvents);
|
const eventMap = getEventMap(defaultEvents);
|
||||||
@ -99,10 +117,45 @@ const createAuditLogsService = (strapi) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
async register() {
|
async register() {
|
||||||
const retentionDays =
|
console.log('audit logs register');
|
||||||
features.get('audit-logs')?.options.retentionDays ?? DEFAULT_RETENTION_DAYS;
|
// Handle license being enabled
|
||||||
|
if (!this._eeEnableUnsubscribe) {
|
||||||
|
this._eeEnableUnsubscribe = strapi.eventHub.once('ee.enable', () => {
|
||||||
|
console.log('listened to ee.enable');
|
||||||
|
// Recreate the service to use the new license info
|
||||||
|
this.destroy();
|
||||||
|
this.register();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle license being updated
|
||||||
|
this._eeUpdateUnsubscribe = strapi.eventHub.on('ee.update', () => {
|
||||||
|
console.log('listened to ee.update');
|
||||||
|
// Recreate the service to use the new license info
|
||||||
|
this.destroy();
|
||||||
|
this.register();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle license being disabled
|
||||||
|
this._eeDisableUnsubscribe = strapi.eventHub.on('ee.disable', () => {
|
||||||
|
console.log('listened to ee.disable');
|
||||||
|
// Turn off service when the license gets disabled
|
||||||
|
// Only the ee.enable listener remains active to recreate the service
|
||||||
|
this.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check current state of license
|
||||||
|
if (!features.isEnabled('audit-logs')) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start saving events
|
||||||
this._provider = await localProvider.register({ strapi });
|
this._provider = await localProvider.register({ strapi });
|
||||||
this._eventHubUnsubscribe = strapi.eventHub.subscribe(handleEvent.bind(this));
|
this._eventHubUnsubscribe = strapi.eventHub.subscribe(handleEvent.bind(this));
|
||||||
|
|
||||||
|
// Manage audit logs auto deletion
|
||||||
|
const retentionDays = getRetentionDays(strapi);
|
||||||
|
console.log('registering audit logs service', retentionDays);
|
||||||
this._deleteExpiredJob = scheduleJob('0 0 * * *', () => {
|
this._deleteExpiredJob = scheduleJob('0 0 * * *', () => {
|
||||||
const expirationDate = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000);
|
const expirationDate = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000);
|
||||||
this._provider.deleteExpiredEvents(expirationDate);
|
this._provider.deleteExpiredEvents(expirationDate);
|
||||||
@ -143,6 +196,14 @@ const createAuditLogsService = (strapi) => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
unsubscribe() {
|
unsubscribe() {
|
||||||
|
if (this._eeUpdateUnsubscribe) {
|
||||||
|
this._eeUpdateUnsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._eeDisableUnsubscribe) {
|
||||||
|
this._eeDisableUnsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
if (this._eventHubUnsubscribe) {
|
if (this._eventHubUnsubscribe) {
|
||||||
this._eventHubUnsubscribe();
|
this._eventHubUnsubscribe();
|
||||||
}
|
}
|
||||||
@ -155,6 +216,7 @@ const createAuditLogsService = (strapi) => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
|
console.log('audit logs destroy');
|
||||||
return this.unsubscribe();
|
return this.unsubscribe();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { pick } = require('lodash/fp');
|
const { pick, isEqual } = require('lodash/fp');
|
||||||
|
|
||||||
const { readLicense, verifyLicense, fetchLicense, LicenseCheckError } = require('./license');
|
const { readLicense, verifyLicense, fetchLicense, LicenseCheckError } = require('./license');
|
||||||
const { eeStoreModel } = require('./ee-store');
|
const { eeStoreModel } = require('./ee-store');
|
||||||
const { shiftCronExpression } = require('../lib/utils/cron');
|
const { shiftCronExpression } = require('../lib/utils/cron');
|
||||||
|
|
||||||
const ONE_MINUTE = 1000 * 60;
|
const ONE_MINUTE = 1 * 60;
|
||||||
|
|
||||||
const ee = {
|
const ee = {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
@ -14,10 +14,33 @@ const ee = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const disable = (message) => {
|
const disable = (message) => {
|
||||||
|
// Prevent emitting ee.disable if it was already disabled
|
||||||
|
const shouldEmitEvent = ee.enabled !== false;
|
||||||
|
|
||||||
ee.logger?.warn(`${message} Switching to CE.`);
|
ee.logger?.warn(`${message} Switching to CE.`);
|
||||||
// Only keep the license key for potential re-enabling during a later check
|
// Only keep the license key for potential re-enabling during a later check
|
||||||
ee.licenseInfo = pick('licenseKey', ee.licenseInfo);
|
ee.licenseInfo = pick('licenseKey', ee.licenseInfo);
|
||||||
|
|
||||||
|
// Prevent emitting ee.disable if it was already disabled
|
||||||
|
console.log('disabling EE');
|
||||||
ee.enabled = false;
|
ee.enabled = false;
|
||||||
|
|
||||||
|
if (shouldEmitEvent) {
|
||||||
|
// Notify EE features that they should be disabled
|
||||||
|
strapi.eventHub.emit('ee.disable');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const enable = () => {
|
||||||
|
// Prevent emitting ee.disable if it was already disabled
|
||||||
|
const shouldEmitEvent = ee.enabled !== true;
|
||||||
|
|
||||||
|
ee.enabled = true;
|
||||||
|
|
||||||
|
if (shouldEmitEvent) {
|
||||||
|
// Notify EE features that they should be disabled
|
||||||
|
strapi.eventHub.emit('ee.enable');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let initialized = false;
|
let initialized = false;
|
||||||
@ -42,7 +65,7 @@ const init = (licenseDir, logger) => {
|
|||||||
|
|
||||||
if (license) {
|
if (license) {
|
||||||
ee.licenseInfo = verifyLicense(license);
|
ee.licenseInfo = verifyLicense(license);
|
||||||
ee.enabled = true;
|
enable();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
disable(error.message);
|
disable(error.message);
|
||||||
@ -55,6 +78,7 @@ const init = (licenseDir, logger) => {
|
|||||||
* Store the result in database to avoid unecessary requests, and will fallback to that in case of a network failure.
|
* Store the result in database to avoid unecessary requests, and will fallback to that in case of a network failure.
|
||||||
*/
|
*/
|
||||||
const onlineUpdate = async ({ strapi }) => {
|
const onlineUpdate = async ({ strapi }) => {
|
||||||
|
console.log('onlineUpdate');
|
||||||
const { get, commit, rollback } = await strapi.db.transaction();
|
const { get, commit, rollback } = await strapi.db.transaction();
|
||||||
const transaction = get();
|
const transaction = get();
|
||||||
|
|
||||||
@ -90,8 +114,22 @@ const onlineUpdate = async ({ strapi }) => {
|
|||||||
|
|
||||||
if (license) {
|
if (license) {
|
||||||
try {
|
try {
|
||||||
ee.licenseInfo = verifyLicense(license);
|
// Verify license and check if its info changed
|
||||||
|
const newLicenseInfo = verifyLicense(license);
|
||||||
|
const fieldsToCompare = ['licenseKey', 'features', 'plan'];
|
||||||
|
const licenseInfoChanged = !isEqual(
|
||||||
|
pick(fieldsToCompare, newLicenseInfo),
|
||||||
|
pick(fieldsToCompare, ee.licenseInfo)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Store the new license info
|
||||||
|
ee.licenseInfo = newLicenseInfo;
|
||||||
validateInfo();
|
validateInfo();
|
||||||
|
|
||||||
|
// Notify EE features
|
||||||
|
if (licenseInfoChanged) {
|
||||||
|
strapi.eventHub.emit('ee.update');
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
disable(error.message);
|
disable(error.message);
|
||||||
}
|
}
|
||||||
@ -126,7 +164,8 @@ const validateInfo = () => {
|
|||||||
return disable('License expired.');
|
return disable('License expired.');
|
||||||
}
|
}
|
||||||
|
|
||||||
ee.enabled = true;
|
// Prevent emitting ee.enable if it was already enabled
|
||||||
|
enable();
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkLicense = async ({ strapi }) => {
|
const checkLicense = async ({ strapi }) => {
|
||||||
@ -137,7 +176,9 @@ const checkLicense = async ({ strapi }) => {
|
|||||||
|
|
||||||
if (!shouldStayOffline) {
|
if (!shouldStayOffline) {
|
||||||
await onlineUpdate({ strapi });
|
await onlineUpdate({ strapi });
|
||||||
strapi.cron.add({ [shiftCronExpression('0 0 */12 * * *')]: onlineUpdate });
|
|
||||||
|
// strapi.cron.add({ [shiftCronExpression('0 0 */12 * * *')]: onlineUpdate });
|
||||||
|
strapi.cron.add({ [shiftCronExpression('*/10 * * * * *')]: onlineUpdate });
|
||||||
} else {
|
} else {
|
||||||
if (!ee.licenseInfo.expireAt) {
|
if (!ee.licenseInfo.expireAt) {
|
||||||
return disable('Your license does not have offline support.');
|
return disable('Your license does not have offline support.');
|
||||||
|
|||||||
@ -4,7 +4,10 @@ const auditLogContentType = require('./content-types/audit-log');
|
|||||||
|
|
||||||
const provider = {
|
const provider = {
|
||||||
async register({ strapi }) {
|
async register({ strapi }) {
|
||||||
|
const contentTypes = strapi.container.get('content-types');
|
||||||
|
if (!contentTypes.keys().includes('admin::audit-log')) {
|
||||||
strapi.container.get('content-types').add('admin::', { 'audit-log': auditLogContentType });
|
strapi.container.get('content-types').add('admin::', { 'audit-log': auditLogContentType });
|
||||||
|
}
|
||||||
|
|
||||||
// Return the provider object
|
// Return the provider object
|
||||||
return {
|
return {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user