Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { connect as mongoConnect } from './db_connect';
import { resubscribeInvoices } from './ln';
import { logger } from './logger';
import { Telegraf } from 'telegraf';
import { delay } from './util';
import { delay, buildSocksProxyUrl } from './util';
import { imageCache } from './util/imageCache';
import { createIndexes } from './models/indexes';
import { CommunityContext } from './bot/modules/community/communityContext';
Expand Down Expand Up @@ -50,9 +50,7 @@ import { startMonitoring } from './monitoring';
const socksProxyHost = process.env.SOCKS_PROXY_HOST?.trim();
const telegramAgent = socksProxyHost
? (() => {
const proxyUrl = /^socks[45]?:\/\//i.test(socksProxyHost)
? socksProxyHost
: `socks5://${socksProxyHost}`;
const proxyUrl = buildSocksProxyUrl(socksProxyHost);
logger.info(`Using SOCKS proxy for Telegram API: ${proxyUrl}`);
return new SocksProxyAgent(proxyUrl) as any;
})()
Expand Down
30 changes: 30 additions & 0 deletions tests/util/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
toKebabCase,
getDetailedOrder,
getUserI18nContext,
buildSocksProxyUrl,
} from '../../util/index';

const { expect } = require('chai');
Expand Down Expand Up @@ -222,4 +223,33 @@ describe('Utility Functions', () => {
expect(ctx.locale()).to.equal('en');
});
});

describe('buildSocksProxyUrl', () => {
// Guards a regression (#826) where socks5h:// (used with Tor to resolve
// DNS through the proxy) was treated as a bare host and got a scheme
// prepended twice, producing an invalid URL like socks5://socks5h://...
['socks', 'socks4', 'socks5', 'socks5h'].forEach(scheme => {
it(`passes through URLs with the ${scheme}:// scheme unchanged`, () => {
const url = `${scheme}://localhost:9050`;
expect(buildSocksProxyUrl(url)).to.equal(url);
});
});

it('is case-insensitive when matching the scheme', () => {
const url = 'SOCKS5H://localhost:9050';
expect(buildSocksProxyUrl(url)).to.equal(url);
});

it('prepends socks5:// to a bare host with no scheme', () => {
expect(buildSocksProxyUrl('localhost:9050')).to.equal(
'socks5://localhost:9050',
);
});

it('prepends socks5:// to an unsupported scheme, such as socks4h', () => {
expect(buildSocksProxyUrl('socks4h://localhost:9050')).to.equal(
'socks5://socks4h://localhost:9050',
);
});
});
});
6 changes: 6 additions & 0 deletions util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,12 @@ export const removeLightningPrefix = (invoice: string) => {
return invoice;
};

export const buildSocksProxyUrl = (socksProxyHost: string) => {
return /^(?:socks|socks4|socks5|socks5h):\/\//i.test(socksProxyHost)
? socksProxyHost
: `socks5://${socksProxyHost}`;
};

const generateRandomImage = (nonce: string) => {
// Import imageCache here to avoid circular dependency
const { imageCache } = require('./imageCache');
Expand Down