removed allow_session_ip_change from config, as it's useless now that we have the same in the frontend
Massimo Melina committed
Mar 9, 2025 at 12:31 UTC
ac9f3a50db01a3fa3dcd6d095c21e9a646907401
7 files changed
+15
-18
admin/src/LoginRequired.ts
+4
-4
@@ -2,7 +2,7 @@
2
3
import { state, useSnapState } from './state'
4
import { createElement as h, Fragment, useEffect, useRef, useState } from 'react'
5
-import { CFG, HTTP_FORBIDDEN, HTTP_UNAUTHORIZED, makeSessionRefresher } from './misc'
5
+import { ALLOW_SESSION_IP_CHANGE, HTTP_FORBIDDEN, HTTP_UNAUTHORIZED, makeSessionRefresher } from './misc'
6
import { BoolField, Form } from '@hfs/mui-grid-form'
7
import { apiCall } from './api'
8
import { srpClientSequence } from '@hfs/shared'
@@ -22,7 +22,7 @@ export function LoginRequired({ children }: any) {
22
}
23
24
function LoginForm() {
25
- const [values, setValues] = useState({ username: '', password: '', ipChange: false })
25
+ const [values, setValues] = useState({ username: '', password: '', [ALLOW_SESSION_IP_CHANGE]: false })
26
const [error, setError] = useState('')
27
const formRef = useRef<HTMLFormElement>()
28
const empty = formRef.current?.querySelector('input[value=""]')
@@ -39,7 +39,7 @@ function LoginForm() {
39
fields: [
40
{ k: 'username', autoComplete: 'username', autoFocus: true, required: true },
41
{ k: 'password', type: 'password', autoComplete: 'current-password', required: true },
42
- { k: 'ipChange', comp: BoolField, label: "Allow IP change during this session" },
42
+ { k: ALLOW_SESSION_IP_CHANGE, comp: BoolField, label: "Allow IP change during this session" },
43
],
44
addToBar: [ error && h(Alert, { severity: 'error', sx: { flex: 1 } }, error) ],
45
saveOnEnter: true,
@@ -50,7 +50,7 @@ function LoginForm() {
50
try {
51
setError('')
52
await login(values.username, values.password, {
53
- [CFG.allow_session_ip_change]: values.ipChange
53
+ [ALLOW_SESSION_IP_CHANGE]: values[ALLOW_SESSION_IP_CHANGE]
54
})
55
}
56
catch(e) {
config.md
-1
@@ -121,7 +121,6 @@ Configuration can be done in several ways
121
Multiple URLs are supported, and you can specify one for each line.
122
- `outbound_proxy` if you need outgoing http(s) requests to pass through an HTTP proxy. Default is none.
123
- `auto_basic` automatically detect (based on user-agent) when the basic web interface should be served, to support legacy browsers. Default is true. No UI.
124
-- `allow_session_ip_change` should requests of the same login session be allowed from different IP addresses. Default is false, to prevent cookie stealing. You can set it `true` to always allow it, or `https` to allow only on https, where stealing the cookie is harder. No UI.
124
- `authorization_header` support Authentication HTTP header. Default is true. No UI.
125
- `cache_control_disk_files` number of seconds after which the browser should bypass the cache and check the server for an updated version of the file. Default is 5. No UI.
126
- `disable_custom_html` disable the content of `custom_html`. Default is false.
frontend/src/login.ts
+4
-4
@@ -5,7 +5,7 @@ import { state, useSnapState } from './state'
5
import { alertDialog, newDialog, toast } from './dialog'
6
import {
7
getHFS, hIcon, makeSessionRefresher, srpClientSequence, working, fallbackToBasicAuth,
8
- HTTP_CONFLICT, HTTP_UNAUTHORIZED, CFG, HTTP_METHOD_NOT_ALLOWED,
8
+ HTTP_CONFLICT, HTTP_UNAUTHORIZED, HTTP_METHOD_NOT_ALLOWED, ALLOW_SESSION_IP_CHANGE,
9
} from './misc'
10
import { createElement as h, Fragment, useEffect, useRef } from 'react'
11
import { reloadList } from './useFetchList'
@@ -107,8 +107,8 @@ export async function loginDialog(closable=true, reloadAfter=true) {
107
h('div', { className: 'submit' },
108
h('button', { type: 'submit' }, t`Continue`)),
109
h('div', { id: 'login-options' },
110
- h(Checkbox, { ref: ipRef, id: 'allow_session_ip_change' },
111
- t('allow_session_ip_change', "Allow IP change during this session")),
110
+ h(Checkbox, { ref: ipRef, id: ALLOW_SESSION_IP_CHANGE },
111
+ t(ALLOW_SESSION_IP_CHANGE, "Allow IP change during this session")),
112
),
113
)
114
@@ -131,7 +131,7 @@ export async function loginDialog(closable=true, reloadAfter=true) {
131
going = true
132
try {
133
const res = await login(u, password, {
134
- [CFG.allow_session_ip_change]: ipRef.current?.checked,
134
+ [ALLOW_SESSION_IP_CHANGE]: ipRef.current?.checked,
135
...rest
136
})
137
await close(true)
src/auth.ts
+3
-3
@@ -1,9 +1,9 @@
1
import { Account, getAccount, normalizeUsername, updateAccount } from './perm'
2
-import { HTTP_NOT_ACCEPTABLE, HTTP_SERVER_ERROR } from './cross-const'
2
+import { ALLOW_SESSION_IP_CHANGE, HTTP_NOT_ACCEPTABLE, HTTP_SERVER_ERROR } from './cross-const'
3
import { SRPParameters, SRPRoutines, SRPServerSession } from 'tssrp6a'
4
import { Context } from 'koa'
5
import { srpClientPart } from './srp'
6
-import { CFG, DAY } from './cross'
6
+import { DAY } from './cross'
7
import { expiringCache } from './expiringCache'
8
import { createHash } from 'node:crypto'
9
import events from './events'
@@ -67,7 +67,7 @@ export async function setLoggedIn(ctx: Context, username: string | false) {
67
await events.emitAsync('finalizingLogin', { ctx, username, inputs: { ...ctx.state.params, ...ctx.query } })
68
s.username = normalizeUsername(username)
69
s.ts = Date.now()
70
- const k = CFG.allow_session_ip_change
70
+ const k = ALLOW_SESSION_IP_CHANGE
71
s[k] = k in ctx.query || Boolean(ctx.state.params?.[k]) || undefined // login APIs will get ctx.state.params, others can rely on ctx.query
72
if (!a.expire && a.days_to_live)
73
updateAccount(a, { expire: new Date(Date.now() + a.days_to_live! * DAY) })
src/cross-const.ts
+1
@@ -12,6 +12,7 @@ export const UPLOAD_RESUMABLE = 'upload.resumable'
12
export const UPLOAD_RESUMABLE_HASH = 'upload.hash'
13
export const UPLOAD_REQUEST_STATUS = 'upload.status'
14
export const PREVIOUS_TAG = 'previous'
15
+export const ALLOW_SESSION_IP_CHANGE = 'allow_session_ip_change'
16
17
export const HTTP_OK = 200
18
export const HTTP_NO_CONTENT = 204
src/cross.ts
+1
-2
@@ -31,8 +31,7 @@ export const THEME_OPTIONS = { auto: '', light: 'light', dark: 'dark' }
31
export const CFG = constMap(['geo_enable', 'geo_allow', 'geo_list', 'geo_allow_unknown', 'dynamic_dns_url',
32
'log', 'error_log', 'log_rotation', 'dont_log_net', 'log_gui', 'log_api', 'log_ua', 'log_spam', 'track_ips',
33
'max_downloads', 'max_downloads_per_ip', 'max_downloads_per_account', 'roots', 'force_address', 'split_uploads',
34
- 'allow_session_ip_change', 'force_lang', 'suspend_plugins', 'base_url', 'size_1024', 'disable_custom_html',
35
- 'comments_storage'])
34
+ 'force_lang', 'suspend_plugins', 'base_url', 'size_1024', 'disable_custom_html', 'comments_storage'])
35
export const LIST = { add: '+', remove: '-', update: '=', props: 'props', ready: 'ready', error: 'e' }
36
export type Dict<T=any> = Record<string, T>
37
export type Falsy = false | null | undefined | '' | 0
src/middlewares.ts
+2
-4
@@ -3,7 +3,7 @@
3
import compress from 'koa-compress'
4
import Koa from 'koa'
5
import { API_URI, DEV, HTTP_FOOL } from './const'
6
-import { CFG, DAY, dirTraversal, isLocalHost, netMatches, splitAt, stream2string, tryJson } from './misc'
6
+import { ALLOW_SESSION_IP_CHANGE, DAY, dirTraversal, isLocalHost, netMatches, splitAt, stream2string, tryJson } from './misc'
7
import { Readable } from 'stream'
8
import { applyBlock } from './block'
9
import { Account, accountCanLogin, getAccount, getFromAccount } from './perm'
@@ -16,7 +16,6 @@ import session from 'koa-session'
16
import { app } from './index'
17
import events from './events'
18
19
-const allowSessionIpChange = defineConfig<boolean | 'https'>(CFG.allow_session_ip_change, false)
19
const forceHttps = defineConfig('force_https', true)
20
const ignoreProxies = defineConfig('ignore_proxies', false)
21
const allowAuthorizationHeader = defineConfig('authorization_header', true)
@@ -52,8 +51,7 @@ export let cloudflareDetected: undefined | Date
51
export const someSecurity: Koa.Middleware = (ctx, next) => {
52
ctx.request.ip = normalizeIp(ctx.ip)
53
const ss = ctx.session
55
- const allowIpChange = ss?.[allowSessionIpChange.key()] ?? allowSessionIpChange.get() // session can override server setting
56
- if (ss?.username && (!allowIpChange || !ctx.secure && allowIpChange === 'https'))
54
+ if (ss?.username && !ss?.[ALLOW_SESSION_IP_CHANGE])
55
if (!ss.ip)
56
ss.ip = ctx.ip
57
else if (ss.ip !== ctx.ip) {