Commit a465cb4d authored by nanahira's avatar nanahira

use origin IP provided by nest

parent b04a520b
...@@ -14,7 +14,7 @@ import { createServer, Server } from 'http'; ...@@ -14,7 +14,7 @@ import { createServer, Server } from 'http';
import Koa from 'koa'; import Koa from 'koa';
import KoaBodyParser from 'koa-bodyparser'; import KoaBodyParser from 'koa-bodyparser';
import { KoishiMetascanService } from './providers/koishi-metascan.service'; import { KoishiMetascanService } from './providers/koishi-metascan.service';
import { KOISHI_MODULE_OPTIONS } from './utility/koishi.constants'; import { KOISHI_MODULE_OPTIONS, KoishiIpSym } from './utility/koishi.constants';
import { KoishiLoggerService } from './providers/koishi-logger.service'; import { KoishiLoggerService } from './providers/koishi-logger.service';
import { KoishiHttpDiscoveryService } from './koishi-http-discovery/koishi-http-discovery.service'; import { KoishiHttpDiscoveryService } from './koishi-http-discovery/koishi-http-discovery.service';
import { Filter, ReplacedContext } from './utility/replaced-context'; import { Filter, ReplacedContext } from './utility/replaced-context';
...@@ -44,6 +44,10 @@ export class KoishiService ...@@ -44,6 +44,10 @@ export class KoishiService
this.baseDir ??= process.cwd(); this.baseDir ??= process.cwd();
this.globalInterceptors = this.koishiModuleOptions.globalInterceptors || []; this.globalInterceptors = this.koishiModuleOptions.globalInterceptors || [];
this.router = new Router(); this.router = new Router();
this._nestKoaTmpInstance.use((ctx, next) => {
ctx.request.ip = ctx.req[KoishiIpSym];
return next();
});
this._nestKoaTmpInstance.use(KoaBodyParser()); this._nestKoaTmpInstance.use(KoaBodyParser());
this._nestKoaTmpInstance.use(this.router.routes()); this._nestKoaTmpInstance.use(this.router.routes());
this._nestKoaTmpInstance.use(this.router.allowedMethods()); this._nestKoaTmpInstance.use(this.router.allowedMethods());
......
...@@ -4,12 +4,17 @@ import { KoishiService } from '../koishi.service'; ...@@ -4,12 +4,17 @@ import { KoishiService } from '../koishi.service';
import { IncomingMessage, ServerResponse } from 'http'; import { IncomingMessage, ServerResponse } from 'http';
import { Http2ServerRequest, Http2ServerResponse } from 'http2'; import { Http2ServerRequest, Http2ServerResponse } from 'http2';
import { parse } from 'url'; import { parse } from 'url';
import { KoishiIpSym } from '../utility/koishi.constants';
export type RequestWithOriginalUrl = IncomingMessage & { originalUrl?: string }; export type RequestExtended = IncomingMessage & {
originalUrl?: string;
ip?: string;
ips?: string[];
};
@Injectable() @Injectable()
export class KoishiMiddleware export class KoishiMiddleware
implements NestMiddleware<RequestWithOriginalUrl, ServerResponse> implements NestMiddleware<RequestExtended, ServerResponse>
{ {
private readonly koaCallback: ( private readonly koaCallback: (
req: IncomingMessage | Http2ServerRequest, req: IncomingMessage | Http2ServerRequest,
...@@ -19,7 +24,7 @@ export class KoishiMiddleware ...@@ -19,7 +24,7 @@ export class KoishiMiddleware
this.koaCallback = this.koishi._nestKoaTmpInstance.callback(); this.koaCallback = this.koishi._nestKoaTmpInstance.callback();
} }
use(req: RequestWithOriginalUrl, res: ServerResponse, next: NextFunction) { use(req: RequestExtended, res: ServerResponse, next: NextFunction) {
const exactUrl = req.originalUrl || req.url; const exactUrl = req.originalUrl || req.url;
const matchingUrl = parse(exactUrl).pathname || ''; const matchingUrl = parse(exactUrl).pathname || '';
const match = this.koishi.router.match(matchingUrl, req.method); const match = this.koishi.router.match(matchingUrl, req.method);
...@@ -27,6 +32,7 @@ export class KoishiMiddleware ...@@ -27,6 +32,7 @@ export class KoishiMiddleware
return next(); return next();
} }
req.url = exactUrl; req.url = exactUrl;
req[KoishiIpSym] = req.ip;
return this.koaCallback(req, res); return this.koaCallback(req, res);
} }
} }
...@@ -20,3 +20,5 @@ export interface MetadataArrayMap { ...@@ -20,3 +20,5 @@ export interface MetadataArrayMap {
} }
export interface MetadataMap {} export interface MetadataMap {}
export const KoishiIpSym = Symbol('KoishiIpSym');
...@@ -15,7 +15,9 @@ describe('Koishi module in Fastify adapter', () => { ...@@ -15,7 +15,9 @@ describe('Koishi module in Fastify adapter', () => {
beforeEach(async () => { beforeEach(async () => {
const moduleFixture = await testingModule(); const moduleFixture = await testingModule();
app = moduleFixture.createNestApplication<NestFastifyApplication>( app = moduleFixture.createNestApplication<NestFastifyApplication>(
new FastifyAdapter(), new FastifyAdapter({
trustProxy: true,
}),
); );
app.useWebSocketAdapter(new KoishiWsAdapter(app)); app.useWebSocketAdapter(new KoishiWsAdapter(app));
await app.init(); await app.init();
...@@ -46,4 +48,21 @@ describe('Koishi module in Fastify adapter', () => { ...@@ -46,4 +48,21 @@ describe('Koishi module in Fastify adapter', () => {
expect(res.body).toBe('pong'); expect(res.body).toBe('pong');
}); });
}); });
it('should response to koishi routes', () => {
koishiApp.router.get('/ip', (ctx) => {
ctx.status = 233;
ctx.body = ctx.ip;
});
return app
.inject({
method: 'GET',
url: '/ip',
headers: { 'x-forwarded-for': '1.1.1.1' },
})
.then((res) => {
expect(res.statusCode).toBe(233);
expect(res.body).toBe('1.1.1.1');
});
});
}); });
import { KoishiService } from '../src/koishi.service'; import { KoishiService } from '../src/koishi.service';
import { INestApplication } from '@nestjs/common';
import { KoishiWsAdapter } from '../src/koishi.ws-adapter'; import { KoishiWsAdapter } from '../src/koishi.ws-adapter';
import http from 'http'; import http from 'http';
import request from 'supertest'; import request from 'supertest';
import { Session } from 'koishi'; import { Session } from 'koishi';
import { testingModule } from './utility/testing-module'; import { testingModule } from './utility/testing-module';
import { NestExpressApplication } from '@nestjs/platform-express';
describe('Koishi in Nest.js', () => { describe('Koishi in Nest.js', () => {
let app: INestApplication; let app: NestExpressApplication;
let koishiApp: KoishiService; let koishiApp: KoishiService;
beforeEach(async () => { beforeEach(async () => {
const moduleFixture = await testingModule(); const moduleFixture = await testingModule();
app = moduleFixture.createNestApplication(); app = moduleFixture.createNestApplication<NestExpressApplication>();
app.useWebSocketAdapter(new KoishiWsAdapter(app)); app.useWebSocketAdapter(new KoishiWsAdapter(app));
app.set('trust proxy', ['loopback']);
await app.init(); await app.init();
koishiApp = app.get(KoishiService); koishiApp = app.get(KoishiService);
}); });
...@@ -43,6 +44,18 @@ describe('Koishi in Nest.js', () => { ...@@ -43,6 +44,18 @@ describe('Koishi in Nest.js', () => {
.expect('pong'); .expect('pong');
}); });
it('should be correct client ip', () => {
koishiApp.router.get('/ip', (ctx) => {
ctx.status = 233;
ctx.body = ctx.ip;
});
return request(app.getHttpServer())
.get('/ip')
.set('X-Forwarded-For', '1.1.1.1')
.expect(233)
.expect('1.1.1.1');
});
it('should register command', () => { it('should register command', () => {
const command = koishiApp.command('echo'); const command = koishiApp.command('echo');
expect(command._usage).toBe('foo'); expect(command._usage).toBe('foo');
......
import { Injectable, NotFoundException } from '@nestjs/common'; import { Injectable, NotFoundException } from '@nestjs/common';
import { KoishiCommandInterceptor } from '../../src/utility/koishi.interfaces'; import { KoishiCommandInterceptor } from '../../src/utility/koishi.interfaces';
import { Argv } from 'koishi'; import { Argv, Context } from 'koishi';
import { import {
CommandUsage, CommandUsage,
OnGuild, OnGuild,
OnPlatform, OnPlatform,
PluginDef,
PutOption, PutOption,
UseCommand, UseCommand,
} from 'koishi-decorators'; } from 'koishi-decorators';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment