SECURITY: fix private config file leak
parent
ef8ab25f44
commit
377a5963c6
|
|
@ -1,3 +1,32 @@
|
||||||
{
|
{
|
||||||
"extends": "next/core-web-vitals"
|
"extends": "next/core-web-vitals",
|
||||||
}
|
"rules": {
|
||||||
|
"no-restricted-imports": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"group": [
|
||||||
|
"**/uptime.config"
|
||||||
|
],
|
||||||
|
"importNames": [
|
||||||
|
"workerConfig"
|
||||||
|
],
|
||||||
|
"message": "Do not import workerConfig in client-bundled files. See https://github.com/lyc8503/UptimeFlare/issues/198 for details."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"pages/api/data.ts",
|
||||||
|
"middleware.ts"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"no-restricted-imports": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
A more advanced, serverless, and free uptime monitoring & status page solution, powered by Cloudflare Workers, complete with a user-friendly interface.
|
A more advanced, serverless, and free uptime monitoring & status page solution, powered by Cloudflare Workers, complete with a user-friendly interface.
|
||||||
|
|
||||||
|
📢 **[SECURITY 2026/03/04]** A vulnerability that could expose monitor configuration and credentials in `uptime.config.ts` to clients was fixed. Versions between 2025-09-21 (from commit `41257c6`) and 2026-03-04 are affected. **Affected users are strongly advised to upgrade to the latest version.**
|
||||||
|
|
||||||
🎉 **[UPDATE 2026/01/03]** I have just migrated UptimeFlare from KV to D1 Database. I also updated the Terraform Cloudflare provider to v5 and improved the deployment process. The data structure has been optimized to resolve long-standing performance issues.
|
🎉 **[UPDATE 2026/01/03]** I have just migrated UptimeFlare from KV to D1 Database. I also updated the Terraform Cloudflare provider to v5 and improved the deployment process. The data structure has been optimized to resolve long-standing performance issues.
|
||||||
|
|
||||||
New users can deploy directly, while existing users can have a simple auto migration process (upgrade docs below)! Feel free to open an issue if you run into any trouble deploying.
|
New users can deploy directly, while existing users can have a simple auto migration process (upgrade docs below)! Feel free to open an issue if you run into any trouble deploying.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import Head from 'next/head'
|
||||||
|
|
||||||
import { Inter } from 'next/font/google'
|
import { Inter } from 'next/font/google'
|
||||||
import { MaintenanceConfig, MonitorTarget } from '@/types/config'
|
import { MaintenanceConfig, MonitorTarget } from '@/types/config'
|
||||||
import { maintenances, pageConfig, workerConfig } from '@/uptime.config'
|
import { maintenances, pageConfig } from '@/uptime.config'
|
||||||
import Header from '@/components/Header'
|
import Header from '@/components/Header'
|
||||||
import { Box, Button, Center, Container, Group, Select } from '@mantine/core'
|
import { Box, Button, Center, Container, Group, Select } from '@mantine/core'
|
||||||
import Footer from '@/components/Footer'
|
import Footer from '@/components/Footer'
|
||||||
|
|
@ -25,7 +25,8 @@ function getSelectedMonth() {
|
||||||
|
|
||||||
function filterIncidentsByMonth(
|
function filterIncidentsByMonth(
|
||||||
incidents: MaintenanceConfig[],
|
incidents: MaintenanceConfig[],
|
||||||
monthStr: string
|
monthStr: string,
|
||||||
|
monitors: MonitorTarget[]
|
||||||
): (Omit<MaintenanceConfig, 'monitors'> & { monitors: MonitorTarget[] })[] {
|
): (Omit<MaintenanceConfig, 'monitors'> & { monitors: MonitorTarget[] })[] {
|
||||||
return incidents
|
return incidents
|
||||||
.filter((incident) => {
|
.filter((incident) => {
|
||||||
|
|
@ -35,7 +36,7 @@ function filterIncidentsByMonth(
|
||||||
})
|
})
|
||||||
.map((e) => ({
|
.map((e) => ({
|
||||||
...e,
|
...e,
|
||||||
monitors: (e.monitors || []).map((e) => workerConfig.monitors.find((mon) => mon.id === e)!),
|
monitors: (e.monitors || []).map((e) => monitors.find((mon) => mon.id === e)!),
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => (new Date(a.start) > new Date(b.start) ? -1 : 1))
|
.sort((a, b) => (new Date(a.start) > new Date(b.start) ? -1 : 1))
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +54,7 @@ function getPrevNextMonth(monthStr: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function IncidentsPage() {
|
export default function IncidentsPage({ monitors }: { monitors: MonitorTarget[] }) {
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
const [selectedMonitor, setSelectedMonitor] = useState<string | null>('')
|
const [selectedMonitor, setSelectedMonitor] = useState<string | null>('')
|
||||||
const [selectedMonth, setSelectedMonth] = useState(getSelectedMonth())
|
const [selectedMonth, setSelectedMonth] = useState(getSelectedMonth())
|
||||||
|
|
@ -64,7 +65,7 @@ export default function IncidentsPage() {
|
||||||
return () => window.removeEventListener('hashchange', onHashChange)
|
return () => window.removeEventListener('hashchange', onHashChange)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const filteredIncidents = filterIncidentsByMonth(maintenances, selectedMonth)
|
const filteredIncidents = filterIncidentsByMonth(maintenances, selectedMonth, monitors)
|
||||||
const monitorFilteredIncidents = selectedMonitor
|
const monitorFilteredIncidents = selectedMonitor
|
||||||
? filteredIncidents.filter((i) => i.monitors.find((e) => e.id === selectedMonitor))
|
? filteredIncidents.filter((i) => i.monitors.find((e) => e.id === selectedMonitor))
|
||||||
: filteredIncidents
|
: filteredIncidents
|
||||||
|
|
@ -73,7 +74,7 @@ export default function IncidentsPage() {
|
||||||
|
|
||||||
const monitorOptions = [
|
const monitorOptions = [
|
||||||
{ value: '', label: t('All') },
|
{ value: '', label: t('All') },
|
||||||
...workerConfig.monitors.map((monitor) => ({
|
...monitors.map((monitor) => ({
|
||||||
value: monitor.id,
|
value: monitor.id,
|
||||||
label: monitor.name,
|
label: monitor.name,
|
||||||
})),
|
})),
|
||||||
|
|
@ -131,3 +132,13 @@ export default function IncidentsPage() {
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getServerSideProps() {
|
||||||
|
const { workerConfig } = await import('@/uptime.config')
|
||||||
|
// Only present these values to client
|
||||||
|
const monitors: MonitorTarget[] = workerConfig.monitors.map((monitor) => ({
|
||||||
|
id: monitor.id,
|
||||||
|
name: monitor.name,
|
||||||
|
})) as MonitorTarget[]
|
||||||
|
return { props: { monitors } }
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import Head from 'next/head'
|
||||||
|
|
||||||
import { Inter } from 'next/font/google'
|
import { Inter } from 'next/font/google'
|
||||||
import { MonitorTarget } from '@/types/config'
|
import { MonitorTarget } from '@/types/config'
|
||||||
import { maintenances, pageConfig, workerConfig } from '@/uptime.config'
|
import { maintenances, pageConfig } from '@/uptime.config'
|
||||||
import OverallStatus from '@/components/OverallStatus'
|
import OverallStatus from '@/components/OverallStatus'
|
||||||
import Header from '@/components/Header'
|
import Header from '@/components/Header'
|
||||||
import MonitorList from '@/components/MonitorList'
|
import MonitorList from '@/components/MonitorList'
|
||||||
|
|
@ -69,6 +69,7 @@ export default function Home({
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getServerSideProps() {
|
export async function getServerSideProps() {
|
||||||
|
const { workerConfig } = await import('@/uptime.config')
|
||||||
// Read state as string from storage, to avoid hitting server-side cpu time limit
|
// Read state as string from storage, to avoid hitting server-side cpu time limit
|
||||||
const compactedStateStr = await getFromStore(process.env as any, 'state')
|
const compactedStateStr = await getFromStore(process.env as any, 'state')
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue