From b8c51d332b611a4297533e812302571e905012d0 Mon Sep 17 00:00:00 2001 From: undefined Date: Mon, 23 Jan 2023 19:06:30 +0800 Subject: [PATCH] core: support session.domain --- packages/hydrooj/src/entry/common.ts | 2 +- packages/hydrooj/src/model/setting.ts | 2 + packages/hydrooj/src/service/layers/base.ts | 41 ++++++++----------- packages/hydrooj/src/service/server.ts | 2 + packages/ui-default/pages/user_verify.page.ts | 3 +- 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/packages/hydrooj/src/entry/common.ts b/packages/hydrooj/src/entry/common.ts index 81aff283..2733a1d8 100644 --- a/packages/hydrooj/src/entry/common.ts +++ b/packages/hydrooj/src/entry/common.ts @@ -48,7 +48,7 @@ const getLoader = (type: LoadTask, filename: string) => async function loader(pe fail.push(i); app.inject( 'Notification', `${name} load fail: {0}`, - { args: [i] }, PRIV.PRIV_VIEW_SYSTEM_NOTIFICATION, + { args: [i], type: 'warn' }, PRIV.PRIV_VIEW_SYSTEM_NOTIFICATION, ); logger.info(`${name} load fail: %s`, i); logger.error(e); diff --git a/packages/hydrooj/src/model/setting.ts b/packages/hydrooj/src/model/setting.ts index 81174843..a9cf3329 100644 --- a/packages/hydrooj/src/model/setting.ts +++ b/packages/hydrooj/src/model/setting.ts @@ -202,6 +202,7 @@ SystemSetting( Setting('setting_server', 'server.port', 8888, 'number', 'server.port', 'Server Port'), Setting('setting_server', 'server.xff', null, 'text', 'server.xff', 'IP Header'), Setting('setting_server', 'server.xhost', null, 'text', 'server.xhost', 'Hostname Header'), + Setting('setting_server', 'server.xproxy', false, 'boolean', 'server.xproxy', 'Use reverse_proxy'), Setting('setting_server', 'server.language', 'zh_CN', langRange, 'server.language', 'Default display language'), Setting('setting_server', 'server.login', true, 'boolean', 'server.login', 'Allow builtin-login', FLAG_PRO), Setting('setting_server', 'server.message', true, 'boolean', 'server.message', 'Allow users send messages'), @@ -232,6 +233,7 @@ SystemSetting( Setting('setting_basic', 'pagination.reply', 50, 'number', 'pagination.reply', 'Replies per page'), Setting('setting_session', 'session.keys', [String.random(32)], 'text', 'session.keys', 'session.keys', FLAG_HIDDEN), Setting('setting_session', 'session.secure', false, 'boolean', 'session.secure', 'session.secure', FLAG_HIDDEN), + Setting('setting_session', 'session.domain', '', 'text', 'session.domain', 'session.domain', FLAG_HIDDEN), Setting('setting_session', 'session.saved_expire_seconds', 3600 * 24 * 30, 'number', 'session.saved_expire_seconds', 'Saved session expire seconds'), Setting('setting_session', 'session.unsaved_expire_seconds', 3600 * 3, diff --git a/packages/hydrooj/src/service/layers/base.ts b/packages/hydrooj/src/service/layers/base.ts index 9817c526..c7663e61 100644 --- a/packages/hydrooj/src/service/layers/base.ts +++ b/packages/hydrooj/src/service/layers/base.ts @@ -1,8 +1,9 @@ import { PassThrough } from 'stream'; -import { cloneDeep } from 'lodash'; +import type { Next } from 'koa'; +import { cloneDeep, pick } from 'lodash'; import * as system from '../../model/system'; import token from '../../model/token'; -import type { HydroRequest, HydroResponse } from '../server'; +import type { HydroRequest, HydroResponse, KoaContext } from '../server'; export interface UiContextBase { cdn_prefix: string; @@ -15,32 +16,18 @@ export const UiContextBase: UiContextBase = { ws_prefix: '/', }; -export default async (ctx, next) => { +export default async (ctx: KoaContext, next: Next) => { // Base Layer const { domainId, domainInfo } = ctx; - const isWebsocket = ctx.request.headers.upgrade === 'websocket'; - const [xff, xhost] = system.getMany(['server.xff', 'server.xhost']); - // ignore reverse_proxy chains - const ipHeader = ctx.request.headers[xff?.toLowerCase() || ''] || ctx.request.ip; - const ip = (typeof ipHeader === 'string' ? ipHeader : ipHeader[0]).split(',')[0].trim(); - const host = ctx.request.headers[xhost?.toLowerCase() || ''] as string || ctx.request.host; const request: HydroRequest = { method: ctx.request.method.toLowerCase(), - host, - hostname: ctx.request.hostname, - ip, - headers: ctx.request.headers, - cookies: ctx.cookies, + ...pick(ctx.request, ['host', 'hostname', 'ip', 'headers']), + ...pick(ctx, ['query', 'path', 'params', 'originalPath', 'querystring', 'cookies']), body: ctx.request.body, files: ctx.request.files as any, - query: ctx.query, - querystring: ctx.querystring, - path: ctx.path, - originalPath: ctx.originalPath, - params: ctx.params, referer: ctx.request.headers.referer || '', json: (ctx.request.headers.accept || '').includes('application/json'), - websocket: isWebsocket, + websocket: ctx.request.headers.upgrade === 'websocket', }; const response: HydroResponse = { body: {}, @@ -78,18 +65,24 @@ export default async (ctx, next) => { const expireSeconds = ctx.session.save ? system.get('session.saved_expire_seconds') : system.get('session.unsaved_expire_seconds'); - Object.assign(ctx.session, { updateIp: ip, updateUa: ua }); + Object.assign(ctx.session, { updateIp: request.ip, updateUa: ua }); if (ctx.session._id) { await token.update(ctx.session._id, token.TYPE_SESSION, expireSeconds, ctx.session); } else { - Object.assign(ctx.session, { createIp: ip, createUa: ua, createHost: host }); + Object.assign(ctx.session, { createIp: request.ip, createUa: ua, createHost: request.host }); [ctx.session._id] = await token.add(token.TYPE_SESSION, expireSeconds, ctx.session); } if (!request.websocket) { - ctx.cookies.set('sid', ctx.session._id, { + const options: any = { expires: new Date(Date.now() + expireSeconds * 1000), secure: !!system.get('session.secure'), httpOnly: false, - }); + }; + if (system.get('session.domain')) { + options.domain = system.get('session.domain'); + options.sameSite = 'none'; + options.secure = true; + } + ctx.cookies.set('sid', ctx.session._id, options); } }; diff --git a/packages/hydrooj/src/service/server.ts b/packages/hydrooj/src/service/server.ts index 29737906..618f271a 100644 --- a/packages/hydrooj/src/service/server.ts +++ b/packages/hydrooj/src/service/server.ts @@ -96,6 +96,8 @@ export const router = new Router(); export const httpServer = http.createServer(app.callback()); export const wsServer = new WebSocket.Server({ server: httpServer }); export const captureAllRoutes = {}; +app.proxy = !!system.get('server.xproxy') || !!system.get('server.xff'); +app.proxyIpHeader = system.get('server.xff'); app.on('error', (error) => { if (error.code !== 'EPIPE' && error.code !== 'ECONNRESET' && !error.message.includes('Parse Error')) { logger.error('Koa app-level error', { error }); diff --git a/packages/ui-default/pages/user_verify.page.ts b/packages/ui-default/pages/user_verify.page.ts index 2618d18e..2b8224ae 100644 --- a/packages/ui-default/pages/user_verify.page.ts +++ b/packages/ui-default/pages/user_verify.page.ts @@ -87,7 +87,8 @@ export default new AutoloadPage('user_verify', () => { const challenge = await verifywebauthn($form); if (challenge) $form['authnChallenge'].value = challenge; else return; - } else $form['tfa'].value = $('[name="tfa_code"]').val() as string; + } else if (action === 'tfa') $form['tfa'].value = $('[name="tfa_code"]').val() as string; + else return; } $form.submit(); });