x1ongzhu hace 1 año
padre
commit
a421f05d0d

+ 18 - 1
src/device/device.controller.ts

@@ -1,7 +1,8 @@
-import { Body, Controller, Delete, Param, Post } from '@nestjs/common'
+import { Body, Controller, Delete, Get, Param, Patch, Post } from '@nestjs/common'
 import { DeviceService } from './device.service'
 import { PageRequest } from 'src/common/dto/page-request'
 import { Device } from './entities/device.entity'
+import { Public } from 'src/auth/public.decorator'
 
 @Controller('device')
 export class DeviceController {
@@ -12,8 +13,24 @@ export class DeviceController {
         return await this.deviceService.findAllDevice(page)
     }
 
+    @Get('/:id')
+    @Public()
+    async findByIds(@Param('id') id: string) {
+        return await this.deviceService.findById(id)
+    }
+
     @Delete('/:id')
     async deviceDisconnect(@Param('id') id: string) {
         return await this.deviceService.deleteDevice(id)
     }
+
+    @Post('/pinCountry')
+    async pinCountry(@Body() body: { ids: number[]; country: string }) {
+        return await this.deviceService.pinCountry(body.ids, body.country)
+    }
+
+    @Post('/:id')
+    async updateDevice(@Param('id') id: string, @Body() data: any) {
+        return await this.deviceService.updateDevice1(id, data.pinCountry, data.clashProfile)
+    }
 }

+ 36 - 2
src/device/device.service.ts

@@ -1,17 +1,25 @@
-import { Injectable } from '@nestjs/common'
+import { Injectable, Logger } from '@nestjs/common'
 import { PageRequest } from '../common/dto/page-request'
 import { Device } from './entities/device.entity'
 import { Pagination, paginate } from 'nestjs-typeorm-paginate'
 import { InjectRepository } from '@nestjs/typeorm'
 import { In, Like, Repository } from 'typeorm'
+import { IpmoyuProvider } from '../proxy-provider/ipmoyu-provider'
 
 @Injectable()
 export class DeviceService {
+    private ipmoyuProvider: ProxyProvider = new IpmoyuProvider()
     constructor(
         @InjectRepository(Device)
         private deviceRepository: Repository<Device>
     ) {}
 
+    async findById(id: string) {
+        return await this.deviceRepository.findOneBy({
+            id
+        })
+    }
+
     async findAllDevice(req: PageRequest<Device>): Promise<Pagination<Device>> {
         return await paginate<Device>(this.deviceRepository, req.page, req.search)
     }
@@ -51,13 +59,39 @@ export class DeviceService {
     }
 
     async updateDevice(socketId: string, data: any) {
-        const device = await this.deviceRepository.findOneBy({ socketId })
+        let device = await this.deviceRepository.findOneBy({ socketId })
         if (device) {
             Object.assign(device, data)
             await this.deviceRepository.save(device)
         }
     }
 
+    async updateDevice1(id: string, country: string, clashProfile: string) {
+        let device = await this.deviceRepository.findOneBy({ id })
+        if (device) {
+            device.pinCountry = country
+            device.clashProfile = clashProfile
+            if (device.pinCountry && !device.clashProfile) {
+                const profiles = await this.ipmoyuProvider.genProfiles(device.pinCountry, 1)
+                device.clashProfile = profiles[0]
+            }
+            await this.deviceRepository.save(device)
+        }
+    }
+
+    async pinCountry(ids: number[], country: string) {
+        if (ids && ids.length > 0) {
+            if (country) {
+                const profiles = await this.ipmoyuProvider.genProfiles(country, ids.length)
+                for (let i = 0; i < ids.length; i++) {
+                    await this.deviceRepository.update(ids[i], { pinCountry: country, clashProfile: profiles[i] })
+                }
+            } else {
+                await this.deviceRepository.update(ids, { pinCountry: null, clashProfile: null })
+            }
+        }
+    }
+
     async findAvailableDevice(matchDevice?: string) {
         const where: any = { online: true, busy: false, canSend: true }
         if (matchDevice) {

+ 6 - 0
src/device/entities/device.entity.ts

@@ -25,4 +25,10 @@ export class Device {
 
     @Column({ default: false })
     busy: boolean
+
+    @Column({ nullable: true })
+    pinCountry: string
+
+    @Column({ type: 'text', nullable: true })
+    clashProfile: string
 }

+ 0 - 1
src/file/file.controller.ts

@@ -10,7 +10,6 @@ import { FileInterceptor } from '@nestjs/platform-express'
 export class FileController {
     constructor(private readonly fileService: FileService) {}
 
-    @Public()
     @Post('upload')
     @UseInterceptors(FileInterceptor('file'))
     public async uploadFile(@UploadedFile() file: Express.Multer.File) {

+ 3 - 0
src/proxy-provider/index.ts

@@ -0,0 +1,3 @@
+declare interface ProxyProvider {
+    genProfiles(country: string, num: number): Promise<string[]> 
+}

+ 44 - 0
src/proxy-provider/ipmoyu-provider.ts

@@ -0,0 +1,44 @@
+import { Logger } from '@nestjs/common'
+import axios from 'axios'
+import { readFileSync } from 'fs'
+import { resolve } from 'path'
+import * as randomstring from 'randomstring'
+
+export class IpmoyuProvider implements ProxyProvider {
+    async genProfiles(country, num) {
+        const {
+            data: { data: countryList }
+        } = await axios.get('http://global.ipmoyu.com/proxy/web/map/countryList', {
+            params: {
+                page: 1,
+                limit: 1000
+            }
+        })
+
+        let countryId = countryList.find((i) => i.abbr === country.toUpperCase())?.id
+        if (!countryId) {
+            Logger.log(`Invalid country ${country}, use US as default`)
+            country = 'US'
+        }
+        countryId = countryList.find((i) => i.abbr === country.toUpperCase())?.id
+        if (!countryId) {
+            throw new Error(`Invalid country ${country}`)
+        }
+
+        const template = readFileSync(resolve(__dirname, '../../views/template.yaml'), 'utf-8').toString()
+        return Array.from({ length: num }).map(() => {
+            return template
+                .replaceAll('$name', country)
+                .replaceAll('$server', 'global.ipmoyu.com')
+                .replaceAll('$port', '3000')
+                .replaceAll(
+                    '$username',
+                    `buyerevent_${countryId}_0_0_10_${randomstring.generate({
+                        length: 8,
+                        charset: 'alphanumeric'
+                    })}_15_1`
+                )
+                .replaceAll('$password', '123456')
+        })
+    }
+}

+ 24 - 0
src/proxy-provider/template.yaml

@@ -0,0 +1,24 @@
+mode: rule
+unified-delay: true
+proxies:
+  - {name: mcttmn0n, server: laboratory.mesgity.top, port: 15166, reality-opts: {public-key: NWDoTczcSP-hxIhhFQt8J_m9jCG554igEaOFr81ISyQ, short-id: 340026c5e60e}, client-fingerprint: chrome, type: vless, uuid: bde0c64d-1f42-46ef-a207-3d0adee29ee8, tls: true, tfo: false, skip-cert-verify: false, servername: yahoo.com, network: tcp}
+  - name: $name
+    type: socks5
+    server: $server
+    port: $port
+    username: $username
+    password: $password
+    dialer-proxy: mcttmn0n
+proxy-groups:
+  - name: 节点选择
+    type: select
+    proxies:
+      - $name
+rules:
+  - DOMAIN-SUFFIX,izouma.com,DIRECT
+  - IP-CIDR,47.98.225.28/32,DIRECT
+  - IP-CIDR,8.149.128.251/32,DIRECT
+  - DOMAIN-SUFFIX,baidu.com,DIRECT
+  - DOMAIN-SUFFIX,aliyuncs.com,DIRECT
+  - GEOIP,CN,DIRECT
+  - MATCH,节点选择

+ 0 - 2
src/sms/sms.controller.ts

@@ -9,13 +9,11 @@ import { Public } from '../auth/public.decorator'
 export class SmsController {
     constructor(private readonly smsService: SmsService) {}
 
-    @Public()
     @Post('/sendVerify')
     public async sendVerify(@Body() body: SendCodeDto) {
         return await this.smsService.sendVerify(body)
     }
 
-    @Public()
     @Post('/verify')
     public async verify(@Body() body: VerifyCodeDto) {
         return {

+ 0 - 1
src/sys-config/sys-config.admin.controller.ts

@@ -7,7 +7,6 @@ import { SysConfig } from './entities/sys-config.entity'
 
 @ApiTags('sys-config.admin')
 @Controller('/admin/sys-config')
-@Public()
 export class SysConfigAdminController {
     constructor(private readonly sysConfigService: SysConfigService) {}
 

+ 0 - 6
src/task/entities/task-item.entity.ts

@@ -36,10 +36,4 @@ export class TaskItem {
 
     @Column({ default: false })
     embed: boolean
-
-    @Column({ nullable: true })
-    country: string
-
-    @Column({ type: 'text', nullable: true })
-    clashProfile: string
 }

+ 0 - 1
src/users/users.controller.ts

@@ -81,7 +81,6 @@ export class UsersController {
         }
     }
 
-    @Public()
     @Get('/:userId/hasInvite')
     public async hasInvite(@Param('userId') userId: string) {
         return await this.usersService.hasInvite(parseInt(userId))

+ 24 - 0
views/template.yaml

@@ -0,0 +1,24 @@
+mode: rule
+unified-delay: true
+proxies:
+  - {name: mcttmn0n, server: laboratory.mesgity.top, port: 15166, reality-opts: {public-key: NWDoTczcSP-hxIhhFQt8J_m9jCG554igEaOFr81ISyQ, short-id: 340026c5e60e}, client-fingerprint: chrome, type: vless, uuid: bde0c64d-1f42-46ef-a207-3d0adee29ee8, tls: true, tfo: false, skip-cert-verify: false, servername: yahoo.com, network: tcp}
+  - name: $name
+    type: socks5
+    server: $server
+    port: $port
+    username: $username
+    password: $password
+    dialer-proxy: mcttmn0n
+proxy-groups:
+  - name: 节点选择
+    type: select
+    proxies:
+      - $name
+rules:
+  - DOMAIN-SUFFIX,izouma.com,DIRECT
+  - IP-CIDR,47.98.225.28/32,DIRECT
+  - IP-CIDR,8.149.128.251/32,DIRECT
+  - DOMAIN-SUFFIX,baidu.com,DIRECT
+  - DOMAIN-SUFFIX,aliyuncs.com,DIRECT
+  - GEOIP,CN,DIRECT
+  - MATCH,节点选择