Codebase audit: remove dead code, fix broken patterns, consolidate duplicates; v2.0.27
Publish Container / docker (push) Failing after 10m40s
Publish Container / docker (push) Failing after 10m40s
- Remove unused prop-types dep, deprecated useOutboundLinkTracking export - Fix missing linkClicks key in analyticsEvents initial state (B-01) - Export ADMIN_SESSION_COOKIE from auth.js; remove local copy in admin-auth.js (D-02) - Remove cookieFlags() wrapper in auth.js and study-helpers.js; use cookieSecureFlag() directly (U-04) - Remove ADMIN_SESSION_TTL_MS duplicate from config.js (D-01) - Remove DEFAULT_SEO/DEFAULT_LEGAL/DEFAULT_REDIRECT_RULES/DEFAULT_PODCAST_FEATURED_LINKS/DEFAULT_PUBLISH_STATE duplicates from config.js; re-export from helpers.js (D-04, fixes sitemapPaths divergence) - Fix email.js hardcoded fallback strings to use DEFAULT_RESEND_TO/DEFAULT_RESEND_REPLY_TO (M-02) - Remove duplicate normalizeIp, isPrivateOrLocalIp, normalizeRedirectPath, sanitizeUrl, sanitizeRedirectRules bodies from study-helpers.js; re-export from helpers.js (D-03) - Fix pruneStatsByDays to import VISITOR_RETENTION_DAYS_DEFAULT from config.js (B-02) - Fix createTitusDownloadToken to use DOWNLOAD_TOKEN_TTL_MS constant (B-03) - Remove normalizeMessageType duplicate from study-helpers.js (U-03/D-08) - Remove dead wantsWelcome variable in contact.js; use shouldSendWelcome (B-04) - Replace dynamic imports in contact.js with static imports (B-07) - Remove dead wantsWelcome=true in study-auth.js (B-05) - Merge duplicate import blocks in analytics.js and public.js (D-05, D-06) - Replace dynamic readFile re-import in nuggets-host-upload.js (B-06) - Replace hardcoded SITE_URL fallbacks with getCanonicalBaseUrl() (M-06) - Replace raw resend.emails.send in study-account.js with sendResendEmailWithRetry (M-01) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
1ddb8ee7be
commit
e158e1e53a
14 files changed
+58
-185
No files matched your search
+15
-82
@@ -1,6 +1,15 @@
|
||||
import { createHash, createHmac, randomUUID } from 'node:crypto'
|
||||
import path from 'node:path'
|
||||
import { parseCookies, cookieSecureFlag } from './helpers.js'
|
||||
import {
|
||||
parseCookies,
|
||||
cookieSecureFlag,
|
||||
normalizeIp,
|
||||
isPrivateOrLocalIp,
|
||||
normalizeRedirectPath,
|
||||
sanitizeUrl,
|
||||
sanitizeRedirectRules,
|
||||
} from './helpers.js'
|
||||
export { normalizeIp, isPrivateOrLocalIp, normalizeRedirectPath, sanitizeUrl, sanitizeRedirectRules } from './helpers.js'
|
||||
import {
|
||||
STUDY_SESSION_COOKIE,
|
||||
STUDY_SESSION_TTL_MS,
|
||||
@@ -9,6 +18,8 @@ import {
|
||||
EMAIL_OTP_MAX_ATTEMPTS,
|
||||
CONTACT_EMAIL_COOLDOWN_MS,
|
||||
DEFAULT_REDIRECT_RULES,
|
||||
VISITOR_RETENTION_DAYS_DEFAULT,
|
||||
DOWNLOAD_TOKEN_TTL_MS,
|
||||
} from './config.js'
|
||||
import { state } from './state.js'
|
||||
import { queueStudyRemindersWrite, queueStudyUsersWrite } from './data.js'
|
||||
@@ -130,10 +141,6 @@ export function getStudyAvatarUrl(subject) {
|
||||
|
||||
// ── Session management ─────────────────────────────────────────────────────
|
||||
|
||||
export function cookieFlags() {
|
||||
return cookieSecureFlag()
|
||||
}
|
||||
|
||||
export function createStudySession(userId) {
|
||||
const token = randomUUID()
|
||||
state.studySessions.set(token, { userId, expiresAt: Date.now() + STUDY_SESSION_TTL_MS })
|
||||
@@ -143,14 +150,14 @@ export function createStudySession(userId) {
|
||||
export function setStudySessionCookie(res, token) {
|
||||
res.append(
|
||||
'Set-Cookie',
|
||||
`${STUDY_SESSION_COOKIE}=${encodeURIComponent(token)}; Max-Age=${Math.floor(STUDY_SESSION_TTL_MS / 1000)}; Path=/; HttpOnly; SameSite=Lax${cookieFlags()}`,
|
||||
`${STUDY_SESSION_COOKIE}=${encodeURIComponent(token)}; Max-Age=${Math.floor(STUDY_SESSION_TTL_MS / 1000)}; Path=/; HttpOnly; SameSite=Lax${cookieSecureFlag()}`,
|
||||
)
|
||||
}
|
||||
|
||||
export function clearStudySessionCookie(res) {
|
||||
res.append(
|
||||
'Set-Cookie',
|
||||
`${STUDY_SESSION_COOKIE}=; Max-Age=0; Path=/; HttpOnly; SameSite=Lax${cookieFlags()}`,
|
||||
`${STUDY_SESSION_COOKIE}=; Max-Age=0; Path=/; HttpOnly; SameSite=Lax${cookieSecureFlag()}`,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -233,7 +240,7 @@ export function createTitusDownloadToken(email) {
|
||||
const token = randomUUID()
|
||||
state.titusDownloadTokens.set(token, {
|
||||
email,
|
||||
expiresAt: Date.now() + (10 * 60 * 1000),
|
||||
expiresAt: Date.now() + DOWNLOAD_TOKEN_TTL_MS,
|
||||
})
|
||||
return token
|
||||
}
|
||||
@@ -381,29 +388,6 @@ export function detectBot(userAgent) {
|
||||
return { isBot: false, reason: null }
|
||||
}
|
||||
|
||||
export function normalizeIp(rawIp) {
|
||||
if (!rawIp) return 'unknown'
|
||||
let ip = String(rawIp).trim()
|
||||
if (ip.includes(',')) ip = ip.split(',')[0].trim()
|
||||
if (ip.startsWith('::ffff:')) ip = ip.slice(7)
|
||||
if (ip === '::1') ip = '127.0.0.1'
|
||||
return ip || 'unknown'
|
||||
}
|
||||
|
||||
export function isPrivateOrLocalIp(ip) {
|
||||
return (
|
||||
ip === '127.0.0.1'
|
||||
|| ip === 'localhost'
|
||||
|| ip.startsWith('10.')
|
||||
|| ip.startsWith('192.168.')
|
||||
|| /^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(ip)
|
||||
|| ip.startsWith('fc')
|
||||
|| ip.startsWith('fd')
|
||||
|| ip.startsWith('fe80:')
|
||||
|| ip === 'unknown'
|
||||
)
|
||||
}
|
||||
|
||||
export function buildTopLocations(list, key) {
|
||||
const counts = {}
|
||||
for (const row of list) {
|
||||
@@ -455,7 +439,6 @@ export function recordHit(pathname, isBot = false, botReason = null) {
|
||||
}
|
||||
|
||||
export function pruneStatsByDays(daysRaw) {
|
||||
const { VISITOR_RETENTION_DAYS_DEFAULT, EMPTY_HIT_STATS: _unused } = { VISITOR_RETENTION_DAYS_DEFAULT: 180 }
|
||||
const days = Number(daysRaw)
|
||||
const retentionDays = Number.isFinite(days) && days > 0 ? Math.floor(days) : 180
|
||||
const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000
|
||||
@@ -505,51 +488,6 @@ export function pruneStatsByDays(daysRaw) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Redirect / URL helpers ─────────────────────────────────────────────────
|
||||
|
||||
export function normalizeRedirectPath(value) {
|
||||
if (typeof value !== 'string') return ''
|
||||
const trimmed = value.trim()
|
||||
if (!trimmed) return ''
|
||||
const withSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`
|
||||
const normalized = withSlash.replace(/\/+/g, '/')
|
||||
if (normalized === '/') return ''
|
||||
if (normalized.startsWith('/api/') || normalized.startsWith('/admin')) return ''
|
||||
return normalized
|
||||
}
|
||||
|
||||
export function sanitizeUrl(value) {
|
||||
if (typeof value !== 'string') return ''
|
||||
const trimmed = value.trim()
|
||||
if (!trimmed) return ''
|
||||
if (trimmed.startsWith('/')) return trimmed
|
||||
if (/^https?:\/\//i.test(trimmed)) return trimmed
|
||||
return ''
|
||||
}
|
||||
|
||||
export function sanitizeRedirectRules(value) {
|
||||
const source = Array.isArray(value) ? value : []
|
||||
const seen = new Set()
|
||||
const out = []
|
||||
|
||||
for (const item of source) {
|
||||
const pathValue = normalizeRedirectPath(item?.path)
|
||||
const target = sanitizeUrl(item?.target)
|
||||
const statusCode = Number(item?.statusCode) === 302 ? 302 : 301
|
||||
if (!pathValue || !target) continue
|
||||
if (seen.has(pathValue)) continue
|
||||
seen.add(pathValue)
|
||||
out.push({
|
||||
id: typeof item?.id === 'string' && item.id.trim() ? item.id.trim() : randomUUID(),
|
||||
path: pathValue,
|
||||
target,
|
||||
statusCode,
|
||||
})
|
||||
}
|
||||
|
||||
return out.length > 0 ? out : DEFAULT_REDIRECT_RULES
|
||||
}
|
||||
|
||||
// ── Contact / email tracking ───────────────────────────────────────────────
|
||||
|
||||
export function noteContactEmailCooldown(emailAddress) {
|
||||
@@ -609,11 +547,6 @@ export function extractResendMessageId(result) {
|
||||
return ''
|
||||
}
|
||||
|
||||
export function normalizeMessageType(value) {
|
||||
if (value === 'question' || value === 'testimony' || value === 'topic') return value
|
||||
return 'general'
|
||||
}
|
||||
|
||||
// ── Study reminder scheduler ───────────────────────────────────────────────
|
||||
|
||||
export async function scheduleStudyReminders(sendStudyReminderEmail) {
|
||||
|
||||
Reference in new issue
Block a user