Files
3dp-manager/server/test/inbounds/inbound-builder.service.spec.ts
T
2026-03-29 03:58:07 +03:00

546 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import { Test, TestingModule } from '@nestjs/testing';
import { InboundBuilderService } from 'src/inbounds/inbound-builder.service';
// Mock crypto.randomBytes для детерминированных тестов
jest.mock('crypto', () => ({
randomBytes: jest.fn().mockReturnValue(Buffer.from('abcd1234', 'hex')),
randomFillSync: jest.fn((buffer: Buffer) => {
for (let i = 0; i < buffer.length; i++) {
buffer[i] = i;
}
return buffer;
}),
}));
describe('InboundBuilderService', () => {
let service: InboundBuilderService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [InboundBuilderService],
}).compile();
service = module.get<InboundBuilderService>(InboundBuilderService);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('buildVlessRealityTcp', () => {
const params = {
port: 443,
uuid: 'test-uuid-123',
sni: 'ya.ru',
privateKey: 'private-key',
publicKey: 'public-key',
};
it('должен создать конфиг vless-tcp-reality', () => {
const result = service.buildVlessRealityTcp(params);
expect(result).toMatchObject({
enable: true,
port: 443,
protocol: 'vless',
remark: 'vless-tcp-reality',
});
const settings = JSON.parse(result.settings);
expect(settings.clients[0].id).toBe('test-uuid-123');
expect(settings.clients[0].flow).toBe('xtls-rprx-vision');
});
it('должен установить Reality настройки', () => {
const result = service.buildVlessRealityTcp(params);
const streamSettings = JSON.parse(result.streamSettings);
expect(streamSettings.security).toBe('reality');
expect(streamSettings.realitySettings.target).toBe('ya.ru:443');
expect(streamSettings.realitySettings.serverNames).toContain('ya.ru');
expect(streamSettings.realitySettings.privateKey).toBe('private-key');
});
it('должен сгенерировать shortIds', () => {
const result = service.buildVlessRealityTcp(params);
const streamSettings = JSON.parse(result.streamSettings);
expect(streamSettings.realitySettings.shortIds).toHaveLength(2);
});
});
describe('buildVlessRealityXhttp', () => {
const params = {
port: 8443,
uuid: 'test-uuid-456',
sni: 'vk.com',
privateKey: 'private-key',
publicKey: 'public-key',
};
it('должен создать конфиг vless-xhttp-reality', () => {
const result = service.buildVlessRealityXhttp(params);
expect(result).toMatchObject({
enable: true,
port: 8443,
protocol: 'vless',
remark: 'vless-xhttp-reality',
});
const settings = JSON.parse(result.settings);
expect(settings.clients[0].id).toBe('test-uuid-456');
expect(settings.clients[0].flow).toBe('');
});
it('должен установить xhttp настройки', () => {
const result = service.buildVlessRealityXhttp(params);
const streamSettings = JSON.parse(result.streamSettings);
expect(streamSettings.security).toBe('reality');
expect(streamSettings.network).toBe('xhttp');
});
});
describe('buildVlessRealityGrpc', () => {
const params = {
port: 2053,
uuid: 'test-uuid-789',
sni: 'ok.ru',
privateKey: 'private-key',
publicKey: 'public-key',
};
it('должен создать конфиг vless-grpc-reality', () => {
const result = service.buildVlessRealityGrpc(params);
expect(result).toMatchObject({
enable: true,
port: 2053,
protocol: 'vless',
remark: 'vless-grpc-reality',
});
const streamSettings = JSON.parse(result.streamSettings);
expect(streamSettings.network).toBe('grpc');
expect(streamSettings.grpcSettings?.serviceName).toBeTruthy();
});
});
describe('buildVlessWs', () => {
const params = {
port: 10000,
uuid: 'test-uuid-ws',
sni: 'ozon.ru',
};
it('должен создать конфиг vless-ws', () => {
const result = service.buildVlessWs(params);
expect(result).toMatchObject({
enable: true,
port: 10000,
protocol: 'vless',
remark: 'vless-ws',
});
const streamSettings = JSON.parse(result.streamSettings);
expect(streamSettings.network).toBe('ws');
});
it('должен установить ws настройки', () => {
const result = service.buildVlessWs(params);
const streamSettings = JSON.parse(result.streamSettings);
expect(streamSettings.wsSettings?.path).toBe('/');
});
});
describe('buildVmessTcp', () => {
const params = {
port: 20000,
uuid: 'test-uuid-vmess',
};
it('должен создать конфиг vmess-tcp', () => {
const result = service.buildVmessTcp(params);
expect(result).toMatchObject({
enable: true,
port: 20000,
protocol: 'vmess',
remark: 'vmess-tcp',
});
const settings = JSON.parse(result.settings);
expect(settings.clients[0].id).toBe('test-uuid-vmess');
});
});
describe('buildShadowsocksTcp', () => {
const params = {
port: 30000,
uuid: 'test-uuid-ss',
};
it('должен создать конфиг shadowsocks-tcp', () => {
const result = service.buildShadowsocksTcp(params);
expect(result).toMatchObject({
enable: true,
port: 30000,
protocol: 'shadowsocks',
remark: 'shadowsocks-tcp',
});
const settings = JSON.parse(result.settings);
expect(settings.method).toBe('2022-blake3-aes-256-gcm');
expect(settings.password).toBeTruthy(); // Генерируется из uuid
});
});
describe('buildTrojanRealityTcp', () => {
const params = {
port: 443,
uuid: 'test-uuid-trojan',
sni: 'ya.ru',
privateKey: 'private-key',
publicKey: 'public-key',
};
it('должен создать конфиг trojan-tcp-reality', () => {
const result = service.buildTrojanRealityTcp(params);
expect(result).toMatchObject({
enable: true,
port: 443,
protocol: 'trojan',
remark: 'trojan-tcp-reality',
});
const settings = JSON.parse(result.settings);
expect(settings.clients[0].password).toBeTruthy(); // Генерируется из uuid
});
it('должен установить Reality настройки для trojan', () => {
const result = service.buildTrojanRealityTcp(params);
const streamSettings = JSON.parse(result.streamSettings);
expect(streamSettings.security).toBe('reality');
expect(streamSettings.realitySettings.target).toBe('ya.ru:443');
});
});
describe('buildHysteria2Link', () => {
beforeEach(() => {
jest.spyOn(console, 'warn').mockImplementation(() => {});
});
afterEach(() => {
jest.restoreAllMocks();
});
it('должен создать ссылку hysteria2', () => {
const result = service.buildHysteria2Link(
'192.168.1.1',
'ya.ru',
'%F0%9F%92%AF%20hysteria2',
);
expect(result).toContain('hy2://');
expect(result).toContain('192.168.1.1');
// SNI может быть IP, если конфиг не найден
});
it('должен создать ссылку hysteria2 с портом', () => {
const result = service.buildHysteria2Link(
'192.168.1.1',
'ya.ru',
'%F0%9F%92%AF%20hysteria2',
443,
);
expect(result).toContain(':443');
});
});
describe('buildInboundLink', () => {
const baseInbound = {
protocol: 'vless',
port: 443,
remark: 'vless-tcp-reality',
settings: JSON.stringify({
clients: [{ id: 'test-uuid', flow: 'xtls-rprx-vision' }],
}),
streamSettings: JSON.stringify({
network: 'tcp',
security: 'reality',
realitySettings: {
serverNames: ['ya.ru'],
publicKey: 'public-key',
},
}),
};
it('должен создать ссылку vless reality', () => {
const result = service.buildInboundLink(
baseInbound as any,
'192.168.1.1',
'test-uuid',
'%F0%9F%92%AF',
);
expect(result).toContain('vless://');
expect(result).toContain('192.168.1.1');
expect(result).toContain('443');
});
it('должен создать ссылку vless reality с xhttp', () => {
const inbound = {
protocol: 'vless',
port: 8443,
remark: 'vless-xhttp-reality',
settings: JSON.stringify({
clients: [{ id: 'test-uuid', flow: '' }],
}),
streamSettings: JSON.stringify({
network: 'xhttp',
security: 'reality',
realitySettings: {
serverNames: ['ya.ru'],
publicKey: 'public-key',
settings: { publicKey: 'pk', fingerprint: 'random' },
shortIds: ['abc123'],
},
xhttpSettings: {
path: '/path',
host: 'ya.ru',
mode: 'auto',
},
}),
};
const result = service.buildInboundLink(
inbound as any,
'192.168.1.1',
'test-uuid',
'%F0%9F%92%AF',
);
expect(result).toContain('vless://');
expect(result).toContain('type=xhttp');
expect(result).toContain('path=%2Fpath');
});
it('должен создать ссылку vless reality с grpc', () => {
const inbound = {
protocol: 'vless',
port: 8443,
remark: 'vless-grpc-reality',
settings: JSON.stringify({
clients: [{ id: 'test-uuid', flow: '' }],
}),
streamSettings: JSON.stringify({
network: 'grpc',
security: 'reality',
realitySettings: {
serverNames: ['ya.ru'],
publicKey: 'public-key',
settings: { publicKey: 'pk', fingerprint: 'random' },
shortIds: ['abc123'],
},
grpcSettings: {
serviceName: 'grpc-service',
authority: 'ya.ru',
},
}),
};
const result = service.buildInboundLink(
inbound as any,
'192.168.1.1',
'test-uuid',
'%F0%9F%92%AF',
);
expect(result).toContain('vless://');
expect(result).toContain('type=grpc');
expect(result).toContain('serviceName=grpc-service');
});
it('должен создать ссылку vless с ws', () => {
const inbound = {
protocol: 'vless',
port: 443,
remark: 'vless-ws',
settings: JSON.stringify({
clients: [{ id: 'test-uuid' }],
}),
streamSettings: JSON.stringify({
network: 'ws',
security: 'tls',
wsSettings: {
path: '/ws',
headers: { Host: 'example.com' },
},
}),
};
const result = service.buildInboundLink(
inbound as any,
'192.168.1.1',
'test-uuid',
'%F0%9F%92%AF',
);
expect(result).toContain('vless://');
expect(result).toContain('type=ws');
expect(result).toContain('path=%2Fws');
});
it('должен создать ссылку vmess', () => {
const vmessInbound = {
protocol: 'vmess',
port: 20000,
remark: 'vmess-tcp',
settings: JSON.stringify({
clients: [{ id: 'test-uuid' }],
}),
streamSettings: JSON.stringify({
network: 'tcp',
}),
};
const result = service.buildInboundLink(
vmessInbound as any,
'192.168.1.1',
'test-uuid',
'%F0%9F%92%AF',
);
expect(result).toContain('vmess://');
});
it('должен создать ссылку shadowsocks', () => {
const ssInbound = {
protocol: 'shadowsocks',
port: 30000,
remark: 'shadowsocks-tcp',
settings: JSON.stringify({
method: '2022-blake3-aes-256-gcm',
password: 'test-password',
clients: [{ password: 'client-pass' }],
}),
streamSettings: JSON.stringify({
network: 'tcp',
}),
};
const result = service.buildInboundLink(
ssInbound as any,
'192.168.1.1',
'',
'%F0%9F%92%AF',
);
expect(result).toContain('ss://');
});
it('должен создать ссылку trojan', () => {
const trojanInbound = {
protocol: 'trojan',
port: 443,
remark: 'trojan-reality',
settings: JSON.stringify({
clients: [{ password: 'trojan-pass' }],
}),
streamSettings: JSON.stringify({
network: 'tcp',
security: 'reality',
realitySettings: {
serverNames: ['ya.ru'],
publicKey: 'public-key',
settings: { publicKey: 'pk', fingerprint: 'random' },
shortIds: ['abc123'],
},
}),
};
const result = service.buildInboundLink(
trojanInbound as any,
'192.168.1.1',
'trojan-pass',
'%F0%9F%92%AF',
);
expect(result).toContain('trojan://');
expect(result).toContain('security=reality');
});
it('должен вернуть пустую строку для trojan без reality', () => {
const trojanInbound = {
protocol: 'trojan',
port: 443,
remark: 'trojan',
settings: JSON.stringify({
clients: [{ password: 'pass' }],
}),
streamSettings: JSON.stringify({
network: 'tcp',
security: 'none',
}),
};
const result = service.buildInboundLink(
trojanInbound as any,
'192.168.1.1',
'pass',
'%F0%9F%92%AF',
);
expect(result).toBe('');
});
it('должен вернуть пустую строку для vless без reality settings', () => {
const vlessInbound = {
protocol: 'vless',
port: 443,
remark: 'vless',
settings: JSON.stringify({
clients: [{ id: 'uuid' }],
}),
streamSettings: JSON.stringify({
network: 'tcp',
security: 'reality',
realitySettings: null,
}),
};
const result = service.buildInboundLink(
vlessInbound as any,
'192.168.1.1',
'uuid',
'%F0%9F%92%AF',
);
expect(result).toBe('');
});
});
describe('generateUuid', () => {
it('должен сгенерировать UUID', () => {
const uuid = service.generateUuid();
expect(uuid).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
);
});
});
});