fix: certificate expiration not detected if happened while running

Massimo Melina committed Nov 6, 2023 at 00:41 UTC 98b7861457914d2a6485e7b243f6cb1ae848d683
2 files changed +35 -4
src/cross.ts
+21
@@ -339,3 +339,24 @@ export async function promiseBestEffort<T>(promises: Promise<T>[]) {
339 const res = await Promise.allSettled(promises)
340 return res.filter(x => x.status === 'fulfilled').map((x: any) => x.value as T)
341 }
342 +
343 +export function runAt(ts: number, cb: Callback) {
344 + let cancel = false
345 + let t: any
346 + setTimeout(async () => {
347 + if (missing() < 0) return
348 + const max = 0x7FFFFFFF
349 + while (!cancel && missing() > max)
350 + await wait(max)
351 + if (cancel) return
352 + t = setTimeout(cb, missing())
353 +
354 + function missing() {
355 + return ts - Date.now()
356 + }
357 + })
358 + return () => {
359 + cancel = true
360 + clearTimeout(t)
361 + }
362 +}
\ No newline at end of file
src/listen.ts
+14 -4
@@ -8,7 +8,7 @@ import { watchLoad } from './watchLoad'
8 import { networkInterfaces } from 'os';
9 import { newConnection } from './connections'
10 import open from 'open'
11 -import { debounceAsync, ipForUrl, objSameKeys, onlyTruthy, wait, waitFor } from './misc'
11 +import { debounceAsync, ipForUrl, objSameKeys, onlyTruthy, runAt, wait, waitFor } from './misc'
12 import { ADMIN_URI, argv, DEV, IS_WINDOWS } from './const'
13 import findProcess from 'find-process'
14 import { anyAccountCanLoginAdmin } from './adminApis'
@@ -96,9 +96,19 @@ const considerHttps = debounceAsync(async () => {
96 if (cn)
97 console.log("certificate loaded for", cn)
98 const now = new Date()
99 - httpsSrv.error = new Date(cert.validFrom) > now ? "certificate not valid yet"
100 - : new Date(cert.validTo) < now ? "certificate expired"
101 - : undefined
99 + const from = new Date(cert.validFrom)
100 + const to = new Date(cert.validTo)
101 + updateError() // error will change at from and to dates of the certificate
102 + const cancelTo = runAt(to.getTime(), updateError)
103 + const cancelFrom = runAt(from.getTime(), updateError)
104 + httpsSrv.on('close', () => {
105 + cancelTo()
106 + cancelFrom()
107 + })
108 + function updateError() {
109 + if (!httpsSrv) return
110 + httpsSrv.error = from > now ? "certificate not valid yet" : to < now ? "certificate expired" : undefined
111 + }
112
113 const namesForOutput: any = { cert: 'certificate', private_key: 'private key' }
114 const missing = httpsNeeds.find(x => !x.get())?.key()