Ground-Zerro / Phobos Public
Code Issues Pull requests Actions Releases View on GitHub ↗
2.7 KB typescript
import { effectiveObfuscateBytes } from '../../shared/utils/obfuscation';
import { renderIni, type IniEntries } from './template';
import { wg } from './wgHelper';

import type { ClientType } from '#db/repositories/client/types';
import type { InterfaceType } from '#db/repositories/interface/types';
import type { ObfuscatorPresetType } from '#db/repositories/obfuscatorPreset/types';
import type { UserConfigType } from '#db/repositories/userConfig/types';

export type Socks5Credentials = { login: string; password: string };

export type ClientFullConfigInput = {
  iface: InterfaceType;
  userConfig: UserConfigType;
  client: ClientType;
  preset: ObfuscatorPresetType;
  enableIpv6: boolean;
  socks5Credentials: Socks5Credentials | null;
};

function instanceEntries(
  preset: ObfuscatorPresetType,
  iface: InterfaceType,
  localPort: number
): IniEntries {
  return [
    ['source-if', '127.0.0.1'],
    ['source-lport', localPort],
    [
      'target',
      `${iface.serverPublicDomain || iface.serverPublicIpV4}:${preset.extPort}`,
    ],
    ['key', preset.key],
    ['masking', preset.masking],
  ];
}

export function buildWireguardObfConf(
  preset: ObfuscatorPresetType,
  iface: InterfaceType
): string {
  return renderIni([
    [
      'instance',
      [
        ...instanceEntries(preset, iface, preset.clientWgLocalPort),
        ['obfuscate-bytes', effectiveObfuscateBytes(preset)],
        ['max-dummy', preset.dummy],
        ['verbose', preset.verbose],
      ],
    ],
  ]);
}

export function buildSocks5ObfConf(
  preset: ObfuscatorPresetType,
  iface: InterfaceType
): string {
  return renderIni([
    [
      'instance',
      [
        ['mode', 'socks5'],
        ['role', 'client'],
        ...instanceEntries(preset, iface, preset.clientLocalPort),
        ['verbose', preset.verbose],
        ['media-ssrc', preset.masking === 'MEDIA' ? preset.mediaSsrc : null],
      ],
    ],
  ]);
}

function buildSocks5CredentialsSection({
  login,
  password,
}: Socks5Credentials): string {
  return renderIni([
    [
      'socks5',
      [
        ['login', login],
        ['password', password],
      ],
    ],
  ]);
}

export function buildClientFullConfig({
  iface,
  userConfig,
  client,
  preset,
  enableIpv6,
  socks5Credentials,
}: ClientFullConfigInput): string {
  if (preset.mode === 'SOCKS5') {
    if (!socks5Credentials) {
      throw new Error(`Client ${client.id} has no SOCKS5 credentials`);
    }
    return `${buildSocks5ObfConf(preset, iface).trimEnd()}\n\n${buildSocks5CredentialsSection(socks5Credentials)}`;
  }

  const wgConfig = wg.generateClientConfig(iface, userConfig, client, {
    enableIpv6,
    clientWgLocalPort: preset.clientWgLocalPort,
  });
  return `${wgConfig.trimEnd()}\n\n${buildWireguardObfConf(preset, iface)}`;
}