merge: sync codex/fix/flash-no-catalog with master

This commit is contained in:
Tommaso Casaburi
2026-06-01 12:42:45 +07:00
8 changed files with 167 additions and 13 deletions
@@ -17,30 +17,34 @@ describe('comment-flag-selection', () => {
expect(hasCommentFlagsForDirectory({ features: { hasFlags: true }, title: '/pol/ - Politically Incorrect' })).toBe(true);
});
it('uses geographic location as the default for country flag boards', () => {
it('uses geographic location as the default for other flag boards', () => {
expect(
getCommentFlagOptionsForDirectory({
directoryCode: 'int',
directoryCode: 'fit',
features: { hasFlags: true },
title: '/int/ - International',
title: '/fit/ - Fitness',
}),
).toEqual([{ label: 'Geographic Location', value: 'country:auto' }]);
});
it('does not expose a flag selector on /bant/ but still publishes geographic location', () => {
it.each([
{ directoryCode: 'bant', title: '/bant/ - International/Random' },
{ directoryCode: 'int', title: '/int/ - International' },
{ directoryCode: 'sp', title: '/sp/ - Sports' },
])('does not expose a flag selector on /$directoryCode/ but still publishes geographic location', ({ directoryCode, title }) => {
expect(
getCommentFlagOptionsForDirectory({
directoryCode: 'bant',
directoryCode,
features: { hasFlags: true },
title: '/bant/ - International/Random',
title,
}),
).toEqual([]);
expect(
getCommentFlagPublishOptionsForDirectory({
directoryCode: 'bant',
directoryCode,
features: { hasFlags: true },
title: '/bant/ - International/Random',
title,
}),
).toEqual({
challengeRequest: {
+32
View File
@@ -37,6 +37,13 @@ describe('extractIpv6FromAddress', () => {
expect(extractIpv6FromAddress('/ip6/2001:4860:4860::8888/tcp/4001/ws')).toBe('2001:4860:4860::8888');
expect(extractIpFromAddress('/ip6/2001:4860:4860::8888/tcp/4001/ws')).toBe('2001:4860:4860::8888');
});
it('extracts an IPv6 embedded with dashes in a DNS hostname', () => {
const address = '/dns6/2a11-6100-0-5e9f--0.k51qzi5uqu5djg5pdoi9a98.example/tcp/443/wss/p2p/12D3KooWExample';
expect(extractIpv6FromAddress(address)).toBe('2a11:6100:0:5e9f::0');
expect(extractIpFromAddress(address)).toBe('2a11:6100:0:5e9f::0');
});
});
describe('isPrivateOrReservedIpv4', () => {
@@ -261,6 +268,31 @@ describe('fetchPeerMapLocation', () => {
vi.unstubAllGlobals();
});
it('resolves a peer location from a DNS6 hostname with an embedded IPv6', async () => {
const fetchMock = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({
cityName: 'Reykjavik',
countryCode: 'IS',
ipAddress: '2a11:6100:0:5e9f::0',
latitude: 64.1466,
longitude: -21.9426,
}),
});
vi.stubGlobal('fetch', fetchMock);
await expect(fetchPeerMapLocation('/dns6/2a11-6100-0-5e9f--0.k51qzi5uqu5djg5pdoi9a98.example/tcp/443/wss')).resolves.toMatchObject({
countryCode: 'is',
label: 'Reykjavik, IS',
lat: 64.1466,
lon: -21.9426,
source: 'geoip',
});
expect(fetchMock.mock.calls[0][0]).toBe('https://free.freeipapi.com/api/json/2a11%3A6100%3A0%3A5e9f%3A%3A0');
vi.unstubAllGlobals();
});
});
describe('getApproximateCountryCode', () => {
+1 -1
View File
@@ -38,7 +38,7 @@ const NO_FLAG_OPTION: CommentFlagSelectOption = {
};
/** Boards that always publish geographic location without showing a flag selector. */
const AUTO_GEOGRAPHIC_FLAG_DIRECTORY_CODES = new Set(['bant']);
const AUTO_GEOGRAPHIC_FLAG_DIRECTORY_CODES = new Set(['bant', 'int', 'sp']);
const getDirectoryCode = (directory: Pick<DirectoryCommunity, 'directoryCode' | 'title'> | undefined): string | undefined => {
const directoryCode = directory?.directoryCode?.trim().toLowerCase();
+11 -1
View File
@@ -284,7 +284,17 @@ export const extractIpv4FromAddress = (address: string): string | null => {
export const extractIpv6FromAddress = (address: string): string | null => {
const direct = /\/ip6\/([^/]+)/.exec(address);
return direct ? direct[1] : null;
if (direct) return direct[1];
const dns = /\/dns6\/([^/]+)/i.exec(address);
const firstLabel = dns?.[1]?.split('.')[0];
if (!firstLabel || !firstLabel.includes('-') || !/^[0-9a-f-]+$/i.test(firstLabel)) return null;
const candidate = firstLabel.replaceAll('-', ':').toLowerCase();
try {
new URL(`http://[${candidate}]/`);
return candidate;
} catch {
return null;
}
};
const parseOctets = (ip: string): number[] | null => {