Commit d2efb2e2 authored by nanahira's avatar nanahira

fix injection issue

parent 6c592e61
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
"@types/ws": "^8.5.3", "@types/ws": "^8.5.3",
"koa": "^2.13.4", "koa": "^2.13.4",
"koa-bodyparser": "^4.3.0", "koa-bodyparser": "^4.3.0",
"koishi-thirdeye": "^11.0.2", "koishi-thirdeye": "^11.0.4",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"typed-reflector": "^1.0.11", "typed-reflector": "^1.0.11",
"ws": "^8.7.0" "ws": "^8.7.0"
...@@ -2844,9 +2844,9 @@ ...@@ -2844,9 +2844,9 @@
} }
}, },
"node_modules/cordis-decorators": { "node_modules/cordis-decorators": {
"version": "1.0.16", "version": "1.0.17",
"resolved": "https://registry.npmjs.org/cordis-decorators/-/cordis-decorators-1.0.16.tgz", "resolved": "https://registry.npmjs.org/cordis-decorators/-/cordis-decorators-1.0.17.tgz",
"integrity": "sha512-S5XULywHemcob+KqSItv3kAo1mNRjbDchmfrKJALYs3wqzp4q4PPZRQftbW5SVuLReSis14hgwTHbgoXNGJVEA==", "integrity": "sha512-Y3FB4Aa1irDRQOGSLht3Dtwovza94KFjYCst6HrtPQE9nWzTKa3vUAZp0kIOBCaY/G/fNgAAd3O6TA27jgcouA==",
"dependencies": { "dependencies": {
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mustache": "^4.2.0", "mustache": "^4.2.0",
...@@ -5720,14 +5720,14 @@ ...@@ -5720,14 +5720,14 @@
} }
}, },
"node_modules/koishi-thirdeye": { "node_modules/koishi-thirdeye": {
"version": "11.0.2", "version": "11.0.4",
"resolved": "https://registry.npmjs.org/koishi-thirdeye/-/koishi-thirdeye-11.0.2.tgz", "resolved": "https://registry.npmjs.org/koishi-thirdeye/-/koishi-thirdeye-11.0.4.tgz",
"integrity": "sha512-0Mk1Nb3OwAaONgVE5YIFpHI4QHGQlQlfMC9r2Am8+FKKyxL0oqivg9eiJJj7eopTpZ8c8WBPdoFlJl9MEDs4PA==", "integrity": "sha512-R/p+YePSjnBsZalaJy+U9gkvJae2wiOn7rZeg+mFU/gEtxQ38roh7dyIaB+IWXYnc7k4+6VqEa52DHqPZtxh0Q==",
"dependencies": { "dependencies": {
"lodash": "^4.17.21", "lodash": "^4.17.21",
"minato-decorators": "^2.0.8", "minato-decorators": "^2.0.8",
"rxjs": "^7.5.6", "rxjs": "^7.5.6",
"satori-decorators": "^1.0.8" "satori-decorators": "^1.0.10"
}, },
"peerDependencies": { "peerDependencies": {
"koishi": "^4.8.1", "koishi": "^4.8.1",
...@@ -7048,13 +7048,13 @@ ...@@ -7048,13 +7048,13 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"node_modules/satori-decorators": { "node_modules/satori-decorators": {
"version": "1.0.8", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/satori-decorators/-/satori-decorators-1.0.8.tgz", "resolved": "https://registry.npmjs.org/satori-decorators/-/satori-decorators-1.0.10.tgz",
"integrity": "sha512-9AbhozP7pRc82mtDydOeiQSBfhnKBjM7bzk3sh8TKbI8EWh+58cykpXwYNMKUya8eRkvs3jlKtAdoArBzuOPFw==", "integrity": "sha512-kIHEFq8FGWEq7jn8zglEeD3qV6fSS8phpMJVuJ0qWVY1M+r9wKfBSQw8zvE2f6DECIFH0xDii0aIepaOgfLCUA==",
"dependencies": { "dependencies": {
"@types/koa": "^2.13.5", "@types/koa": "^2.13.5",
"@types/koa__router": "^8.0.11", "@types/koa__router": "^8.0.11",
"cordis-decorators": "^1.0.16", "cordis-decorators": "^1.0.17",
"lodash": "^4.17.21" "lodash": "^4.17.21"
}, },
"peerDependencies": { "peerDependencies": {
...@@ -10491,9 +10491,9 @@ ...@@ -10491,9 +10491,9 @@
} }
}, },
"cordis-decorators": { "cordis-decorators": {
"version": "1.0.16", "version": "1.0.17",
"resolved": "https://registry.npmjs.org/cordis-decorators/-/cordis-decorators-1.0.16.tgz", "resolved": "https://registry.npmjs.org/cordis-decorators/-/cordis-decorators-1.0.17.tgz",
"integrity": "sha512-S5XULywHemcob+KqSItv3kAo1mNRjbDchmfrKJALYs3wqzp4q4PPZRQftbW5SVuLReSis14hgwTHbgoXNGJVEA==", "integrity": "sha512-Y3FB4Aa1irDRQOGSLht3Dtwovza94KFjYCst6HrtPQE9nWzTKa3vUAZp0kIOBCaY/G/fNgAAd3O6TA27jgcouA==",
"requires": { "requires": {
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mustache": "^4.2.0", "mustache": "^4.2.0",
...@@ -12694,14 +12694,14 @@ ...@@ -12694,14 +12694,14 @@
} }
}, },
"koishi-thirdeye": { "koishi-thirdeye": {
"version": "11.0.2", "version": "11.0.4",
"resolved": "https://registry.npmjs.org/koishi-thirdeye/-/koishi-thirdeye-11.0.2.tgz", "resolved": "https://registry.npmjs.org/koishi-thirdeye/-/koishi-thirdeye-11.0.4.tgz",
"integrity": "sha512-0Mk1Nb3OwAaONgVE5YIFpHI4QHGQlQlfMC9r2Am8+FKKyxL0oqivg9eiJJj7eopTpZ8c8WBPdoFlJl9MEDs4PA==", "integrity": "sha512-R/p+YePSjnBsZalaJy+U9gkvJae2wiOn7rZeg+mFU/gEtxQ38roh7dyIaB+IWXYnc7k4+6VqEa52DHqPZtxh0Q==",
"requires": { "requires": {
"lodash": "^4.17.21", "lodash": "^4.17.21",
"minato-decorators": "^2.0.8", "minato-decorators": "^2.0.8",
"rxjs": "^7.5.6", "rxjs": "^7.5.6",
"satori-decorators": "^1.0.8" "satori-decorators": "^1.0.10"
} }
}, },
"leven": { "leven": {
...@@ -13704,13 +13704,13 @@ ...@@ -13704,13 +13704,13 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"satori-decorators": { "satori-decorators": {
"version": "1.0.8", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/satori-decorators/-/satori-decorators-1.0.8.tgz", "resolved": "https://registry.npmjs.org/satori-decorators/-/satori-decorators-1.0.10.tgz",
"integrity": "sha512-9AbhozP7pRc82mtDydOeiQSBfhnKBjM7bzk3sh8TKbI8EWh+58cykpXwYNMKUya8eRkvs3jlKtAdoArBzuOPFw==", "integrity": "sha512-kIHEFq8FGWEq7jn8zglEeD3qV6fSS8phpMJVuJ0qWVY1M+r9wKfBSQw8zvE2f6DECIFH0xDii0aIepaOgfLCUA==",
"requires": { "requires": {
"@types/koa": "^2.13.5", "@types/koa": "^2.13.5",
"@types/koa__router": "^8.0.11", "@types/koa__router": "^8.0.11",
"cordis-decorators": "^1.0.16", "cordis-decorators": "^1.0.17",
"lodash": "^4.17.21" "lodash": "^4.17.21"
} }
}, },
......
...@@ -52,7 +52,7 @@ const koishiContextProvider: Provider<Context> = { ...@@ -52,7 +52,7 @@ const koishiContextProvider: Provider<Context> = {
KoishiInterceptorManagerService, KoishiInterceptorManagerService,
KoishiExceptionHandlerService, KoishiExceptionHandlerService,
], ],
exports: [KoishiService, koishiContextProvider], exports: [koishiContextProvider],
}) })
export class KoishiModule implements NestModule { export class KoishiModule implements NestModule {
configure(consumer: MiddlewareConsumer) { configure(consumer: MiddlewareConsumer) {
......
...@@ -4,6 +4,7 @@ import { ...@@ -4,6 +4,7 @@ import {
Injectable, Injectable,
OnModuleDestroy, OnModuleDestroy,
OnModuleInit, OnModuleInit,
Scope,
} from '@nestjs/common'; } from '@nestjs/common';
import { import {
KoishiCommandInterceptorRegistration, KoishiCommandInterceptorRegistration,
...@@ -21,7 +22,9 @@ import { KoishiNestRouter } from './utility/koa-router'; ...@@ -21,7 +22,9 @@ import { KoishiNestRouter } from './utility/koa-router';
import './utility/koishi.workarounds'; import './utility/koishi.workarounds';
import './utility/koishi.declares'; import './utility/koishi.declares';
@Injectable() @Injectable({
scope: Scope.DEFAULT,
})
export class KoishiService export class KoishiService
extends Context extends Context
implements OnModuleInit, OnModuleDestroy implements OnModuleInit, OnModuleDestroy
...@@ -74,15 +77,18 @@ export class KoishiService ...@@ -74,15 +77,18 @@ export class KoishiService
} }
async onModuleInit() { async onModuleInit() {
if (this.forkedProvider) {
return;
}
await this.setHttpServer(); await this.setHttpServer();
this.metascan.preRegisterContext(this.any()); this.metascan.preRegisterContext(this);
if (this.koishiModuleOptions.usePlugins) { if (this.koishiModuleOptions.usePlugins) {
for (const pluginDef of this.koishiModuleOptions.usePlugins) { for (const pluginDef of this.koishiModuleOptions.usePlugins) {
this.plugin(pluginDef.plugin, pluginDef.options); this.plugin(pluginDef.plugin, pluginDef.options);
} }
} }
await this.metascan.registerContext(this.any()); await this.metascan.registerContext(this);
return this.start(); await this.start();
} }
async onModuleDestroy() { async onModuleDestroy() {
...@@ -95,4 +101,11 @@ export class KoishiService ...@@ -95,4 +101,11 @@ export class KoishiService
) { ) {
return this.metascan.addInterceptors(command, interceptorDefs); return this.metascan.addInterceptors(command, interceptorDefs);
} }
override extend(meta = {}): this {
return super.extend({
...meta,
forkedProvider: true,
});
}
} }
...@@ -24,7 +24,10 @@ export class KoishiInjectionService { ...@@ -24,7 +24,10 @@ export class KoishiInjectionService {
getInjectContext(inquerier: string | any) { getInjectContext(inquerier: string | any) {
const token = const token =
typeof inquerier === 'string' ? inquerier : inquerier.constructor; typeof inquerier === 'string' ? inquerier : inquerier?.constructor;
if (!token) {
return this.koishi;
}
const interceptors = this.metaFetcher.getMetadataArray( const interceptors = this.metaFetcher.getMetadataArray(
KoishiCommandInterceptorDef, KoishiCommandInterceptorDef,
token, token,
......
import { Injectable, NestMiddleware } from '@nestjs/common'; import { Inject, Injectable, NestMiddleware } from '@nestjs/common';
import { NextFunction } from 'express'; import { NextFunction } from 'express';
import { KoishiService } from '../koishi.service'; import { KoishiService } from '../koishi.service';
import { IncomingMessage, ServerResponse } from 'http'; import { IncomingMessage, ServerResponse } from 'http';
......
import { KoishiCommandInterceptorRegistration } from './koishi.interfaces'; import { KoishiCommandInterceptorRegistration } from './koishi.interfaces';
import { IntercepterManagerService } from './koishi.workarounds'; import { IntercepterManagerService } from './koishi.workarounds';
interface ContextInterceptorMeta { interface ContextNestMeta {
forkedProvider?: boolean;
interceptors: KoishiCommandInterceptorRegistration[]; interceptors: KoishiCommandInterceptorRegistration[];
} }
...@@ -9,11 +10,11 @@ declare module 'koishi' { ...@@ -9,11 +10,11 @@ declare module 'koishi' {
// eslint-disable-next-line @typescript-eslint/no-namespace // eslint-disable-next-line @typescript-eslint/no-namespace
namespace Context { namespace Context {
// eslint-disable-next-line @typescript-eslint/no-empty-interface // eslint-disable-next-line @typescript-eslint/no-empty-interface
interface Meta extends ContextInterceptorMeta {} interface Meta extends ContextNestMeta {}
} }
// eslint-disable-next-line @typescript-eslint/no-empty-interface // eslint-disable-next-line @typescript-eslint/no-empty-interface
interface Context extends ContextInterceptorMeta { interface Context extends ContextNestMeta {
$interceptorManager: IntercepterManagerService; $interceptorManager: IntercepterManagerService;
withInterceptors( withInterceptors(
interceptors: KoishiCommandInterceptorRegistration[], interceptors: KoishiCommandInterceptorRegistration[],
......
import { Command, Commander, Context } from 'koishi'; import { Command, Commander, Context } from 'koishi';
import { KoishiService } from '../koishi.service'; import { KoishiService } from '../koishi.service';
import { KoishiCommandInterceptorRegistration } from './koishi.interfaces'; import { KoishiCommandInterceptorRegistration } from './koishi.interfaces';
import { StarterPlugin } from 'koishi-thirdeye/dist/src/registrar';
import { Caller, DefinePlugin, Internal, Provide } from 'koishi-thirdeye';
// command interceptor supports // command interceptor supports
const oldCommand = Commander.prototype.command; const oldCommand = Commander.prototype.command;
...@@ -14,22 +16,19 @@ Commander.prototype.command = function (this: Commander, ...args: any[]) { ...@@ -14,22 +16,19 @@ Commander.prototype.command = function (this: Commander, ...args: any[]) {
return command; return command;
}; };
export class IntercepterManagerService { @Provide('$interceptorManager', { internal: true })
constructor(private ctx: Context) {} @DefinePlugin()
protected get caller(): Context { export class IntercepterManagerService extends StarterPlugin() {
return this[Context.current] || this.ctx; @Caller()
} caller: Context;
static methods = ['withInterceptors'];
@Internal()
withInterceptors( withInterceptors(
interceptors: KoishiCommandInterceptorRegistration[], interceptors: KoishiCommandInterceptorRegistration[],
): Context { ): Context {
const ctx = this.caller; const ctx = this.caller;
return ctx['fork']({ return ctx.extend({
interceptors: [...(ctx.interceptors || []), ...interceptors], interceptors: [...(ctx.interceptors || []), ...interceptors],
}); });
} }
} }
Context.service('$interceptorManager', IntercepterManagerService);
...@@ -3,14 +3,13 @@ import { KoishiWsAdapter } from '../src/koishi.ws-adapter'; ...@@ -3,14 +3,13 @@ import { KoishiWsAdapter } from '../src/koishi.ws-adapter';
import http from 'http'; import http from 'http';
import request from 'supertest'; import request from 'supertest';
import { Context, Events, Session } from 'koishi'; import { Context, Events, Session } from 'koishi';
import { testingModule } from './utility/testing-module'; import { KoishiTestService, testingModule } from './utility/testing-module';
import { NestExpressApplication } from '@nestjs/platform-express'; import { NestExpressApplication } from '@nestjs/platform-express';
type EventName = keyof Events; type EventName = keyof Events;
describe('Koishi in Nest.js', () => { describe('Koishi in Nest.js', () => {
let app: NestExpressApplication; let app: NestExpressApplication;
let koishiApp: KoishiService; let koishiApp: Context;
beforeEach(async () => { beforeEach(async () => {
const moduleFixture = await testingModule(); const moduleFixture = await testingModule();
...@@ -89,6 +88,45 @@ describe('Koishi in Nest.js', () => { ...@@ -89,6 +88,45 @@ describe('Koishi in Nest.js', () => {
expect(methodCtx.filter(wrongSession2)).toBe(false); expect(methodCtx.filter(wrongSession2)).toBe(false);
}); });
it('should inject correct context', () => {
const testService = app.get(KoishiTestService);
expect(testService.ctx1).toBeDefined();
expect(testService.ctx2).toBeDefined();
expect(testService.ctx1.filter({ platform: 'discord' } as Session)).toBe(
true,
);
expect(testService.ctx1.filter({ platform: 'telegram' } as Session)).toBe(
false,
);
expect(testService.ctx2.filter({ platform: 'telegram' } as Session)).toBe(
false,
);
expect(
testService.ctx1.filter({
platform: 'discord',
userId: '111111111',
} as Session),
).toBe(true);
expect(
testService.ctx2.filter({
platform: 'discord',
userId: '111111111',
} as Session),
).toBe(true);
expect(
testService.ctx1.filter({
platform: 'discord',
userId: '111111112',
} as Session),
).toBe(true);
expect(
testService.ctx2.filter({
platform: 'discord',
userId: '111111112',
} as Session),
).toBe(false);
});
it('should handle command error', () => { it('should handle command error', () => {
const command = koishiApp.command('boo'); const command = koishiApp.command('boo');
expect(command).toBeDefined(); expect(command).toBeDefined();
......
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,
...@@ -12,10 +12,12 @@ import { ...@@ -12,10 +12,12 @@ import {
} from 'koishi-thirdeye'; } from 'koishi-thirdeye';
import { import {
CommandInterceptors, CommandInterceptors,
InjectContextUser,
UsingService, UsingService,
} from '../../src/utility/koishi.decorators'; } from '../../src/utility/koishi.decorators';
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { KoishiModule } from '../../src/koishi.module'; import { KoishiModule } from '../../src/koishi.module';
import { InjectContext } from '../../src/utility/koishi.decorators';
@Injectable() @Injectable()
class MooInterceptor implements KoishiCommandInterceptor { class MooInterceptor implements KoishiCommandInterceptor {
...@@ -49,16 +51,21 @@ class PeeInterceptor implements KoishiCommandInterceptor { ...@@ -49,16 +51,21 @@ class PeeInterceptor implements KoishiCommandInterceptor {
@OnPlatform('discord') @OnPlatform('discord')
@Injectable() @Injectable()
@CommandInterceptors(PooInterceptor) @CommandInterceptors(PooInterceptor)
class KoishiTestService { export class KoishiTestService {
constructor(
@InjectContext() public ctx1: Context,
@InjectContextUser('111111111') public ctx2: Context,
) {}
@OnGuild('1111111111') @OnGuild('1111111111')
@UseCommand('echo', 'hi') @UseCommand('echo', 'hi')
@CommandUsage('foo') @CommandUsage('foo')
async onEcho(@PutOption('content', '-c <content:string>') content: string) { async onEcho(@PutOption('content', '-c <content>') content: string) {
return `bot: ${content}`; return `bot: ${content}`;
} }
@UseCommand('boo') @UseCommand('boo')
async onBoo(@PutOption('content', '-c <content:string>') content: string) { async onBoo(@PutOption('content', '-c <content>') content: string) {
throw new NotFoundException(`boo: ${content}`); throw new NotFoundException(`boo: ${content}`);
} }
...@@ -107,5 +114,6 @@ export function testingModule() { ...@@ -107,5 +114,6 @@ export function testingModule() {
PooInterceptor, PooInterceptor,
PeeInterceptor, PeeInterceptor,
], ],
exports: [KoishiTestService],
}).compile(); }).compile();
} }
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