From 8dcecbcfa2c1c3cb6b6cd2b50c8ed6e3109e4873 Mon Sep 17 00:00:00 2001 From: William Mantly Date: Sun, 12 Jul 2026 17:41:57 -0400 Subject: [PATCH] Fix api-tokens date display + quiet authIO no-token log (#120) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - api_tokens.ejs: created_on/last_used_on come back from Redis as strings (model-redis only coerces fields with an explicit `type`), so `new Date(ms)` yielded "Invalid date". Use `moment(ms, "x")` (the hosts.ejs/dns.ejs precedent) which parses a numeric string-or-number as a Unix-ms timestamp. - api_tokens.ejs: `isExpired` is a class getter not serialized to the client JSON, so the "expired" badge never showed — compute expiry in the view via `Date.now() > Number(expires_at)`. Also guard the `last_used_on: 0` / falsy case (string "0" is truthy) so unset timestamps render "—" not "1970". - middleware/auth.js: authIO did `checkToken(socket.handshake.auth.token || 0)`, so any socket connect without a token (login page, pre-login) did an `AuthToken.get(0)` lookup and logged a noisy `EntryNotFound` trace. Guard: reject the socket with a generic 401 when there's no token (behavior- preserving — unauth sockets were already rejected; just no Redis lookup / 404). - dns_provider.js: drop a stray `console.log('currentDomains:', ...)` debug line in updateDomains() (unrelated, noticed while investigating). Co-authored-by: Claude --- nodejs/middleware/auth.js | 7 ++++++- nodejs/models/dns_provider.js | 1 - nodejs/views/api_tokens.ejs | 18 +++++++++++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/nodejs/middleware/auth.js b/nodejs/middleware/auth.js index a12b20a..29baf4d 100755 --- a/nodejs/middleware/auth.js +++ b/nodejs/middleware/auth.js @@ -37,7 +37,12 @@ async function auth(req, res, next){ async function authIO(socket, next){ try{ - let token = await Auth.checkToken(socket.handshake.auth.token || 0); + // No token in the handshake (e.g. a page hit before login, or a socket + // opened while logged out) → reject the socket cleanly without doing an + // AuthToken.get(0) lookup that throws a noisy EntryNotFound trace. + let tok = socket.handshake.auth && socket.handshake.auth.token; + if(!tok) return next(Auth.errors.login()); + let token = await Auth.checkToken(tok); socket.user = token.user; next(); }catch(error){ diff --git a/nodejs/models/dns_provider.js b/nodejs/models/dns_provider.js index f6e5640..6c0a671 100644 --- a/nodejs/models/dns_provider.js +++ b/nodejs/models/dns_provider.js @@ -200,7 +200,6 @@ class DnsProvider extends Table{ ...(domain.zoneId !== undefined ? {zoneId: domain.zoneId} : {}), }); } - console.log('currentDomains:', currentDomains) for(let domain of currentDomains){ if(!domain) continue diff --git a/nodejs/views/api_tokens.ejs b/nodejs/views/api_tokens.ejs index 5c57cb5..5aa27b0 100644 --- a/nodejs/views/api_tokens.ejs +++ b/nodejs/views/api_tokens.ejs @@ -43,13 +43,21 @@ } function fmtTime(ms){ - if(!ms) return '—'; - return moment(new Date(ms)).fromNow() + ' (' + moment(new Date(ms)).format('YYYY-MM-DD HH:mm') + ')'; + // created_on/last_used_on come back from Redis as strings (model-redis + // only coerces fields with an explicit `type`); moment(value, "x") parses + // a numeric string-or-number as a Unix-ms timestamp, unlike new Date(str). + if(!ms || Number(ms) === 0) return '—'; + var t = moment(ms, "x"); + if(!t.isValid()) return '—'; + return t.fromNow() + ' (' + t.format('YYYY-MM-DD HH:mm') + ')'; } function fmtExpiry(token){ - if(!token.expires_at) return 'never'; - if(token.isExpired) return 'expired'; - return '' + moment(new Date(token.expires_at)).fromNow() + ''; + // expires_at is type:number (a real number); isExpired is a class getter + // that is NOT serialized to the client, so compute expiry here. + var exp = Number(token.expires_at); + if(!exp) return 'never'; + if(Date.now() > exp) return 'expired'; + return '' + moment(exp, "x").fromNow() + ''; } function processToken(token){