fix: admin/internet: crash if an IPv6 (no square brackets) is entered as main address
Massimo Melina committed
Jun 8, 2026 at 15:27 UTC
fad79616a1cb93653108a817622e18dc2423939a
2 files changed
+9
-7
admin/src/FileForm.ts
+5
-4
@@ -10,7 +10,8 @@ import { apiCall, UseApi, useApiEx } from './api'
10
import {
11
basename, defaultPerms, formatBytes, formatTimestamp, isWhoObject, newDialog, useRequestRender, try_, pathEncode,
12
onlyTruthy, prefix, VfsPerms, wantArray, WhoVfs, WhoObject, matches, xlate, md, Callback, copyTextToClipboard,
13
- splitAt, IMAGE_FILEMASK, CFG, MASK_IN_TESTS, WHO_ANY_ACCOUNT, WHO_ADMIN, WHO_NO_ONE, WHO_ANYONE,
13
+ splitAt, IMAGE_FILEMASK, CFG, MASK_IN_TESTS, WHO_ANY_ACCOUNT, WHO_ADMIN, WHO_NO_ONE, WHO_ANYONE, stringBefore,
14
+ ipForUrl
15
} from './misc'
16
import { isModifiedConfig } from './AccountForm'
17
import { Btn, Flex, IconBtn, LinkBtn, propsForModifiedValues, useBreakpoint, wikiLink } from './mui'
@@ -294,7 +295,7 @@ export function WhoField({ value, onChange, parent, inherit, accountsApi, helper
295
296
const timeout = 500
297
const arrayMode = Array.isArray(thisValue)
297
- // a large side band will convey union across the fields
298
+ // a large sideband will convey union across the fields
299
return h(Box, { sx: { borderRight: objectMode ? '8px solid #8884' : undefined, transition: `all ${timeout}ms` } },
300
h(SelectField as typeof SelectField<typeof thisValue | null>, {
301
...rest,
@@ -466,7 +467,7 @@ export async function changeBaseUrl() {
467
title: "Main address",
468
Content() {
469
const [v, setV] = useState(base_url || '')
469
- const proto = new URL(v || urls[0]).protocol + '//'
470
+ const proto = stringBefore('//', v || urls[0]) + '//'
471
const host = urls.includes(v) ? '' : v.slice(proto.length)
472
const check = h(Check, { sx: { ml: 2 } })
473
return h(Box, { sx: { display: 'flex', flexDirection: 'column' } },
@@ -486,7 +487,7 @@ export async function changeBaseUrl() {
487
label: "Custom IP or domain",
488
helperText: md("You can type any address but *you* are responsible to make the address work.\nThis functionality is just to help you copy the link in case you have a domain or a complex network configuration."),
489
value: host,
489
- onChange: v => set(prefix(proto, v)),
490
+ onChange: v => set(prefix(proto, ipForUrl(v))),
491
start: h(SelectField as Field<string>, {
492
value: proto,
493
onChange: v => host ? set(v + host) : toast("Enter domain first"),
src/cross.ts
+4
-3
@@ -179,9 +179,9 @@ export function stringAfter(sub: string, all: string) {
179
return i < 0 ? '' : all.slice(i + sub.length)
180
}
181
182
-export function stringBefore(sub: string, all: string, returnEmptyWhenSubMissing=true) {
182
+export function stringBefore(sub: string, all: string, returnEmptyWhenSubIsMissing=true) {
183
const i = all.indexOf(sub)
184
- return i >= 0 ? all.slice(0, i + sub.length - 1) : returnEmptyWhenSubMissing ? '' : all
184
+ return i >= 0 ? all.slice(0, i) : returnEmptyWhenSubIsMissing ? '' : all
185
}
186
187
export function truthy<T>(value: T): value is Truthy<T> {
@@ -461,7 +461,8 @@ export function isIpLan(ip: string) {
461
}
462
463
export function ipForUrl(ip: string) {
464
- return ip.includes(':') ? '[' + ip + ']' : ip
464
+ const i = ip.indexOf(':')
465
+ return i >= 0 && ip.indexOf(':', i + 1) >= 0 ? `[${ip}]` : ip
466
}
467
468
export function escapeHTML(text: string) {