diff --git a/package-lock.json b/package-lock.json index 145e36573..12ccd4d69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "connect-timeout": "^1.9.0", "cookie-parser": "^1.4.6", "cookie-session": "^2.1.0", - "cron": "^2.4.4", + "cron": "^3.1.7", "db-migrate": "^0.11.14", "db-migrate-mysql": "^2.3.2", "debug": "^4.3.4", @@ -446,9 +446,9 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" }, "node_modules/@types/luxon": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.2.tgz", - "integrity": "sha512-l5cpE57br4BIjK+9BSkFBOsWtwv6J9bJpC7gdXIzZyI0vuKvNTk0wZZrkQxMGsUAuGW9+WMNWF2IJMD7br2yeQ==" + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" }, "node_modules/@types/node": { "version": "20.12.7", @@ -1026,28 +1026,6 @@ "validator": "^13.11.0" } }, - "node_modules/cloudron-manifestformat/node_modules/@types/luxon": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", - "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" - }, - "node_modules/cloudron-manifestformat/node_modules/cron": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/cron/-/cron-3.1.7.tgz", - "integrity": "sha512-tlBg7ARsAMQLzgwqVxy8AZl/qlTc5nibqYwtNGoCrd+cV+ugI+tvZC1oT/8dFH8W455YrywGykx/KMmAqOr7Jw==", - "dependencies": { - "@types/luxon": "~3.4.0", - "luxon": "~3.4.0" - } - }, - "node_modules/cloudron-manifestformat/node_modules/luxon": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", - "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", - "engines": { - "node": ">=12" - } - }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -1331,12 +1309,12 @@ } }, "node_modules/cron": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/cron/-/cron-2.4.4.tgz", - "integrity": "sha512-MHlPImXJj3K7x7lyUHjtKEOl69CSlTOWxS89jiFgNkzXfvhVjhMz/nc7/EIfN9vgooZp8XTtXJ1FREdmbyXOiQ==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/cron/-/cron-3.1.7.tgz", + "integrity": "sha512-tlBg7ARsAMQLzgwqVxy8AZl/qlTc5nibqYwtNGoCrd+cV+ugI+tvZC1oT/8dFH8W455YrywGykx/KMmAqOr7Jw==", "dependencies": { - "@types/luxon": "~3.3.0", - "luxon": "~3.3.0" + "@types/luxon": "~3.4.0", + "luxon": "~3.4.0" } }, "node_modules/cross-spawn": { @@ -3546,9 +3524,9 @@ } }, "node_modules/luxon": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz", - "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", "engines": { "node": ">=12" } diff --git a/package.json b/package.json index 59c180c92..3a804cd48 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "connect-timeout": "^1.9.0", "cookie-parser": "^1.4.6", "cookie-session": "^2.1.0", - "cron": "^2.4.4", + "cron": "^3.1.7", "db-migrate": "^0.11.14", "db-migrate-mysql": "^2.3.2", "debug": "^4.3.4", diff --git a/src/apps.js b/src/apps.js index 7c7935b17..11b78da9b 100644 --- a/src/apps.js +++ b/src/apps.js @@ -150,7 +150,7 @@ const appstore = require('./appstore.js'), backups = require('./backups.js'), BoxError = require('./boxerror.js'), constants = require('./constants.js'), - CronJob = require('cron').CronJob, + { CronTime } = require('cron'), dashboard = require('./dashboard.js'), database = require('./database.js'), debug = require('debug')('box:apps'), @@ -340,7 +340,7 @@ function parseCrontab(crontab) { const command = parts[6]; try { - new CronJob('00 ' + schedule, function() {}); // second is disallowed + new CronTime('00 ' + schedule); // second is disallowed } catch (ex) { throw new BoxError(BoxError.BAD_FIELD, `Invalid cron pattern at line ${i+1}`); } diff --git a/src/backups.js b/src/backups.js index 9b54357ad..09802d1cb 100644 --- a/src/backups.js +++ b/src/backups.js @@ -56,7 +56,7 @@ const assert = require('assert'), BoxError = require('./boxerror.js'), constants = require('./constants.js'), cron = require('./cron.js'), - CronJob = require('cron').CronJob, + { CronTime } = require('cron'), crypto = require('crypto'), database = require('./database.js'), debug = require('debug')('box:backups'), @@ -182,7 +182,7 @@ function validateLabel(label) { async function validatePolicy(policy) { assert.strictEqual(typeof policy, 'object'); - const job = safe.safeCall(function () { return new CronJob(policy.schedule); }); + const job = safe.safeCall(function () { return new CronTime(policy.schedule); }); if (!job) return new BoxError(BoxError.BAD_FIELD, 'Invalid schedule pattern'); const retention = policy.retention; diff --git a/src/cron.js b/src/cron.js index 6dc345876..159278fdc 100644 --- a/src/cron.js +++ b/src/cron.js @@ -27,7 +27,7 @@ const appHealthMonitor = require('./apphealthmonitor.js'), backups = require('./backups.js'), cloudron = require('./cloudron.js'), constants = require('./constants.js'), - CronJob = require('cron').CronJob, + { CronJob } = require('cron'), debug = require('debug')('box:cron'), dyndns = require('./dyndns.js'), externalLdap = require('./externalldap.js'), @@ -99,75 +99,75 @@ async function startJobs() { debug(`startJobs: starting cron jobs with hour ${hour} and minute ${minute}`); - gJobs.systemChecks = new CronJob({ + gJobs.systemChecks = CronJob.from({ cronTime: `00 ${minute} 2 * * *`, // once a day. if you change this interval, change the notification messages with correct duration onTick: async () => await safe(system.runSystemChecks(), { debug }), start: true }); - gJobs.mailStatusCheck = new CronJob({ + gJobs.mailStatusCheck = CronJob.from({ cronTime: `00 ${minute} 2 * * *`, // once a day. if you change this interval, change the notification messages with correct duration onTick: async () => await safe(mail.checkStatus(), { debug }), start: true }); - gJobs.diskUsage = new CronJob({ + gJobs.diskUsage = CronJob.from({ cronTime: `00 ${minute} 3 * * *`, // once a day onTick: async () => await safe(system.startUpdateDiskUsage(), { debug }), start: true }); - gJobs.diskSpaceChecker = new CronJob({ + gJobs.diskSpaceChecker = CronJob.from({ cronTime: '00 30 * * * *', // every 30 minutes. if you change this interval, change the notification messages with correct duration onTick: async () => await safe(system.checkDiskSpace(), { debug }), start: true }); // this is run separately from the update itself so that the user can disable automatic updates but can still get a notification - gJobs.updateCheckerJob = new CronJob({ + gJobs.updateCheckerJob = CronJob.from({ cronTime: `00 ${minute} 1,5,9,13,17,21,23 * * *`, onTick: async () => await safe(updateChecker.checkForUpdates({ automatic: true }), { debug }), start: true }); - gJobs.cleanupTokens = new CronJob({ + gJobs.cleanupTokens = CronJob.from({ cronTime: '00 */30 * * * *', // every 30 minutes onTick: async () => await safe(janitor.cleanupTokens(), { debug }), start: true }); - gJobs.cleanupBackups = new CronJob({ + gJobs.cleanupBackups = CronJob.from({ cronTime: DEFAULT_CLEANUP_BACKUPS_PATTERN, onTick: async () => await safe(backups.startCleanupTask(AuditSource.CRON), { debug }), start: true }); - gJobs.cleanupEventlog = new CronJob({ + gJobs.cleanupEventlog = CronJob.from({ cronTime: '00 */30 * * * *', // every 30 minutes onTick: async () => await safe(eventlog.cleanup({ creationTime: new Date(Date.now() - 90 * 60 * 24 * 60 * 1000) }), { debug }), // 90 days ago start: true }); - gJobs.dockerVolumeCleaner = new CronJob({ + gJobs.dockerVolumeCleaner = CronJob.from({ cronTime: '00 00 */12 * * *', // every 12 hours onTick: async () => await safe(janitor.cleanupDockerVolumes(), { debug }), start: true }); - gJobs.schedulerSync = new CronJob({ + gJobs.schedulerSync = CronJob.from({ cronTime: constants.TEST ? '*/10 * * * * *' : '00 */1 * * * *', // every minute onTick: async () => await safe(scheduler.sync(), { debug }), start: true }); // randomized per Cloudron based on hourlySeed - gJobs.certificateRenew = new CronJob({ + gJobs.certificateRenew = CronJob.from({ cronTime: `00 10 ${hour} * * *`, onTick: async () => await safe(reverseProxy.startRenewCerts({}, AuditSource.CRON), { debug }), start: true }); - gJobs.appHealthMonitor = new CronJob({ + gJobs.appHealthMonitor = CronJob.from({ cronTime: '*/10 * * * * *', // every 10 seconds onTick: async () => await safe(appHealthMonitor.run(10), { debug }), // 10 is the max run time start: true @@ -189,7 +189,7 @@ async function handleBackupPolicyChanged(value) { if (gJobs.backup) gJobs.backup.stop(); gJobs.backup = null; - gJobs.backup = new CronJob({ + gJobs.backup = CronJob.from({ cronTime: value.schedule, onTick: async () => await safe(backups.startBackupTask(AuditSource.CRON), { debug }), start: true, @@ -217,7 +217,7 @@ async function handleAutoupdatePatternChanged(pattern) { if (pattern === constants.AUTOUPDATE_PATTERN_NEVER) return; - gJobs.autoUpdater = new CronJob({ + gJobs.autoUpdater = CronJob.from({ cronTime: pattern, onTick: async function() { const updateInfo = updateChecker.getUpdateInfo(); @@ -255,7 +255,7 @@ function handleDynamicDnsChanged(enabled) { if (!enabled) return; - gJobs.dynamicDns = new CronJob({ + gJobs.dynamicDns = CronJob.from({ // until we can be smarter about actual IP changes, lets ensure it every 10minutes cronTime: '00 */10 * * * *', onTick: async () => { await safe(dyndns.refreshDns(AuditSource.CRON), { debug }); }, @@ -271,7 +271,7 @@ async function handleExternalLdapChanged(config) { if (config.provider === 'noop') return; - gJobs.externalLdapSyncer = new CronJob({ + gJobs.externalLdapSyncer = CronJob.from({ cronTime: '00 00 */4 * * *', // every 4 hours onTick: async () => await safe(externalLdap.startSyncer(AuditSource.CRON), { debug }), start: true diff --git a/src/scheduler.js b/src/scheduler.js index 5add69f6e..f08c201bd 100644 --- a/src/scheduler.js +++ b/src/scheduler.js @@ -10,7 +10,7 @@ const apps = require('./apps.js'), assert = require('assert'), BoxError = require('./boxerror.js'), constants = require('./constants.js'), - CronJob = require('cron').CronJob, + { CronJob } = require('cron'), debug = require('debug')('box:scheduler'), docker = require('./docker.js'), safe = require('safetydance'), @@ -81,7 +81,7 @@ async function createJobs(app, schedulerConfig) { cronTime = (constants.TEST ? '*/5 ' : `${Math.floor(60*Math.random())} `) + schedule; // time ticks faster in tests } - const cronJob = new CronJob({ + const cronJob = CronJob.from({ cronTime, onTick: async () => { const [error] = await safe(runTask(appId, taskName)); // put the app id in closure, so we don't use the outdated app object by mistake diff --git a/src/updater.js b/src/updater.js index e8dd05429..7909044a9 100644 --- a/src/updater.js +++ b/src/updater.js @@ -18,7 +18,7 @@ const apps = require('./apps.js'), backuptask = require('./backuptask.js'), constants = require('./constants.js'), cron = require('./cron.js'), - CronJob = require('cron').CronJob, + { CronTime } = require('cron'), crypto = require('crypto'), debug = require('debug')('box:updater'), df = require('./df.js'), @@ -43,7 +43,7 @@ async function setAutoupdatePattern(pattern) { assert.strictEqual(typeof pattern, 'string'); if (pattern !== constants.AUTOUPDATE_PATTERN_NEVER) { // check if pattern is valid - const job = safe.safeCall(function () { return new CronJob(pattern); }); + const job = safe.safeCall(function () { return new CronTime(pattern); }); if (!job) throw new BoxError(BoxError.BAD_FIELD, 'Invalid pattern'); }