core: support session.domain

pull/498/head
undefined 2 years ago
parent d20bf5b1e7
commit b8c51d332b

@ -48,7 +48,7 @@ const getLoader = (type: LoadTask, filename: string) => async function loader(pe
fail.push(i); fail.push(i);
app.inject( app.inject(
'Notification', `${name} load fail: {0}`, '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.info(`${name} load fail: %s`, i);
logger.error(e); logger.error(e);

@ -202,6 +202,7 @@ SystemSetting(
Setting('setting_server', 'server.port', 8888, 'number', 'server.port', 'Server Port'), 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.xff', null, 'text', 'server.xff', 'IP Header'),
Setting('setting_server', 'server.xhost', null, 'text', 'server.xhost', 'Hostname 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.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.login', true, 'boolean', 'server.login', 'Allow builtin-login', FLAG_PRO),
Setting('setting_server', 'server.message', true, 'boolean', 'server.message', 'Allow users send messages'), 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_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.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.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, Setting('setting_session', 'session.saved_expire_seconds', 3600 * 24 * 30,
'number', 'session.saved_expire_seconds', 'Saved session expire seconds'), 'number', 'session.saved_expire_seconds', 'Saved session expire seconds'),
Setting('setting_session', 'session.unsaved_expire_seconds', 3600 * 3, Setting('setting_session', 'session.unsaved_expire_seconds', 3600 * 3,

@ -1,8 +1,9 @@
import { PassThrough } from 'stream'; 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 * as system from '../../model/system';
import token from '../../model/token'; import token from '../../model/token';
import type { HydroRequest, HydroResponse } from '../server'; import type { HydroRequest, HydroResponse, KoaContext } from '../server';
export interface UiContextBase { export interface UiContextBase {
cdn_prefix: string; cdn_prefix: string;
@ -15,32 +16,18 @@ export const UiContextBase: UiContextBase = {
ws_prefix: '/', ws_prefix: '/',
}; };
export default async (ctx, next) => { export default async (ctx: KoaContext, next: Next) => {
// Base Layer // Base Layer
const { domainId, domainInfo } = ctx; 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 = { const request: HydroRequest = {
method: ctx.request.method.toLowerCase(), method: ctx.request.method.toLowerCase(),
host, ...pick(ctx.request, ['host', 'hostname', 'ip', 'headers']),
hostname: ctx.request.hostname, ...pick(ctx, ['query', 'path', 'params', 'originalPath', 'querystring', 'cookies']),
ip,
headers: ctx.request.headers,
cookies: ctx.cookies,
body: ctx.request.body, body: ctx.request.body,
files: ctx.request.files as any, 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 || '', referer: ctx.request.headers.referer || '',
json: (ctx.request.headers.accept || '').includes('application/json'), json: (ctx.request.headers.accept || '').includes('application/json'),
websocket: isWebsocket, websocket: ctx.request.headers.upgrade === 'websocket',
}; };
const response: HydroResponse = { const response: HydroResponse = {
body: {}, body: {},
@ -78,18 +65,24 @@ export default async (ctx, next) => {
const expireSeconds = ctx.session.save const expireSeconds = ctx.session.save
? system.get('session.saved_expire_seconds') ? system.get('session.saved_expire_seconds')
: system.get('session.unsaved_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) { if (ctx.session._id) {
await token.update(ctx.session._id, token.TYPE_SESSION, expireSeconds, ctx.session); await token.update(ctx.session._id, token.TYPE_SESSION, expireSeconds, ctx.session);
} else { } 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); [ctx.session._id] = await token.add(token.TYPE_SESSION, expireSeconds, ctx.session);
} }
if (!request.websocket) { if (!request.websocket) {
ctx.cookies.set('sid', ctx.session._id, { const options: any = {
expires: new Date(Date.now() + expireSeconds * 1000), expires: new Date(Date.now() + expireSeconds * 1000),
secure: !!system.get('session.secure'), secure: !!system.get('session.secure'),
httpOnly: false, 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);
} }
}; };

@ -96,6 +96,8 @@ export const router = new Router();
export const httpServer = http.createServer(app.callback()); export const httpServer = http.createServer(app.callback());
export const wsServer = new WebSocket.Server({ server: httpServer }); export const wsServer = new WebSocket.Server({ server: httpServer });
export const captureAllRoutes = {}; export const captureAllRoutes = {};
app.proxy = !!system.get('server.xproxy') || !!system.get('server.xff');
app.proxyIpHeader = system.get('server.xff');
app.on('error', (error) => { app.on('error', (error) => {
if (error.code !== 'EPIPE' && error.code !== 'ECONNRESET' && !error.message.includes('Parse Error')) { if (error.code !== 'EPIPE' && error.code !== 'ECONNRESET' && !error.message.includes('Parse Error')) {
logger.error('Koa app-level error', { error }); logger.error('Koa app-level error', { error });

@ -87,7 +87,8 @@ export default new AutoloadPage('user_verify', () => {
const challenge = await verifywebauthn($form); const challenge = await verifywebauthn($form);
if (challenge) $form['authnChallenge'].value = challenge; if (challenge) $form['authnChallenge'].value = challenge;
else return; 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(); $form.submit();
}); });

Loading…
Cancel
Save